BUY THIS BOOK
Add to Cart

Print Book $34.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £24.95

What is this?

Looking to Reprint this content?


Java Extreme Programming Cookbook
Java Extreme Programming Cookbook

By Eric M. Burke, Brian M. Coyner
Price: $34.95 USD
£24.95 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: XP Tools
This is a book about open source Java tools that complement Extreme Programming (XP) practices. In this chapter, we outline the relationship between programming tools and XP, followed by a brief introduction to the tools covered in this book. Our approach to tool selection and software development revolves around three key concepts: automation, regression testing, and consistency among developers. First, let's explain how tools relate to XP.
XP is a set of principles and practices that guide software development. It is an agile process in that it makes every effort to eliminate unnecessary work, instead focusing on tasks that deliver value to the customer. XP is built upon four principles: simplicity, communication, feedback, and courage, all described in Chapter 2. The four XP principles have nothing to do with programming languages and tools. Although this book shows a set of Java tools that work nicely with XP, you are not limited to Java and these tools. XP is a language-independent software development approach.
While XP works with any language, we believe it works well with Java for a few reasons. Most important is the speed with which Java compiles. XP relies on test-first development in which programmers write tests for code before they write the code. For each new feature, you should write a test and then watch the test run and fail. You should then add the feature, compile, and watch the test run successfully. This implies that you must write a little code, compile, and run the tests frequently, perhaps dozens of times each day. Because Java compiles quickly, it is well suited to the test-first approach.
The second reason Java is a good choice for XP development is Java's wealth of tools supporting unit testing and continuous integration. JUnit, covered in Chapter 4, provides a lightweight framework for writing automated unit tests. Ant, the premier build tool for Java, makes continuous integration possible even when working with large development teams. You will also find more specialized testing tools such as Cactus and HttpUnit for server-side testing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Java and XP
XP is a set of principles and practices that guide software development. It is an agile process in that it makes every effort to eliminate unnecessary work, instead focusing on tasks that deliver value to the customer. XP is built upon four principles: simplicity, communication, feedback, and courage, all described in Chapter 2. The four XP principles have nothing to do with programming languages and tools. Although this book shows a set of Java tools that work nicely with XP, you are not limited to Java and these tools. XP is a language-independent software development approach.
While XP works with any language, we believe it works well with Java for a few reasons. Most important is the speed with which Java compiles. XP relies on test-first development in which programmers write tests for code before they write the code. For each new feature, you should write a test and then watch the test run and fail. You should then add the feature, compile, and watch the test run successfully. This implies that you must write a little code, compile, and run the tests frequently, perhaps dozens of times each day. Because Java compiles quickly, it is well suited to the test-first approach.
The second reason Java is a good choice for XP development is Java's wealth of tools supporting unit testing and continuous integration. JUnit, covered in Chapter 4, provides a lightweight framework for writing automated unit tests. Ant, the premier build tool for Java, makes continuous integration possible even when working with large development teams. You will also find more specialized testing tools such as Cactus and HttpUnit for server-side testing.
Java's power and simplicity also make it a good language when writing code using XP. Many features of the tools outlined in this book, such as Ant tasks and JUnit's test suites, are built upon Java's reflection capability. Java's relatively easy syntax makes it easier to maintain code written by other team members, which is important for XP's concepts of pair programming, refactoring, and collective code ownership.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Tools and Philosophies
Creating great software is an art. If you ask a dozen programmers to solve a particular problem, you are likely to get a dozen radically different solutions. If you observe how these programmers reach their solutions, you will note that each programmer has her own favorite set of tools. One programmer may start by designing the application architecture using a UML CASE tool. Another may use wizards included with a fancy IDE, while another is perfectly content to use Emacs or vi.
Differences in opinion also manifest themselves at the team and company level. Some companies feel most comfortable with enterprise class commercial tools, while others are perfectly happy to build their development environment using a variety of open source tools. XP works regardless of which tools you choose, provided that your tools support continuous integration and automated unit testing. These concepts are detailed in the next chapter.
We are very skeptical of the term "enterprise class." This tends to be a marketing ploy, and actually means "the features you really need," such as integrated support for free tools like JUnit, Ant, and CVS.
Many commercial IDEs focus very heavily on graphical "wizards" that help you automatically generate code, hide complexity from beginners, and deploy to application servers. If you choose such a tool, make sure it also allows for command-line operation so you can support continuous integration and automated unit testing. If you are forced to use the graphical wizards, you will be locked into that vendor's product and unable to automate your processes. We strongly recommend XDoclet, Covered in Chapter 9, for automated code generation. This is a free alternative to wizard-based code generation and does not lock you into a particular vendor's product.
This book does not cover commercial development environments and tools. Instead, we show how you can use free tools to build your own development environment and support XP practices. Perhaps in a sign of things to come, more and more commercial development environments now provide direct support for the open source tools covered in this book. With free IDEs like Eclipse and Netbeans growing in popularity and functionality, you will soon be hard-pressed to justify spending thousands of dollars per developer for functionality you can get for free.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Open Source Toolkit
Open source tools have been with us for a long time, but did not always enjoy widespread acceptance within the corporate environment. This has all changed in the past few years, as free tools became increasingly powerful and popular. In many cases, open source tools have no commercial equivalent. In others, commercial tools have embraced open source tools due to popular demand—although you may have to purchase the most expensive enterprise edition to get these features. This is ironic because Ant and JUnit are free.
In this section, we introduce the tools used throughout this book. While we have no reason to suggest that you avoid commercial tools, we believe you can achieve the same end result without an expensive investment in tools.
Version control tools are an essential building block of any software development project, so much so that we assume you are familiar with the basic concepts. We do not cover any specific tool in this book; however, we do want to spend a few moments pointing out how tools like CVS fit into an XP toolkit.
CVS keeps a master copy of each file on a shared directory or server, known as the repository. The repository keeps a history of all changes to each file, allowing you to view a history of changes, recover previous revisions of files, and mark particular revisions with tag names. In a nutshell, tools like CVS allow an entire team to update and maintain files in a predictable, repeatable way.
Each programmer has a copy of the entire code base on his computer, and makes changes locally without affecting other programmers. When the current task is complete, the programmer commits the modified files back to the CVS repository. The newly revised files are then visible to other programmers, who can choose to update to the new revisions whenever they are ready.
Regardless of whether you are using CVS or some other tool, two key principles always apply. These principles are:
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: XP Overview
This chapter provides a quick introduction to the key programming-related XP activities. These activities are the aspects of XP that affect programmers the most.
XP encompasses much more than programming techniques. XP is a complete approach to software development, including strategies for planning, gathering user requirements, and everything else necessary to develop complete applications. Understanding these strategies is essential if you wish to base an entire project on XP.
XP is based on four key principles: simplicity, communication, feedback, and courage. This section introduces each principle, and the remainder of this chapter touches on each concept where appropriate.
Simplicity is the heart of XP. Applying the principle of simplicity affects everything you do, and profoundly impacts your ability to successfully apply XP. Focusing on simple designs minimizes the risk of spending a long time designing sophisticated frameworks that the customer may not want. Keeping code simple makes changing code easier as the requirements inevitably change. In addition, adopting simple techniques for communicating requirements and tracking progress maximizes chances that the team will actually follow the process. Most importantly, focusing on simple solutions to today's problems minimizes the cost of change over time. Figure 2-1 shows that the intended result of XP practices is to tame the cost of change curve, making it increase much less over time than we would otherwise expect.
Figure 2-1: Cost of change on an XP project
Traditional theory argues that software becomes increasingly expensive to change over the lifetime of a project. The theory is that it is ten times harder to fix a mistake of requirements when you are in the design phase, and 100 times harder to make changes late in a project during the coding phase. There are many reasons. For one, there is more code to change as time goes on. If the design is not simple, one change can affect many other parts of the system. Over time, as more and more programmers change the system, it becomes increasingly complex and hard to understand.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
What Is XP?
XP is based on four key principles: simplicity, communication, feedback, and courage. This section introduces each principle, and the remainder of this chapter touches on each concept where appropriate.
Simplicity is the heart of XP. Applying the principle of simplicity affects everything you do, and profoundly impacts your ability to successfully apply XP. Focusing on simple designs minimizes the risk of spending a long time designing sophisticated frameworks that the customer may not want. Keeping code simple makes changing code easier as the requirements inevitably change. In addition, adopting simple techniques for communicating requirements and tracking progress maximizes chances that the team will actually follow the process. Most importantly, focusing on simple solutions to today's problems minimizes the cost of change over time. Figure 2-1 shows that the intended result of XP practices is to tame the cost of change curve, making it increase much less over time than we would otherwise expect.
Figure 2-1: Cost of change on an XP project
Traditional theory argues that software becomes increasingly expensive to change over the lifetime of a project. The theory is that it is ten times harder to fix a mistake of requirements when you are in the design phase, and 100 times harder to make changes late in a project during the coding phase. There are many reasons. For one, there is more code to change as time goes on. If the design is not simple, one change can affect many other parts of the system. Over time, as more and more programmers change the system, it becomes increasingly complex and hard to understand.
The XP approach recognizes that the cost of change generally increases like one would expect, but this increase is not inevitable. If you constantly refactor and keep your code simple, you can avoid ever-increasing complexity. Writing a full suite of unit tests is another tool at your disposal, as described later in this chapter. With complete regression testing, you have the ability to make big changes late in the development cycle with confidence. Without these tests, the cost of change does increase because you have to manually test everything else that you may have just broken.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Coding
Coding is an art, and XP acknowledges that. Your success at XP depends largely on your love of coding. Without good code, the exponential cost of change as shown in Figure 2-1 is inevitable. Let's look at some specific ways that XP helps keep code simple.
One of the most frustrating misconceptions about XP is that it is a chaotic approach to software development that caters to hackers. The opposite is true. XP works best with meticulous, detail-oriented programmers who take great pride in their code.
Just getting code to work is not good enough, because the first solution you come up with is hardly ever the simplest possible solution. Your methods may be too long, which makes them harder to test. You may have duplicated functionality, or you may have tightly coupled classes. Complex code is hard to understand and hard to modify, because every little change may break something else in the system. As a system grows, complexity can become overwhelming to the point where your only remaining option is to start over.
When compared to beginners, expert programmers typically implement superior solutions using fewer lines of code. This is a hint that simplicity is harder than complexity, and takes time to master.
Simple code is self-documenting because you pick meaningful names, your methods are concise, and your classes have clearly defined responsibilities. Simple code is hard to achieve, and relies on knowledge in the areas of object-oriented programming, design patterns, and other facets of software engineering.
If code is self-documenting, do you need source code comments? In short, there will always be cases where you need comments, but you should never write comments simply for the sake of commenting. If the meaning of a method is completely obvious, you do not need a comment. An abundance of comments in code is often an indication that the code is unclear and in need of refactoring. Let's look at a method that needs a comment, and see how to eliminate this need.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Unit Testing
A unit test is a programmer-written test for a single piece of functionality in an application. Unit tests should be fine grained, testing small numbers of closely-related methods and classes. Unit tests should not test high-level application functionality. Testing application functionality is called acceptance testing, and acceptance tests should be designed by people who understand the business problem better than the programmers.
XP cannot be done without unit testing. Unit tests build confidence that the code works correctly. Tests also provide the safety net enabling pairs of programmers to make changes to any piece of code in the system without fear. Making changes to code written by someone else takes courage, because you might not be familiar with all of the ins-and-outs of the original solution.
Imagine a scenario in which you are presented with a legacy payroll application consisting of 50,000 lines of code and zero unit tests. You have been asked to change the way that part-time employee salaries are computed, due to a recent change in the tax laws. After making the change, how can you be confident that you did not introduce a bug somewhere else in the system? In a traditional model, you hand the application to a quality assurance team that manually tests everything they can think of. Hopefully, everybody gets the correct paycheck next month.
Now imagine the XP scenario. If the original development team used XP, each class would have a suite of automated unit tests. Before you make your change, you run all of the unit tests to ensure they pass. You then write a new unit test for your new payroll calculation feature. This new test fails, because you have not written the new feature yet. You then implement the new feature and run all of the tests again.
Once all of the tests pass, you check in your code and feel confident that you did not break something else while making the improvement. This is called test-driven development, and it is how XP teams operate.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Refactoring
Refactoring is the practice of improving the design of code without breaking its functionality. In order to keep code simple and prevent the cost of making changes from skyrocketing, you must constantly refactor. This keeps your code as simple as possible.
Here is a simple refactoring. Suppose you have this code:
public class Person {
    private String firstName;
    public void setFirst(String n) {
       this.firstName = n;
    }
}
This code can be improved by picking a better argument name, changing n to firstName:
public class Person {
    private String firstName;
    public void setFirst(String firstName) {
       this.firstName = firstName;
    }
}
The code can be improved even further by renaming the method to setFirstName( ):
public class Person {
    private String firstName;
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
}
The method has been refactored and is now more easily understandable. Of course, changing the method name requires you to change all references to the method throughout your application. This is where a good IDE can help out, because it can identify all usages and update the calls automatically.
You refactor code to make it simpler. Each individual refactoring introduces a small improvement; however, these small improvements add up over time. By constantly striving to keep code as concise and as simple as possible the cost of making changes to an application does not rise so dramatically over time.
Removing duplication is another goal of refactoring that deserves mention. Duplicated logic is almost always harder to maintain because changes must be made to more than one part of the system as it evolves. We have found that duplicated logic is often a signal that code should be refactored and simplified.
Without refactoring, complexity inevitably increases as more and more features are tacked onto a system. Increasing complexity is known as entropy, and is a fundamental reason why the cost of change increases over time. Our goal is to stave off entropy as long as possible through constant refactoring.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Design
XP does not encourage a lot of up-front design. Instead, the XP approach recognizes that humans cannot accurately design every single feature of an application before writing code. So why not design a little bit right away and then write the code immediately? As a result, your customer can get his or her hands on some working software right away.
XP practitioners typically obsess about good design, taking it much more seriously than other developers. They simply have a different point of view on when to do it—all the time, instead of all at the beginning.
Customers define which features are most important, and programmers work on those features first. As each new feature is implemented, the application is delivered to customers and they have the opportunity to offer immediate feedback.
In this customer-centric delivery model, we do not have time to spend months and months of time doing detailed design and analysis. We also cannot afford to develop complex frameworks to accommodate every anticipated feature. If we did either of these things, we would not be able to deliver working code (and thus get feedback) to the customer in a timely fashion.
Figure 2-2 shows the relationship between time-to-customer and the likelihood that the finished product does not meet expectations. Stated simply, the longer you work in a vacuum without getting feedback from your customer, the higher the probability is that you will develop the wrong features.
Figure 2-2: Strive for short release cycles
This is where courage comes back into the picture. The best developers may have the most trouble accepting the fact that they should not worry so much about framework development. Instead, they should worry more about writing exactly what the customer wants today, along with extensive unit tests. The code may or may not be reusable, but we can resolve that later using refactoring techniques.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Builds
A good build environment is essential to XP teams. Constant refactoring, collective code ownership, and ever-changing pair programming teams require that each developer have the ability to reliably build the software using an identical configuration. If this is not the case, then tests that pass for one developer may fail for everyone else.
Continuous integration means that XP teams build the software application frequently, often several times per day. In fact, the Cruise Control tool (mentioned in Chapter 1) performs a complete build of the application after every check-in to version control.
After you and your programming partner have finished a task, you should integrate your changes with the shared source code repository. This means that you check in your changes to your version control tool, run a complete build, and run all of the unit tests. If any tests fail, you fix them right away.
Since you probably build your application many times per day, you won't have any trouble when it comes time to deliver a build to your customer. For this task, you might want to define a script that copies the latest build to a "stable" build directory of some sort. This gives the customers a stable playground from which to run and test the application while the programmers continue with their day-to-day coding and builds.
There is no reason why automated builds should not go all the way to a customer deliverable. For example, if you are building a shrink-wrap product, going all the way to an installation CD image is not a bad idea. The desire to create completely automated build processes is very much in tune with the desire to create automated test suites. Taking manual, human-controlled steps out of the process improves quality and lets you focus on delivering features to customers rather than working on mundane software compilation steps.
Continuous integration works best when pairs of programmers work on small tasks. Once each task is tested and implemented, it should be integrated with the main build as soon as possible. This is the best way to ensure that all of the team members are in sync with one another.
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 3: Ant
Ant is a portable, Java-based build tool designed to support software builds—and many other tasks—on any platform supporting Java. An XML file known as a buildfile specifies which tasks Ant follows when building your project. Ant ships with well over 100 tasks that perform operations ranging from compiling code to playing sound files when a build finishes. Java classes implement Ant tasks that can do anything Java can do. The Ant API is open and designed for extensibility; you can write your own custom tasks if the need arises.
A good build tool like Ant is critical to any successful XP implementation. You cannot expect a team of programmers to constantly refactor their code, run unit tests, and integrate their changes without a fast, predictable build environment. Consider the problems that occur when one of the programmers on a team has a newer version of a JAR file on his classpath. Unit tests may pass on his machine, but fail for everyone else. Ant helps avoid this sort of problem by clearly defining the files the project depends on, and the steps are followed to perform the build.
Build times must be kept to a minimum and Ant excels in this area. XP assumes that programmers write a lot of small, incremental pieces of code. Programmers must compile and run all unit tests after making each small change; therefore, the build needs to be fast. When builds are slow, programmers are discouraged from the constant refactoring and testing that XP demands. Ant helps performance in several ways:
  • Most tasks only do their work if files are out of date. For example, code is only compiled when .java files are newer than their corresponding .class files.
  • In most cases, individual build steps execute in the same JVM. Ant is written in Java and efficiently invokes many tools, such as the Java compiler, through direct method calls rather than spawning new processes.
  • Ant tasks use a simple pattern-matching syntax to locate files quickly, allowing you to write buildfiles that perform work on the correct subset of a source tree for the job at hand.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction
