ANT-based Java/C++ project template

Introduction

The Codemesh ANT tasks are explained here and here. This page describes a full-featured example that you can use as the basis for your own integration projects. In order to use the integration template, you need the ANT project template ZIP file and the code generator installed.

Once you have the prerequisites, you can copy your Java class or jar files into the project template and create the C++ integration code by running a provided ANT task.

A sample solution template invocation

After uncompressing the sample_project archive into a directory of your choice, you should see a sample_project folder with a build.xml file, two subdirectories (named classpath and imports) and a number of additional files.

The solution template is designed to allow you to override most build options from the command line. The options that cannot be overridden via the command line can be modified in the solution template files. This solution template is not strictly speaking part of the JunC++ion product. You should regard it as an example of building a C++ integration project using the JunC++ion ANT tasks. Feel free to modify all parts of the solution template to satisfy your integration needs.

Before explaining in detail how the solution template works, we'll generate an integration library for the Java Message Service (JMS) to show how easily the solution template can be used to solve a common yet complex enterprise integration problem.

Step 1

Copy jms.jar into the imports directory.

Step 2

Change into the sample_project directory and invoke the code generator's version of ant:

cd c:\sample_project 
C:\junction\staging\bin\ant 
    "-Dcom.codemesh.xmog.home=C:\junction\staging" 
"-Dsolution.module.name=jms" "-Dsolution.name=jms" "-Dsolution.copyright=Copyright 2006 by Codemesh, Inc. ALL RIGHTS RESERVED" "-Dsolution.doc.name=JMS C++ Library 1.0" "-Dsolution.declspec=JMS_DECLSPEC" build

This will kick off the code generation and provide you with a jms directory in which all required files for using JMS from C++ are located.

The solution template

At the heart of the solution template lies the build.xml file that leverages the JunC++ion ANT tasks. The following block contains an abbreviated version of the file. Bold text denotes variables or script elements that you probably need to edit in the script or override from the command line.

<?xml version="1.0"?>

<!-- Copyright 2006 by Codemesh, Inc. ALL RIGHTS RESERVED.              -->

