JaVa
   

Hello World Model Project

In we used a Hello World example that was contained in one file. The Hello World example in this chapter is more complex because it uses several classes. This section explains the basic structure for all the buildfiles and directories you use in this example and the rest of the tutorial. We introduce the three Java class files: a GreetingBean class, a GreetingFactory class, and a Greeting interface. Then, we discuss how to build these files with Ant and break down the Ant buildfiles' target execution step by step. We also explain how to use the Ant command-line utility to build the files with Ant.

Overview of Model Classes

The GreetingFactory knows how to create a Greeting object. Here is the listing for the GreetingFactory:

package xptoolkit.model;
public class GreetingFactory {
 private GreetingFactory(){}
 public Greeting getGreeting()throws Exception {
 String clazz = System.getProperty("Greeting.class",
 "xptoolkit.model.GreetingBean");
 return (Greeting)Class.forName(clazz).newInstance();
 }
 public static GreetingFactory getGreetingFactory(){
 return new GreetingFactory();
 }
}


Next we have a Greeting interface that defines the contract of a Greeting object—that is, what type of behavior it supports. The Greeting interface is as follows:

package xptoolkit.model;
public interface Greeting extends java.io.Serializable{
 public String getGreeting();
}


Finally, the GreetingBean class implements the Greeting Interface. GreetingBean is defined as follows:

package xptoolkit.model;
public class GreetingBean implements Greeting{
 public GreetingBean(){}
 public String getGreeting(){
 return "Hello World!";
 }
}


The GreetingBean returns the message “Hello World!” just like the message in the app. To create a Greeting instance, you use the GreetingFactory. The default implementation of the GreetingFactory gets the implementation class from a property and instantiates an instance of that class with the Class.forName().newInstance() method. It casts the created instance to the Greeting interface. These two lines of code create the Greeting instance from the GreetingFactory's getGreeting() method:

 String clazz = System.getProperty("Greeting.class",
 "xptoolkit.model.GreetingBean");
 return (Greeting)Class.forName(clazz).newInstance();


Thus any class that implements the Greeting interface can be substituted as the Greeting.class system property. Then, when the class is instantiated with the factory's getGreeting() method, the app uses the new implementation of the Greeting interface.

We use this technique in to add support for EJBs to the Web app seamlessly. We create an Ant script that can deploy the same Web app to use either enterprise beans or another bean implementation just by setting an Ant property. Later, we also map the Greeting interface with the use bean action of a JSP when we implement the Model 2 using servlets and JSP.

Creating a Project Directory Structure for Model

This part of the sample app uses the smallest buildfile. Basically, we just need to create a JAR file that acts as a common library. We don't need any special manifest file or deployment files. This is the most basic buildfile and directory structure you will see in this example. Here is the directory structure for the Model directory:

Root of Model
| build.xml
|
+---src
 +---xptoolkit
 \---model
 GreetingFactory.java
 Greeting.java
 GreetingBean.java


Notice that there are only four files in the Model directory and subdirectories. Also notice that the name of the Ant file is build.xml. Remember from that build.xml is the default buildfile; if Ant is run in this directory, it automatically finds build.xml without you having to specify it on the command line. Let's dig into the model buildfile.

Creating a Buildfile for a Shared Library

The model buildfile has six targets: setProps, init, clean, delete, prepare, compile, package, and all. The buildfiles in this example have similar targets:

Analysis of the Model Project Buildfile

The following listing shows the entire buildfile for the model project. In this section we provide a step by step analysis of how this buildfile executes. All the buildfiles in the Hello World example are structured in a similar fashion, so understanding the model project's buildfile is essential to understanding the others. A quick note on naming conventions: As you see from the first line of code in the next listing, the project name for this buildfile is model. Thus we refer to this buildfile as the model project buildfile. This naming convention becomes essential once we begin dealing with the five other buildfiles in this project.

<project default="all" >
 <target unless="setProps" description="setup the properties.">
 <property value="/tmp/app/" /> 
 </target>
 <target depends="setProps" description="initialize the properties.">
 <tstamp/>
 <property name="local_outdir" value="${outdir}/model" />
 <property value="${local_outdir}/classes" />
 <property value="${outdir}/lib" />
 <property name="model_jar" value="${lib}/greetmodel.jar" />
 </target>
 <target depends="init" description="clean up the output directories and jar.">
 <delete dir="${local_outdir}" />
 <delete file="${model_jar}" />
 </target>
 <target depends="init" description="prepare the output directory.">
 <mkdir dir="${build}" />
 <mkdir dir="${lib}" />
 </target>
 <target depends="prepare" description="compile the Java source.">
 <javac srcdir="./src" destdir="${build}" />
 </target>
 <target depends="compile"
 description="package the Java classes into a jar.">
 <jar jarfile="${model_jar}"
 basedir="${build}" />
 </target>
 <target depends="clean,package" description="perform all targets."/> </project>