Ant is a portable, Java-based build tool designed to support software builds—and many other tasks—on any platform supporting Java. An XML file known as a buildfile specifies which tasks Ant follows when building your project. Ant ships with well over 100 tasks that perform operations ranging from compiling code to playing sound files when a build finishes. Java classes implement Ant tasks that can do anything Java can do. The Ant API is open and designed for extensibility; you can write your own custom tasks if the need arises.
A good build tool like Ant is critical to any successful XP implementation. You cannot expect a team of programmers to constantly refactor their code, run unit tests, and integrate their changes without a fast, predictable build environment. Consider the problems that occur when one of the programmers on a team has a newer version of a JAR file on his classpath. Unit tests may pass on his machine, but fail for everyone else. Ant helps avoid this sort of problem by clearly defining the files the project depends on, and the steps are followed to perform the build.
Build times must be kept to a minimum and Ant excels in this area. XP assumes that programmers write a lot of small, incremental pieces of code. Programmers must compile and run all unit tests after making each small change; therefore, the build needs to be fast. When builds are slow, programmers are discouraged from the constant refactoring and testing that XP demands. Ant helps performance in several ways:
  • Most tasks only do their work if files are out of date. For example, code is only compiled when .java files are newer than their corresponding .class files.
  • In most cases, individual build steps execute in the same JVM. Ant is written in Java and efficiently invokes many tools, such as the Java compiler, through direct method calls rather than spawning new processes.
  • Ant tasks use a simple pattern-matching syntax to locate files quickly, allowing you to write buildfiles that perform work on the correct subset of a source tree for the job at hand.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Writing a Basic Buildfile
