BUY THIS BOOK
Add to Cart

Print Book $59.99


Add to Cart

Print+PDF $77.99

Add to Cart

PDF $47.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £37.50

What is this?

Looking to Reprint or License this content?


Java Power Tools
Java Power Tools

By John Ferguson Smart
Book Price: $59.99 USD
£37.50 GBP
PDF Price: $47.99

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Setting Up a Project Using Ant
Ant is a popular and widely used open source build tool, written in Java. Indeed, it is probably the most widely used build tool in the Java world. It is supported by virtually all modern IDEs, and (being a Java application) runs on almost any Java-friendly .
In a nutshell, Ant helps you transform the source code, libraries, and other files that make up your project into a deliverable software package. And, more importantly, it helps you do this in an orderly, repeatable manner. If you design your build script well, you can also ensure that it will behave the same way on any machine. This leads the way to automatic builds, which can be run on a remote machine with little or no human intervention. In , we discuss how to use Continuous Integration tools to take this process even further.
Ant is a highly flexible tool—you can make it do pretty much anything you want. However, this flexibility can come at a cost of complexity. Good Ant build scripts are written in a way that will be easy to read and maintain in a year’s time. In this chapter, I will try to show some best practices that should help make your scripts clean and .
At the time of this writing, there were no graphical installers available, although Ant is now provided as a standard package for many Unix distributions. Nevertheless, you will often get a more complete installation if you download and install Ant manually.
Ant should run correctly on any Java-friendly platform. Ant is a pure Java tool, so it does require a (preferably recent) JDK installation to work.
So, as a prerequisite for installation, you should check that your machine has a correctly installed JVM:
$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Server VM (build 1.6.0-b105, mixed mode)
The following two sections will discuss how to install Ant on Unix and Windows .
Download the latest stable binary release of Ant from the Ant web site, and extract it into an appropriate directory. On my machine, I installed it into the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Ant in the Build Process
Ant is a popular and widely used open source build tool, written in Java. Indeed, it is probably the most widely used build tool in the Java world. It is supported by virtually all modern IDEs, and (being a Java application) runs on almost any Java-friendly .
In a nutshell, Ant helps you transform the source code, libraries, and other files that make up your project into a deliverable software package. And, more importantly, it helps you do this in an orderly, repeatable manner. If you design your build script well, you can also ensure that it will behave the same way on any machine. This leads the way to automatic builds, which can be run on a remote machine with little or no human intervention. In , we discuss how to use Continuous Integration tools to take this process even further.
Ant is a highly flexible tool—you can make it do pretty much anything you want. However, this flexibility can come at a cost of complexity. Good Ant build scripts are written in a way that will be easy to read and maintain in a year’s time. In this chapter, I will try to show some best practices that should help make your scripts clean and .
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Installing Ant
At the time of this writing, there were no graphical installers available, although Ant is now provided as a standard package for many Unix distributions. Nevertheless, you will often get a more complete installation if you download and install Ant manually.
Ant should run correctly on any Java-friendly platform. Ant is a pure Java tool, so it does require a (preferably recent) JDK installation to work.
So, as a prerequisite for installation, you should check that your machine has a correctly installed JVM:
$ java -version
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Server VM (build 1.6.0-b105, mixed mode)
The following two sections will discuss how to install Ant on Unix and Windows .
Download the latest stable binary release of Ant from the Ant web site, and extract it into an appropriate directory. On my machine, I installed it into the /usr/share directory. I also created a convenient symbolic link to make later updates easier:
# cd /usr/share
# tar xvfz apache-ant-1.7.0-bin.tar.gz ant-1.7.0
# ln -s ant-1.7.0 Ant
Now, you should have a full Ant distribution installed on your machine:
# ls -al /usr/share/ant
lrwxrwxrwx 1 root root 9 2007-08-04 22:36 Ant -> ant-1.7.0
# ls /usr/share/ant
bin   fetch.xml   KEYS     LICENSE.dom     NOTICE
docs  get-m2.xml  lib      LICENSE.sax     README
etc   INSTALL     LICENSE  LICENSE.xerces  WHATSNEW
Once this is done, you need to set up some environment variables. Ant requires two to function. First, set the ANT_HOME variable to the directory where you have installed Ant. You also need to ensure that the JAVA_HOME variable is correctly defined, as the Ant startup script uses both of these variables. This usually goes in one of your environment initialization scripts (for example, if you are using Bash, you could place this configuration in the ~/.bashrc file if you just need to set it up for your account, or in if you want to set it up for all users on this machine):
ANT_HOME=/usr/share/ant
JAVA_HOME=/usr/lib/jvm/java
PATH=$PATH:$ANT_HOME/bin:$JAVA_HOME/bin
export PATH ANT_HOME JAVA_HOME
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
A Gentle Introduction to Ant
Now that you have installed Ant, we can take it through its paces. Ant is an extremely powerful tool, and experienced users can really make it sing. We will start off simply, going through how to set up a small Java project with Ant.
Ant build files are written in XML, using a quite readable set of tags. The overall structure of an Ant file is relatively straightforward and intuitive. An Ant build file describes how to build one (and only one) project. A build project is made up of targets and tasks.
A target is a goal that you want your build process to achieve. Such a goal might be to compile your application code, run your tests, or prepare a production-ready release package. You can (and usually do) define several targets in your build file, which you may run on different occasions.
A target can also depend on other targets. This lets you ensure that certain targets are always executed before others. For example, you might want to ensure that your unit test’s target is always run before you prepare a new release. You do this by declaring dependencies between your targets.
A task lets you define a piece of work you want done. This might be compiling some Java source code using javac, running a set of unit tests using JUnit, or generating a production-ready JAR file using the jar utility. This is where the work actually gets done. The task is the workhorse of the Ant build process and the source of a lot of its power and flexibility. Behind the scenes, Ant tasks are actually implemented as Java classes, which makes it fairly easy to extend Ant by writing new tasks. This is one of the reasons that the majority of Java tools, both open source and commercial, provide an Ant task library. Indeed, Ant comes with a rich library of built-in (or “core”) and optional tasks. Core tasks are built into Ant, and need no special configuration. Optional tasks are maintained by the Ant team and delivered with Ant, but they rely on an external library. For example, the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Compiling Your Java Code in Ant
In Java development, one of the most fundamental things that any build script needs to do is compile your code. In Ant, the <javac> task provides a convenient one-stop shop for Java compilation.
Let’s look at a simple use of the <javac> task. In the example given above, we use a simple form of this task to compile the Java classes in the src/main directory, and place the compiled classes in the build/classes directory:
  <target name="compile" depends="init" description="Compile Java code">
    <javac srcdir="src" destdir="build/classes"/>
  </target>
