ant: Part 2

These notes were developed by Rod Byrne and adapted by Andrew Vardy.

Compiling, Running, and Jaring --- Without ant

A collection of Java files is used to create a receipt printing program.

Script:
% ls -l src
total 20
-rw------- 1 rod rod  568 Mar 17 18:41 ExemptTaxableProduct.java
-rw------- 1 rod rod 1962 Mar 17 18:50 FormattedReceiptPrinter.java
-rw------- 1 rod rod  670 Mar 17 18:41 Product.java
-rw------- 1 rod rod  607 Mar 17 18:41 TaxableProduct.java
-rw------- 1 rod rod 1229 Mar 17 18:41 TypedProduct.java
% wc src/*java
  26   65  568 src/ExemptTaxableProduct.java
  63  209 1962 src/FormattedReceiptPrinter.java
  32   90  670 src/Product.java
  23   88  607 src/TaxableProduct.java
  48  171 1229 src/TypedProduct.java
 192  623 5036 total
% grep main src/*java  # find the main class
src/FormattedReceiptPrinter.java:    public static void main( String[] args ) {
% 

In addition to storing the java files in the src directory, the class files are stored in the classes directory. The project directory contains:

Script:
% ls -l
total 24
-rw------- 1 rod rod 1608 Mar 17 19:58 build.xml
drwx------ 2 rod rod 4096 Mar 19 15:04 classes
-rw------- 1 rod rod   36 Mar 17 18:56 manifest.txt
-rw------- 1 rod rod 3950 Mar 19 14:49 pcsv.jar
-rw------- 1 rod rod 3473 Mar 19 15:04 rp.jar
drwx------ 2 rod rod 4096 Mar 17 18:50 src
% 

To start off in a known state, the contents of the classes directory and rp.jar are deleted with:

Script:
% rm -f classes/*
% rm -f rp.jar
% ls -l classes
total 0
% 

The java files can be compiled with:

Script:
% javac -d classes src/*.java
% ls -l classes
total 20
-rw------- 1 rod rod  457 Mar 19 15:05 ExemptTaxableProduct.class
-rw------- 1 rod rod 2456 Mar 19 15:05 FormattedReceiptPrinter.class
-rw------- 1 rod rod  609 Mar 19 15:05 Product.class
-rw------- 1 rod rod  521 Mar 19 15:05 TaxableProduct.class
-rw------- 1 rod rod  770 Mar 19 15:05 TypedProduct.class
% ls -l src # class file here
total 20
-rw------- 1 rod rod  568 Mar 17 18:41 ExemptTaxableProduct.java
-rw------- 1 rod rod 1962 Mar 17 18:50 FormattedReceiptPrinter.java
-rw------- 1 rod rod  670 Mar 17 18:41 Product.java
-rw------- 1 rod rod  607 Mar 17 18:41 TaxableProduct.java
-rw------- 1 rod rod 1229 Mar 17 18:41 TypedProduct.java
% 

The -d flag causes javac to save all the class files in the classes directory.

The program can be run with:

Script:
% java -cp classes FormattedReceiptPrinter
d-store
Thu Mar 19 15:05:27 NDT 2015

tooth p...   1    3.50  0.00
eggs         6    1.80  0.27
pop         20   10.00  0.00

total price:   15.30
total tax:      0.27
total:         15.57
% 

The -cp specifies the class path. The class path is where java searches for any class files. The shell variable CLASSPATH can also be used.

Script:
% CLASSPATH=classes java FormattedReceiptPrinter
d-store
Thu Mar 19 15:05:28 NDT 2015

tooth p...   1    3.50  0.00
eggs         6    1.80  0.27
pop         20   10.00  0.00

total price:   15.30
total tax:      0.27
total:         15.57
% echo "'$CLASSPATH'" # note CLASSPATH only exists in the above cmd
''
% export CLASSPATH=classes
% java FormattedReceiptPrinter
d-store
Thu Mar 19 15:05:28 NDT 2015

tooth p...   1    3.50  0.00
eggs         6    1.80  0.27
pop         20   10.00  0.00

total price:   15.30
total tax:      0.27
total:         15.57
% 

All the class files and manifest file can be bundled into a jar file with:

Script:
% cd classes
% jar cvfm ../rp.jar ../manifest.txt *.class
added manifest
adding: ExemptTaxableProduct.class(in = 457) (out= 313)(deflated 31%)
adding: FormattedReceiptPrinter.class(in = 2456) (out= 1385)(deflated 43%)
adding: Product.class(in = 609) (out= 363)(deflated 40%)
adding: TaxableProduct.class(in = 521) (out= 346)(deflated 33%)
adding: TypedProduct.class(in = 770) (out= 496)(deflated 35%)
% 

The manifest.txt contains:

Main-Class: FormattedReceiptPrinter

All the *.class are now stored in rp.jar. The flags cvfm stand for: create, verbose, file, manifest. The jar file is listed with:

Script:
% jar tvf rp.jar
     0 Thu Mar 19 15:05:28 NDT 2015 META-INF/
   105 Thu Mar 19 15:05:28 NDT 2015 META-INF/MANIFEST.MF
   457 Thu Mar 19 15:05:26 NDT 2015 ExemptTaxableProduct.class
  2456 Thu Mar 19 15:05:26 NDT 2015 FormattedReceiptPrinter.class
   609 Thu Mar 19 15:05:26 NDT 2015 Product.class
   521 Thu Mar 19 15:05:26 NDT 2015 TaxableProduct.class
   770 Thu Mar 19 15:05:26 NDT 2015 TypedProduct.class
% 

The flags tvf stand for: table, verbose, file. The program can be executed with:

Script:
% java -jar rp.jar
d-store
Thu Mar 19 15:05:29 NDT 2015

tooth p...   1    3.50  0.00
eggs         6    1.80  0.27
pop         20   10.00  0.00

total price:   15.30
total tax:      0.27
total:         15.57
% 

ant

The ant tool automates the building of a software system. It was created to automate the building of systems that use the Java programming language. The ant tool uses a build file (build.xml) based on XML that describes which tasks to execute to build a target. Ant uses the following terms:

project
the root element of the build file which specifies the default target. The project element contains target elements. In this description, element refers to an XML element (content between the <project> and </project> tags).
target
a target is the name assigned by the user to the entity created by a list of tasks given in the target element. Targets can also specify a set of targets that must be done before the tasks in this target can be executed. Typical target names are: compile, jar, clean, and test.
task
Ant provides a standard set of tasks required to build a software product. Some tasks are: create directory, remove files, compile java programs, create a jar file, ...
property
Ant allows named properties (variables) to be associated with values. Properties are used to customize the building process.

greetings from ant

The greetings project has one target called sayit. The sayit target contains the echo task. The echo task outputs its contents to the screen. A description element can be used to document the project. The source of greetings.xml is:

scripts/greetings.xml

<?xml version="1.0" ?>
<project name="greetings" default="sayit">
    <description>
        Do a greeting.
    </description>

    <target name="sayit">
        <echo> Hi there. </echo>
    </target>
</project>

The command to invoke ant on this file is:

% ant -f greetings.xml

Ant will then produce:

scripts/greetings.out

Buildfile: greetings.xml

sayit:
     [echo]  Hi there. 

BUILD SUCCESSFUL
Total time: 0 seconds

greetings with properties

Properties are set with the element:

<property name="name" value="value" />

where the name attribute defines the name and the value is found in the value attribute.

The value of the property is retrieved with:

${property-name}

Properties are use when a configuration value can appear more than once. Properties can be specified on the command line with:

-Dname=value

greetings with properties as arguments

The properties can be specfied on the command line. Notice there is no property definitions in the build file.

scripts/greetargs.xml

<?xml version="1.0" ?>
<project name="greetings" default="sayit" >
    <description>
        Demonstrate properties.
    </description>

    <target name="init">
        <!-- message can appear in the
             message attribute -->
         <echo message="init( ${projectname} )."/>
    </target>

    <target name="sayit" depends="init">
        <echo>
            Project ${projectname} is at
            version  ${version}
        </echo>
    </target>
</project>

The command to invoke ant with properties specified on the command line for this file is:

Command:
ant -f greetargs.xml -Dprojectname=p1 -Dversion=v1
Standard output:
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/scripts/greetargs.xml

init:
     [echo] init( p1 ).

sayit:
     [echo] 
     [echo]             Project p1 is at
     [echo]             version  v1
     [echo]         

BUILD SUCCESSFUL
Total time: 0 seconds

Greetings saved to a file

The file attribute to echo can be used to send the output of echo to a file.

scripts/file-greetargs.xml

<?xml version="1.0" ?>
<project name="file-greetings" default="sayit" >
    <property name="result" value="result.txt" />

    <description>
        Demonstrate properties.
    </description>

    <target name="init">
        <!-- message can appear in the
             message attribute -->
         <echo message="init( ${projectname} )."/>
    </target>

    <target name="sayit" depends="init">
        <echo file="${result}">
            Project ${projectname} is at
            version  ${version}

        </echo>
    </target>
</project>
Command:
ant -f file-greetargs.xml -Dprojectname=P1 -Dversion=v10
Standard output:
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/scripts/file-greetargs.xml

init:
     [echo] init( P1 ).

sayit:

BUILD SUCCESSFUL
Total time: 0 seconds
Command:
cat result.txt
Standard output:
            Project P1 is at
            version  v10

        

file tasks

Creating and maintaining directory layouts are accomplished with the mkdir, delete, and copy tasks.

The example mkdir task is:

<mkdir dir="some/dir/list" />

This task will create all the directories (if necessary) to the last directory named on the path.

The delete task will delete a file if the file attribute is used, or delete a directory tree if the dir attribute is used.

<delete file="junk" />
<delete dir="classes" />

Files are copied with:

<copy file="stuff" tofile="stuff.bak"/>

A file can be copied to a directory with

<copy file="stuff" todir="backup"/>

fileset

More complex file sets can be constructed with the fileset element. Many tasks use the fileset element to select the files to operate on.

All the java files in a directory tree are selected with:

<fileset dir="base_dir">
    <include name="**/*.java">