You want to write a basic Ant buildfile.
Example 3-1 lists a simple Ant buildfile that you may use as a boilerplate for your own projects.
Example 3-1. Boilerplate Ant buildfile
<?xml version="1.0"?>
<project name="Template Buildfile" default="compile" basedir=".">
  <property name="dir.src" value="src"/>
  <property name="dir.build" value="build"/>
  <property name="dir.dist" value="dist"/>

  <!-- Creates the output directories -->
  <target name="prepare">
    <mkdir dir="${dir.build}"/>
    <mkdir dir="${dir.dist}"/>
  </target>

  <target name="clean"
          description="Remove all generated files.">
    <delete dir="${dir.build}"/>
    <delete dir="${dir.dist}"/>
  </target>

  <target name="compile" depends="prepare"
          description="Compile all source code.">
    <javac srcdir="${dir.src}" destdir="${dir.build}"/>
  </target>

  <target name="jar" depends="compile"
          description="Generates oreilly.jar in the 'dist' directory.">
    <jar jarfile="${dir.dist}/oreilly.jar" 
         basedir="${dir.build}"/>
  </target>
</project>
You generally call this file build.xml, and can put it anywhere you like. In our example, the buildfile is found in the directory containing the src directory. The <project> tag is found in all buildfiles:
<project name="Template Buildfile" default="compile" basedir=".">
The project name should be something descriptive, as this may show up when you run Ant from other tools. The default attribute specifies which target is invoked when the user types ant. Finally, the basedir attribute specifies the directory from which all paths are relative to. Regardless of where you invoke Ant, "." is the directory containing the buildfile.
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 Ant
You want to run Ant.
The complete command-line syntax is as follows:
ant [options] [target [target2 [target3] ...]]
Table 3-1 lists all of the Ant command-line options. This table applies to Ant Version 1.5.1.
Table 3-1: Ant command-line options
Option
Description
-buildfile file
-f file
-file file
Specify which buildfile to use. If omitted, Ant searches for a file named build.xml.
-D property = value
Pass name/value pairs as properties.
-debug
Write debugging information as the build progresses.
-diagnostics
Write diagnostic information as the build progresses.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Providing Help
You want to provide help messages in your buildfiles.
Include a description attribute on the <project> and <target> tags. Also consider writing a help target, and use XML comments throughout the buildfile.
Example 3-2 shows several techniques for providing additional help in Ant buildfiles. In this example, the help target is listed as the default target and is executed when the user types ant at the command line.
Example 3-2. Various ways to provide help
<?xml version="1.0"?>

