19.5. Basic Java Rules Functionality

Virtually all Java-based build items will set the abuild.rules parameter to the value 'java' or to a list that includes that value. The java rules are quite flexible and give you considerable leeway on how things should work. In this section, we will describe only the most basic use of the java rules. When using the rules in this way, you control everything that you are going to build by setting a few simple parameters, and you set up your build item's directory structure according to abuild's conventions. In later sections, we will discuss other more general ways to customize or override abuild's default behavior.

The java rules perform a variety of functions, most of which must be enabled by setting one or more parameters. With appropriate parameters, the java rules can perform the following tasks:

We will discuss each of these briefly in turn. In the discussions below, we describe the default behavior of each of these capabilities. Keep in mind that virtually every aspect of them, including all the default paths and file locations, can be customized. We will be describing how to customize and override the default behavior in later sections.

The sections below include prose descriptions of the default locations of files. To see all this presented in one place, please refer to Section 19.3, “Directory Structure for Java Builds”.

Note

At this time, this manual does not include any examples of creating high-level archives or signed JAR files. To see examples, you may refer to abuild's test suite, which fully exercises all available functionality. The most comprehensive example that uses the Groovy framework is the code generator example (Section 22.3, “Code Generator Example for Groovy”), which also illustrates a few other aspects of the Groovy framework.

19.5.1. Compiling Java Source Code

By default, Java compilation involves compiling with javac every .java file found in src/java and writing the output files into abuild-java/classes. In addition to src/java, abuild also looks for Java sources in abuild-java/src/java, which is where automatic code generators are expected to put generated Java sources. You may add additional directories in which abuild will search for .java files to compile by adding the names of the directories to the java.dir.extraSrc parameter.

By default, abuild invokes javac with debug and deprecation turned on and with the additional arguments -Xlint and -Xlint:-path.

You may customize Java compilation in several ways including changing the locations in which abuild finds source files or writes output files, changing the compile-time classpath, or changing the attributes passed to the ant javac task. For details, see Section 19.6, “Advanced Customization of Java Rules”.

19.5.2. Building Basic Jar Files

If the java.jarName parameter is set, abuild will create a JAR file with the indicated name. For an example of this, see Section 3.6, “Building a Java Library”. By default, you are expected to put any hand-created files other than class files in src/resources. Build items that automatically generate additional files to include in the JAR file should place those files in abuild-java/src/resources. All files in src/resources, abuild-java/classes, and abuild-java/src/resources, subject to the usual ant exclusions (version control directories, editor backup files, etc.), will be included in the JAR file. You may specify additional directories whose contents should be included by appending the names of the directories to the parameter java.dir.extraResources. Additionally, any files in the src/conf/META-INF and abuild-java/src/conf/META-INF directories will be included in the META-INF directory of the JAR file. You can specify additional META-INF directories by setting the parameter java.dir.extraMetainf.

As always, all default path names may be overridden. It is also possible to provide additional arguments to the jar task, to set additional keys in the manifest, and to create multiple JAR targets. For details, see Section 19.6, “Advanced Customization of Java Rules”.

19.5.3. Wrapper Scripts

If the java.wrapperName and java.mainClass parameters are set in addition to the java.jarName parameter, abuild will generate a simple wrapper script that will invoke java on the JAR file using the specified main class and with the calculated or specified runtime class path. For an example of this, see Section 3.7, “Building a Java Program”. The wrapper script is placed directly in the abuild output directory.

It is possible to have abuild generate multiple wrapper scripts that invoke the application using different main classes. For details, see Section 19.6, “Advanced Customization of Java Rules”. For an example, see (Section 22.4, “Multiple Wrapper Scripts”).

19.5.4. Testing with JUnit

If you have implemented JUnit tests suites, you can run them using either the test or batchtest nested tasks of the junit ant task. If you have a single test suite that you want to run, you can set the java.junitTestsuite parameter to the name of the class that implements the test suite. If you want to run multiple test suites using the batchtest task, you can set the parameter java.junitBatchIncludes and optionally also java.junitBatchExcludes to patterns that will be matched against the classes in abuild-java/classes. You may provide values for all of these if you wish, in which case abuild will run all test specified. Abuild will write XML test output to the abuild-java/junit directory and, whether the tests pass or fail, will also generate an HTML report in abuild-java/junit/html. By default, if the test fails, the “build” of the test target for the item will fail. This and other behavior can be overridden; see Section 19.6, “Advanced Customization of Java Rules”.