</fileset>

Files can also be excluded from a fileset, for example the following excludes any file with a .bak suffix.

<fileset dir="base_dir">
    <include name="**/*">
    <exclude name="**/*.bak">
</fileset>

backing up and cleaning up

The following ant script contains tasks to save a copy of all java files in a directory, and to remove the backup directory during cleanup.

scripts/files.xml

<?xml version="1.0" ?>
<project name="files" default="backup">
    <property name="src.dir" value="src" />
    <property name="backup.dir" value="backup" />

    <target name="remove">
        <delete dir="${backup.dir}" />
        <mkdir dir="${backup.dir}" />
    </target>

    <target name="backup" depends="remove">
        <copy todir="${backup.dir}">
            <fileset dir="${src.dir}">
                <include name="**/*.java"/>
            </fileset>
        </copy>
    </target>
</project>

compiling java source

The javac task invokes a java compiler to transform java source into class files. The javac task supports that same file selection elements as the fileset element. A ant script to compile a java package and store the class files in a separate directory is:

scripts/compile.xml

<?xml version="1.0"?>
<project name="javacc" default="compile">

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

    <target name="init">
        <mkdir dir="${dest.dir}"/>
    </target>

    <target name="compile" depends="init">
        <javac
            srcdir="${src.dir}"
            destdir="${dest.dir}"
            includes="**/*.java"/>
    </target>