<!-- You can document the buildfile using XML comments -->
<project name="My Big Project" default="help" basedir=".">
  <description>Shows how to provide help in an Ant buildfile.</description>

  <property name="dir.src" value="src"/>

  <target name="help">
    <echo message="This buildfile shows how to get help."/>
    <echo>(Type 'ant -projecthelp' for more info)</echo>
    <echo><![CDATA[  
       Here is a block of text
       that you want to format
       in a very specific way!]]></echo>
  </target>

  <!-- Here is an example of a subtarget -->
  <target name="prepare">
    <mkdir dir="${dir.build}"/>
    <mkdir dir="${dir.dist}"/>
  </target>

  <!-- Here is an example of a main target -->
  <target name="clean"
          description="Remove all generated files.">
    <delete dir="${dir.build}"/>
    <delete dir="${dir.dist}"/>
  </target>

  <target name="compile" depends="prepare"
          description="Compile all source code.">
    <javac srcdir="${dir.src}" destdir="${dir.build}"/>
  </target>
</project>
The help target uses the echo task to print some usage information for Ant beginners. It reminds the user of the -projecthelp option, and uses an XML CDATA section to format a paragraph of text. CDATA sections are useful whenever you want to preserve linefeeds, spaces, and other characters precisely. CDATA is also useful because it allows you to print special XML characters like "<" without using entities like "&lt;".
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 Environment Variables
You want to obtain and use environment variables within Ant. This is a way to avoid hardcoding values in buildfiles.
Use a special form of the <property> task:
<?xml version="1.0"?>
<project name="envSample" default="deploy" basedir=".">
  <!-- Set up the 'env' prefix for environment variables -->
               <property environment="env"/>

  <!-- Abort the build if TOMCAT_HOME is not set -->
  <target name="checkTomcatHome" unless="env.TOMCAT_HOME">
    <fail message="TOMCAT_HOME must be set!"/>
  </target>

  <target name="compile">
    ... compile the code
  </target>

  <!-- Deploy the WAR file to TOMCAT_HOME/webapps -->
  <target name="deploy" depends="checkTomcatHome,compile">
               <echo>Deploying to ${env.TOMCAT_HOME}</echo>
               <copy file="myapp.war" todir="${env.TOMCAT_HOME}/webapps"/>
               </target>