19.5.5. JAR Signing

When creating WAR files, EAR files, or other high-level archives that may contain other JAR files, JAR signing is available by default. In order for abuild to sign any JAR files, you must set the java.sign.alias and java.sign.storepass parameters, which correspond to the mandatory alias and storepass attributes of the signjar ant task. You will usually also want to set the java.sign.keystore and java.sign.keypass parameters, corresponding to the keystore and keypass attributes to the signjar task. In most cases, you will set these parameters in one place. This place can be either a plugin or a single build item that all build items that sign JARs will depend on. It's okay to put these in a plugin if all JARs in your project will be signed in the same way.

Setting the above parameters is necessary in order to have any JARs be signed, but it is not sufficient; you must also indicate which JARs are to be signed, which you will generally do in the higher-level archive build item that actually does the signing. The usual way to do this is to set the java.jarsToSign parameter to a list of paths to JAR files that should be signed. Although these JARs are typically created by other build items, you should never have your build item's Abuild.groovy file refer to JARs created by other build items directly by path even using a relative path. Instead, you should always have the build item that creates the JAR file provide the path to the JAR file with an abuild interface variable, and you should add that to the java.jarsToSign parameter by calling abuild.resolve on the interface variable. This way, your build item will continue to work even if the one that provides the JAR file moves or is resolved in a backing area.

It is also possible to arrange for JARs to be signed by having them appear in the abuild-java/signed-jars directory. This case can be useful if the same build item that is signing the JAR files is also creating them, either because it is actually compiling Java code itself or because it is repackaging other JAR files. However, if you find yourself writing code that just copies other JAR files into abuild-java/signed-jars, then you should probably be assigning the paths to the those JAR files to the java.jarsToSign parameter instead.

Whichever method you use, or even if you use both methods together, the signed JARs will be placed in the abuild-java/signed-jars directory. Since abuild will sign unsigned JARs in that directory, abuild invokes the signjar task with lazy JAR signing by default. If it didn't, then every time you invoked abuild, it would re-sign all JAR files in that directory even if they were already signed. Lazy JAR signing allows abuild to avoid repeatedly signing the same JARs, which makes it possible to have abuild do nothing if invoked on an area that is fully built. (In other words, this allows builds to be idempotent.) If you have a reason not to use lazy JAR signing, it is possible to disable it and override the JAR signing behavior to avoid re-signing the JARs, but this should seldom if ever be required. For details on the full range of customization opportunities available, please see Section 19.6, “Advanced Customization of Java Rules”.

19.5.6. WAR Files

If you wish to build a WAR file, you must set the java.warname parameter to the name of the WAR file and the java.webxml parameter to the path to the web.xml file for that WAR. The java.webxml parameter may be set to a relative path, in which case it is resolved relative to the build item's top-level directory (the directory containing Abuild.groovy). By default, abuild will package into WEB-INF/classes the contents of src/resources, abuild-java/classes, abuild-java/src/resources and any additional directories named in java.dir.extraResources. It will also package at the root of the WAR file any files in src/web/content, abuild-java/src/web/content, and any directories named in java.dir.extraWebContent. It will populate META-INF exactly as it does for JAR files. The WEB-INF directory will be populated from src/web/WEB-INF, abuild-java/src/web/WEB-INF, and any directories named in java.dir.extraWebinf. For additional information about creating WAR files, please see Section 19.6, “Advanced Customization of Java Rules”.

19.5.7. High Level Archives

Abuild includes default rules for creation of high-level archives, in addition to WAR and EAR files, that may contain other JAR files, including signed JARs. To create a JAR-like high-level archive, set the parameter java.highLevelArchiveName to the name of the archive to be created. By default, the archive is populated exactly as a regular JAR file is, including pulling files from all the same places. In addition, by default, high-level archives contain all archives in the package class path at the root of the archive. The list of additional files to package in the high-level archive can be customized along with all the things that can be customized for regular JAR files. For details, see Section 19.6, “Advanced Customization of Java Rules”.

19.5.8. EAR Files

To create an EAR file, you must set the java.earName and java.appxml parameters. EAR files are populated with the same files from the same places as high-level JAR-like archives, including packaging all items from the package class path at the root of the EAR file, except that they to not contain files from abuild-java/classes. For additional information about customizing creation of EAR files, see Section 19.6, “Advanced Customization of Java Rules”.