</project>

compiling with fileset

The source can be specified with include element inside the javac element.

scripts/compile2.xml

<?xml version="1.0"?>
<project name="javacc" default="compile">

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

    <target name="init">
        <mkdir dir="${dest.dir}"/>
    </target>

    <target name="compile" depends="init">
        <javac
            srcdir="${src.dir}"
            destdir="${dest.dir}" >
            <include name="**/*.java"/>
        </javac>
    </target>

</project>

jar files

The jar (Java archive) tool is used to manage a collection of class files. It uses the zip archive format. An archive (jar file) is created, specified by the c flag, with:

% jar cvf file.jar input-files ...

A listing of the jar file's contents is done with:

% jar tvf file.jar

Extracting, specified by x, the contents is done by:

% jar xvf file.jar

The v flag means verbose, it causes jar to describe its progress. The f flag means that the next argument is the name of the jar file.

executing jar files

The classes that make up a Java program can be stored into a jar file and a manifest file can be used to specify the main class. The program contained in the jar file is executed with:

% java -jar file.jar

The manifest file must contain the name of the main class. For example, the main class is specified with:

Main-Class: FormattedReceiptPrinter

The class path used by the Main-Class: can be specified by the following line in the manifest file.

Class-Path: path1/t.jar path2/tt.jar