</project>
Although most operating systems support the concept of environment variables, not all do. As a result, Sun deprecated Java's System.getEnv( ) method, which used to return the values of environment variables. Undeterred by this restriction, Ant's programmers added the ability to obtain environment variables using the technique shown here.
Use the property task's environment attribute to define a prefix, conventionally "env". Then use this prefix when referencing environment variables in other parts of a buildfile, as if you are referencing any normal Ant property. Our example Ant buildfile uses the TOMCAT_HOME environment variable to deploy a Web Application Archive (WAR) file to the correct directory.
Our example takes this technique to the next level by verifying that TOMCAT_HOME is actually set before attempting to deploy the WAR file. This is done in the checkTomcatHome target:
<target name="checkTomcatHome" unless="env.TOMCAT_HOME">
  <fail message="TOMCAT_HOME must be set!"/>
</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!
Passing Arguments to a Buildfile
You want to pass system properties to a buildfile. Java system properties are a more portable alternative to environment variables.
Pass the system properties to Ant using the -D command-line argument. For example:
ant -Dprop1="My Property" run
Within the buildfile, refer to the property using Ant's ${prop1} syntax. You can specify default values for properties using the <property> tag, and you can pass system properties to Java applications using the <sysproperty> tag nested within the <java> element.
Example 3-3 shows an Ant buildfile that demonstrates system properties. It echoes the property name/value pairs to the console, and then invokes a Java application that echoes the same properties.
Example 3-3. Buildfile demonstrating system properties
<?xml version="1.0"?>
<project name="sysprops" default="run" basedir=".">
  <!-- define two properties -->
  <property name="prop1" value="Property 1 from Buildfile"/>
  <property name="prop2" value="Property 2 from Buildfile"/>

  <target name="clean">
    <delete dir="com"/>
  </target>

  <target name="compile">
    <javac srcdir="." destdir=".">
      <classpath path="."/>
    </javac>
  </target>

  <target name="run" depends="compile">
    <!-- echo each of the properties to the console -->
    <echo message="Now in buildfile..."/>
    <echo message="prop1     = ${prop1}"/>
    <echo message="prop2     = ${prop2}"/>
    <!-- The 'prop3' property must be defined on the command 
         line or it shows up like '${prop3}' -->
    <echo message="prop3     = ${prop3}"/>
    <echo message="user.home = ${user.home}"/>

    <!-- execute the main(  ) method in a Java class -->
    <java classname="com.oreilly.javaxp.ShowProps">
      <classpath path="."/>
      <!-- pass one of the properties -->
      <sysproperty key="prop1" value="${prop1}"/>
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Checking for the Existence of Properties
You want to check for the existence of several properties and/or environment variables before you perform a build.
Define a "checkProperties" target that uses the fail task to abort the build if any properties are undefined.
Suppose that various parts of your buildfile require several environment variables. First, specify a target that checks those properties:
<target name="checkProperties">
  <fail unless="env.TOMCAT_HOME">TOMCAT_HOME must be set</fail>
  <fail unless="env.JUNIT_HOME">JUNIT_HOME must be set</fail>
  <fail unless="env.JBOSS_HOME">JBOSS_HOME must be set</fail>