<!--                                                                    -->
<!--                                                                    -->
<!-- A generic build script for creating an integration library         -->
<!--                                                                    -->
<!--                                                                    -->
<project name="Generic example" default="all" basedir=".">

  <!--                                                                    -->
  <!--  The install directory of the code generator                       -->
  <!--                                                                    -->
  <!--  PROBABLY NEEDS TO BE OVERRIDDEN ON COMMANDLINE                    -->
  <!--                                                                    -->
  <property name="com.codemesh.xmog.home" value="../.." />

  <!--                                                                    -->
  <!--  The solution name (directory)                                     -->
  <!--                                                                    -->
  <!--  NEEDS TO BE OVERRIDDEN ON COMMANDLINE                             -->
  <!--                                                                    -->
  <property name="solution.name" value="proxy" />

  <!--                                                                    -->
  <!--  The solution module name                                          -->
  <!--                                                                    -->
  <!--  NEEDS TO BE OVERRIDDEN ON COMMANDLINE                             -->
  <!--                                                                    -->
  <property name="solution.module.name" value="proxy" />

  <!--                                                                    -->
  <!--  The solution copyright notice                                     -->
  <!--                                                                    -->
  <!--  NEEDS TO BE OVERRIDDEN ON COMMANDLINE                             -->
  <!--                                                                    -->
  <property name="solution.copyright" 
            value="Copyright 2006 by Codemesh, Inc. ALL RIGHTS RESERVED." />

  <!--                                                                    -->
  <!--  The solution documentation name                                   -->
  <!--                                                                    -->
  <!--  NEEDS TO BE OVERRIDDEN ON COMMANDLINE                             -->
  <!--                                                                    -->
  <property name="solution.doc.name" value="Proxy Library 1.0" />

  <!--                                                                    -->
  <!--  The solution declspec                                             -->
  <!--                                                                    -->
  <!--  NEEDS TO BE OVERRIDDEN ON COMMANDLINE                             -->
  <!--                                                                    -->
  <property name="solution.declspec" value="PROXY_DECLSPEC" />

  <!--                                                                    -->
  <!--  Declares the custom tasks and types we're using                   -->
  <!--                                                                    -->
  <import file="${com.codemesh.xmog.home}/examples-c++/taskdefs.xml"/>

  <!--                                                                    -->
  <!--  Declares the compiler settings and other build properties for     -->
  <!--  all examples.  Modifying the settings in this file makes sure     -->
  <!--  that you can build all examples with your desired compiler and    -->
  <!--  the desired options.                                              -->
  <!--                                                                    -->
  <import file="${com.codemesh.xmog.home}/examples-c++/buildoptions.xml"/>

  <!--                                                                    -->
  <!--  The directory in which the inputs can be found                    -->
  <!--                                                                    -->
  <!--  PROBABLY NEEDS TO BE OVERRIDDEN ON COMMANDLINE                    -->
  <!--                                                                    -->
  <property name="input.dir" value="${basedir}" />

  <!--                                                                    -->
  <!--  The directory into which the solution is assembled                -->
  <!--                                                                    -->
  <!--  PROBABLY NEEDS TO BE OVERRIDDEN ON COMMANDLINE                    -->
  <!--                                                                    -->
  <property name="target.dir" value="${basedir}/${solution.name}"/>

  <!--                                                                    -->
  <!--  The directory into which the include files are copied             -->
  <!--                                                                    -->
  <property name="include.dir" value="${target.dir}/cpp/include"/>

  <!--                                                                    -->
  <!--  The directory into which the proxies are generated                -->
  <!--                                                                    -->
  <property name="temp.dir" value="${basedir}/temp"/>

  <!--                                                                    -->
  <!--  The set of files that is imported                                 -->
  <!--                                                                    -->
  <fileset id="solution.imports" dir="${input.dir}/imports">
    <include name="*.jar"/>
    <include name="**/*.class"/>
  </fileset>

  <!--                                                                    -->
  <!--  The classpath on which all Java types of the project can be found -->
  <!--                                                                    -->
  <path id="solution.classpath">
    <pathelement location="${input.dir}/classpath" />
    <fileset dir="${input.dir}/classpath">
      <include name="*.jar" />
      <include name="**/*.class" />
    </fileset>
    <fileset refid="solution.imports" />
  </path>
  <property name="solution.classpath.string" refid="solution.classpath"/>


  <!--                                                                    -->
  <!--  Builds and runs the example components                            -->
  <!--                                                                    -->
  <target name="all" 
          depends="build" 
          description="Builds and runs the executable"/>


  <!--                                                                    -->
  <!--  Builds the example components                                     -->
  <!--                                                                    -->
  <target name="build" 
          depends="create-dirs,generate-cpp,build-lib,make-projects" 
          description="Builds the executable"/>


  <!--                                                                    -->
  <!--  Creates the directories into which the solution is staged         -->
  <!--                                                                    -->
  <target name="create-dirs" description="Creates the staging directories">
    
    <mkdir dir="${include.dir}" />
    <mkdir dir="${target.dir}/cpp/${runtime.directory}" />
    <copy todir="${include.dir}" >
      <fileset dir="${com.codemesh.xmog.home}/cpp/include">
        <include name="*.h"/>
        <include name="*.inl"/>
      </fileset>
    </copy>

  </target>


  <!--                                                                    -->
  <!--  Deletes generated files                                           -->
  <!--                                                                    -->
  <target name="clean" description="Deletes generated files">
    
    <delete dir="${temp.dir}" />
    <delete dir="${include.dir}" />

  </target>


  <!--                                                                    -->
  <!--  Generates the C++ proxy classes                                   -->
  <!--                                                                    -->
  <target name="generate-cpp" description="Generates the C++ source code">

    <mkdir dir="${temp.dir}" />

    <junction cli="true" logfile="${temp.dir}/${solution.name}.gen.log">

      <!-- set the two possibly external documentation tool paths -->
      <sysproperty key="com.codemesh.xmog.doc.doxygen.path" value="${doxygen.path}"/>
      <sysproperty key="com.codemesh.xmog.doc.dot.path" value="${dot.path}"/>

      <modelfile name="${solution.name}" libdir="${jre.lib.dir}" sort="true">
        <jdkhome value="${jdk.dir}"/>
        <targetdir value="${temp.dir}"/>
        <generatemakefile/>
        <targetname value="${solution.module.name}"/>
        <devstudioprojectname value="${solution.module.name}"/>
        <devstudioprojectversion value="${project.version}"/>
        <doctype value="text/html"/>
        <generatedoc value="${doc.generate}" />
        <generateframeworkdoc value="true"/>
        <doccopyright value="${solution.copyright}"/>
        <docproductname value="${solution.doc.name}"/>
        <storageclassmacro value="${solution.declspec}"/>
        <classpath>
          <path refid="solution.classpath" />
        </classpath>
        <import dir="${input.dir}/imports">
          <include name="*.jar"/>
          <include name="**/*.class"/>
        </import>

        <!--                                           -->
        <!-- import some commonly useful Java types    -->
        <!-- you don't HAVE to, but they often come in -->
        <!-- handy.  Comment or delete if you don't    -->
        <!-- want them; add more if you wish.          -->
        <!--                                           -->
        <importclass name="java.lang.Class"/>
        <importclass name="java.lang.reflect.*"/>
        <importclass name="javax.naming.InitialContext"/>

        <!--                                           -->
        <!-- turn off usually unused Java types        -->
        <!--                                           -->
        <generatepackage packagename="sun" generate="false" recurse="true"/>

      </modelfile>

    </junction>

    <antcall target="create-dirs"/>
    <copy todir="${include.dir}" >
      <fileset dir="${temp.dir}">
        <include name="*.h"/>
      </fileset>
    </copy>

  </target>


  <!--                                                                    -->
  <!--  Build the C++ proxy classes into a shared library                 -->
  <!--                                                                    -->
  <target name="build-lib" 
          description="Builds the C++ proxy classes into a shared library">

    <cc>

      <ccopts refid="console.sharedlib"/>

      <shared value="${solution.module.name}"/>
      <targetdir value="${temp.dir}"/>
      <tempdir value="${temp.dir}"/>
      
      <include location="${temp.dir}"/>
      <sources dir="${temp.dir}" includes="*.cpp"/>

      <!-- export the generated proxy API from the library -->
      <define name="${solution.declspec}" value="__declspec(dllexport)" os="win32,win64"/>
      <define name="${solution.declspec}" value="" notos="win32,win64"/>

    </cc>

    <copy todir="${target.dir}/cpp/${runtime.directory}">
      <fileset dir="${temp.dir}">
        <include name="*${library.suffix}" />
        <include name="*.lib" />
      </fileset>
      <fileset dir="${com.codemesh.xmog.home}/cpp/${runtime.directory}">
        <include name="*${library.suffix}" />
        <include name="*.lib" />
      </fileset>
    </copy>

  </target>


  <!--                                                                    -->
  <!--  Create some projects that use the generated proxy library         -->
  <!--                                                                    -->
  <!--  This task uses some pre-created templates with placeholders in    -->
  <!--  them and copies them into your target directory while expanding   -->
  <!--  the placeholders with solution-specific values. You can edit the  -->
  <!--  template projects to create projects with other options.          -->
  <!--                                                                    -->
  <target name="make-projects" 
          description="Create Visual Studio project files that use the integration library">
  
    <antcall target="create-dirs"/>
    <copy todir="${target.dir}">
      <filterset>
        <filter token="include.dir" value="${include.dir}"/>
        <filter token="target.dir" value="${target.dir}"/>
        <filter token="runtime.directory" value="${runtime.directory}"/>
        <filter token="solution.declspec" value="${solution.declspec}"/>
        <filter token="solution.module.name" value="${solution.module.name}"/>
      </filterset>
      <fileset dir="${basedir}">
        <include name="*.dsp"/>
        <include name="*.vcproj"/>
      </fileset>
      <globmapper from="*" to="${solution.module.name}User*"/>
    </copy>

    <copy todir="${target.dir}">
      <filterset>
        <filter token="solution.classpath" value="${solution.classpath.string}"/>
      </filterset>
      <fileset dir="${basedir}">
        <include name="main.cpp"/>
      </fileset>
    </copy>

  </target>

