Mike's face
Thursday, July 24th, 2014








Exslant

Photo of Exslant

"An excellent build system."  Project-XML -> XSL -> build.xml.

Question 1: Why not stick with just ant?
Answer: managing build.xml files gets nasty and they become convoluted and unmanageable?

Question 2: Why not use an existing and proven system like Maven?
Answer: Too fragile and bloated, too many dependencies.  Way too much stuff if all you need is build a basic jar, war, or ear file.  I don't like my projects being dependent on the secret under the hood tucked away components.  If any of them fail or becomes a problem, you're screwed.  Exslant is much easier and far more predictable.  The last thing you want is your build process become unpredictable.  Often, when I download Maven based projects, they don't work out of the box.  Exslant based projects work out of the box, every time.

A few of my former colleagues 'borrowed' some of my previous techniques, where I used xml include files, which could be imported in the build.xml file using xml entities.  They've introduced it into other companies are have been getting some pretty good momentum with it.  They'll definitely will like the new Exslant build system, which takes things to a whole new level.

The documentation is a work in progress.  If you have any specific problems or issues, drop me a line, and I'll see what I can do.

How it works

You write an exslant_build.xml and have Exslant produce a build.xml for you.  It does this by using xsl templates, which you can customize to your own needs, in the event you need something more than your normal jar, war, or ear project.  Writing an exslant_build.xml is much simpler than writing a build.xml file.

Normally, when you write a build.xml file, you'll need to write all the low level details, like how to javac and jar, war, ear, manage manifest files, decide where to place them, decide what to do in what order, etc.  If you follow the Exslant structure, Exslant can do the rest all for you.

Contents

  • A set of xsl files for things like jar, war, ear, junit, xdoclet, proguard obfuscation, etc.
  • An ant-server and an ant-client, to help speed up compile time
  • Integrated Java debugger with hotswap.

Example

Here's an example of an exslant_build.xml file:

<project name="test" default="jar" run="jar,runjar">
    <jar>
        <java>
            <src>com/exslant/test/Test.java</src>
        </java>
        <libs>
          <lib>jdom/jdom.jar</lib>
        </libs>
    </jar>
</project>

Run it through Exslant, and you'll get:

<project default="jar" xmlns:xalan="http://xml.apache.org/xslt">
    <property environment="env"/>
    <property file="build.properties"/>
    <property name="LIB_DIR" value=""/>
    <property name="BUILD_DIR" value="tmp/build/jar"/>
    <property name="DIST_DIR" value="tmp/dist/jar"/>
    <property name="RUN_DIR" value="tmp/build/jar"/>
    <property name="RUN_OPTS" value=""/>
    <property name="RUN_ARGS" value=""/>
    <property name="project" value="test"/>
    <property name="jvm" value="1.5"/>
    <target name="init">
        <echo message="build.xml generated by Exslant, an excellent build system - http://www.exslant.com"/>
        <condition property="unix">
            <os family="unix"/>
        </condition>
        <condition property="windows">
            <os family="windows"/>
        </condition>
    </target>
    <target name="clean" depends="init">
        <delete dir="tmp"/>
    </target>
    <fileset id="libs" dir="${LIB_DIR}" excludes="**"/>
    <fileset id="j2eelibs" dir="${LIB_DIR}" excludes="**"/>
    <path id="classpath"/>
	<target name="jar" depends="jar2"/>
    <target name="quickjar" depends="jar2"/>
    <target name="jar2" depends="compile,jar3"/>
    <target name="native">
        <exec os="Linux" dir="native/linux_i686" executable="make"/>
    </target>
    <target name="compile" depends="init">
        <mkdir dir="tmp/jar"/>
        <mkdir dir="tmp/src"/>
        <mkdir dir="${BUILD_DIR}/lib"/>
        <taskdef name="dep" classname="com.exslant.ant.Dep"/>
        <dep srcdir="${SRC_DIR}" destdir="tmp/jar"/>
        <javac debug="true" destdir="tmp/jar" source="${jvm}" target="${jvm}" nowarn="" includeAntRuntime="no">
            <src path="${SRC_DIR}"/>
            <src path="tmp/src"/>
            <classpath>
                <fileset dir="${LIB_DIR}" includes="jdom/jdom.jar"/>
            </classpath>
            <include name="com/exslant/test/Test.java"/>
        </javac>
        <dep/>
    </target>
    <target name="jar3" depends="init">
        <zip destfile="${BUILD_DIR}/lib/${project}.jar">
            <fileset dir="tmp/jar"/>
            <fileset dir="res/jar" excludes="**/CVS/**"/>
        </zip>
        <copy todir="${BUILD_DIR}/lib">
            <fileset dir="${LIB_DIR}" includes="jdom/jdom.jar"/>
        </copy>
        <copy todir="${BUILD_DIR}">
            <fileset dir="res/build/jar"/>
        </copy>
    </target>
    <target name="runjar">
        <java jar="${BUILD_DIR}/lib/${project}.jar" dir="${RUN_DIR}" fork="true">
            <jvmarg line="${RUN_OPTS}"/>
            <arg line="${RUN_ARGS}"/>
        </java>
    </target>