</target>
This causes the build to fail if any one of these environment variables is not set. To execute this target, list it as a dependency from some other target:
<target name="compile" depends="checkProperties">
  ...
</target>
The dependency ensures that the checkProperties target executes before Ant attempts to compile your code.
The previous two recipes showed how to define environment variables and Ant 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!
Defining a Classpath
You want to define a classpath and reuse it throughout a buildfile.
Use the <path> element to define the classpath along with a unique ID. Then refer to the classpath using the ID.
Example 3-5 shows how to define a classpath and refer to it later from the javac task.
Example 3-5. Reusing a classpath
<?xml version="1.0" encoding="UTF-8"?>
<project name="Classpath Sample" default="compile" basedir=".">
  <!-- get an environment variable -->
  <property environment="env"/>
  <property name="tomcatHome" value="${env.TOMCAT_HOME}"/>

  <!-- define some directories -->
  <property name="dir.src" value="src"/>
  <property name="dir.build" value="build"/>
  <property name="dir.lib" value="lib"/>
  
  <!-- Define a classpath for use throughout the buildfile -->
  <path id="project.classpath">
    <pathelement location="${dir.src}"/>
    <!-- include Tomcat libraries -->
    <fileset dir="${tomcatHome}/common/lib">
      <include name="*.jar"/>
    </fileset>    
    <!-- include our own libraries -->
    <fileset dir="${dir.lib}">
      <include name="*.jar"/>
    </fileset>
  </path>
  
  <target name="clean">
    <delete dir="${dir.build}"/>
  </target>
  
  <target name="prepare">
    <mkdir dir="${dir.build}"/>
  </target>
  
  <target name="compile" depends="prepare">
    <!-- use <pathconvert> to convert the path into a property -->
    <pathconvert targetos="windows" property="windowsPath"
                 refid="project.classpath"/>
    <!-- now echo the path to the console -->
    <echo>Windows path = ${windowsPath}</echo>
        
    <!-- Here is how to use the classpath for compiling -->
    <javac destdir="${dir.build}">
      <src path="${dir.src}"/>
      <classpath refid="project.classpath"/>
    </javac>
  </target>
