Build Process
The build process is performed by Ant and is governed by two files sitting on the top of the source hierarchy: build.xml and build.properties. The latter contains name-value pairs that indicate, mostly, where things are in the file system. It looks similar to Listing 3.1.
Listing 3.1 build.properties File
# Subdirectories of the project tree src=src build=build dist=dist temp=temp deploy=${catalina}/webapps/${app.name} # Third party tools catalina=d:/tools/tomcat-4.0.1 aspectj=d:/t/aspectj1.0 jdbc=d:/tools/mm.mysql.jdbc-1.2c # Flags and settings preprocess=false exclude=aspects/Tracer.java # How the project is called app.name=AspectNews app.version=1.0
As you can see, the properties can depend on other properties. The property deploy, which denotes the destination directory of the compiled application, depends on where Tomcat is installed (catalina=d:/tools/tomcat-4.0.1) and what the application is called (app.name=AspectNews). Thus, at runtime this property will be set to D:/tools/tomcat-4.0.1/webapps/AspectNews.
The build.xml file contains detailed instructions for tools on building the entire project. These instructions are called tasks in Ant's lingo, and the file is presented in Listing 3.2.
Listing 3.2 build.xml File
<project name="aj" default="deploy" basedir="."> <!-- Set global properties for this build from the file --> <property file="build.properties"/> <!-- Special task to run AspectJ compiler --> <taskdef name="ajc" classname="org.aspectj.tools.ant.taskdefs.Ajc" > <classpath> <pathelement location="${aspectj}/aspectj-ant.jar"/> <pathelement location="${aspectj}/lib/aspectjtools.jar"/> </classpath> </taskdef> <target name="init" description="Do all the preparation work."> <!-- Create the build directory structure used by compile --> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="Creates an executable content in build subdirectory."> <!-- Copy the content of the web subdirectory with JSP and configuration files to the destination --> <copy todir="${build}"> <fileset dir="web"/> </copy> <!-- Create subdirectory for classes --> <mkdir dir="${build}/WEB-INF/classes"/> <!-- Run the AspectJ compiler using the special task --> <ajc workingdir="${temp}" srcdir="${src}" preprocess="${preprocess}" includes="tags/*,security/*,servlets/*,db/*,aspects/*" excludes="${exclude}" destdir="${build}/WEB-INF/classes" > <!-- include libraries needed to compile the target files --> <classpath> <pathelement location="${aspectj}/lib/aspectjrt.jar"/> <pathelement location="${catalina}/common/lib/servlet.jar"/> </classpath> </ajc> </target> <target name="deploy" depends="compile" description="Deploy application to servlet container"> <!-- Copy the contents of the build directory --> <mkdir dir="${deploy}"/> <copy todir="${deploy}"> <fileset dir="${build}"/> </copy> <!-- Copy external dependencies as required --> <mkdir dir="${deploy}/WEB-INF/lib"/> <copy todir="${deploy}/WEB-INF/lib" file="${aspectj}/lib/aspectjrt.jar" /> <copy todir="${deploy}/WEB-INF/lib" file="${jdbc}/mysql_uncomp.jar" /> </target> </project>
Several things in this file deserve special notice. At the beginning, the properties file build.properties is read. It is far more convenient to keep properties in a separate file than to edit the main build file every time something changes. Next comes the definition of a special task for AspectJ compiler. Ant comes with a collection of predefined tasks for pretty much anything a reasonable Java developer will need to build a project. But because AspectJ pushes the boundaries, it needs to tell Ant how to run its compiler ajc. For that purpose the AspectJ team has developed the special class library that does just that. Ant has to be configured to use it and this is what the task definition task (almost anything in Ant is a task) doesit defines tasks new to Ant, in this case called ajc and implemented by the main class org.aspectj.tools.ant.taskdefs.Ajc. These two things (reading the property file and defining a special task for ajc) are all that is required to configure the build process.
The main content of the build file is the collection of targets. Each target contains a set of tasks that are executed in sequence unless otherwise specified (it will not be in this example). Targets might depend on each other; for example, target compile will not execute until target init is done. Target deploy needs to be preceded by compile and so on.
The init target is straightforward, it just creates the build directory. The most interesting target is the compile. First of all, it creates a directory where Java byte codes will go. Second, it executes the AspectJ compilation task ajc. Its attributes correspond to command-line parameters of the AspectJ compiler ajc described in detail in Appendix B, "AspectJ Command-Line Tools" (this is ajc, after all). Their meanings are as follows:
workingdir is the directory where intermediate files are storedin this case mapped to the temporary directory. In the case of the preprocess flag set to true (see the following), this is where all precompiled Java files will end up.
srcdir is the directory where sources are. The particular filenames specified using the includes attribute are relative to this directory.
preprocess is a flag that tells ajc just to compile aspects to plain Java and stop without producing any byte codes.
includes lists all the sources that need to be compiled (wild cards are supported). On Listing 3.2 only sources for AspectNews application are specifiedpackages intro and language are not included into the build process.
excludes lists all the sources that need not to be compiled (wild cards, again, are supported). It is used to exclude development aspects for production builds.
destdir specifies where byte codes should goin this case where the servlet container will expect to find them.
The ajc task also needs the class path. Only two additional libraries are needed: AspectJ's own runtime library aspectjrt.jar and the servlet library from the Tomcat distribution servlet.jar. Note that there is no need for the JDBC library because all needed interfaces are described in the standard java.sql package. The deploy target just copies what has been built in the build directory to Tomcat's Web application hierarchy as specified by the deploy parameter. It also copies two libraries that will be needed at runtime: the AspectJ's runtime and JDBC driverthis time around it is, indeed, needed.
The Ant's build process can be started as follows:
shell>ant.bat file path_to_aj/aj/build.xml target
target is the name of the target we are trying to build. If target is omitted, Ant will build the default onedeploy in our example (see Listing 3.2).