This is equivalent to executing the javac tool as shown here:
  $ javac -nowarn -d build/classes src/main
Admittedly, you would rarely compile an application this simple in the real world. In most real applications, your application will require a set of libraries both to compile and to run. In Ant projects, these libraries are often stored (in the form of JAR files) in a directory called lib. When you compile your application, you need to tell Ant where to find these libraries.
Ant comes with some very powerful features to help you do this. Ant excels at defining and manipulating classpaths and other file path definitions. In Ant, these definitions are known as “path-like” structures, and they are used extensively in all but the most trivial build files. At its simplest, you can use the <path> tag to identify a particular library using the location attribute:
  <path id="junit.classpath" location="lib/junit.jar"/>
This path could also be defined in the same way using the path attribute. However, in addition to defining single JAR files or directories, the path attribute lets you use a more path-like construction using a combination of directory paths and a JAR file, as shown here:
  <path id="junit.classpath" path="build/classes:lib/junit.jar"/>
One of the nice things about the Ant path-handling features is that they are (like the underlying Java APIs) portable across different operating systems. Here, by convention, we use Unix-style paths containing forward slashes (“/”). For example, on a Windows machine, Ant will automatically translate the above path into “build\classes;lib\.”
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Customizing Your Build Script Using Properties
In development, people often speak of the DRY (Don’t Repeat Yourself) principle. This is a general principle aimed at making code more readable and easier to maintain by avoiding the duplication of data. In a Java application, for example, key values that are used in several places, or that may need to be modified easily, are stored as constants or as parameters in a configuration file. This makes the code easier to read and understand, and makes maintenance less of a headache.
In Ant, you can do the same sort of thing by using the <property> tag, which lets you declare constant values that can be used throughout the rest of your build file. Declaring a property is straightforward; you just need to provide a name and value attribute, as shown here:
<property name="javac.debug" value="on"/>
If you are referring to a directory, you can use the location attribute instead of value:
<property name="build.dir" location="build"/>
This property value will be set to the absolute filename of the build directory.
To use a property elsewhere in the build file, you just quote the name of the property surrounded by ${...}. For example, you can subsequently refer to this property anywhere in your build file as ${build.dir}. You could use the <echo> task to display the property value to the screen, as shown here:
    <target name="display-properties">
        <echo>Debug = ${javac.debug}</echo>
        <echo>Build directory (build.dir) = ${build.dir}</echo>
    </target>
Calling this target would display the value of this property on the console. On my machine, it displays the following:
$ ant display-properties
Buildfile: build.xml

display-properties:
     [echo] Build directory (build.dir) = /home/john/projects/tax-calculator/build

BUILD SUCCESSFUL
Total time: 0 seconds
Another way to do this would be to use the <echoproperties> task, which, as the name suggests, lets you display all of the current property values to the console:
    <target name="display-properties">
        <echoproperties />
    </target>