</project>
Several aspects of this buildfile are worthy of discussion. We define our classpath using 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!
Defining Platform-Independent Paths
You want to define paths that work on Windows, Unix, and other operating systems.
Define your paths, as shown in Recipe 3.8. Ant takes care of converting the paths to whatever platform you are running on. Use forward-slashes (/) between directories. Use either semi-colons (;) or colons (:) between paths; Ant handles both.
Ant determines what operating system you are running on and converts paths accordingly. You should avoid Windows-style drive letters whenever possible; they will not work on Unix. If you must refer to a drive letter, use a system property as outlined in Recipe 3.6 to avoid hardcoding the path.
Use the pathconvert task to convert an Ant path to native format and store it in a property. Here is how you define a path and then convert it to Unix format:
  
               <path id="path.test">
               <!-- find all unit tests under the build directory -->
               <fileset dir="${dir.build}">
               <include name="**/Test*.class"/>
               </fileset>
               </path>  

               <!-- convert the path to UNIX format, storing it in a property -->
               <pathconvert targetos="unix" property="unixPath" refid="path.test"/>
            
See the Ant user manual for more examples of the pathconvert task.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Including and Excluding Files
You want to include and/or exclude certain files and directories from a build.
Use Ant patterns along with <include> and <exclude> tags, or includes and excludes attributes.
Ant uses a simple pattern syntax for selecting files, which you have undoubtedly seen in other examples throughout this chapter. Here is how you can use this syntax to include all .java files in a particular directory:
includes="src/com/oreilly/util/*.java"
Because Java projects are typically divided into numerous packages and subdirectories, you frequently use the ** wildcard to scan all subdirectories:
includes="src/**/*.java"
This tells Ant to locate all files ending with .java in the src directory and any subdirectories.
In the Ant pattern language, " *" matches any number of characters and " ?" matches one character. So you can locate Test1.java and Test2.java as follows:
includes="Test?.java"
Because "?" matches a single character, TestABC.java is not matched by the preceding pattern.
Patterns can be combined. Table 3-2 shows some additional pattern examples.
Table 3-2: Ant pattern-matching examples
Pattern
Matches
Does not match
*.java
Person.java
Person.class
Person*.java
Person.java, PersonA.java, PersonBoss.java
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Implementing Conditional Logic
You want to selectively execute portions of a build based on conditional logic.
Use target dependencies, properties, and the if and unless attributes of the <target> tag.
Ant does not support true conditional logic, such as if/then/else. You can, however, execute targets depending on the state of properties. This target only executes if the xalanInstalled property is set:
<target name="compile" if="xalanInstalled">
  ...