on a line by itself in the manifest file. A jar file containing a manifest is created with:

% jar cvmf manifest-file file.jar input-files

The m flag indicates that a manifest file follows. The f flag indicates the name of the jar file to create. Since the flags are specified as mf, the the manifest file precedes the jar file.

The manifest file, specifies that the main class is FormattedReceiptPrinter and the class path includes path1/t.jar and path2/tt.jar.

jar task

Creating jar files is supported by the jar task in the ant build tool. An example of creating a jar file for the vds program with a manifest is:

scripts/jar.xml

<?xml version="1.0"?>
<project name="jar" default="jar">

    <!-- creates jar files that can be run with
      java -jar rp.jar -->
    <target name="jar" depends="compile">
        <jar jarfile="rp.jar" basedir="classes"
            includes="**/*.class">
            <manifest>
                <attribute name="Main-Class"
                    value="FormattedReceiptPrinter" />
            </manifest>
        </jar>
    </target>

</project>

Note the above is only a partial build file.

The main class and class path can be specified by:

<manifest>
    <attribute name="Main-Class"
        value="FormattedReceiptPrinter" />
    <attribute name="Class-Path"
        value="path1/t.jar path2/tt.jar" />
</manifest>

using the java task

Java programs can be executed with the java task. An example is:

scripts/java.xml

<?xml version="1.0"?>
<project name="exercute" default="run">
    <target name="run">
        <java classname="Test" fork="true">
            <arg value="one"/>
            <classpath>
                <pathelement location="./test.jar"/>
                <pathelement path="classes"/>
            </classpath>
        </java>
    </target>
</project>

The fork attribute specifies if a new JavaVM is created to run the program. When fork is "true" an new JavaVM is forked(created).

Using ant for receipt

The ant build file for the receipt project is:

receipt/build.xml

<?xml version="1.0"?>
<project name="receipt" default="help" basedir=".">

    <target name="help">
        <echo message="ant help -- print this message"/>
        <echo message="ant compile -- compiles the source"/>
        <echo message="ant run -- run the program"/>
        <echo message="ant jar -- create an executable jar"/>
        <echo message="ant runjar -- run the executable jar"/>
        <echo message="ant clean -- removes classes"/>
    </target>

    <property name="dest.dir" value="./classes" />

    <target name="init">
        <mkdir dir="${dest.dir}"/>
    </target>

    <target name="compile" depends="init">
        <javac
            includeantruntime="false"
            srcdir="src" destdir="${dest.dir}">

            <include name="**/*.java"/>
        </javac>
    </target>

    <target name="jar" depends="compile">
        <jar jarfile="rp.jar" basedir="classes"
            includes="**/*.class">
            <manifest>
                <attribute name="Main-Class"
                    value="FormattedReceiptPrinter" />
            </manifest>
        </jar>
    </target>

    <target name="run" depends="compile">
        <java classname="FormattedReceiptPrinter" fork="true">
            <classpath>
                <pathelement path="${dest.dir}"/>
            </classpath>
        </java>
    </target>

    <target name="runjar" depends="jar">
        <java jar="rp.jar" fork="true"/>
    </target>

    <target name="clean">
        <delete includeemptydirs="true">
            <fileset dir="classes" includes="**/*"/>
        </delete>
    </target>

