Page 1 of 1

Advice on modifying Compiere source code

PostPosted: Mon Jun 20, 2005 4:49 am
by neilg
Please see reply below for the instructions for 2.5.2D. Things are alot simpler and you hardly have to change any original compiere source code at all.

This post is based on 2.5.1g

For any customizations to Compiere.

(1) Never modify the Compiere code directly. Compiere's original source code is referred to as the 'Reference'. We build it completely as originally released.
If you modify the source directly you will probably live long enough to regret this decision because then you are stuck forever with that version of code, and Compiere is constantly improving
(2) Reference these .jars (CClient.jar, etc... all the Compiere runtime jars) from your project. This project is a brand new separate project and will be quite small, apart from the Compiere jar files.
(3) Your jar - build it as a standalone from Compiere's.
It must be a completely new jar. The advantage is that deploying is MUCH smaller.
Incorporate any 3rd party libraries into this one jar, as part of the build.xml.
(4) Modify the CLASSPATH everywhere and put your own jar first in the searchpath so that it overrides Compiere's.
(5) If you really have to (HAVE TO) modify Compiere code then make a copy of the class and put it into your project under the same package as the original. Because of the classpath, your modifications to this file will take precedance.
(6) You will need to make mods to the webstart deployment stuff to download the new jar (and possibly for the new classpath), it is documented in Compilo I think.
(7) You can incorporate the source as jars into your new project so that you can still drill down into the source code (read only). (Your project is completely separate to Compiere, you only reference the compiled source code.)

Advantages of doing it this way are many. This was advised to me by someone MUCH more experienced than I am at Java and in hindsite I can recommend it as being the only way to go.

However, the build file is quite complex. The build I wrote includes a target for building the customizations, and also one for building the 'reference'. We don't touch the original but put certain 'patches' into the new code. This allows modifications to certain files of the reference build, at build time (e.g. RUN_Compiere2.bat, where you have to change the classpath to include your new jar first).

Another option, if you are working on a CVS server which is remote or low-bandwidth, is to put all the Compiere jars, 3rd party libraries, builds etc into a separate project. You then reference these jars in your new project. This avoids the problem of the CVS server always trying to synchronize large jars and build files (which change every time and if you forget to add the built jar into the .cvsignore ... if you find a way to get rid of it on the CVS or ever ignore it afterwards, let me know).

Anyone interested I will write further and share the relevant code.

Just my experience up-to-date.


PostPosted: Mon Jun 20, 2005 7:57 am
by red1
The world is interested in them Neil, i will make sure of that. :)

We welcome any writings and contributions to be public here, to ensure the OS journey completes itself.

Your advice is true and i shall write them into the Compilo document (credited to u for this part).

Remember. Contributors are priceless. Its the Universal Law. If we do not stake the flags on the ground, others will.


Source code coming up soon

PostPosted: Mon Jun 20, 2005 12:59 pm
by neilg
Hi Red1,


Source code coming up soon - just need to revise a bit then will post.

The original idea was not mine, as I said....

Maybe this should be in the contributors section. If so, who moves it?


PostPosted: Mon Jun 20, 2005 1:38 pm
by red1
Anything that has source codes in it and is directly for compiere goes into the Contributor's Corner. If u put it anywhere else, i will just move it for you. Dont bother about housekeeping. Just go crazy on the canvass.

And u shuld add in a bit of credits of others that helped u in your post. Somehow they are fated to be discovered by u and so they do have the same right of passage to immortality.

PostPosted: Thu Jun 23, 2005 5:08 pm
by neilg
I believe the info shared in this post is one of the more important to take heed of when implementing a new compiere project. You must find a way to extend the project without modifying the core.

These are not all my own ideas (who cares as long as it is shared) and none of them are patentable, and I consider them important enough to share URGENTLY. These concepts can make or break your project when it comes to upgrade time and save you MONTHS of work. That is why I consider this post critical. Several projects have helped confirm the beliefs shared here. (So it is independantly verified!) And comes from 2 years of personal experience with large customizations.

You've been warned :twisted:

PostPosted: Thu Jun 23, 2005 7:47 pm
by red1
'After receiving some rather stern warning from aboard, RED1 decides to redo his codes in a separate jar...' :oops:

PostPosted: Thu Jun 23, 2005 8:36 pm
by neilg
Well I still have to post the build.xml here in a palateable form, and the question remains, is it really practical to customize without EVER changing Compiere's stuff? ... and how does one go about it. If we solve this question, upgrades will be painless in comparison. Imagine, just downloading the most recent jars, then migrating, and no code changes.... bliss....

heres the build.xml

PostPosted: Thu Jun 23, 2005 9:29 pm
by neilg
Here is the build.xml.

I wrote it while on the time of NTier Software Services (S.A) - Red1, I've left this in as some possible advertising for them in compensation let me know if OK.

This is also based on the principle 'release early, release often'. I doubt if the build will work as presented because some things changed since I wrote it but it contains the core principles.

Code: Select all
<!-- ============================================= -->
<!-- NTier   (ntier build)                        -->
<!-- ============================================= -->
<!-- $Header: /home/cvs/NTier/src/build.xml,v 1.3 2005/06/18 11:22:19 ngordon Exp $ -->

<!-- Prerequisites: Ensure the compiereReference251g project has been built. -->
<!--             We must ensure the source jars are synchronized with the classes -->

<!-- Strategy:      -->
<!--            reference contains the reference distribution of Compiere with no changes -->
<!--             This was compiled from -->
<!--             the project 'compiereReference251g' then copied from the /compiere/Compiere2 folder -->
<!--            build/NTier contains the modified distribution (from reference, with changes) -->
<!--            Include all NTier required libraries into NTier.jar -->
<!--            compiere.jnlp needs to be customized, and it is built into compiereRootBase.jar -->
<!--            (compiere.jnlp is under serverRoot/src/web folder of the original project). -->
<!--            We extract the files from compiereRootBase.jar -->
<!--            and update the required files, then resign -->
<!--            -->
<!--            Copy install/Compiere2/build.xml (server build) over the install files -->

<!--            2005/06/08 modified to build in the libraryproject structure -->

