Flexible User and Environment Ant Configuration

The de facto standard for building, packaging, and deploying Java applications is
Apache Ant. Small differences in developers' environments
or preferences may cause problems with some Ant tasks that involve
finding or copying files. Standardization takes care of many environmental problems, but
there may be problems when some developers use Linux while others are
using Windows.

There are many good reasons to customize a development environment but, like a tiny pebble caught in your shoe, seemingly minor customizations may cause others a great deal of pain. Changing the build settings to reflect your environment is simple: make the changes and check them into
CVS or VSS. Switching to Jikes from javac or to an app server customized to use appdomain instead of mydomain seem insignificant in the grand scheme of things, but can cause a great deal of confusion and mistrust in the build process. There are, however, legitimate reasons to deviate from the standardized
development environment; therefore, the developer should have the option to do
so without imposing upon the other developers. In this article, you will use standard features of Ant to provide developers and build processes with simple and painless configuration to support their special requirements.

Local Properties

The Ant core tasks include the ability to load properties files, and to use the
properties as build variables. Ant provides the ability to define and use
build variables to hold directory and application values. The variables can
be defined within the build script, the build.xml file, or can be
defined externally, in a properties file. An interesting feature of Ant is that
build variables will keep the original value if the variable is defined and
redefined by the build file or external properties files.

All of the build variables in my build scripts are stored in a properties file
called build.properties. The build.properties file
holds all of the settings of a standardized default development environment. Any
special settings are in a properties file named local.properties.
Any property that is defined in local.properties redefines a
property from build.properties. In my build script, I check for
the existence of the local.properties file. If the file is
available, I load it. Then I load the build.properties file.
The properties from local.properties will have precedence over the properties from
build.properties. My Ant scripts always start with the following code
to load those properties.

A drawback of this strategy is that the local.properties files are
not stored in source control. However, a well-written build.xml
and build.properties file will have minimum settings that can be reasonably
overridden. If local.properties holds a large number of values, the
build.properties file may be poorly defined or the standardized
development environment may not be so standardized.

Organizing the Properties

When a large number of settings are defined for a build script, the build
developer and users need an easy way to view them, preferably before the
build task is executed. For complex settings that depend on other settings,
viewing their values is extremely important. For example, the build script
may have a property for the project directory name, project.dir,
and a set of properties to describe the subdirectories for the source, the
Java source, the Python source, the libraries, and the configuration files that
are based on the project.dir setting.

Using previously defined settings to define new settings is an intelligent and
effective way of avoiding the duplication of information. Knowing how Ant
processes the settings is important when embedding properties to define others.
When a property is interpreted, Ant performs the property expansion and the
value is set. Once set, the value becomes immutable. A common problem is
property expansion of an undefined property. If Ant attempts to process the
project.java.dir property above, and project.src.dir
was not yet set, the value would be ${project.src.dir}/java.
Attempting to change into the ${project.src.dir}/java will result
in unexpected and unwanted behavior.

I use an additional term to describe properties as they are interpreted by Ant
during a build: effective properties. A effective property is a fully expanded
value, and holds the value that Ant will use to execute its tasks. Ensuring
that the effective properties are what the developer expects will ensure that
the build script executes as expected. Therefore, a level of transparency
is needed to view the properties as Ant will use them.

A build task can and should provide a task to display the effective build
settings. The task simply displays the properties that the build task will use
as it executes. An important step is that Ant performs any variable replacement that is
required, so the properties displayed by the task properly reflect how Ant will
see them.

When using the local.properties file, this properties task is
important to make sure that the local properties are being picked
up properly, and that the proper properties are being overridden.

In Practice: Deploying to a J2EE App Server

A common use for using local properties at my job is to deploy our J2EE
application to WebLogic. We recently standardized on WebLogic 7.0 from 6.1,
and during the migration developers found themselves needing to use 6.1 for
bug fixing. The web application for WebLogic 6.1 needed to be deployed into
the C:\bea\wlserver6.1\config\mydomain\applications\FooApp directory, and
for WebLogic 7.0, C:\bea\user_projects\mydomain\applications\FooApp. The
updated build.properties file, after the migration, contained
the following lines for deploying.

When I want to deploy my web application, I copy files to the
${deploy.webapp.dir}, which translates to
C:/bea/user_projects/mydomain/applications/FooWeb. When I want to
deploy the application to WebLogic 6.1, I need to adjust the
${deploy.appserver.dir} and ${deploy.domain.dir}
properties. I create a local.properties file, and override
those two properties. The file looks like the following.

The local.properties overridden properties could have, in fact,
been limited to one. The ${deploy.appserver.dir} could have
been changed to C:/bea/wlserver.6.1/config, and the ${deploy.domain.dir}
been left unchanged. I chose to change two because the app server
directory is C:\bea\wlserver6.1 instead of C:\bea\wlserver6.1\config, in case I
need to get to the C:\bea\wlserver6.1\lib or C:\bea\wlserver6.1\bin
directories.

The changes are simple and tied to the environment of the system, and therefore
can safely live outside of source control and on the edge of standardization.
The developer has not deviated from the standardized environment in a way that
will introduce problems to other developers.

Conclusion

Introducing the ability to work within a flexible area for build and
deployment configuration can reap benefits when small and isolated changes are
required. Used appropriately, the flexibility can free developers from
stiff and unforgiving development environment standards.