Properties can also be used to take into account environment differences on each developer’s machine. For example, you may need to store a path to a local server or to application directories, which may be different on different machines. To do this, you can store local properties in an ordinary Java properties file. The following directories would be different on Unix and Windows machines. On a Linux development box, you might have the following set of properties:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Running Unit Tests in Ant
Unit testing is a fundamental part of Java development, and, applied correctly, can contribute substantially to the quality and reliability of your code. Modern coding techniques, such as test-driven development (TDD) and, more recently, behavior- development, rely heavily on unit testing to ensure that code is both well designed and well tested.
Unit testing is good, but automated unit testing is better. When your unit tests are integrated into your build process, you can run them automatically before each build or before committing code to your version control system. This helps to ensure that your latest changes haven’t introduced any new errors. This is also known as regression testing. It makes refactoring your code safer and easier, as you can change code without having to worry about unknowingly breaking existing code—as long as you rerun the entire set of unit tests at frequent intervals.
Let’s look at how to integrate JUnit tests into your Ant build process.
JUnit (see ) is probably the most well-known and widely used unit testing framework in the Java world. A groundbreaking piece of software in its time, JUnit 3 is still the basis of a very large range of unit testing libraries. The more recent JUnit 4 introduces annotation-based testing and some other more modern features.
You can run your JUnit tests in Ant using the <junit> task, which is what’s known as an optional task. In Ant, optional tasks are tasks that generally depend on external libraries, such as the JUnit library in this case. Ant comes bundled with the task itself, but, if you want to use the task, you need to provide the external library yourself. This is as opposed to core tasks, which are fully integrated into Ant and need no external libraries.
Historically, Ant’s JUnit integration has been a bit rough. In older versions of Ant (prior to Ant 1.7), you need to place your own copy of the junit.jar file into the $ANT_HOME/lib directory, alongside the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Generating Documentation with Javadoc
Technical documentation is an important part of any project, and Javadoc is one of the cornerstones of technical documentation in Java. Javadoc produces a quite decent, usable set of API documentation for your Java code, which can be a valuable aid as a communication tool, helping team members understand what other team members are doing. Of course, good Javadoc requires well-written and meaningful comments within the source code, and enforcing that is a tall order for any tool. And Javadoc documentation is by definition low-level reference material—it can be very useful for an application developer familiar with the application, but it will be of limited use for a new developer trying to learn the application architecture. Despite these reservations, Javadoc should be an integral part of any development project.
It is a good idea to generate Javadoc as part of your build process. Javadoc documentation should be generated and published alongside the compiled source code and the unit test results as part of the automatic build lifecycle. In Ant, you can do this using the <javadoc> task. This task has a lot of attributes and nested elements, but only a few are essential. Here is a simple example:
    <target name="javadoc" depends="compile,init" description="Generate JavaDocs.">        
         <javadoc sourcepath="${src.dir}"
                   destdir="${reports.javadoc}"
                   author="true"
                   version="true"
                   use="true"
                   access="private"
                   linksource="true"             
                   windowtitle="${ant.project.name} API">            
            <classpath>
                <path refid="compile.classpath" />
                <pathelement path="${build.classes.dir}" />
            </classpath>             
            <doctitle><![CDATA[<h1>${ant.project.name}</h1>]]></doctitle>
            <bottom><![CDATA[<i>Copyright &#169; 2007 All Rights Reserved.
            </i>]]></bottom>             
          </javadoc>        
    </target>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Packaging Your Application
Once you have compiled and tested your application, the next step is to bundle up the compiled code into a deliverable application or library. This can take different forms, depending on your project: you may have to prepare a JAR file, a WAR file, or possibly a ZIP or TAR file containing the executable code plus other files such as documentation and source code. Ant has many powerful features that can help you prepare your application for delivery. In the following sections, we will look at a few of the more interesting ones.
The most fundamental Java packaging mechanism is the JAR file. A JAR file is essentially a ZIP file containing a hierarchy of compiled Java classes, plus some metadata. WAR and EAR files are similar, with some extra constraints on their internal directory structure and content.
The basic usage of the <jar> task is simple. Here is an example from our sample application, where we bundle the compiled classes into a JAR file:
    <property name="project.name" value="{ant.project.name}" />
    <property name="project.version" value="1.0" />
    ...
    <target name="package" depends="compile" description="Generate JAR file">
        <jar destfile="${dist.dir}/${project.name}-${project.version}.jar" basedir=
         "${build.classes.dir}"/>
    </target>
Running this will (surprise, surprise!) generate a JAR file containing your compiled classes:
$ ant clean package
Buildfile: build.xml

clean:
   [delete] Deleting directory /home/wakaleo/projects/jpt-sample-code/ant-demo/dist
   [delete] Deleting directory /home/wakaleo/projects/jpt-sample-code/ant-demo/reports

init:
    [mkdir] Created dir: /home/wakaleo/projects/jpt-sample-code/ant-demo/dist
    [mkdir] Created dir: /home/wakaleo/projects/jpt-sample-code/ant-demo/reports/xml
    [mkdir] Created dir: /home/wakaleo/projects/jpt-sample-code/ant-demo/reports/html

