Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 68 trang
THÔNG TIN TÀI LIỆU
Cấu trúc
Java Development with Ant
brief contents
contents
preface
acknowledgments
about this book
about the authors
about the cover illustration
foreword
chapter1
1.1 What is Ant?
1.1.1 What is a build process and why do you need one?
1.1.2 Why do we think Ant makes a great build tool?
1.2 The core concepts of Ant
1.2.1 An example project
1.3 Why use Ant?
1.3.1 Integrated development environments
1.3.2 Make
1.3.3 Other build tools
1.3.4 Up and running, in no time
1.4 The evolution of Ant
1.5 Ant and software development methodologies
1.5.1 eXtreme Programming
1.5.2 Rational Unified Process
1.6 Our example project
1.6.1 Documentation search engine—example Ant project
1.7 Yeah, but can Ant…
1.8 Beyond Java development
1.8.1 Web publishing engine
1.8.2 Simple workflow engine
1.8.3 Microsoft .NET and other languages
1.9 Summary
chapter2
2.1 Defining our first project
2.2 Step one: verifying the tools are in place
2.3 Step two: writing your first Ant build file
2.3.1 Examining the build file
2.4 Step three: running your first build
2.4.1 If the build fails
2.4.2 Looking at the build in more detail
2.5 Step four: imposing structure
2.5.1 Laying out the source directories
2.5.2 Laying out the build directories
2.5.3 Laying out the dist directories
2.5.4 Creating the build file
2.5.5 Target dependencies
2.5.6 Running the new build file
2.5.7 Rerunning the build
2.5.8 How Ant handles multiple targets on the command line
2.6 Step five: running our program
2.6.1 Why execute from inside Ant
2.6.2 Adding an execute target
2.6.3 Running the new target
2.7 Ant command line options
2.7.1 Specifying which build file to run
2.7.2 Controlling the amount of information provided
2.7.3 Getting information about a projec t
2.8 The final build file
2.9 Summary
chapter3
3.1 Preliminaries
3.1.1 Datatype overview
3.1.2 Property overview
3.2 Introducing datatypes and properties with <javac>
3.3 Paths
3.4 Filesets
3.4.1 Fileset examples
3.4.2 Default excludes
3.5 Patternsets
3.6 Selectors
3.7 Datatype element naming
3.8 Filterset
3.8.1 Inserting date stamps in files at build-time
3.9 FilterChains and FilterReaders
3.10 Mappers
3.10.1 Identity mappe r
3.10.2 Flatten mapper
3.10.3 Merge mapper
3.10.4 Glob mapper
3.10.5 Regexp mapper
3.10.6 Package mapper
3.11 Additional Ant datatypes
3.11.1 ZipFileset
3.11.2 Dirset
3.11.3 Filelist
3.11.4 ClassFileset
3.12 Properties
3.12.1 Setting properties with the <property> task
3.12.2 How the <property> task is different
3.12.3 Checking for the availability of resources: <available>
3.12.4 Saving time by skipping unnecessary steps: <uptodate>
3.12.5 Testing conditions with <condition>
3.12.6 Setting properties from the command-line
3.12.7 Creating a build timestamp with <tstamp>
3.12.8 Loading properties from an XML file
3.13 Controlling Ant with properties
3.13.1 Conditional target execution
3.13.2 Conditional patternset inclusion/exclusion
3.13.3 Conditional build failure
3.14 References
3.14.1 Properties and references
3.14.2 Using references for nested patternsets
3.15 Best practices
3.16 Summary
chapter4
4.1 Refactoring
4.2 Java main() testing
4.3 JUnit primer
4.3.1 Writing a test case
4.3.2 Running a test case
4.3.3 Asserting desired results
4.3.4 TestCase lifecycle
4.3.5 Writing a TestSuite
4.3.6 Obtaining and installing JUnit
4.3.7 Extensions to JUnit
4.4 Applying unit tests to our application
4.4.1 Writing the test first
4.4.2 Dealing with external resources during testing
4.5 The JUnit task—<junit>
4.5.1 Structure directories to accommodate testing
4.5.2 Fitting JUnit into the build process
4.6 Test failures are build failures
4.6.1 Capturing test results
4.6.2 Running multiple tests
4.6.3 Creating your own results formatter
4.7 Generating test result reports
4.7.1 Generate reports and allow test failures to fail the build
4.7.2 Run a single test case from the command-line
4.7.3 Initializing the test environment
4.7.4 Other test issues
4.8 Short-circuiting tests
4.8.1 Dealing with large number of tests
4.9 Best practices
4.10 Summary
chapter5
5.1 Why you need to run externalprograms
5.2 Running Java programs
5.2.1 Introducing the <java> task
5.2.2 Setting the classpath
5.2.3 Arguments
5.2.4 Defining system properties
5.2.5 Running the program in a new JVM
5.2.6 Setting environment variables
5.2.7 Controlling the new JVM
5.2.8 Handling errors with failonerror
5.2.9 Executing JAR files
5.2.10 Calling third-party programs
5.2.11 Probing for a Java program before calling it
5.2.12 Setting a timeout
5.3 Starting native programs with<exec>
5.3.1 Setting environment variables
5.3.2 Handling errors
5.3.3 Handling timeouts
5.3.4 Making and executing shell commands
5.3.5 Probing for a program before calling it
5.4 Bulk execution with <apply>
5.5 Processing output
5.6 Limitations on execution
5.7 Best practices
5.8 Summary
chapter6
6.1 Moving, copying, and deleting files
6.1.1 How to delete files
6.1.2 How to copy files
6.1.3 How to move files
6.1.4 Filtering
6.2 Preparing to package
6.2.1 Building and documenting release code
6.2.2 Adding data files
6.2.3 Preparing documentation
6.2.4 Preparing install scripts and documents
6.2.5 Preparing libraries for redistribution
6.3 Creating archive files
6.3.1 JAR files
6.3.2 Creating a JAR file
6.3.3 Testing the JAR file
6.3.4 Creating JAR manifests
6.3.5 Adding extra metadata to the JAR
6.3.6 JAR file best practices
6.3.7 Signing JAR files
6.4 Creating Zip files
6.4.1 Creating a binary distribution
6.4.2 Creating a source distribution
6.4.3 Merging Zip files
6.4.4 Zip file best practices
6.5 Creating tar files
6.6 Creating web applications with WARfiles
6.7 Testing packaging
6.8 Summary
chapter7
7.1 Example deployment problems
7.1.1 Reviewing the tasks
7.1.2 Tools for deployment
7.2 Tasks for deployment
7.2.1 File transfer with <ftp>
7.2.2 Probing for server availability
7.2.3 Inserting pauses into the build with <sleep>
7.2.4 Ant’s email task
7.2.5 Fetching remote files with <get>
7.2.6 Using the tasks to deploy
7.3 FTP-based distribution of apackagedapplication
7.3.1 Asking for information with the <input> task
7.4 Email-based distribution of apackagedapplication
7.5 Local deployment to Tomcat4.x
7.5.1 The Tomcat management servlet API
7.5.2 Deploying to Tomcat with Ant
7.6 Remote deployment to Tomcat
7.6.1 Interlude: calling targets with <antcall>
7.6.2 Using <antcall> in deployment
7.7 Testing deployment
7.8 Summary
chapter8
8.1 Our application thus far
8.2 Building the custom Ant task library
8.3 Loading common properties across multipleprojects
8.4 Handling versioned dependencies
8.4.1 Installing a new library version
8.5 Build file philosophy
8.5.1 Begin with the end in mind
8.5.2 Integrate tests with the build
8.5.3 Support automated deployment
8.5.4 Make it portable
8.5.5 Allow for customizations
8.6 Summary
chapter9
9.1 Designing an Ant-based build process
9.1.1 Analyzing your project
9.1.2 Creating the core build file
9.1.3 Evolve the build file
9.2 Migrating to Ant
9.3 The ten steps of migration
9.3.1 Migrating from Make-based projects
9.3.2 Migrating from IDE-based projects
9.4 Master builds: managing large projects
9.4.1 Refactoring build files
9.4.2 Introducing the <ant> task
9.4.3 Example: a basic master build file
9.4.4 Designing a scalable, flexible master build file
9.5 Managing child project builds
9.5.1 How to control properties of child projects
9.5.2 Inheriting properties and references from a master build file
9.5.3 Declaring properties and references in <ant>
9.5.4 Sharing properties via XML file fragments
9.5.5 Sharing targets with XML file fragments
9.6 Creating reusable library build files
9.7 Looking ahead: large project support evolution
9.8 Ant project best practices
9.8.1 Managing libraries
9.8.2 Implementing processes
9.9 Summary
chapter10
10.1 Understanding types of tasks
10.1.1 So, what is an “optional” task?
10.1.2 Ant’s major optional tasks
10.1.3 Why third-party tasks?
10.2 Optional tasks in action
10.2.1 Manipulating property files
10.2.2 Adding audio and visual feedback during a build
10.2.3 Adding dependency checks
10.2.4 Grammar parsing with JavaCC
10.2.5 Regular expression replacement
10.3 Using software configuration managementtasks
10.3.1 CVS
10.3.2 ClearCase
10.4 Using third-party tasks
10.4.1 Defining tasks with <taskdef>
10.5 Notable third-party tasks
10.5.1 Checkstyle
10.5.2 Torque–object-relational mapping
10.6 The ant-contrib tasks
10.7 Sharing task definitions amongprojects
10.8 Best practices
10.9 Summary
chapter11
11.1 Installing XDoclet
11.2 To-do list generation
11.3 XDoclet architecture
11.3.1 XDoclet’s Ant tasks
11.3.2 Templating
11.3.3 How XDoclet works
11.4 Writing your own XDoclet template
11.4.1 Code generation
11.4.2 Per-class versus single-file generation
11.4.3 Filtering classes processed
11.5 Advanced XDoclet
11.5.1 Custom subtasks
11.5.2 Creating a custom tag handler
11.6 The direction of XDoclet
11.6.1 XDoclet versus C#
11.6.2 Looking into Java’s future: JSR 175 and 181
11.7 XDoclet best practices
11.7.1 Dependency checking
11.8 Summary
chapter12
12.1 How are web applications different?
12.2 Working with tag libraries
12.2.1 Creating a tag library
12.2.2 Integrating tag libraries
12.2.3 Summary of taglib development with Ant
12.3 Compiling JSP pages
12.3.1 Installing the <jspc> task
12.3.2 Using the <jspc> task
12.3.3 JSP compilation for deployment
12.3.4 Other JSP compilation tasks
12.4 Customizing web applications
12.4.1 Filterset-based customization
12.4.2 Customizing deployment descriptors with XDoclet
12.4.3 Customizing libraries in the WAR file
12.5 Generating static content
12.5.1 Generating new content
12.5.2 Creating new files
12.5.3 Modifying existing files
12.6 Testing web applications with HttpUnit
12.6.1 Writing HttpUnit tests
12.6.2 Compiling the tests
12.6.3 Preparing to run HttpUnit tests from Ant
12.6.4 Running the HttpUnit tests
12.6.5 Integrating the tests
12.6.6 Limitations of HttpUnit
12.6.7 Canoo WebTest
12.7 Server-side testing with Cactus
12.7.1 Cactus from Ant’s perspective
12.7.2 How Cactus works
12.7.3 And now our test case
12.7.4 Cactus summary
12.8 Summary
chapter13
13.1 Preamble: all about XML libraries
13.2 Validating XML
13.2.1 When a file isn’t validated
13.2.2 Resolving XML DTDs
13.2.3 Supporting alternative XML validation mechanisms
13.3 Transforming XML with XSLT
13.3.1 Using the XMLCatalog datatype
13.3.2 Generating PDF files from XML source
13.3.3 Styler–a third-party transformation task
13.4 Generating an XML build log
13.4.1 Stylesheets
13.4.2 Output files
13.4.3 Postprocessing the build log
13.5 Loading XML data into Antproperties
13.6 Next steps in XML processing
13.7 Summary
chapter14
14.1 EJB overview
14.1.1 The many types of Enterprise JavaBeans
14.1.2 EJB JAR
14.1.3 Vendor-specific situations
14.2 A simple EJB build
14.3 Using Ant’s EJB tasks
14.4 Using <ejbjar>
14.4.1 Vendor-specific <ejbjar> processing
14.5 Using XDoclet for EJB development
14.5.1 XDoclet subtasks
14.5.2 XDoclet’s @tags
14.5.3 Supporting different application servers with XDoclet
14.5.4 Ant property substitution
14.6 Middlegen
14.7 Deploying to J2EE application servers
14.8 A complete EJB example
14.9 Best practices in EJB projects
14.10 Summary
chapter15
15.1 What are web services and what is SOAP?
15.1.1 The SOAP API
15.1.2 Adding web services to Java
15.2 Creating a SOAP client application with Ant
15.2.1 Preparing our build file
15.2.2 Creating the proxy classes
15.2.3 Using the SOAP proxy classes
15.2.4 Compiling the SOAP client
15.2.5 Running the SOAP service
15.2.6 Reviewing SOAP client creation
15.3 Creating a SOAP service with Axisand Ant
15.3.1 The simple way to build a web service
15.4 Adding web services to an existing webapplication
15.4.1 Configuring the web application
15.4.2 Adding the libraries
15.4.3 Including SOAP services in the build
15.4.4 Testing the server for needed classes
15.4.5 Implementing the SOAP endpoint
15.4.6 Deploying our web service
15.5 Writing a client for our SOAPservice
15.5.1 Importing the WSDL
15.5.2 Implementing the tests
15.5.3 Writing the Java client
15.6 What is interoperability, and why is it a problem?
15.7 Building a C# client
15.7.1 Probing for the classes
15.7.2 Importing the WSDL in C#
15.7.3 Writing the C# client class
15.7.4 Building the C# client
15.7.5 Running the C# client
15.7.6 Review of the C# client build process
15.8 The rigorous way to build a webservice
15.9 Reviewing web service development
15.10 Calling Ant via SOAP
15.11 Summary
chapter16
16.1 Scheduling Ant builds with the operating system
16.1.1 The Windows way
16.1.2 The Unix version
16.1.3 Making use of scripting
16.2 CruiseControl
16.2.1 How it works
16.2.2 It’s all about the cruise—getting the build runner working
16.2.3 Build log reporting
16.2.4 Email notifications and build labeling
16.2.5 CruiseControl summary
16.2.6 Tips and tricks
16.2.7 Pros and cons to CruiseControl
16.3 Anthill
16.3.1 Getting Anthill working
16.3.2 How Anthill works
16.3.3 Anthill summary
16.4 Gump
16.4.1 Installing and running Gump
16.4.2 How Gump works
16.4.3 Summary of Gump
16.5 Comparison of continuous integration tools
16.6 Summary
chapter17
17.1 The challenge of native code
17.2 Using existing build tools
17.2.1 Delegating to an IDE
17.2.2 Using Make
17.3 Introducing the <cc> task
17.3.1 Installing the tasks
17.3.2 Adding a compiler
17.3.3 A quick introduction to the <cc> task
17.4 Building a JNI library in Ant
17.4.1 Steps to building a JNI library
17.4.2 Writing the Java stub
17.4.3 Writing the C++ class
17.4.4 Compiling the C++ source
17.4.5 Deploying and testing the library
17.5 Going cross-platform
17.5.1 Migrating the C++ source
17.5.2 Extending the build file
17.5.3 Testing the migration
17.5.4 Porting the code
17.6 Looking at <cc> in more detail
17.6.1 Defining preprocessor macros
17.6.2 Linking to libraries with <libset>
17.6.3 Configuring compilers and linkers
17.6.4 Customizing linkers
17.7 Distributing native libraries
17.8 Summary
chapter18
18.1 The challenge of different application servers
18.1.1 Fundamentally different underlying behaviors
18.1.2 Different Java run-time behavior
18.1.3 Coping with different API implementations
18.1.4 Vendor-specific libraries
18.1.5 Deployment descriptors
18.1.6 Server-specific deployment processes
18.1.7 Server-specific management
18.2 Working with operations
18.2.1 Operations use cases
18.2.2 Operations tests
18.2.3 Operations defect tracking
18.2.4 Integrating operations with the build process
18.3 Addressing the deployment challenge with Ant
18.3.1 Have a single source tree
18.3.2 Have a unified target for creating the archive files
18.3.3 Run Ant server-side to deploy
18.3.4 Automate the upload and deployment process
18.4 Introducing Ant’s deployment power tools
18.4.1 The <copy> task
18.4.2 The <serverdeploy> task
18.4.3 Remote control with <telnet>
18.5 Building a production deployment process
18.5.1 The plan
18.5.2 The directory structure
18.5.3 The configuration files
18.5.4 The build files
18.5.5 The remote build.xml build file
18.5.6 Writing the build file for installing to a server
18.5.7 Uploading to the remote server
18.5.8 The remote deployment in action
18.5.9 Reviewing the deployment process
18.6 Deploying to specific application servers
18.6.1 Tomcat 4.0 and 4.1
18.6.2 BEA WebLogic
18.6.3 HP Bluestone application server
18.6.4 Other servers
18.7 Verifying deployment
18.7.1 Creating the timestamp file
18.7.2 Adding the timestamp file to the application
18.7.3 Testing the timestamp
18.8 Best practices
18.9 Summary
chapter19
19.1 What exactly is an Ant task?
19.1.1 The world’s simplest Ant task
19.1.2 Compiling and using a task in the same build
19.1.3 Task lifecycle
19.2 Ant API primer
19.2.1 Task
19.2.2 Project
19.2.3 Path
19.2.4 FileSet
19.2.5 DirectoryScanner
19.2.6 EnumeratedAttribute
19.2.7 FileUtils
19.3 How tasks get data
19.3.1 Setting attributes
19.3.2 Supporting nested elements
19.3.3 Supporting datatypes
19.3.4 Allowing free-form body text
19.4 Creating a basic Ant Task subclass
19.4.1 Adding an attribute to a task
19.4.2 Handling element text
19.5 Operating on a fileset
19.6 Error handling
19.7 Testing Ant tasks
19.8 Executing external programs
19.8.1 Dealing with process output
19.8.2 Summary of native execution
19.9 Executing a Java program withinatask
19.9.1 Example task to execute a forked Java program
19.10 Supporting arbitrarily named elements and attributes
19.11 Building a task library
19.12 Supporting multiple versionsofAnt
19.13 Summary
chapter20
20.1 Scripting within Ant
20.1.1 Implicit objects provided to <script>
20.1.2 Scripting summary
20.2 Listeners and loggers
20.2.1 Writing a custom listener
20.2.2 Using Log4j logging capabilities
20.2.3 Writing a custom logger
20.2.4 Using the MailLogger
20.3 Developing a custom mapper
20.4 Creating custom selectors
20.4.1 Using a custom selector in a build
20.5 Implementing a custom filter
20.5.1 Coding a custom filter reader
20.6 Summary
appendixa
appendixb
appendixc
appendixd
appendixe
index
Resources
index
Nội dung
STEP FOUR: IMPOSING STRUCTURE 35 2.5.4 Creating the build file Now that we have the files in the right places, and we know what we want to do, the build file needs to be rewritten. Rather than glue all the tasks together in one long list of actions, we have broken the separate stages—directory creation, compilation, packaging, and cleanup—into four separate targets inside the build file. <?xml version="1.0" ?> <project name="structured" default="archive" > <target name="init"> <mkdir dir="build/classes" /> <mkdir dir="dist" /> </target> <target name="compile" depends="init" > <javac srcdir="src" destdir="build/classes" /> </target> <target name="archive" depends="compile" > <jar destfile="dist/project.jar" basedir="build/classes" /> </target> <target name="clean" depends="init"> <delete dir="build" /> <delete dir="dist" /> </target> </project> This build file adds an init target to do initialization work, which means creating directories. We’ve also added two other new targets, clean and archive. The archive target uses the <jar> task to create the JAR file containing all files in and below the build/classes directory, which in this case means all .class files created by the compile target. One target has a dependency upon another, a dependency that Ant needs to know about. The clean target cleans up the output directories by deleting them. It uses the <delete> task to do this. We have also changed the default target to archive, so this will be the target that Ant executes when you run it. 2.5.5 Target dependencies We need a way of ensuring that Ant runs some targets before other targets that depend on their outputs. In our current project, for the archive to be up to date, all the source files must be compiled, which means the archive target must come after the compilation target. Likewise, compile needs the directories created in init, so Ant must execute it after the init task. These are dependencies that we need to communicate to Ant. We do this as the targets are declared, listing the dependencies in their depends attributes: Creates the output directories Compiles into the output directories Creates the archive Cleans the output directories Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 36 CHAPTER 2 GETTING STARTED WITH ANT <target name="compile" depends="init" > <target name="archive" depends="compile" > <target name="clean" depends="init"> If a target directly depends on more than one predecessor target, then you should list both dependencies in the dependency attribute, for example depends="com- pile,test" . In our example build, the archive task does depend upon both init and compile, but we do not bother to state the dependency upon init because the compile target depends upon it. If Ant must execute init before compile, and archive depends upon compile then Ant must run init before archive. Put formally, dependencies are transitive. They are not however reflexive: the compile target does not know or care about the archive target. Another useful fact is that the order of targets inside the build file is not important: Ant reads in the whole file before it builds the dependency tree and executes targets. There is no need to worry about forward references. If you look at the dependency tree of targets in the current example, it looks like figure 2.3. Before Ant executes any target, all the predecessor targets must already have been executed. If these predecessors depend on targets themselves, the execution order will also consider those and produce an order that satisfies all dependencies. If two tar- gets in this execution order share a common dependency, then that predecessor will only execute once. Experienced makefile editors will recognize that Ant targets resemble Make’s pseudotargets—targets in a makefile that you refer to by name in the dependencies of other makefile targets. Usually in Make, you name the source files that a target depends on, and the build tool itself works out what to do to create the target file from the source files. In Ant, you name stages of work as targets, and the tasks inside each target work out for themselves what their dependencies are. 2.5.6 Running the new build file Now that there are multiple targets in the build file, we need a way of specifying which to run. You can simply list one or more targets on the command line, so all of the following are valid, as are other combinations: ant ant init ant clean init cleancompile archive Figure 2.3 Once you add dependencies, the graph of targets gets more complex. Here clean depends upon init; archive depends on compile directly and init indirectly. All of a target’s dependencies will be executed ahead of the target itself. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com STEP FOUR: IMPOSING STRUCTURE 37 ant compile ant archive ant clean archive Calling Ant with no target is the same as calling the default target named in the project. In this example, it is the archive target: init: [mkdir] Created dir: C:\AntBook\secondbuild\build [mkdir] Created dir: C:\AntBook\secondbuild\dist compile: [javac] Compiling 1 source file to C:\AntBook\secondbuild\build archive: [jar] Building jar: C:\AntBook\secondbuild\dist\project.jar BUILD SUCCESSFUL Total time: 2 seconds This demonstrates that Ant has determined execution order of tasks. When you invoke a target with dependencies, all their dependencies execute first. As both the compile and archive targets depend upon the init target, Ant must call init before it executes either of those targets. It orders the targets so that first the directo- ries get created, then the source compiled, and finally the JAR archive built. 2.5.7 Rerunning the build What happens when the build is run a second time? Let’s try it and see: init: compile: archive: BUILD SUCCESSFUL Total time: 1 second We go through all the targets, but none of the tasks say that they are doing any work. Here’s why: all of these tasks check their dependencies, <mkdir> does not create directories that already exist, <javac> compares source and class file timestamps, and the <jar> task compares the time of all files to be added to the archive with the time of the file itself. Only if a source file is newer than the generated archive file does the task rebuild the JAR file. If you add the -verbose flag to the command line you will get more detail on what did or, in this case, did not take place. >ant -verbose Apache Ant version 1.5alpha compiled on February 1 2002 Buildfile: build.xml Detected Java version: 1.3 in: D:\Java\jdk13\jre Detected OS: Windows 2000 parsing buildfile C:\AntBook\secondbuild\build.xml with Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 38 CHAPTER 2 GETTING STARTED WITH ANT URI = file:C:/AntBook/secondbuild/build.xml Project base dir set to: C:\AntBook\secondbuild Build sequence for target `archive’ is [init, compile, archive] Complete build sequence is [init, compile, archive, clean] init: compile: [javac] org\example\antbook\lesson1\Main.java omitted as C:\AntBook\secondbuild\build\org\example\antbook\ lesson1\Main.class is up to date. archive: [jar] org\example\antbook\lesson1\Main.class omitted as C:\AntBook\secondbuild\dist\project.jar is up to date. BUILD SUCCESSFUL Total time: 2 seconds The verbose run provides a lot of information, much of which may seem distracting. When a build is working well, you do not need it, but it is invaluable while develop- ing that file. TIP If ever you are unsure why a build is not behaving as expected, run Ant with the - verbose option to get lots more information. 2.5.8 How Ant handles multiple targets on the command line Here is an interesting question which expert users of Make will usually get wrong: what happens when you type ant compile archive at the command line? Many people would expect Ant to pick an order that executes each target and its dependen- cies once only: init, compile, archive. Make would certainly do that, but Ant does not. Instead, it executes each target and dependents in turn, so the actual sequence is init, compile, then init, compile, archive: C:\AntBook\secondbuild>ant compile archive Buildfile: build.xml init: [mkdir] Created dir: C:\AntBook\secondbuild\build [mkdir] Created dir: C:\AntBook\secondbuild\dist compile: [javac] Compiling 1 source file to C:\AntBook\secondbuild\build init: compile: archive: [jar] Building jar: C:\AntBook\secondbuild\dist\project.jar BUILD SUCCESSFUL Total time: 2 seconds This behavior can be unexpected to anyone experienced in other build tools, as it seems to add extra work rather than save work by sharing dependencies. However, if you Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com STEP FIVE: RUNNING OUR PROGRAM 39 look closely, the second time Ant executes the compile target it does no work; the tasks get executed but their dependency checking stops existing outputs being rebuilt. Our next question is this: when a target lists multiple dependencies, does Ant exe- cute them in the order listed? The answer is yes, unless other dependency rules prevent it. Imagine if we modified the archive target with the dependency attribute depends="compile,init". A simple left-to-right execution order would run the compile target before it was initialized. Ant would try to execute the targets in this order, but because the compile target depends upon init, Ant will call init first. This subtle detail can catch you out. If you try to control the execution order by listing targets in order, you may not get the results you expect as explicit dependencies always take priority. 2.6 STEP FIVE: RUNNING OUR PROGRAM We now have a structured build process that creates the JAR file from the Java source. At this point the next steps could be to run tests on the code, distribute it, or deploy it. We shall be covering how to do all these things in the following chapters. For now, we just want to run the program. 2.6.1 Why execute from inside Ant We could just call our program from the command line, stating the classpath, the name of the entry point and the arguments: >java -cp build/classes org.example.antbook.lesson1.Main a b . a b . If the classpath is not complex and the arguments to the application are simple, call- ing Java programs from the command line is not particularly hard, just a manual pro- cess. We still want to run our program from the build file, not just to show it is possible, but because it provides some tangible benefits the moment we do so: • A target to run the program can depend upon the compilation target, so we know we are always running the latest version of the code. • It is easy to pass complex arguments to the program. • It is easier to set up the classpath. • The program can run inside Ant’s own JVM; so it loads faster. • You can halt a build if the return code of the program is not zero. The fact that the execute target can be made to depend on the compile target is one of the key benefits during development. There is simply no need to split program compilation from execution. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 40 CHAPTER 2 GETTING STARTED WITH ANT 2.6.2 Adding an execute target To call the program from inside Ant, we merely add a new target, execute, which we make dependent upon compile. It contains one task, <java>, that runs our Main.class using the interim build/classes directory tree as our classpath: <target name="execute" depends="compile"> <java classname="org.example.antbook.lesson1.Main" classpath="build/classes"> <arg value="a"/> <arg value="b"/> <arg file="."/> </java> </target> We have three <arg> tags inside the <java> task; each tag contains one of the argu- ments to the program: "a", "b", and ".", as with the command line version. Note, however, that the final argument, <arg file="."/>, is different from the other two. The first two arguments use the value attribute of the <arg> tag, which passes the value straight down to the program. The final argument uses the file attribute, which tells Ant to resolve that attribute to an absolute file location before calling the program. 2.6.3 Running the new target What does the output of the run look like? First, let’s it run it on Windows: C:\AntBook\secondbuild>ant execute Buildfile: build.xml init: compile: execute: [java] a [java] b [java] C:\AntBook\secondbuild The compile task didn’t need to do any recompilation, and the execute task called our program. Ant has prefixed every line of output with the name of the task currently running, showing here that this is the output of an invoked Java applica- tion. The first two arguments went straight to our application, while the third argu- ment was resolved to the current directory; Ant turned "." into an absolute file reference. Next, let’s try the same program on Linux: [secondbuild]$ ant execute Buildfile: build.xml init: compile: execute: [java] a [java] b [java] /home/ant/Projects/secondbuild Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ANT COMMAND LINE OPTIONS 41 Everything is identical, apart from the final argument, which has been resolved to a dif- ferent location, the current directory in the Unix path syntax, rather than the DOS one. This shows another benefit of starting programs from Ant rather than any batch file or shell script: a single build file can start the same program on multiple platforms, trans- forming file names and file paths into the appropriate values for the target platform. This is a very brief demonstration of how and why to call programs from inside Ant; enough to round off this little project. We have dedicated an entire chapter to the subject of calling Java and native programs from Ant during a build process. Chapter 5 explores the options and issues of the topic in detail. 2.7 ANT COMMAND LINE OPTIONS We have nearly finished our quick look at some of what Ant can do, but we have one more little foundational topic to cover: how to call Ant. We have already shown that Ant is a command-line program, and that you can specify multiple targets as parame- ters, and we have introduced the - verbose option to get more information on a build. We want to do some more with Ant’s command line to run our program. First, we want to remove the [java] prefixes, then we will run the build without any out- put at all unless something goes wrong. Ant command line options can do this. Ant can take a number of options, which it lists if you ask for them with ant -help . The current set of options is listed in table 2.2. Table 2.2 Ant command line options Option Meaning -help List the options Ant supports and exit -version Print the version information and exit -buildfile file Use the named buildfile, use -f as a shortcut -find file Search for the named buildfile up the tree -projecthelp Print information about the current project -verbose Be extra verbose -quiet Be extra quiet -debug Print debugging information -emacs Produce logging information without adornments -Dproperty=value Set a property to a value -propertyfile file Load all properties from file -logfile file Use given file for log -listener classname Add a project listener -logger classname Name a different logger -inputhandler classname The name of a class to respond to <input> requests -diagnostics Print information that might be helpful to diagnose or report problems. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 42 CHAPTER 2 GETTING STARTED WITH ANT Some options require more explanation of Ant before they make sense. In particular, the two options related to properties are not relevant until we explore Ant’s properties in chapter 3. Likewise, we don’t introduce listeners and loggers until chapter 13, so let’s ignore those options for now. Just keep in mind that it is possible to write Java classes that get told when targets are executed, or that get fed all the output from the tasks as they execute, a feature that is the basis for integrating Ant into IDEs. 2.7.1 Specifying which build file to run Perhaps the most important option for Ant is -buildfile. This option lets you control which build file Ant uses, allowing you to divide the targets of a project into multiple files, and select the appropriate build file depending on your actions. Ashortcut to - buildfile is -f. To invoke our existing project, we just name it im- mediately after the - f or -buildfile argument: ant -buildfile build.xml compile This is exactly equivalent to calling ant compile with no file specified. If for some reason the current directory was somewhere in the source tree, which is sometimes the case when you are editing text from a console application such as vi, emacs, or even edit, then you can refer to a build file by passing in the appropriate relative file name for your platform, such as / / /build.xml or \ \ \build.xml . This is fiddly. It is better to use the -find option, which must be followed by the name of a build file. This variant does something very special: it searches up the directory tree to find the first build file in a parent directory of that name, and invokes it. With this option, when you are deep down the source tree editing files, you can easily invoke the project build with the simple command: ant -find build.xml 2.7.2 Controlling the amount of information provided We stated that we want to reduce the amount of information provided when we invoke Ant. Getting rid of the [java] prefix is easy: we run the build file with the - emacs option; this omits the task-name prefix from all lines printed. The option is called - emacs because the output is now in the emacs format for invoked tools, which enables that and other editors to locate the lines on which errors occurred. When calling Ant from any IDE that lacks built-in support, the - emacs option may tighten the integration. For our exercise, we only want to change the presentation from the command line, which is simple enough: [secondbuild]$ ant -emacs execute Buildfile: build.xml init: compile: execute: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com ANT COMMAND LINE OPTIONS 43 a b /home/ant/Projects/secondbuild BUILD SUCCESSFUL Total time: 2 seconds. This leaves the next half of the problem, hiding all the output entirely. Three of the Ant options control how much information is output when Ant runs. Two of these (- verbose and -debug) progressively increase the amount. The verbose option is useful when you are curious about how Ant works, or why a build isn’t behaving. The debug option includes all the normal and verbose output, and much more low level information, primarily only of interest to Ant developers. The - quiet option reduces the amount of information to a success message or errors: [secondbuild]$ ant -quiet execute BUILD SUCCESSFUL Total time: 2 seconds This leaves us with no way of telling if the program worked, unless we can infer it from the time to execute. Would adding an <echo> statement in the execute tar- get help? Not by default. One of the attributes of echo is the level attribute: error, warning, info, verbose, and debug control the amount of information that appears. The default value info ensures that echoed messages appear in normal builds, or the two levels of even more information, verbose and debug. By insert- ing an echo statement into our execute target with the level set to warning, we ensure that even when the build is running in quiet mode the output appears. The Ant task declaration <echo level="warning" message="running" /> results in the following output: >ant -quiet [echo] running To eliminate the [echo] prefix, we add the -emacs option again, calling >ant -quiet -emacs to get the following output: running BUILD SUCCESSFUL Total time: 2 seconds. Controlling the output level of programs is not only useful when debugging, but when trying to run a large build that has worked in the past; only errors and occa- sional progress messages matter. A quiet build with a few manual <echo level= "warning"> tags is ideal for a bulk build. Likewise, some <echo level="verbose"> tags can provide extra trace information when more detail is required. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 44 CHAPTER 2 GETTING STARTED WITH ANT 2.7.3 Getting information about a project The final option of immediate relevance is -projecthelp. It lists the main targets in a project, and is invaluable whenever you need to know what targets a build file provides. Ant only lists targets containing the optional description attribute, as these are the targets intended for public consumption. >ant -projecthelp Buildfile: build.xml Main targets: Subtargets: archive clean compile execute init Default target: archive This is not very informative, which is our fault for not documenting the file thor- oughly enough. If we add a description attribute to each target, such as description="Compiles the source code" for the compile target, and a <description> tag right after the project declaration, then the target listing includes these descriptions, marks all the described targets as “main targets,” and hides all sub targets from view: Buildfile: build.xml Compiles and runs a simple program Main targets: archive Creates the JAR file clean Removes the temporary directories used compile Compiles the source code execute Runs the program Default target: archive To see both main and sub targets in a project, you must call Ant with the options - projecthelp and -verbose. The more complex a project is, the more useful the - projecthelp feature becomes. We strongly recommend providing description strings for every target intended to act as an entry point to external callers, and a line or two at the top of each build file describing what it does. 2.8 THE FINAL BUILD FILE We close with the complete listing of the final build file, listing 2.1. As well as adding the description tags, we decided to change the default target to run the program, rather than just create the archive. We have marked the major changes in bold, to show where this build file differs from the build files and build file fragments shown earlier. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... Sun’s JDK 1.3.1 javac compiler, the following command line is used: javac -d build\classes -classpath lib\lucene-1 .2- rc3\lucene-1 .2- rc3.jar; lib\jtidy-04aug2000r7-dev\build\Tidy.jar; C:\AntBook\jakarta -ant- 1.5\lib \ant. jar; -sourcepath src -g src\org\example\antbook \ant\ lucene\* .java The following Java compilation with Ant, utilizing Ant s datatypes and properties, shows the equivalent Ant task declaration... message= "ant. home = $ {ant. home}"/> This generates output similar to this: echo: [echo] [echo] [echo] [echo] [echo] 66 ant. file = C:\AntBook\Sections\Learning\datatypes\properties.xml ant. home = c:\AntBook\jakarta -ant- 1.5Beta1 ant .java. version = 1.3 ant. version... can do 46 CHAPTER 2 GETTING STARTED WITH ANT Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com C H A P T E R 3 Understanding Ant datatypes and properties 3.1 3 .2 3.3 3.4 3.5 3.6 3.7 3.8 Preliminaries 48 Introducing datatypes and properties with 49 Paths 51 Filesets 52 Patternsets 54 Selectors 56 Datatype element naming 57 Filterset 58 3.9 3.10 3.11 3. 12 3.13 3.14 3.15... constant: package org.example.antbook; public interface Constants { public static final String VERSION ="1.7"; } Our build compiles the code into the build directory Using the and FilterReaders in a task, we can now give Ant access to the VERSION constant ... similar conceptually to java util.Properties Ant provides the built-in properties listed in table 3.7 Table 3.7 Built-in properties Name Definition ant. file The absolute path of the build file ant. home The path to executing version of Ant s root directory ant .java. version The JVM version Ant detected; currently it can hold the values 1.1, 1 .2, 1.3, and 1.4 ant. project.name The name of the project that... interface The task is the common interface to JDK 1.1 and up, Jikes, and several other Java compilers There is much more to Java compilation than just specifying a source directory and destination directory A comparison of Sun’s JDK 1.3.1 javac command-line compiler switches to Ant s task is shown in table 3.1 Table 3.1 Sun’s JDK 1.3.1 javac compared to Ant s wrapper task Note... concepts natively You can think of an Ant datatype as similar to Java s own built-in core classes: data that can be passed around and provided to tasks The fileset and path datatypes, and several others, form the basic building blocks of Ant build files Classpath-related headaches are commonplace in Java development Ant makes dealing with classpaths much more natural and pleasant than the command-line manual... important to note that Ant guarantees no order within a Each element in a path is ordered from the top and down so that all files within a fileset would be grouped together in a path However, the order within that fileset is not guaranteed 3.4 FILESETS Implicitly, all build processes will operate on sets of files, either to compile, copy, delete, or operate on them in any number of other ways Ant. .. defined once for compilation with , and reused for execution (via , covered in chapter 5) One of the consequences of classpaths being specified inside the build file is that Ant can be invoked without an explicitly defined system classpath, making it easy to install Ant and build a project with little or no environmental configuration.1 Another no less important consequence is that classpaths... Assume that there is a single file in the data directory called data _20 020 2 02. dat, yet this file name is dynamically generated The use of the merge mapper will copy it to the output directory with the name data.dat This particular technique, remember, is only useful with filesets containing a single file 62 CHAPTER 3 UNDERSTANDING ANT DATATYPES AND PROPERTIES Simpo PDF Merge and Split Unregistered Version . C:AntBookjakarta -ant- 1.5lib ant. jar; -sourcepath src -g srcorgexampleantbook ant lucene* .java The following Java compilation with Ant, utilizing Ant s datatypes and properties, shows the equivalent Ant task. options can do this. Ant can take a number of options, which it lists if you ask for them with ant -help . The current set of options is listed in table 2. 2. Table 2. 2 Ant command line options Option. place. > ;ant -verbose Apache Ant version 1.5alpha compiled on February 1 20 02 Buildfile: build.xml Detected Java version: 1.3 in: D: Java jdk13jre Detected OS: Windows 20 00 parsing buildfile C:AntBooksecondbuilduild.xml