<project name="NTier" default="NTierDistribute" basedir=".">

    This buildfile is used to build the NTier subproject within
    the Compiere project.

  <!-- set global properties for this build -->
  <property name="libProject.path" value="../../libraryproject" /> <!-- the path for the separated libraryproject project -->
  <property name="src" value="."/>
  <property name="build.dir" value="${libProject.path}/build"/>
  <property name="classes.dir" value="${libProject.path}/classes"/>
  <property name="ntiersrc.dir" value="./"/>
  <property name="dist.dir" value="${libProject.path}/etc"/>
  <property name="jar.originals" value="${libProject.path}/lib" />
  <property name="lib.path" value="${libProject.path}/lib"/>
  <property name="" value="NTier"/>
  <property name="patches" value="../config/patch" />
  <property name="build.reference" value="${libProject.path}/etc/reference" />      <!-- dont modify these resources -->
  <property name="keystore" value="../keystore/myKeystore" />      
  <property name="build.for.NTier" value="${build.dir}/NTier" />   
  <property name="test.home"   value="../test"/>
   <!-- patched to include NTier -->
  <property environment="env"/>

  <!-- set path to include the necessary jar files for javac -->
  <path id="project.class.path">
    <pathelement path="${classpath}"/>
    <pathelement path="${jar.originals}/CClient.jar"/>
    <pathelement path="${jar.originals}/CTools.jar"/>
    <pathelement path="${jar.originals}/CLooks.jar"/>
    <pathelement path="${jar.originals}/compiereRoot.jar"/>
    <pathelement path="${lib.path}/oracle.jar"/>
    <pathelement path="${lib.path}/servlet.jar"/>
     <pathelement path="${lib.path}/jasperreports-0.6.4.jar"/> <!-- Customization -->
     <pathelement path="${jar.originals}/Base.jar"/>
    <pathelement path="${jar.originals}/Print.jar"/>
    <pathelement path="${jar.originals}/dbPort.jar"/>
    <pathelement path="${jar.originals}/acrobat.jar"/>
    <pathelement path="${jar.originals}/CLooks.jar"/>
    <pathelement path="${jar.originals}/Extend.jar"/>
    <pathelement path="${jar.originals}/Interfaces.jar"/>

   <target name="clean">
       <!-- Delete the ${build.dir} directory trees -->
       <delete dir="${build.dir}"/>
       <delete file="${dist.dir}/${}.jar" failonerror="false"/>
  <target name="NTierInit" description="initialization target" depends="clean">
    <echo message="=========== Build NTier"/>
    <!-- create the time stamp -->
    <!-- create the build directory structure used by compile -->
    <mkdir dir="${build.dir}"/>
    <!-- check for the distribution directory -->
    <available file="${dist.dir}" type="dir" property="dist.dir.exists"/>

    <uptodate property="jar.uptodate"
      <srcfiles dir="${src}" includes="**/*.java"/>

  <target name="NTierMakedir" depends="NTierInit" unless="dist.dir.exists">
    <!-- create the distribution directory if not available -->
    <mkdir dir="${dist.dir}"/>

  <!-- =========================================== -->
  <!-- Compile                                     -->
  <!-- =========================================== -->
  <target name="NTierCompile" depends="NTierMakedir">
    <!-- compile the java code from ${src} into ${build.dir} -->
    <javac srcdir="${src}" destdir="${build.dir}" deprecation="off" source="1.4" target="1.4" debug="on">
      <classpath refid="project.class.path"/>
    <!-- copy all image & sound files from src to the build directory -->
    <copy todir="${build.dir}">
      <fileset dir="${src}">
        <include name="**/images/*"/>
        <include name="**/*.gif"/>
        <include name="**/*.jpg"/>
        <include name="**/*.wav"/>
        <include name="**/*.htm"/>
        <include name="**/*.html"/>
        <include name="**/*.jrxml"/>   <!-- Customization - jasper -->
        <include name="**/*.jasper"/>   <!-- Customization - jasper -->
        <include name="**/*.properties"/>
        <exclude name="**/package.html"/>

  <!-- =========================================== -->
  <!-- Distribution NTier.jar                      -->
  <!-- =========================================== -->
  <target name="NTierDistribute" depends="NTierCompile" unless="jar.uptodate">
    <!-- get included jars -->
   <unjar src="${lib.path}/jasperreports-0.6.4.jar" dest="${build.dir}" />
    <!-- put everything from ${build.dir} into the ${}.jar file -->
        <attribute name="Specification-Title" value="NTier"/>
        <attribute name="Specification-Version" value="${env.COMPIERE_VERSION}"/>
        <attribute name="Specification-Vendor" value="(C) NTier Software Services"/>
        <attribute name="Implementation-Title" value="NTier ${env.COMPIERE_VERSION}"/>
        <attribute name="Implementation-Version" value="${env.COMPIERE_VERSION} ${DSTAMP}-${TSTAMP}"/>
        <attribute name="Implementation-Vendor" value="${env.COMPIERE_VENDOR}"/>
        <attribute name="Implementation-URL" value=""/>
        <attribute name="Main-Class" value="org.compiere.Compiere"/>
        <attribute name="Class-Path" value="CTools.jar oracle.jar"/>
     <!-- sign the jar -->
     <echo>Warning keystore password hard coded here as myPassword</echo>
      <signjar jar="${dist.dir}/${}.jar"
   <!-- copy also to custom distribution -->
     <copy file="${dist.dir}/${}.jar" toDir="${build.for.NTier}/Compiere2/lib}" />
  <!-- =========================================== -->
  <!-- Create customized complete distribution     -->
  <!-- =========================================== -->   
  <target name="createCustomizedDistribution" depends="NTierDistribute">
     <!-- Recreate the build dir for tasks coming up-->
     <delete dir="${build.dir}" />
     <mkdir dir="${build.dir}" />
   <!-- get the new distribution ready -->
     <echo>Prepare distribution in ${build.for.NTier}</echo>
     <!-- Make the copy of reference -> NTier -->
     <delete dir="${build.for.NTier}" />
   <copy toDir="${build.for.NTier}" >
      <fileset dir="${build.reference}" />
     <!-- Copy modified files to the NTier install dir -->
     <!-- NTier.jar - The only additional jar we will require -->
     <copy toDir="${build.for.NTier}/Compiere2/lib" overwrite="true">
   <!-- RUN_Compiere.* -->
     <!-- For clients to have the right classpath -->
     <copy toDir="${build.for.NTier}/Compiere2" overwrite="true">
     <!-- Similiar files but this time in the utils folder -->
     <copy toDir="${build.for.NTier}/Compiere2/utils" overwrite="true">
     <!-- The build file when we run server setup . Must be modified because -->
     <!--  the jars NTier.jar be copied to jboss deployment dir -->
     <copy toDir="${build.for.NTier}/Compiere2" overwrite="true">
     <!--                      -->
     <!-- Patch existing jars where we need to extract the contents -->
     <!--  add or replace a file, then jar it up again -->
   <delete file="${build.for.NTier}/Compiere2/lib/compiereRootBase.war" />
     <unjar src="${build.reference}/Compiere2/lib/compiereRootBase.war" dest="${build.dir}/compiereRootBasePatch" />
   <!-- Apply patches -->
     <!-- compiere.jnlp lets us know which files webstart must download -->
   <copy toDir="${build.dir}/compiereRootBasePatch" file="${patches}/web/compiere.jnlp" />

     <!-- Resign the war -->
   <echo>Warning keystore password hard coded here as myPassword</echo>
         <signjar jar="${build.for.NTier}/Compiere2/lib/compiereRootBase.war"
     <!-- Delete the patch folder -->
   <delete dir="${build.dir}/compiereRootBasePatch" />
     <echo>Your build is finished check for a complete copy in ${build.for.NTier}</echo>
     <echo> You may deploy etc/NTier.jar on an existing installation while Jboss is still running::::</echo>
     <echo> As follows::: cd COMPIERE_HOME; find . -name "NTier.jar" -print </echo>
     <echo> for example the folder might be </echo>
     <echo> ./jboss/server/compiere/tmp/deploy/tmp22213compiereRoot.ear-contents/compiereRoot.war/compiereHome/NTier.jar </echo>
     <echo> don't forget to also copy the jar into the standard lib folder </echo>
     <echo> Copy NTier.jar over the file </echo>