compile:

package:
      [jar] Building jar: /home/wakaleo/projects/jpt-sample-code/ant-demo/dist/
      tax-calculator-1.0.jar

BUILD SUCCESSFUL
Total time: 0 seconds
We use the Maven convention for naming JAR files here, which is to add the version number to the end of the filename. This makes it easier to identify file versions at a glance. The project name comes from the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Deploying Your Application
Once you have generated a packaged version of your application, you will certainly want to deploy it. For example, if you are developing a web application, you may want to deploy it to a web server on your own machine, or to a remote server for testing. Or, if you are developing a shared library, you may copy your latest version to a local web server, where other users can consult the documentation and download the API.
The simplest way to deploy an application is to copy the packaged file to the target server. Of course, this will only work if the target server is hosted on the development machine or if the target server has a shared drive that can be mapped to from the development/build machine, and the current user has write access to these directories. Because this is generally the case for a local development machine, this approach is often a simple, pragmatic way to deploy (and redeploy) a web application to a locally running application server. You can copy a file to another directory by using the <copy> task, as shown here:
    <property name="tomcat.install.dir" location="${user.home}/servers/tomcat
     /apache-tomcat-5.5.23" />

    <target name="local.deploy" depends="war" description="Deploy to local 
    Tomcat instance">
        <copy file="${dist.dir}/${project.name}-${project.version}.war" 
              todir="${tomcat.install.dir}/webapps" />    
    </target>
In this example, we simply defined a property pointing to a local Tomcat installation, and used the <copy> task to copy the generated WAR file to the Tomcat webapps directory, where Tomcat will be able to pick it up and deploy it automatically. Many application servers work in the same way.
Of course, you may want to rename the WAR file on the way. Typically, you may want to strip off the version number when you deploy the web application so that users can simply access the application using the project name. You can do this using the tofile attribute instead of todir:
    <property name="tomcat.install.dir" location="${user.home}/servers/tomcat
     /apache-tomcat-5.5.23" />

    <target name="local.deploy" depends="war" description="Deploy to local 
     Tomcat instance">
        <copy file="${dist.dir}/${project.name}-${project.version}.war" 
              tofile="${tomcat.install.dir}/webapps/${project.name}.war" />    
    </target>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Bootstrapping Your Build Scripts
As a rule, your build scripts should be as portable as possible. In an ideal world, a new user with a vanilla installation of Ant should be able to check out the project source code and use the build scripts immediately, as-is. No extra configuration should be required—no deploying JAR files in strange places, no setting up exotic configuration files, and so on.
Of course, in real-world projects, things often aren’t quite this simple. Your build file will often use nonstandard tasks that need to be installed. It is a tiresome task to hunt down and install the dozen or more Ant extensions that a real-world Ant build file will typically need, and issues may arise if different users have different versions of the extension libraries. This is clearly a good place to automate things.
One useful technique for doing this is writing bootstrap build files that download and install extra libraries that your project needs. This is fairly easy to do using standard Ant tasks such as <get>, <unzip>, and <available>. An example of a typical bootstrap script (called bootstrap-findbugs.xml), which downloads and installs the Findbugs package, is shown here:
<project name="FindBugs Bootstrap script" default="bootstrap" basedir="." >
    
  <!-- Define the environment-specific variable "findbugs.home" in this file. -->  
  <property file="${user.home}/ant-global.properties"/>
  <!-- This default values used if no properties file is present -->
  <property name="findbugs.home" value="${user.home}/.findbugs"/>
  <property name="findbugs.version" value="1.2.0"/>
  
  <echo>Installing FindBugs into ${findbugs.home}</echo>
  <property name="sourceforge.mirror"  
            value="http://optusnet.dl.sourceforge.net/sourceforge" />
    
  <available file="${findbugs.home}/findbugs.zip" property="findbugs.installed"/>
 
  <echo>Bootstrap FindBugs</echo>      
  <target name="bootstrap" unless="findbugs.installed">
    <echo>Installing FindBugs</echo>
    <mkdir dir="${findbugs.home}" />        
    <get src="${sourceforge.mirror}/findbugs/findbugs-${findbugs.version}.zip" 
         dest="${findbugs.home}/findbugs.zip" usetimestamp="true"/>
    <unzip src="${findbugs.home}/findbugs.zip" 
           dest="${findbugs.home}"/>
    <move todir="${findbugs.home}">
        <fileset dir="${findbugs.home}/findbugs-${findbugs.version}">
          <include name="**/*"/>
        </fileset>              
    </move>
    <delete dir="${findbugs.home}/findbugs-${findbugs.version}"/>
  </target>
  