</project>

The build.xml might have some redundant elements in it, and perhaps could use some improvements.  But that's ok, the exslant_build.xml is really the source file.  It contains so little elements, you can pretty much rely on it staying the same.  If not, the number of changes are likely little, and will be easy to do.  The key lies in the xsl files.  Fine tune those and the produced build.xml will be improved and enhanced.  Rerunning exslant on the projects takes very little effort.  Immediately, it's apparent that Exslant is robust and safe to use, and surely a heck of a lot easier than rolling your own build.xml scheme.
It's also a more direct and easier approach to a more bloated system like Maven.

Other project files

In addition to the exslant_build.xml file, you can an optional build.properties file that lets you override default settings.

SRC_DIR  = ../javatree
LIB_DIR  = ../lib

What this does, is it tells it where it can find the Java source code, and where it can find the jar lib files for compilation and distribution.  The reason for using these settings in a separate files as opposed to containing it inside the exslant_build.xml file, is because I wanted to have a way to reconfigure a few simple settings without having to re-run Exslant on it.  This can also be useful after distributing your project to other people.  They get the produced build.xml file, which will work for them without them having to have Exslant at all.  Even then, they can move things around because they'll just have to modify the build.properties file.  The example above only showed 2 properties, but there are a number of other things you can define in it.

Distributing your Exslant projects

Built programs that use Exslant, don't require or add any dependencies to Exslant.
When you distribute your source code, you don't necessarily have to include the exslant_build.xml file, or any other Exslant components either.  The generated build.xml can stay the same, even if you distribute it to other computers.

Project library jar file dependencies

Your project probably needs a number of jar files to compile and run.
Create a directory and keep all the jar files organized in a sensible hierarchy, like so:

  + lib
  |-+ jdom
  | `-- jdom.jar
  `-+ jakarta
    `-- log4j.jar

EPS - an Excellent Project Structure

Exslant makes a few assumptions where files are located, so chances are that you might have to move a few files around to make it work for your projects.
Here's a rough break down of what Exslant expects:

+ projectname
| 
|-- exslant_build.xml
|-- build.xml
|-- build.properties
|-+ res
| `-+ jar
|   |-- (other files)
|   `-+ META-INF
|     `-- MANIFEST.MF
|---+ war
|   |-+ WEB-INF
|   | |-- web.xml
|   | `-+ classes
|   |   `-- (runtime resources, properties files)
|   `-- (web files)
|---+ ear
|   `-+ META-INF
|     `-- application.xml
|---+ ejb
|   `-+ META-INF
|     |-- ejb-jar.xml
|     `-- (other j2ee implementation specific files)
`---+ test
    `-- (files needed to run test)

Debugging & Hotswap

The integrated debugger uses the standard Java's "hotswap" feature to swap recompiled class files at runtime.  It monitors the Java source files, recompiles them when they get updated, and uploads it to the running JVM automatically.  This can be a big time saver for some tricky debugging scenarios, where people tend or want to use System.out.println's over setting breakpoints in a (better) debugger.  The debugger has a few basic debugging features as well, like setting and clearing breakpoints, traversing stack traces, and printing basic variables.  The debugger uses a TCP port, to which a debug client can hook into.  Telnet can give you access to the debugging interface.  This can be convenient for remote debugging sessions where standard remote debugging might be problematic, inconvenient, unfeasible, or too expensive to implement.

Source code

You can download the source code from the cvs server:

cvs -d :pserver:anonymous@exslant.com:/cvs co exslant

(C) Copyright 2004-2007 Mike Pot