</project>

The project can now be cleaned with:

Script:
% ant clean
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/receipt/build.xml

clean:

BUILD SUCCESSFUL
Total time: 0 seconds
% 

The project is compiled and tested with:

Script:
% ant run
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/receipt/build.xml

init:

compile:
    [javac] Compiling 5 source files to /home/rod/MUN/Winter2015/cs2718/notes/ant/receipt/classes

run:
     [java] d-store
     [java] Thu Mar 19 15:05:35 NDT 2015
     [java] 
     [java] tooth p...   1    3.50  0.00
     [java] eggs         6    1.80  0.27
     [java] pop         20   10.00  0.00
     [java] 
     [java] total price:   15.30
     [java] total tax:      0.27
     [java] total:         15.57

BUILD SUCCESSFUL
Total time: 1 second
% 

The jar file is created with:

Script:
% ant jar
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/receipt/build.xml

init:

compile:

jar:
      [jar] Building jar: /home/rod/MUN/Winter2015/cs2718/notes/ant/receipt/rp.jar

BUILD SUCCESSFUL
Total time: 0 seconds
% 

Compiling, Running, Jaring with other jars

A Java file is used to create a CSV printing program is

csv/src/PrintCSV.java

import au.com.bytecode.opencsv.CSVReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

/**
 * Print csv
 *
 * @author rod
 *
 */
public class PrintCSV {
    public static void main(String args[] ){
        try {
            CSVReader reader = new CSVReader(new FileReader(args[0]));
            List<String []> rows = reader.readAll();
            
            for ( String[] r : rows ) {
                for( String s : r ) {
                    System.out.printf("%-8s", s );
                }
                System.out.println();
            }
        } catch (FileNotFoundException e) {
            System.err.println("File not found");
        } catch (IOException e) {
            System.err.println("Error reading csv");
        }
    }
}

In addition to storing the java files in the src directory, the class files are stored in the classes directory. The project directory contains:

Script:
% ls -l
total 28
-rw------- 1 rod rod 1399 Mar 19 14:26 build.xml
drwx------ 2 rod rod 4096 Mar 19 15:04 classes
-rw------- 1 rod rod  114 Mar 19 14:52 data.csv
drwx------ 2 rod rod 4096 Mar 19 14:12 lib
-rw------- 1 rod rod   49 Mar 19 14:42 manifest.txt
-rw------- 1 rod rod 1244 Mar 19 15:04 pcsv.jar
drwx------ 2 rod rod 4096 Mar 19 14:51 src
% 

To start off in a known state, the contents of the classes directory and pcsv.jar are deleted with:

Script:
% rm -f classes/*
% rm -f pcsv.jar
% 

The java files can be compiled with:

Script:
% javac -cp lib/opencsv.jar -d classes src/*.java
% ls -l classes
total 4
-rw------- 1 rod rod 1245 Mar 19 15:05 PrintCSV.class
% ls -l src # class file here
total 4
-rw------- 1 rod rod 819 Mar 19 14:51 PrintCSV.java
% 

The -d flag causes javac to save all the class files in the classes directory. The class path is specifed with -cp lib/opencsv.jar.

The program can be run with:

Script:
% java -cp classes:lib/opencsv.jar PrintCSV data.csv
red     green   blue    bright  
255      0       0       255    
0        255     0       255    
0        0       255     255    
255      0       255     255    
255      255     255     255    
% 

The -cp specifies the class path. The class path is where java searches for any class files. In addition to directories, the class path can contain jar files. The shell variable CLASSPATH can also be used.

Script:
% CLASSPATH=classes:lib/opencsv.jar java PrintCSV data.csv
red     green   blue    bright  
255      0       0       255    
0        255     0       255    
0        0       255     255    
255      0       255     255    
255      255     255     255    
% 

All the class files and manifest file can be bundled into a jar file with:

Script:
% cd classes
% jar cvfm ../pcsv.jar ../manifest.txt *.class
added manifest
adding: PrintCSV.class(in = 1245) (out= 768)(deflated 38%)
% 

The manifest.txt contains:

csv/manifest.txt

Main-Class: PrintCSV
Class-Path: lib/opencsv.jar

All the *.class are now stored in pcsv.jar. The jar file is listed with:

Script:
% jar tvf pcsv.jar
     0 Thu Mar 19 15:05:38 NDT 2015 META-INF/
   119 Thu Mar 19 15:05:38 NDT 2015 META-INF/MANIFEST.MF
  1245 Thu Mar 19 15:05:38 NDT 2015 PrintCSV.class
% 
Script:
% java -jar pcsv.jar data.csv
red     green   blue    bright  
255      0       0       255    
0        255     0       255    
0        0       255     255    
255      0       255     255    
255      255     255     255    
% 

Ant build file for PrintCSV

The build file is:

csv/build.xml

<?xml version="1.0"?>
<project name="lin" default="compile" basedir=".">

    <property name="src.dir" value="src"/>
    <property name="dest.dir" value="classes"/>
    <property name="lib.dir" value="lib"/>

    <!-- location of libaray jars -->
    <path id="lib-jars">
        <fileset dir="${lib.dir}" />
    </path>

    <target name="init">
        <mkdir dir="${dest.dir}"/>
    </target>

    <target name="compile" depends="init">
        <javac includeantruntime="false"
            srcdir="${src.dir}"
            destdir="${dest.dir}">
            <include name="**/*.java"/>
            <classpath>
                <path refid="lib-jars"/>
            </classpath>
        </javac>
    </target>

    <target name="jar" depends="compile">
        <jar jarfile="pcsv.jar" basedir="classes"
            includes="**/*.class">
            <manifest>
                <attribute name="Main-Class"
                    value="PrintCSV" />
                <attribute name="Class-Path"
                    value="lib/opencsv.jar" />
            </manifest>
        </jar>
    </target>

    <target name="run" depends="compile">
        <java classname="PrintCSV" fork="true">
            <arg value="data.csv"/>
            <classpath>
                <pathelement path="${dest.dir}"/>
                <path refid="lib-jars"/>
            </classpath>
        </java>
    </target>

</project>

The project is compiled and tested with:

Script:
% ant run
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/csv/build.xml

init:

compile:

run:
     [java] red     green   blue    bright  
     [java] 255      0       0       255    
     [java] 0        255     0       255    
     [java] 0        0       255     255    
     [java] 255      0       255     255    
     [java] 255      255     255     255    

BUILD SUCCESSFUL
Total time: 0 seconds
% 

The jar file is created with:

Script:
% ant jar
Buildfile: /home/rod/MUN/Winter2015/cs2718/notes/ant/csv/build.xml

init:

compile:

jar:
      [jar] Building jar: /home/rod/MUN/Winter2015/cs2718/notes/ant/csv/pcsv.jar

BUILD SUCCESSFUL
Total time: 0 seconds
% 

more tasks

Ant supports many task not mentioned here. Some other tasks are:

  • move: rename files and directories
  • junit: runs some junit tests
  • cvs: use cvs to update source code
  • rmic: invoke the rmi compiler
  • unjar: extract files
  • ...