Building Converted Code¶
As a source-to-source conversion technology, FWD produces Java source code as its end product. That Java source code must be compiled into Java byte code in order to run within a Java Virtual Machine (JVM). The Java source code emitted by the conversion process references many entry points into the FWD runtime environment, and will have dependencies upon standard Java class libraries, as well as upon third party libraries. Accordingly, the build process must take into account these linkages. The FWD project does not provide a specific tool to build your project, with the expectation that you will use existing tools available to the Java community.
Ant (ant.apache.org) is a feature rich tool set used to build many Java projects (it is what is used to build the FWD technology itself), and it is well suited for FWD conversion projects. We recommend using it as a starting point to set up a build environment for your own conversion project. This chapter discusses various considerations and requirements when creating a build environment for a new project. It assumes Ant is the tool set in use. If you use a different build tool, you should be able to adapt these concepts to the tool set of your choice.
Configuring the Build Process¶
Ant relies on an XML configuration file, which describes what the build tool should do when it is told to execute a set of tasks. Each such set of tasks is known as a target in Ant parlance. By default, the configuration file is named build.xml
and is located in the project root directory. We follow this convention here. The build.xml
file contains a number of sections, one to describe each target, and additional sections to define common variables and other shared information. Each public target can be executed directly from the command line (e.g., ant compile
), or indirectly, as a dependency of other targets.
Ant provides extensive documentation and a well-commented, sample build.xml
template which you can use to configure your own project's build process. Accordingly, we will not cover every detail of that file here, nor explain the meaning of every build.xml
element and option, as this document is not intended as a substitute for Ant's user documentation. Rather, this section will focus on those elements of build.xml
which commonly are necessary for FWD conversion projects. The intention is to present these items in a broadly applicable way, but as Ant has numerous tools available to specify your build configuration, you may discover various methods that are more suitable to your specific environment and needs. Please consult the Ant user documentation if you are unfamiliar with any of the idioms or syntax used in the subsections below.
Commonly Used Paths¶
References to commonly used paths are necessary throughout the build configuration. Rather than hard coding these references everywhere they are used, take advantage of Ant's user definable properties. The following properties are typical for a FWD conversion project. This section usually appears early in build.xml
:
<!-- ==================== File and Directory Names ======================== --> <property name="build.home" value="${basedir}/build" /> <property name="dist.home" value="${basedir}/dist" /> <property name="src.home" value="${basedir}/src" /> <property name="srcnew.home" value="${basedir}/srcnew" /> <property name="lib.home" value="${basedir}/lib" /> <property name="cfg.home" value="${basedir}/cfg" /> <property name="manifest.dir" value="${basedir}/manifest" /> <property name="p2jlib.home" value="${basedir}/p2j/build/lib" /> <property name="p2jsrc.home" value="${basedir}/p2j/src" />
The basedir
substitution variable references the current working directory from which each Ant target is executed. It is defined by the basedir
attribute of the project
XML element, which is the outermost element of the XML hierarchy in build.xml
. In this case, it is assumed basedir
has been set to “.
”. Thus, all path properties above are defined relative to the current working directory, which corresponds with the project root directory, assuming you will be issuing ant
commands from that location.
Java Classpaths¶
Rather than picking up the CLASSPATH
environment variable, Ant uses Java classpath
s defined in build.xml
. This allows you to specify different classpath
s, which may be useful for certain tasks. An example of this configuration follows:
<!-- ==================== Compilation Classpath =========================== --> <!-- Path used when compiling Java classes --> <path id="compile.classpath"> <fileset dir="${lib.home}"> <include name="*.jar"/> </fileset> <fileset dir="${p2jlib.home}"> <include name="*.jar"/> </fileset> </path> <!-- Only used by special build-time tasks --> <path id="tools.classpath"> <path refid="compile.classpath"/> <!-- add more paths or filesets here if necessary... --> </path>
The compile.classpath
path will be used for most tasks which require a classpath
. Other tasks in the configuration will refer to this path by specifying
<path refid="compile.classpath"/>
in Ant tasks which accept a path reference.
The tools.classpath
path is an example of a reference back to the compile.classpath
path defined above it. The tools.classpath
is set up to include all paths in the compile.classpath
, plus any additional paths necessary for specific build operations. This additional path is optional, and many projects will not need it. However, you might use it if, for example, you need to execute a particular build target occasionally (perhaps building a UML model from your converted project source code), for which you need to specify additional jar files or classes that you would not want in your classpath
for a regular build.
Prepare Target¶
In order to compile your converted source code and create jar
files and javadoc
documentation, you will typically need to perform some preparatory work, such as creating directories, copying files, and so forth. This is the work of the prepare
target. This target is rarely executed directly from the command line, but normally is executed indirectly as a dependency of another target, such as a compile
target. An example follows:
<!-- ==================== Prepare Target ================================== --> <target name="prepare"> <!-- 1. Create build directories --> <mkdir dir="${build.home}" /> <mkdir dir="${build.home}/lib" /> <mkdir dir="${build.home}/classes" /> <!-- 2. Create distribution directory --> <mkdir dir="${dist.home}" /> <mkdir dir="${dist.home}/docs/api" /> <!-- 3. Copy external jars --> <copy todir="${build.home}/lib"> <fileset dir="${lib.home}" /> </copy> <!-- 4. Copy DTDs from source directories to equivalent locations in build directories --> <copy todir="${build.home}/classes"> <fileset dir="${src.home}" includes="**/*.dtd" /> </copy> <!-- 5. Copy DMO index DTD from FWD src to application's build --> <copy todir="${build.home}/classes"> <fileset dir="${p2jsrc.home}" includes="dmo-index*.dtd" /> </copy> <!-- 6. Copy all XML documents --> <copy todir="${build.home}/classes"> <fileset dir="${src.home}" includes="**/*.xml" /> </copy> <!-- 7. Copy ehcache config file into classpath --> <copy file="${cfg.home}/ehcache.xml" tofile="${build.home}/classes/ehcache.xml" /> <!-- 8. Copy hand-written Java code into (generated) permanent package structure --> <copy todir="${src.home}"> <fileset dir="${srcnew.home}" /> </copy> </target>
Let's take a closer look at each of the numbered sections above:
- Create build directories. This item creates
build/lib
andbuild/classes
subdirectories below the project root. Converted Java source files will later be compiled into class (.class
) files, which will reside inbuild/classes
. These in turn will bejar
'd into application jar files, which will be placed inbuild/lib
, along with copies of third party jar files required by the converted application. - Create distribution directory. This item creates a
dist/docs/api
subdirectory below the project root, wherejavadoc
documentation will be emitted. - Copy external jars. This optional item presumes any external or third party jars required by the converted application (besides those required by FWD itself) reside in the
lib
subdirectory off the project root. These are copied into${build.home}/lib
. If no external jars are required by the application, this item can be omitted. - Copy DTDs from source directories to build directories. This optional item copies any DTDs which are in the application's source directory tree to its build directory tree, in preparation for the later
jar
target. The default conversion does not place any DTDs into the application's source directory tree, so this step is only necessary if the conversion has been customized to generate DTDs. Several XML files are generated during conversion which are not validated during runtime. This is likely to change in future versions of FWD, so the inclusion of this item inbuild.xml
anticipates this future need. - Copy DMO index DTD from FWD source directory to application's build directory. A file named
dmo_index.xml
is generated during schema conversion and is read as a runtime resource from the converted application's classpath. A DTD file (dmo-index-{version}.dtd
) is used by the XML parser to validate thedmo-index.xml
file. This DTD is expected to be available with thedmo_index.xml
file, and so this item copies it from its location in the FWD source directory tree to the build directory tree which will be used when creating the application's jar file. More details about thedmo_index.xml
file can be found in the DMO Index chapter of the _FWD Conversion Reference _book. - Copy XML documents from source directories to build directories. Numerous XML documents are generated during conversion, which are needed by the application at runtime. This item copies these files from the locations at which they were created during conversion to their matching, relative locations in the build directory tree. This ensures they will be archived appropriately in the application's jar file during execution of the
jar
target. - Copy ehcache configuration file into the build directory. FWD uses Ehcache to implement Hibernate's second level caching. An Ehcache configuration file with default settings is located in the
cfg
subdirectory (the file can be edited to provide custom cache settings on a per-table basis). This item copies it to theclasses
subdirectory of the build directory, so that once jarred, it will be found in the root of the classpath at runtime, as expected by Hibernate. - Copy hand-written Java code into (generated) permanent package structure. Over time, hand-written Java classes and other source files will be added to a project to either add function or to replace generated Java source code. Such source files should not be placed in the same source directory tree as the one in which the conversion process places its generated files, because any hand-written files with the same names as generated files will be overwritten the next time conversion is run. One way to handle this is to create a parallel source directory tree (in this case represented by the
srcnew.home
property). Any hand-written files are placed in the parallel directory tree. This optional item copies all such custom source from the parallel tree to the same relative location in the generated source directory tree. Note that generated files with the same relative paths and file names as their hand-written counterparts will be overwritten, so careful planning is required.
Clean Target¶
During the conversion and development cycle, it is often necessary to clear out the results of a previous build before attempting a new build. This is done by defining a clean
target:
<!-- ==================== Clean Target ==================================== --> <target name="clean" description="Delete old build and dist directories"> <delete failonerror="false" includeEmptyDirs="true"> <fileset dir="${build.home}"/> <fileset dir="${dist.home}"/> </delete> </target>
Like the prepare
target, the clean
target is rarely run in isolation. It is run more commonly in preparation for a full build. Note that in the form above, this target will delete the directory containing compiled Java classes (and other files copied there by the prepare
or other targets), and the directory containing the project's “distribution” material (usually JavaDoc and other documentation).
This target will not remove generated and hand-written source files. This is intentional, as it is typically necessary during the development cycle to build the project much more often than it is to re-run conversion. We normally don't want to delete the output of the last conversion run every time we build. A separate target can be defined to clear the output of the conversion process if needed; this is left as an exercise to the reader. Normally such a target would involve at least the deletion of the fileset
defined by the src.home
property.
Compile Target¶
Java source files need to be compiled by the Java compiler to class files, which can be loaded and executed by the Java Virtual Machine at runtime. This is the purpose of the compile
target, which uses the Ant javac
directive. Under the covers, Ant invokes the Java compiler, which reads the source files from the directory specified by the srcdir
attribute, and places the compiled class files in the directory indicated by the destdir
attribute.
<!-- ==================== Compile Target ================================== --> <target name="compile" depends="prepare" description="Compile Application's Java sources"> <!-- Compile Java classes as necessary --> <javac srcdir="${src.home}" destdir="${build.home}/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" memoryMaximumSize="2G" fork="true" optimize="${compile.optimize}"> <classpath refid="compile.classpath"/> </javac> <echo message="Compiling Java Sources Done."/> </target>
Other settings are configured here as well, such as those for the compilation classpath
, the inclusion of debug symbols, the handling of deprecated APIs, optimization, and the memory available to the Java compiler. Please consult the Ant user documentation for further details on these options.
The compile
target depends upon the prepare
target, which means that each time the compile
target is run, the prepare
target will be executed first.
Jar Target¶
Java applications normally are not shipped as collections of loose class files. A FWD application usually is deployed in one or more jar files. A jar
file is an archive, similar to a zip
file, which contains resources needed by a Java application to execute at run time. This usually contains at least the compiled Java class files which implement the application's behavior. Often, jar files also include other files, such as static XML documents, DTD or XML schema files, images, and other static resources which are updated infrequently. Typically, these are resources which change in conjunction with application code changes.
The following example of a jar
target creates two jar
archives from application classes and resources:
<!-- ==================== Jar Target ============================ --> <target name="jar" depends="compile"> <!-- business logic classes and resources --> <jar jarfile="${build.home}/lib/myapp.jar" basedir="${build.home}/classes" includes="**/com/mydomain/myapp/** dmo-index*.dtd ehcache.xml" excludes="**/com/mydomain/myapp/ui/**" manifest="${manifest.dir}/myapp.mf" index="true" /> <!-- user interface classes and resources --> <jar jarfile="${build.home}/lib/myapp_ui.jar" basedir="${build.home}/classes" includes="**/com/mydomain/myapp/ui/**" index="true" /> </target>
One archive (myapp.jar
) contains only business logic classes and related resources. The other archive (myapp_ui.jar
) contains only user interface classes and related resources. This delineation is somewhat arbitrary, and is not strictly necessary for all applications. For many applications, a single, application jar
file is sufficient.
The particular delineation into a business logic archive and a user interface archive has historical roots. The FWD project initially was developed using Sun Microsystems' JDK 1.4. Conversion of the FWD pilot project application resulted in a large number of compiled Java classes (many tens of thousands), which could not be loaded from a single jar
file using that version of the Sun JVM. At the time of this writing, the minimum requirement for a FWD project is JDK 1.6 or higher. It is unknown to this author whether the limitation on the number of classes in a single jar
file has been lifted in versions of the Sun JVM since 1.4.
Whether or not this particular limitation still exists, developers may have various reasons for splitting their applications into multiple jar
archives. Accordingly, the example above illustrates this approach.
JavaDoc Target¶
The javadoc
target creates API documentation for the converted application's Java classes. The current version of FWD only generates JavaDoc documentation for the Data Model Object (DMO) classes it creates based on the legacy schemas used by the original, Progress application. However, you may have additional, hand-written classes which contain such documentation. The following example creates JavaDoc documentation under the directory represented by the dist.home
property. Note that for very large projects, running this target may take a long time, and may require more memory than is specified here.
<!-- ==================== Javadoc Target ========================== --> <target name="javadoc" depends="compile" description="Create Javadoc API documentation"> <javadoc sourcepath="${src.home}" destdir="${dist.home}/docs/api" maxmemory="256M" access="private" Footer="Copyright (c) 2010, My Organization, Inc. <br> ALL RIGHTS RESERVED. Use is subject to license terms." Windowtitle="MyApp" locale="en_US" packagenames="*"> <classpath refid="compile.classpath"/> </javadoc> </target>
Schema Generation Target¶
The following is documentation on a deprecated
feature. The recommended approach no longer requires this section. As such, adding it is optional unless using the Alternate Approach to DDL Generation is being used as documented in the Data Migration chapter.
The schema
target is needed infrequently, and it is not executed as part of the regular, application build cycle. This target generates the Data Definition Language (DDL), which you will use to apply a schema to a new, PostgreSQL database. This is necessary when migrating application's data from a Progress database. Details on running this target are provided in the Data Migration chapter.
<!-- ============= Hibernate Schema Generation Target ============= → <!-- The "schema" target uses Hibernate ORM mapping documents to generate Database Definition Language (DDL) statements to create the matching schema in a PostgreSQL database. The schema is not actually applied to the database directly; the DDL is emitted but not executed. To generate the DDL for a particular database, invoke this target, passing the database name to ant as a property named 'target.db'. For instance: ant -Dtarget.db=mydb schema FWD runtime environment is a prerequisite. --> <target name="schema" depends="prepare" description="Generate DDL from hibernate mapping files"> <taskdef name="schema-gen" classname="org.hibernate.tool.hbm2ddl.SchemaExportTask" classpathref="tools.classpath" /> <schema-gen config="${cfg.home}/hibernate.cfg.xml" quiet="yes" text="yes" drop="no" output="schema-create-${target.db}.sql" delimiter=";"> <fileset dir="${build.home}/classes"> <include name="**/${target.db}/impl/*.hbm.xml"/> </fileset> </schema-gen> </target>
The schema
target requires as input Hibernate ORM documents, one of which is generated for each DMO type during the conversion process. Accordingly, this target depends upon the prepare
target, which copies these documents to a location from which they can be used by the schema
target (i.e., within the tools.classpath
defined earlier).
Running the Build¶
Ant provides a very flexible build environment, and you may choose to modify the above configuration elements to better suit your needs. Your project may call for additional properties and new build targets. However, the above elements comprise the basic set of build tasks required by any FWD conversion project. Put them together in a build.xml
file, place that file in the project root directory, and you will be ready to build your project.
To compile your converted (and hand-written) Java classes, switch to the project root directory, and run the following from the command line:
ant compile
This is a good first step to attempt after early conversions of a new project. For a complex project, it is not uncommon to encounter compilation errors initially, even though the conversion process completed without reported errors. There are various reasons for this, which may require changes to your 4GL source code, the addition of conversion hints, or fixes or enhancements to the FWD conversion technology itself. The iterative process of working through these errors is discussed in the chapter entitled Getting Your Project to Compile.
Once your project compiles without error, you will want to create jar
archives, which will allow you to run your application. For this, execute:
ant jar
You may optionally want to generate JavaDoc API documentation for your project:
ant javadoc
You also can specify multiple targets to run in sequence. For example, a useful combination is to run the clean
target before a jar
, as in:
ant clean jar
This will remove all output of the previous build from the file system, ensuring the current build starts from a known, clean state. This is especially important in the event Java source files or other resources have been removed from the project, so obsolete class files and resources do not end up in the application's jar
files.
Summary¶
This chapter recommended the Ant tool set to build your converted application, and discussed the minimum configuration elements necessary for a typical FWD conversion project. We reviewed common build commands. At this point, you should be ready to put together a basic build configuration and begin compiling your converted source code. Newly converted Java source code might not immediately compile cleanly. Strategies for dealing with compilation errors are discussed in the chapter Getting Your Project to Compile.
© 2004-2017 Golden Code Development Corporation. ALL RIGHTS RESERVED.