</project>

You can either modify the template to create your own solution or you can override build settings from your command line invocation. Either way, it is very easy for you to create an integration solution for relatively complex integration problems like:

  • using JMS from C++
  • using RedHat JBoss, IBM WebSphere, BEA Weblogic, or other J2EE servers from C++
  • publishing a C++ version of your own Java API

One of the most important set up steps is the distinction between Java types that are to be imported into the code generator and Java types that are only required on the classpath. Basically, you want all jar or class files that are required at runtime on the classpath but you only want the files that you wish to expose on the import path. Don't worry about duplicating files in both locations; that's perfectly OK.

An example might help you with understanding the distinction between class- and import-path better. Many products rely on the Log4J logging API at runtime but very few people will wish to expose Log4J to C++. Consequently, the log4j.jar file should be in the classpath directory, not in the imports directory.

How you can modify the solution template

You can download the solution template and customize it to your heart's content. You could, for example:

  • add a classpath reference to a jbossall-client.jar file if you are frequently generating EJB C++ integration code for a JBoss server. Then you just need to drop your application client jar file into the imports directory and you can generate immediately.
  • add select Java types or packages by name (see the <importclass> elements).
  • do two C++ builds (using the <cc> task): one debug and one release build.

The possibilities are limitless. Just take this template as a starting point for your own projects and let us know if you have any enhancement requests of general usefulness for our template; we'll try to incorporate them into it.


Copyright 2006-2011 by Codemesh, Inc., ALL RIGHTS RESERVED

:
ant code generator example
home products support customers partners newsroom about us contact us