Tips for building Oracle Application Development Framework projects with Apache Ant outside of the Oracle JDeveloper environment.
By John Stegeman
Published February 2010
Oracle JDeveloper 11g makes it easy to compile applications, generate deployment artifacts (such as Java archives [JARs], Web application archives (WARs), and enterprise archives [EARs]), and deploy applications from within the IDE, but what if you want to be able to perform such tasks outside of the Oracle JDeveloper IDE? For example, if you are using a continuous-build tool or if you need to build an EAR file from a machine that does not have Oracle JDeveloper installed? You could create hand-coded scripts to do these tasks, but that would be quite tedious. The alternative is to use a build tool such as Ant.
Ant is a Java-based build tool that has become a de facto standard for building Java projects. You may have heard of another popular build tool called Maven, which is different in that it enforces a common project structure as well as providing ways to compile and build applications. Most modern Java IDEs, including Oracle JDeveloper, support the development of Ant build files and running them from within the IDE; Ant can also be run independently of any IDE, making it useful for the use cases described above.
Using Ant inside the Oracle JDeveloper IDE is simple and straightforward, because you have access to all of your project settings. However, in this article, I am going to tackle the issue of running Ant outside of the Oracle JDeveloper IDE. I’ll explain Ant concepts and show how to set up an Ant build script for building an Oracle Application Development Framework (Oracle ADF) application without having Oracle JDeveloper installed on your machine.
Build files. Ant build files, the conceptual equivalent of makefiles for the Make utility, are XML files that describe the tasks needed to build a specific target and the dependencies among targets. Although Ant build files are usually named build.xml, you are not required to follow this naming convention.
Targets. Targets are the basic building blocks of an Ant build file and are analogous to makefile targets. Among the common/conventionally used targets:
Tasks. Ant tasks are the steps that must be followed to build a target. Ant has more than 100 built-in types of tasks, such as invoking the Java compiler, creating a JAR file, and invoking the Javadoc tool. In addition, because Ant is Java-based, you can write your own Ant task and invoke that task as part of building a target.
Dependencies. Ant dependencies are a mechanism for declaratively controlling the order in which targets must be built. For example, the application source code must be compiled into .class files before a JAR file can be built. In this case, assuming that the Ant build file contains compile and jar targets, we can say that jar depends on compile. In this way, when you tell Ant to build the jar target, Ant will automatically ensure that the compile target is built first. In fact, Ant is smart enough to know whether the .class files on disk are up-to-date and will perform the actual “compile” tasks only if they are required.
Oracle JDeveloper 11g includes a new command-line tool called ojdeploy that can compile and create JAR/WAR/EAR files by referring to the information in the application (jws) and
project (jpr) files; ojdeploy also has a corresponding Ant task, so you can use the same capabilities from within Ant. However, a drawback of ojdeploy (both the command-line tool and the Ant task) is that it requires Oracle JDeveloper to be installed on the machine on which you are doing the build. In addition, at the time of this writing, there appears to be a bug in the Ant task for ojdeploy that prevents it from creating the application EAR file properly. This article will show you how to build your applications with Ant without using ojdeploy, in order to eliminate these two drawbacks.
In this article, you use the same sample project that was used for the initial parts of this series. Your goal is to create a set of Ant build scripts that will enable you to check out a copy of the application code from Subversion and build it on a “clean” computer containing only a Java Development Kit (JDK) and Ant software (and no installation of Oracle JDeveloper or Oracle WebLogic Server). Being able to build your application from a clean computer will enable you to use other techniques that will be explained later in this series, such as using a continuous integration server.
You create the build scripts by following these steps:
The remainder of this article gives you the instructions for completing each of the steps.
The examples in this article use an Oracle JDeveloper Extension to help manage the Oracle ADF Libraries in the Ant build scripts. To install JDevLibsForAnt:
Figure 1 Checking for updates
Figure 2 Check for Updates Wizard Welcome page
Figure 3 Selecting the Update Center to search
Select the JDevLibsForAnt extension and click Next.
Figure 4 Selecting the JDevLibsForAnt extension
Figure 5 Check for Updates summary page
The project is now visible in the Application Navigator, although there are no files visible when expanding it:
To be able to compile an Oracle ADF application without having the Oracle JDeveloper IDE installed, the Java compiler needs to have access to the Oracle ADF and other required libraries used by the application. There are tools such as Maven and Ivy available that can help manage library dependencies automatically; however, those tools work best when there is a public/private repository available with the library definitions. As of this writing, there was no public Maven repository for the Oracle ADF libraries.
The technique I have used to ensure that the libraries are available to the application is the one I outlined in Part 3 of the ADF Essentials Series for managing third-party libraries. If you set up your application to include a project containing the Oracle JDeveloper libraries’ JAR files, you will be able to build the application on a computer that doesn’t have Oracle JDeveloper installed.
If you have been following along with the example project in this series, you will have an application containing three projects as shown here.
Figure 6 Current application with three projectsThe first step is to create a new project to hold the Oracle JDeveloper libraries. To do this, go to the shortcut menu in the Application Navigator and select New Project
Figure 7 Creating a new projectWhen prompted, choose the Generic Project type.
Figure 8 Selecting a generic projectFinally, provide a descriptive name for the project, such as JDeveloperLibs. You do not need to select any technologies for the project, because the project is just a placeholder for the required libraries and an associated Ant script you will create in the next step:
Figure 9 Naming the new projectYour new application should now look like this screen shot:
Figure 10 Application with new JDeveloperLibs projectIf you are using version control for your project, now would be a good time to add the new project (that step isn’t shown here).
The next step is to set up the new project to reference all the required libraries for the application. To do so, you determine all the libraries referenced by all the projects in the application. First, let’s find out what libraries are used by the Model project. To do that, double-click the Model project to show the project’s properties and then select the Libraries and Classpath category in the properties window.
Figure 11 Model project’s libraries
Make a note of all the libraries referenced by this project (there are 11 in this example). Then cancel the Project Properties dialog box and double-click the JDeveloperLibs project to display its properties. Finally, click the Add Library button to add all the libraries you noted from the Model project. The order of the libraries doesn’t matter, although you may find it easier to reconcile if they are. Next, repeat this same process with the ViewController project to add any other library references from the ViewController project to the JDeveloperLibs project. Note that there will be some overlap between the libraries from the Model project and ViewController project; you do not need to add the libraries a second time. When you are finished, the list of libraries referenced by your JDeveloperLibs project should look like this (again, the order of the libraries isn’t important):
Figure 12 Complete list of libraries for the JDeveloperLibs project
The next step is to create an Ant script that contains library definitions for all the libraries referenced for the application. To do this, you will use the JDevLibsForAnt extension you installed earlier. You first need to configure the extension; to do that, double-click the JDeveloperLibs project to display the Project Properties dialog box, and select the JDevLibsForAnt category. Then provide the filename jdev-libs.xml as the output file location and click OK.
Figure 13 Configuring JDevLibsForAnt
Now you can use the JDevLibsForAnt extension to create a file (it will be called jdev-libs.xml) that contains path references for all the Oracle JDeveloper libraries. To do this, right-click the JDeveloperLibs project and select merge JDevLibsForAnt.
Figure 14 Running merge JDevLibsForAnt
After running merge JDevLibsForAnt, click the Refresh button in the Application Navigator to see the jdev-libs.xml file that was created.
Figure 15 The jdev-libs.xml file in the hierarchy
Finally, remove references to the JDeveloper home directory in jdev-libs.xml, by doing a global search-and-replace as shown here:
Figure 16 ADF Model Runtime library definition
This will ensure that the path references point to the JDeveloperLibs project directory instead of the JDeveloper installation directory.
If you are to be able to compile and build your Oracle ADF application, the appropriate libraries must be available at compile time. When you are building the application from within Oracle JDeveloper, there are no problems, because the libraries’ JAR files are available from the Oracle JDeveloper install. To support compiling on a machine that doesn’t have Oracle JDeveloper installed, you need to make the library JAR files available in another fashion. You will do this by copying them to the JDeveloperLibs project directory and adding them to version control, so that anyone who checks out a copy of the application will also get the required JAR files.
The initial copying of the libraries can be tedious, but once you have accomplished it, you will not have to do it again; you will only have to refresh the JAR files if you upgrade Oracle JDeveloper or install a patch, and you will have to add any new libraries if you add more libraries to your application’s project(s).
To copy the libraries’ JAR files, you will use the jdev-libs.xml file as a reference. You need to copy the JAR files from the JDeveloper home directory, maintaining the same general directory structure. As an example, let’s take the ADF Model Runtime library:
Figure 17 Including content from subfolders
To copy the JAR files for this library, you need to create the same directory structure in your JDeveloperLibs project directory and copy the referenced JAR files from the JDeveloper installation directory. One thing to note is that some of the supplied JDeveloper library definitions refer to files that don’t exist! The JDevLibsForAnt extension helpfully flags these files in its generated script; for this example, there are five “missing” JAR files you do not need to copy.
As an example, let’s take a look at the first JAR file that’s part of the ADF Model Runtime library definition, identitystore.jar. You can find that file in the <JDEVELOPER_INSTALL_DIRECTORY>/jdeveloper/modules/oracle.idm_11.1.1 directory. You should create the jdeveloper/modules/oracle.idm_11.1.1 directory structure inside the JDeveloperLibs project directory and copy identitystore.jar there. You should also configure the JDeveloperLibs project’s Resources folder to show the JAR files you’ve copied. To do this, double-click the JDeveloperLibs project to display the Project Properties dialog box. Next, expand the Project Source Paths node and select the Resources subnode. Then click the Include Contents from Subfolders check box:
Figure 18 Excluding the classes folderFinally, on the Excluded tab, click the Add button; in the Add Exclude Filters dialog box, select the classes folder and click OK.
Figure 19 The identitystore.jar file shown in the Application NavigatorYou should now be able to see the identitystore.jar file in the Application Navigator in the appropriate directory structure:
Figure 20 Adding Ant to the Model project technology scope
You can now copy all the JAR files referenced in the jdev-libs.xml file into the JDeveloperLibs directory (remembering to create the proper subdirectory structure). Don’t forget to add the new files to your version control system as well!
The next step is to create an Ant build file for the Model project. To do this, you can use Oracle JDeveloper to create a default build file and then modify the default file to suit your needs. To create the default build file, first ensure that the Model project contains Ant in the list of project technologies. To do this, double-click the Model project to display the project properties, select the Technology Scope category, shuttle Ant to the list of selected technologies, and click OK:
Figure 21 Creating the default Ant build file
Now you can create the default Ant build file by right-clicking the Model project and selecting New. Next, in the New Gallery, select Ant from the General category, select Buildfile from Project, and click OK:
Figure 22 Creating the build file for the Model projectIn the Create Buildfile from Project dialog box, leave all the default options selected and click OK:
Figure 23 Buildfile options
Once you have completed these steps, you will see two new files in the Resources category for the Model project. The build.xml file contains the Ant targets and library definitions, and the build.properties file contains some properties used by the build script. You will now make some small changes to the properties and build files to enable the build to work on a clean machine. The first change is to the build.properties file. There are two properties you can comment out (remove) from the file. First, the oracle.home property refers to JDeveloper installation directory. Because you have set up the library references to be independent of the JDeveloper home directory, you can remove this line from the build.properties file. Similarly, the build.compiler property specifies that Ant should use the Oracle Java compiler to compile the Java files. You can also remove this line from the file, because the clean machine will not have the Oracle Java compiler installed. After you have removed the two unnecessary properties, your build.properties file should look something like this:
Figure 24 Modified build.properties file
Now you can change the build.xml script to replace the library references that are hard-coded to the JDeveloper installation directory with the references you created in the JDeveloperLibs project. To do this, open the build.xml file for the Model project. You should see a series of <path> definitions (11 of them, to be exact) that correspond to the 11 libraries that are referenced by your project. For example, the ADF Model Runtime path looks like this:
Figure 25 ADF Model Runtime <path> element
You should delete all these path definitions, because they all point to the JDeveloper installation directory (be sure to leave the “classpath” path reference). Once you’ve removed the <path> elements corresponding to the libraries, the start of your build.xml file should look like this:
Figure 26 Start of build.xml with <path> elements removed
Now you can add an <import> element to the file to incorporate the jdev-libs.xml file you created earlier. Add the <import> element before the classpath <path> element like this:
Figure 27 Importing jdev-libs.xml
The <import> element will put the jdev-libs.xml file into the build.xml script when the Ant targets are invoked. Finally, you may have noticed that the <path> IDs used in jdev-libs.xml are slightly different from the <path> IDs expected in build.xml; for example, in build.xml, the ADF Model Runtime has a <path> ID of library.ADF.Model.Runtime whereas the <path> ID for that library in jdev-libs.xml is JDeveloperLibs.library.ADF.Model.Runtime. To reconcile these differences, edit all the refids in build.xml to include JDeveloperLibs. at the start, as shown here:
Figure 28 Changing the path IDs in build.xml
That’s all there is to changing the files. Now let’s have a look at the targets that are in build.xml. If you open build.xml and look at the structure window, you should see something like this
Figure 29 build.xml structure
In that structure, you can see that there are five targets— init, all, clean, compile, and copy— and that the all target is the default. If you like, you can look through the build.xml script to see what each of the targets does. Here is a high-level description of each target:
You will also see that certain targets depend on other targets; for example, for Ant to execute the compile target, the output (target) directory for the compiled Java classes must exist; hence, the compile target depends on the init target.
To avoid naming conflicts when building multiple projects in to an application, it’s a good idea to rename all the targets to include the project name as a prefix. For example, instead of a compile target, the Model project should have a model.compile target. To do this, edit the build.xml file and change all the target names to start with “model.” Change the names of the targets in the depends sections as well. Additionally, because classpath is a common name for a path, change the <path> id from classpath to model.classpath (in two places: the <path> id itself and the classpathref element of the <javac> element).
You can now also test the Ant targets from within Oracle JDeveloper. Let’s do this by running the all target. To do this, right-click the build.xml file and select the model.all target from the Run Ant Target submenu:
Figure 30 Running the model.all Ant target
You can verify that the target executed successfully, by looking at the Apache Ant - Log window:
Figure 31 Apache Ant - Log window
Now you can use a similar process to create and modify the Ant build script for the ViewController project. Follow the same steps you did for the Model project:
A few more steps are needed for completing the ViewController project’s build.xml file. The first step is to remove all the pathelement items that correspond to the JDeveloper libraries. You will find these under the top-level <path id="viewcontroller.classpath"> element in the file. Be sure you don’t remove the <pathelement location="../Model/classes"/> item, because it corresponds to the classes from the Model project. When you have done this step, you should have something like this for the viewcontroller.classpath path:
Figure 32 Updated viewcontroller.classpath path
The next step is to add a dependency to the build file so that the Model project is compiled (if it is out-of-date) before the ViewController project is compiled. To do this, modify the depends element in the viewcontroller.compile Ant target so that it depends on the model.compile target. Because this target is defined in the build.xml file for the Model project, you will also need to include that file in the ViewController project’s build.xml file. To include the Model project’s build.xml file, add an “import” directive to the ViewController’s build.xml file like this:
Figure 33 Importing the Model build.xml file
Then modify the viewcontroller.compile target to depend on the model.compile target, like this:
Figure 34 Adding dependency to the viewcontroller.compile target
If you run the Ant viewcontroller.compile target at this point, you’ll see that Ant gets a bit confused and doesn’t compile the files you think it should. The problem is related to the paths in use; because you are running the target from the build.xml file located in the ViewController project directory, all the path references are relative to that directory. The final step to make Ant work with this multiproject setup is to change all the directory references so that they work properly. All path references will need to “jump up” a directory and then “jump back down” to the project directory. For example, regardless of whether you are in the Model directory or the ViewController directory, you can always refer to the Model directory by using the path reference ../Model and to the UserInterface directory by using the reference ../UserInterface.
To fix up all the directory references, you will need to edit the build.properties and build.xml files for both the Model project and the ViewController project. Let’s start with the Model project. First, in the build.properties file, change the name of the output.dir variable to model.output.dir (to avoid a name collision with output.dir for the ViewController project) and change the path reference as shown here:
Figure 35 model.output.dir
Next, add a variable called model.src.dir, like this:
Figure 36 model.src.dir
Do the same thing to the build.properties file for the ViewController project, so that it looks like this:
Figure 37 build.properties for the ViewController project
Now you will need to change the build.xml files so that all the path references are correct and refer to the variables defined in build.properties. There are six items that need to be changed in each file (the examples below show the changes for the Model project build.xml file—you should make similar changes to the ViewController one):
Once you have made the above changes for both the Model and ViewController build files, you should be able to successfully run the viewcontroller.compile target and see the following output:
Figure 38 Ant output for successful viewcontroller.compile
Adding a WAR Target
Now that you are able to compile the entire application, you can create additional Ant targets to create the deployment artifacts (WAR and EAR files) for the application. Because Ant already includes tasks for building such files, it is quite easy to add these targets. The easiest way I have found to create the Ant targets properly is to use Oracle JDeveloper to create the appropriate file (WAR or EAR) and then to unzip the file to have a look at the structure. By doing this, you can ensure that the resulting file will have the correct structure. For example, you can right-click the ViewController project and use the context menu to create a WAR file:
Figure 39 Creating a WAR file
If you then expand the WAR file, using any unzip utility, you will find that the file contains:
Armed with this knowledge, you can create the appropriate target in the build.xml file. To follow the pattern we have used so far, let’s create three additional properties in the ViewController project’s build.properties file for use in the Ant script:
Figure 40 Adding three more properties
Next, update the viewcontroller.init and viewcontroller.clean targets to create this new directory and delete it, respectively:
Figure 41 Updated viewcontroller.init and viewcontroller.clean targets
Next, you may notice that the viewcontroller.copy target does not copy the page definition and related ADF Model configuration files. You can fix that by changing the viewcontroller.copy target to look like this:
Figure 42 Updated viewcontroller.copy target
The final preparation step is to create three Ant “patternset” references to use for copying the public_html directory and the appropriate ADF libraries that belong in the WAR file:
Figure 43 Additional patternsets used for the WAR file
Once you have done the preceding preliminary work, you can create the viewcontroller.war target like this:
Figure 44 The viewcontroller.war target
Running the viewcontroller.war target from within Oracle JDeveloper should generate the appropriate WAR file. Although this article does not show the steps, you can easily apply the same technique to create an EAR target as well.
Now that you have a build.xml file that you can use to build your application, it’s time to try running the build from outside Oracle JDeveloper. Because you have added all the ADF libraries required for compilation to the project, you should be able to check out the application from Subversion on a machine without Oracle JDeveloper installed and build the application (provided you have installed Apache Ant and a suitable JDK on the machine). In the example below, the machine has both Ant and a JDK installed and has environment variables set for Ant_HOME and JAVA_HOME pointing to those installations:
Figure 45 JDK and Ant are installed
Now you can run Ant from the command line to build the WAR file like this:
Figure 46 Building the WAR file from a command prompt
You have now learned how to create a set of Ant build scripts for building an ADF project, either from within Oracle JDeveloper or from a standalone “clean” computer containing only a JDK and Ant installation. You should be ready to review the Ant documentation and add more targets and steps to your build scripts.
You may also want to read in the Oracle documentation about the WebLogic Scripting Tool (wslt), which is a tool that can help you automate deployments to WebLogic servers (as an alternative to the WebLogic Ant tasks).Go to Part 5 | Back to TOC
John Stegeman ( http://stegemanoracle.wordpress.com) is an Oracle ACE director (Oracle Fusion Middleware) and the principal architect in the EMEA region for Cambridge Solutions, a global BPO and IT services firm. He has been working with Oracle products since 1990 and with Oracle JDeveloper since Release 3.