Let's go over the model project buildfile and each of its targets in the order they execute. First, the model project sets the all target as the default target, as follows:

<project default="all" >


The all target is executed by default, unless we specify another target as a command-line argument of Ant. The all target depends on the clean and package targets. The clean target depends on the init target. The init target depends on the setProps target, and thus the setProps target is executed first. Following is the setProps target defined in build.xml:

 <target unless="setProps" description="setup the properties.">
 <property value="/tmp/app/" /> </target>


The setProps target executes only if the "setProps" property is not set (unless="setProps"). Thus, if a parent buildfile calls this buildfile, it can set the "setProps" property and override the value of outdir so that the setProps target of this file does not execute (we give an example of this later). If the setProps target executes, it sets the value of outdir to /tmp/app. Next, the init target is executed. Following is the init target defined in build.xml:

 <target depends="setProps" description="initialize the properties.">
 <tstamp/>
 <property name="local_outdir" value="${outdir}/model" />
 <property value="${local_outdir}/classes" />
 <property value="${outdir}/lib" />
 <property name="model_jar" value="${lib}/greetmodel.jar" />
 </target>


The init target uses the tstamp task to get the current time, which is used by the javac task to see if a source file is out of data and needs to be compiled. The init target defines several properties that refer to directories and files needed to compile and deploy the model project. We will discuss the meaning of these properties because all the other buildfiles for this example use the same or similar properties. The init target defines the following properties:

As a general rule, if you use the same literal twice, you should go ahead and define it in the init target. You don't know how many times we've shot ourselves in the foot by not following this rule. This buildfile is fairly simple, but the later ones are more complex. Please learn from our mistakes (and missing toes). Now that all the clean target's dependencies have executed, the clean target can execute. The clean target deletes the intermediate files created by the compile and the output common JAR file, which is the output of this project. Here is the code for the clean target:

 <target depends="init" description="clean up the output directories and jar.">
 <delete dir="${local_outdir}" />
 <delete file="${model_jar}" />
 </target>


Remember that the all target depends on the clean and package targets. The clean branch and all its dependencies have now executed, so it is time to execute the package target branch (a branch is a target and all its dependencies). The package target depends on the compile target, the compile target depends on the prepare target, and the prepare target depends on the init target, which has already been executed. Thus, the next target that executes is prepare, because all its dependencies have already executed. The prepare target creates the build output directory, which ensures that the lib directory is created. The prepare target is defined as follows:

 <target depends="init" description="prepare the output directory.">
 <mkdir dir="${build}" />
 <mkdir dir="${lib}" />
 </target>


The next target in the package target branch that executes is the compile target—another dependency of the package target. The compile target compiles the code in the src directory to the build directory, which was defined by the "build" property in the init target. The compile target is defined as follows:

 <target depends="prepare" description="compile the Java source.">
 <javac srcdir="./src" destdir="${build}"/>
 </target>


Now that all the target dependencies of the package target have been executed, we can run the package target. Whew! The package target packages the Java classes created in the compile target into a JAR file that is created in the common lib directory. The package target is defined as follows:

 <target depends="compile"
 description="package the Java classes into a jar.">
 <jar jarfile="${model_jar}"
 basedir="${build}" />
 </target>


Running an Ant Buildfile

In this section, we discuss how to run the Hello World model project buildfile. There are three steps to running the Ant buildfile:

  1. Set up the environment.

  2. Go to the directory that contains the build.xml file for the model.
  3. Run Ant.

Successfully running the buildscript gives us the following output:

Buildfile: build.xml setProps:

init:
clean:
prepare:
 [mkdir] Created dir: C:\tmp\app\model\classes compile:
 [javac] Compiling 3 source files to C:\tmp\app\model\classes package:
 [jar] Building jar: C:\tmp\app\lib\greetmodel.jar all:
BUILD SUCCESSFUL Total time: 3 seconds


If you do not get this output, check that the properties defined in the init target make sense for your environment. If you are on a Unix platform and the buildfile is not working, make sure that the /tmp directory exists and that you have the rights to access it. Alternatively, you could run the previous script by doing the following on the command line:

$ ant -DsetProps=true -Doutdir=/usr/rick/tmp/app


Basically, you want to output to a directory that you have access to, just in case you are not the administrator of your own box. If from some reason Ant still does not run, make sure you set up the Ant environment variables (refer to for details). After successfully running Ant, the output directory for the model project will look like this:

Root of output directory
\---app
 +---lib
 | greetmodel.jar
 |
 \---model
 \---classes
 \---xptoolkit
 \---model
 GreetingFactory.class
 Greeting.class
 GreetingBean.class


Notice that all the intermediate files to build the JAR file are in the model subdirectory. The output from this project is the greetmodel.jar file, which is in ${outdir}/app/lib. The next project, the app project, needs this JAR file in order to compile. In the next section, we discuss how to build a standalone Java app with Ant that uses the JAR file (greetmodel.jar) from the model project.


JaVa
   
Comments