</project>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Maven Dependencies in Ant with the Maven Tasks
One of the key features of Maven (see ) is its use of a central repository to store dependencies and identify the libraries needed by an application. Maven 2 also supports transitive dependencies, a powerful concept that lets you limit the dependencies you need to declare to the strict minimum.
When you bundle and deploy an application, you not only need to include the libraries that your application requires, but you also need to include the additional libraries required by these libraries to work. So, if your application uses Hibernate, you will also need all of the libraries required by Hibernate. In real-world projects, this can amount to quite a list.
If your build framework supports transitive dependency management, you need only to declare the libraries that your application uses directly. The build tool will take care of the others. So, if your application uses Hibernate, you only need to state the exact version of Hibernate you are using, and not the other libraries that Hibernate needs. This makes your project dependencies simpler and easier to understand.
Ant does not support dependency management “out-of-the-box.” In Ant projects, all the libraries needed by an application are typically placed in a project directory—sometimes stored in the version control system, sometimes not (opinions vary on this point). This can create a number of problems because it is hard to know exactly which versions of libraries are required or currently being used. When libraries are stored in the version control system, projects can take up a lot of space (particularly if CVS is used), and they can take a long time to download. By contrast, if they are not stored in the version control system, some convention needs to be established to work out where to obtain the libraries needed for a given project.
A much better approach is to use one of several Ant extensions to manage dependencies declaratively. In this chapter, we will discuss the Maven 2.0 Ant tasks.
An alternative approach to dependency management in Ant is to use Ivy. Ivy is a powerful and flexible dependency management tool that integrates well into Ant projects, and it provides some interesting features as well as some nice reporting capabilities (
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Ant in Eclipse
Ant is well-supported in virtually all modern Java IDEs, and Eclipse is no exception. Eclipse allows you to create a new Eclipse project using an existing Ant file, and recognizes the structure of Ant build files. The Outline view gives you a structured vision of your build file. In addition, you can execute any target directly from within Eclipse using the contextual menu (see ).
Figure : Using Ant in Eclipse
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Ant in NetBeans
Ant integrates smoothly into NetBeans. Indeed, by default, NetBeans uses Ant internally to organize your project, even if you don’t ask it to. NetBeans automatically recognizes Ant build files and displays the build file targets. As in Eclipse, you can execute targets directly using the contextual menu (see ).
Figure : Using Ant in NetBeans
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Manipulating XML with XMLTask
Contributed by: Brian Agnew
For simple text search and replace operations, the Ant <replace> task is sufficient. But in modern Java frameworks, you are more likely to need powerful XML manipulation capabilities to modify servlet descriptors, Spring configurations, and the like.
XMLTask is an Ant external task that provides powerful XML editing tools focused on creating and changing XML files as part of a build/deployment process.
What are the advantages of using XMLTask?
  • Unlike the Ant task, <replace> XMLTask gives you the ability to identify parts of an XML document using XPath, and to insert, remove and copy XML at these locations. You can use XPath to simply identify an XML element, or use more complex logic with predicates (“find me the element called ‘X’ with an attribute of ‘Y’…”).
  • XMLTask is “XML-aware.” This means that you can’t create an XML document that isn’t well-formed. XMLTask will handle character-encoding issues, whereas <replace> has no knowledge of the encoding requirements of your XML . For example, <replace> will allow you to insert the characters “<,” “>,” and “&” into an XML document without using the corresponding entities (“<” “>” and “&”), and thus possibly break the “well-formedness” of your .
  • XMLTask doesn’t require you to learn or use XSLT to perform XML manipulations. It uses intuitive instructions such as insert, replace, and remove.
XMLTask is easy to use. Take a look at the XMLTask home page, or download from Sourceforge. You don’t need to be knowledgeable about XPath to use XMLTask, but if you need an introduction, take a look at the tutorial on http://www.zvon.org.
Let’s look at a simple example. Imagine you have a Spring configuration that you want to modify. For instance, you may be making changes for development, test, and release versions, and want to perform insertions, replacements, and removals.
A simple XMLTask is shown below:
<project name="xmltask-demo" default="main">
  <!--xmltask.jar should be referenced via lib, or in the ${ant.home}/lib or similar 
   --> <taskdef  name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>

  <!-- you may need to reference a local copy of the DTD here if your XML
         documents specify one. See below for more info -->
  <xmlcatalog id="dtd"> 
     <dtd 
        publicId="-//SPRING//DTD BEAN//EN"
        location="./spring-1.0.dtd"/> 
  </xmlcatalog> 

  <target name="main">
    <xmltask source="spring-template.xml" dest="spring.xml" preserveType="true">
      <xmlcatalog refid="dtd"/> 
      <insert path="/beans" position="under">
          <![CDATA[
            <bean id="bean-to-insert" class="com.oopsconsultancy.example.Bean1">
                <constructor-arg index="0">
                  .....
                </constructor-arg>
            </bean>
           ]]>
      </insert>
    </xmltask>
  </target>
</project>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Conclusion
Using XMLTask, you can maintain, create, and modify XML files with a tool that is much more powerful than the standard <replace> or file creation tasks, and yet not have to worry about using XSLT. We’ve not covered many of its functions here. See the home page (http://www.oopsconsultancy.com/software/xmltask) for more information and examples. A mailing list (subscription only) is also available (https://lists.sourceforge.net/lists/listinfo/xmltask-users).
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Setting Up a Project Using Maven 2
In this chapter, we look at the second major player in the Java build tools arena: . Maven is an increasingly popular open source build management tool for enterprise Java projects, designed to take much of the hard work out of the build process. Maven uses a declarative approach, in which the project structure and contents are described, rather then the task-based approach used in Ant or in traditional Make files or shell scripts. Maven also strongly promotes the use of standard directory structures and a well-defined build lifecycle. This helps enforce company-wide development standards and reduces the time needed to write and maintain build scripts.
Maven’s authors describe Maven as a “project management framework,” and it is indeed much more than just a simple build scripting tool. Maven’s declarative, standards-based approach to project build management simplifies many aspects of the project lifecycle. As well as catering for compiling, building, testing, and deploying your with a minimum of effort, Maven offers a number of other key advantages:
  • Project dependencies are declared and managed in a clean, transparent way, which reduces the risk of dependency-related errors and makes for better documentation.
  • Maven lets you easily generate useful, high-quality, technical documentation and reports about the current state of the project and project team members. Note that we aren’t taking about a good user manual, which is an altogether different issue, but, rather, about technical documentation, written by developers for developers. In many technical projects, decent technical documentation is woefully inadequate. It is nevertheless a vital part of modern software development, especially when dislocated teams are involved.
  • Maven proposes a clear standard directory layout for source code, project resources and configuration files, generated output, and project documentation. This makes it easier to understand new Maven projects, and also makes the Maven build scripts cleaner and simpler.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Maven and the Development Build Process
In this chapter, we look at the second major player in the Java build tools arena: . Maven is an increasingly popular open source build management tool for enterprise Java projects, designed to take much of the hard work out of the build process. Maven uses a declarative approach, in which the project structure and contents are described, rather then the task-based approach used in Ant or in traditional Make files or shell scripts. Maven also strongly promotes the use of standard directory structures and a well-defined build lifecycle. This helps enforce company-wide development standards and reduces the time needed to write and maintain build scripts.
Maven’s authors describe Maven as a “project management framework,” and it is indeed much more than just a simple build scripting tool. Maven’s declarative, standards-based approach to project build management simplifies many aspects of the project lifecycle. As well as catering for compiling, building, testing, and deploying your with a minimum of effort, Maven offers a number of other key advantages:
  • Project dependencies are declared and managed in a clean, transparent way, which reduces the risk of dependency-related errors and makes for better documentation.
  • Maven lets you easily generate useful, high-quality, technical documentation and reports about the current state of the project and project team members. Note that we aren’t taking about a good user manual, which is an altogether different issue, but, rather, about technical documentation, written by developers for developers. In many technical projects, decent technical documentation is woefully inadequate. It is nevertheless a vital part of modern software development, especially when dislocated teams are involved.
  • Maven proposes a clear standard directory layout for source code, project resources and configuration files, generated output, and project documentation. This makes it easier to understand new Maven projects, and also makes the Maven build scripts cleaner and simpler.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Maven and Ant
Without a doubt, the most popular and most well-known build tool in the Java sphere is Ant. Ant (see ) is a fine tool and a hugely successful open source project. Millions of Java developers are familiar with it. And, as we will see throughout the rest of the book, there is hardly a Java tool in existence that doesn’t integrate with Ant.
However, when you write a lot of Ant build scripts, you find yourself asking yourself (and other teamg members) the same questions over and over again: Where will the source code go? What about the unit tests? How do we handle dependencies? How will we bundle up the deliverable application? What shall we call the main targets? Individually, Ant lets you deal with each of these tasks with a high degree of flexibility and power. However, you still have to write the tasks from scratch or duplicate and modify an Ant script from a previous project. And when you move to a new project or company, you need to ask these questions once again to (begin to) understand the build process in place.
Many (although not all) projects do follow fairly common and well-known patterns. A lot of what you need to configure in your build process is pretty much run-of-the-mill. It always seems a shame to redo the work again for each new project.
Maven can help you here. Maven takes a lot of the grunt work out of the build process, and tries to lever the combined experience and best practice of a large community of developers. By adhering to a certain number of conventions and best practices, Maven lets you remove the drudgery of all the low-level tasks in your build scripts. In the rest of this chapter, we will see how.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Installing Maven
In this chapter, we will go through how to install Maven 2 on various platforms. The basic installation process is straightforward, and is the same for all platforms. Maven is a pure Java tool, so first of all you need to ensure that there is a recent version of Java (1.4 or later) on your machine. Then, download the latest distribution from the Maven download site and extract it into an appropriate directory. Finally, just add the bin subdirectory to the system path.
If you are familiar with installing Java tools, this should be enough to get you started. In the rest of this chapter, we discuss some more detailed environment-specific .
In this chapter, we run through how to install Maven into a Unix environment.
Installing Maven in a Unix-based environment is a relatively simple task. Download the latest version in the format of your choice, and extract it to an appropriate directory. Conventions vary greatly from one system to another, and from one system administrator to another: I generally place the maven installation in a nonuser-specific directory such as /usr/local, as shown here:
# cd /usr/local
# tar xvfz maven-2.0.7-bin.tar.gz
# ls
This will extract the maven installation in a directory called maven-2.0.7. For convenience, on a Unix system, I generally create a symbolic link to this directory to make upgrades easier to manage:
# ln -s maven-2.0.7 maven
# ls -al
total 16
drwxr-xr-x  3 root root 4096 2006-08-06 13:18 .
drwxr-xr-x 53 root root 4096 2006-07-20 21:32 ..
lrwxrwxrwx  1 root root   11 2006-08-06 13:17 maven -> maven-2.0.7
drwxr-xr-x  6 root root 4096 2006-08-06 13:17 maven-2.0.7
Now just add the maven/bin directory to your environment path. Typically, you will set this up in one of your environment initialization scripts (for example, if you are using Bash, you could place this configuration in the ~/.bashrc file if you just need to set it up for your account, or in /etc/bashrc if you want to set it up for all users on this machine). Don’t forget to make sure that the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Declarative Builds and the Maven Project Object Model
Before we look at how to create and work with projects in Maven, we need to discuss some of the basics. The most fundamental of these is the Maven Project Object Model, or POM, which we will look at in this chapter. In the process, we also will cover some important basic principles of Maven development, as well as a lot of the key features of Maven. As many, if not most, new Maven users are already familiar with Ant, we will look at how the Maven approach differs from the one used by Ant, and how this can help simplify your builds.
For Ant users, the Maven philosophy can take a little getting use to. Unlike Ant, which is very much task-oriented, Maven uses a highly declarative approach to project builds. In Ant, for example, you list the tasks that must be performed to compile, test, and deliver your product. In Maven, by contrast, you describe your project and your build process, relying on conventions and sensible default values to do much of the grunt work. The heart of a Maven 2 project, the POM, describes your project, its structure, and its dependencies. It contains a detailed description of your project, including information about versioning and configuration management, dependencies, application and testing resources, team members and structure, and much more. The POM takes the form of an XML file (called pom.xml by default), which is placed in your project home directory.
Let’s look at a practical example. One of the most fundamental parts of any Java build process involves compiling your Java classes. In a typical Ant build, you would use the <javac> task (see ) to compile your classes. This involves defining the directory or directories containing your Java source code, the directory into which the compiled classes will be placed, and creating a classpath that contains any dependencies needed to compile your classes. Before invoking the compiler, you need to be sure to create the target directory. The corresponding Ant script might look something like this:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Understanding the Maven 2 Lifecycle
Project lifecycles are central to Maven 2. Most developers are familiar with the notion of build phases such as compile, test, and deploy. Ant build scripts typically have targets with names like these. In Maven 2, this notion is standardized into a set of well-known and well-defined lifecycle phases (see ). Instead of invoking tasks or targets, the Maven 2 developer invokes a lifecycle phase. For example, to compile the application source code, you invoke the “compile” lifecycle phase:
$ mvn compile
Figure : Maven 2 lifecycle phases
Some of the more useful Maven 2 lifecycle phases are the following (see ):
generate-sources
Generates any extra source code needed for the application, which is generally accomplished using the appropriate plug-ins.
compile
Compiles the project source code.
test-compile
Compiles the project unit tests.
test
Runs the unit tests (typically using JUnit) in the src/test directory. If any tests fail, the build will stop. In all cases, Maven generates a set of test reports in text and XML test reports in the target/surefire-reports directory (see ).
package
Packages the compiled code in its distributable format (JAR, WAR, etc.).
integration-test
Processes and deploys the package if necessary into an environment in which integration tests can be run.
install
Installs the package into the local repository for use as a dependency in other projects on your local machine.
deploy
In an integration or release environment, this copies the final package to the remote repository for sharing with other developers and projects.
The full list is much longer than this, and can be found on the Maven web site.
These phases illustrate the benefits of the recommended practices encouraged by 2: once a developer is familiar with the main Maven lifecycle phases, he or she should feel at ease with the lifecycle phases of any Maven project. The lifecycle phase invokes the plug-ins it needs to do the job. Invoking a lifecycle phase automatically invokes any previous lifecycle phases as well. Because the lifecycle phases are limited in number, easy to understand, and well organized, becoming familiar with the lifecycle of a new Maven 2 project is easy.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Maven Directory Structure
Much of Maven’s power comes from the standard practices that it encourages. A developer who has previously worked on a Maven project immediately will feel familiar with the structure and organization of a new one. Time need not be wasted reinventing directory structures, conventions, and customized Ant build scripts for each project. Although you can override any particular directory location for your own specific ends, you really should respect the standard Maven 2 directory structure as much as possible, for several reasons:
  • It makes your POM file smaller and simpler.
  • It makes the project easier to understand and makes life easier for the poor guy who must maintain the project when you leave.
  • It makes it easier to integrate plug-ins.
The standard Maven 2 directory structure is illustrated in .
Figure : A typical Maven directory structure
The POM (pom.xml) and two subdirectories go into the project home directory: src for all source code and target for generated artifacts. The src directory has a number of subdirectories, each of which has a clearly defined purpose:
src/main/java
Your Java source code goes here (strangely enough!)
src/main/resources
Other resources your application needs
src/main/filters
Resource filters, in the form of properties files, which may be used to define variables only known at runtime
src/main/config
Configuration files
src/main/webapp
The web application directory for a WAR project
src/test/java
Source code for unit tests, by convention in a directory structure mirroring the one in your main source code directory
src/test/resources
Resources to be used for unit tests, but that will not be
src/test/filters
Resources filters to be used for unit tests, but that will not be deployed
src/site
Files used to generate the Maven project web site
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Configuring Maven to Your Environment
One of the principal aims of Maven is to produce portable project build environments. Nevertheless, each work environment has its particularities, which need to be catered for. In this chapter, we investigate some common areas where you may need to tailor Maven to suit your particular work environment, such as configuring proxy servers, defining enterprise repositories, or specifying usernames and passwords.
When it comes to defining environment-specific configuration details, the most important tool at your disposal is the settings.xml file. Each user can have his or her own individual settings.xml file, which should be placed in the $HOME/.m2 directory. This file is not placed under version control, and therefore can contain details such as usernames and passwords, which should not be shared in the source code repository.
If you are working in a company, you may well be accessing the Internet via a proxy. Maven relies heavily on accessing the Internet to download the libraries that it needs for your projects and for its own purposes. Therefore, if you are behind a proxy, you will need to tell Maven about it. Maven stores environment-specific parameters in a file called $HOME/.m2/settings.xml. You will have to create this file if it doesn’t already exist. To define a proxy, just add a <proxy> element in this file, as follows:
<settings>
  <proxies>
   <proxy>
      <active>true</active>
      <protocol>http</protocol>
      <host>proxy.mycompany.com</host>
      <port>8080</port>
      <username>user</username>
      <password>password</password>
      <nonProxyHosts>*.mycompany.com</nonProxyHosts>
    </proxy>
  </proxies>
</settings>
The <nonProxyHosts> element is useful to define servers that do not need proxy access, such as internal enterprise repositories.
Another common use of the settings.xml file is to configure mirror servers. This typically is done to configure an organization-wide repository. Many organizations use a local repository to store and share internal packages and to act as a proxy to external repositories. This solution is faster and more reliable than requiring users to go to the Internet whenever a new dependency is required.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Dependency Management in Maven 2
Dependency management is one of the more powerful features of Maven 2. Dependencies are the libraries you need to compile, test, and run your application. In tools such as Ant, these libraries typically are stored in a special directory (often called lib), and are maintained either by hand or as project artifacts that are stored in the source code repository along with the source code. Maven, by contrast, uses a declarative approach. In a Maven project, you list the libraries your application needs, including the exact version number of each library. Using this information, Maven will do its best to find, retrieve, and assemble the libraries it needs during the different stages in the build lifecycle. In addition, using a powerful feature called Transitive Dependencies (see ,” later in this section), it will include not only the libraries that you declare but also all the extra libraries that your declared libraries need to work correctly.
In this chapter, we will look at different aspects of how to handle dependencies in Maven 2.
One of the most powerful features of Maven 2 is its ability to handle dependencies in a consistent and reliable manner. In the <dependencies> section of the POM file, you declare the libraries that you need to compile, test, and run your application. Dependencies are retrieved from local or remote repositories, and cached locally on your development machine, in the $HOME/.m2/repository directory structure. If you use the same jar in two projects, it will only be downloaded (and stored) once, which saves time and disk space.
In Maven, dependencies are handled declaratively. Suppose that your project needs to use Hibernate, and that your unit tests are written in JUnit. In this case, the dependency section in your POM file might look something like the following:
  ...
  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate</artifactId>
      <version>3.1</version>
    </dependency>
    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>3.8.1</version>
       <scope>test</scope>
    </dependency>
  </dependencies>
  ...
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Looking for Dependencies with MvnRepository
When you are working with Maven, you often need to look up a particular dependency so that you can add it to your POM file. It can be quite tricky to