</target>
If the property is not set, the target is ignored. You can also specify that a target should execute unless a property is set:
<target name="installXalan" unless="xalanInstalled">
  ...
</target>
Recipe 3.15 shows how to abort the build if a property is not set. This is a form of conditional logic that is specific to the fail task. See the Ant documentation for the condition task to learn how to set properties based upon existence of files, classes, or other resources.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Defining a Consistent Environment
You want to ensure that all developers on a team are building the project with identical configurations.
Ant buildfiles should be as self-contained as possible. Any reliance on external resources, such as the CLASSPATH environment variable, opens the door for different developers to have different settings.
Without tools like Ant, different developers probably use different tools to compile their code. Some might prefer to work in text editors like Emacs, while others may use IDEs like IntelliJ IDEA or Borland JBuilder. Each developer probably has her own unique configuration in such an environment.
Regardless of which tools individuals use, every member of a project should be able to compile her code in a controlled manner before committing changes to a shared repository. Nothing is wrong with letting developers use the tools they are most comfortable with, but you should use a tool like Ant for a common baseline.
Here are some specific tips for setting up an Ant buildfile to ensure a consistent build by all developers:
  • The buildfile should not rely on any external CLASSPATH.
  • If the build requires third party JAR files, put the correct versions in a shared directory so each developer builds with the same versions.
  • The buildfile itself should be kept under version control.
  • Provide a "clean" target that destroys all generated code.
The clean target is essential because it ensures everything will be compiled during the next build. Ant relies on file timestamps to determine when class files are out of date with respect to source files. Although this catches most dependencies, it does not handle many semantic dependencies. For example, you might remove a method from a base class; the base class will recompile, but any derived classes will not. The compile may succeed (incorrectly) until you perform a clean build and find the problem.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Preventing Build Breaks
You are concerned because developers keep "breaking the build" by checking in broken code to your version control tool.
Adopt a policy in which developers must perform a clean bui