Table of Contents
Custom tasks and task factories can be used by just including their classes in the class path and importing the task (Java) packages in the script. However, if tasks are to be distributed, they should be packaged in a task package.
A task package has a name that should be globally unique. There are no enforced naming
rules, but a good practice is to name a task package similar to Java package,
for instance net.findbugs
for the
Findbugs task package or
org.junit.junit4
for the
JUnit 4 task package.
To use a task package, a build script must enable it before it can use its task. When a task package is enabled, its libraries are added to the script's classpath. (Or added to the classpath of a class loader unique to the task package if the script is run with isolated class loaders.) Enabling a task package also imports a number of Java packages so that class names in those packages don't have to be fully qualified when used by the build script.
In addition to tasks, a task package may also contain Plugin:s. Plugins adds additional functionality to tasks in other task packages or to classes in Schmant itself. Every plugin extension point is identified by a globally unique name. The name should be the fully qualified name of the plugin implementation required.
Plugins are registered in the org.schmant,plugin.PluginRegistry. A task that has a plugin extension point can use it to get all available implementations.
Schmant itself has the following plugin extension points:
Table 3.1. Plugin extension points
Name / required type | Description |
---|---|
org.schmant.project.eclipse.EclipseProjectCreatorPlugin | Try to create an Eclipse Project from the contents of a directory. The first registered plugin that is able to create a Project object from the contents is used. |
org.schmant.project.intellij.IntelliJModuleCreatorPlugin | Try to create an IntelliJ IDEA Project (module) from the contents of a directory. The first registered plugin that is able to create a Project object from the contents is used. |
Several plugins may be registered for each extension point. The first registered plugin has the highest precedence.
Task packages are distributed in Zip files. Just like a Java Jar file, the task package file can be used as-is or unpacked. When running a build script, Schmant uses the task package path to find task packages. It works just like Java's classpath.
A standard task package is a standalone module containing tasks, requiring
nothing from other task packages. An extension task package
is another kind of task package that extends the functionality of another task
package. An example from the Schmant distribution is the
com.tarsec.javadoc.pdfdoclet
task package that
adds an ExtJavadocTaskDecorator for creating
PDF Javadocs to the Javadoc task.
An extension task package is implemented just like a standard task package, except that it has the classes of the task package to extend available to it. If a build script using an extension task package is run with isolated class loaders (a separate class loader for each task package), the extension task package uses the same class loader as the task package that it extends.
Information on which task package that an extension task package extends
is put in the task package manifest file taskpackage.xml
.
See Example 3.2, “PDFDoclet task package manifest” for an example.
This is a schematic overview over the contents of a task package file:
/root directory -- The task package root directory. This directory
| should have the same name as the task package itself,
| for instance net.findbugs
.
+ extlib -- (Optional) Libraries used when running external
| | programs.
| + jar files
+ lib -- Libraries that are included in the script's classpath
| | when the task package is enabled.
| + jar files
+ src -- Source files.
| + doc -- Documentation sources.
| + taskref -- Task reference documentation sources.
| + taskref files -- Task reference documentation files.
| + overview.xml -- Task package overview documentation.
+ taskpackage.xml -- Task package manifest file.
A task can use this directory to store library files that it wants to use but does not want to have on the script's classpath. This can for instance be runtime dependencies for external programs.
All Jar files in this directory are appended to the classpath of the running script when the task package is enabled. This directory contains the task and task factory implementations as well as their runtime dependencies, except for the dependencies which are available by default through Schmant (see the section called “Development environment”).
Task reference documentation files. Described in Chapter 4, Writing task reference documentation.
Overview documentation for the task package. Described in Chapter 4, Writing task reference documentation.
The task package manifest file. It contains meta information about the task package. The task package dtd file, taskpackage-1.1.dtd, has the full documentation of the manifest file format. See below for an example.
This is the net.findbugs
task package's
taskpackage.xml
file:
Example 3.1. Findbugs task package manifest
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE taskpackage SYSTEM "http://www.schmant.org/dtd/taskpackage-1.1.dtd"> <!-- The name of the task package. This should be the same as the task package directory name. --> <taskpackage name="net.findbugs"> <!-- Repeat for each Java package that should be imported automatically in the script. Classes in imported Java packages do not have to be used by their fully qualified names, just like how the import statement in Java files work. --> <javapackage>org.schmant.task.findbugs</javapackage> </taskpackage>
This is the taskpackage.xml
file for
the com.tarsec.javadoc.pdfdoclet
extension
task package:
Example 3.2. PDFDoclet task package manifest
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE taskpackage SYSTEM "http://www.schmant.org/dtd/taskpackage-1.1.dtd"> <!-- The classloader attribute tells the task package manager that this task package should be loaded in the same class loader as the org.schmant.task.base task package, making this an extension task package. --> <taskpackage name="com.tarsec.javadoc.pdfdoclet" classloader="org.schmant.task.base"> <javapackage>org.schmant.task.jdk.javadoc.pdfdoclet.ext</javapackage> </taskpackage>
Below is an image showing the layout of the org.at4j
task package file:
![]() |
This image shows the layout of the org.junit.junit4
task package file:
![]() |
The JUnit4TF task runs JUnit in a separate Java process. The
extlib
catalog of the task package contains
Jar files that are necessary for running JUnit4. The task runs a class in the
launcher Jar that sets up the environment before running the unit tests.
Task package management in Schmant is performed by the
TaskPackageManager class. It contains the
getTaskPackage
method that a
task can use to access its TaskPackage.
The example below shows how a task launches a separate Java process with a
classpath consisting of the Jar files in its extlib
directory.
Example 3.3. Launching a process using extlib files
// First get the java command to use // This method invocation gets a "java" or "java.exe" command from: // a) The Java installation referenced by the JAVA_HOME environment variable, if // that is set. // b) The directories of the PATH environment variable, if that is set. File javaCmd = JdkUtil.getJdkExecutable("java", "", "exe"); // Create a classpath string from all Jar files found in the extlib directory. // Our task package. // The TaskPackageManager class has a static InheritableThreadLocal variable // containing the task package manager. TaskPackage tp = TaskPackageManager. get(). getTaskPackage("org.my.task.package"); // Our task package's root directory Directory tpRoot = tp.getRootDirectory(); Collection<EFile> jarEFiles = Directories.getAllFilesMatching( Directories.getDirectory(tpRoot, "extlib"), new Glob("*.jar")); // Make all Jar files File-backed. This is necessary since they are to be used // by another process. // The makeFileBacked method copies the file to a temporary directory if it is // not already File backed. The copy is deleted when the build script // terminates. StringBuilder classpath = new StringBuilder(); for (EFile jarEFile : jarEFiles) { classpath.append( ECFileResolvableUtil.getFileObject( tp.makeFileBacked(jarEFile)).getAbsolutePath()); classpath.append(File.pathSeparatorChar); } // Create an argument list for the process. "true" means that added strings // containing spaces will be quoted. ArgumentList al = new ArgumentList(true); // The program to run al.add(javaCmd.getAbsolutePath()); // Add the classpath al.add("-cp").add(classpath.toString()); // Add the class to run al.add("org.mytask.MyTaskLauncher"); // Save the output from the process to a string SaveToStringProcessOutputStrategy sos = new SaveToStringProcessOutputStrategy(); // Create a configuration object for the process that we will launch. ProcessSettings settings = new ProcessSettings(). setStdoutStrategy(sos). setStderrStrategy(sos). setArgumentList(al); // Run the program and wait until it terminates. ProcessResult result = ProcessSupport.execAndWait(settings); // Deal with the result...