PostPosted: Fri Jun 24, 2005 10:06 am
by red1
It is OK. Such advertising is the honourable thing to do, as long as no money is passed in Open Space :wink:

Again, thanks a million.


Update on this topic for 2.5.2D

PostPosted: Thu Aug 25, 2005 1:23 am
by neilg
I see the build process has changed quite a bit for 2.5.2D and it looks like for the better.

Now it builds everything into a CompiereCLib.jar when you run setup on the client/server. This jar is signed at the same time. So it makes working like this a lot easier (webstart from the clients will pick up the whole CompiereCLib.jar which will now include your jar)

So far I've found only two lines of modification you have to make in the original code. Its in the build.xml in Compiere2 folder (you will find it under install/Compiere2/build.xml)

Here is the mod with a bit of context to show you where to do it:

Code: Select all
<unjar src="lib/CCTools.jar" dest="buildCLib" />
    <unjar src="lib/jPDF.jar" dest="buildCLib" />
     <!-- Patched here -->
     <unjar src="lib/myjar.jar" dest="buildCLib" />

Code: Select all
<zipfileset dir="utils" prefix="Compiere2"
      <!-- Patched here -->
     <zipfileset dir="lib" prefix="Compiere2/lib" includes= "Compiere2.exe,*.ico,myjar.jar,Compiere.jar,CompiereCLib.jar, compiereDirect.jnlp,index.html,*.0"/>

So there are only two lines of modification to the original code which is a Good Thing

Reference build and SQLJ

PostPosted: Thu Jan 19, 2006 1:40 pm
by neilg
For some reason my build did not contain the SQLJ files (required for 252 +).

In the reference version of the source code (the one where we make minimal changes) I had to run the build file in the sqlj folder (from Eclipse as an ant build worked fine). This built sqlj.jar.

Refresh project then make a new ant build for the install folder build.xml(dont run it yet - use the external tools option in the toolbar). In the ant build properties set environment variable COMPIERE_VERSION_FILE to value (for example) 252d, under 'Environment'.

Run the build then refresh the install folder. You will have the new build which you can use as a client.

You might need to (re)create the SQLJ functions in oracle. There is a separate posting on Contributors Corner which mentions how to do this.

PostPosted: Thu Jul 20, 2006 12:30 am
by Noha
I had to modify one of compiere classes and I did as you said and placed my class in the same package as it is in compiere then I created my own jar. I added my jar before compiere in the class path but when i run i get this exception
Exception in thread "main" java.lang.SecurityException: class "org.compiere.mode
l.PO"'s signer information does not match signer information of other classes in
the same package

Any ideas how to solve this problem
Thanks in advance