Chapter 1. Getting Started

This section describes how to install quokka and use it to create a simple project the builds a .jar file from java sources.

1.1. Installation

Download the latest distribution from the Quokka download page.

  • Unzip the contents to any directory, from now on referred to as installDir

  • Add installDir/bin to your PATH environmental variable

  • Verify the installation. From the command prompt, enter:

    $ quokka -version
    Quokka version 0.3                        
  • Ensure that output matches the version you installed. When you use quokka for the first time, it will create a preferences directory and seed it with some default settings. The location is ${user.home}/.quokka on all platforms apart from OS X where it is ~/Library/Preferences/Quokka.

1.1.1. Proxy Configuration

Quokka requires network access to initially download plugins, archetypes and dependencies from its global repository. As such, if you connect via a proxy server, you must configure Quokka appropriately. There are several options:

  • For JDKs >= 1.5, you can use the autoproxy option, by setting the QUOKKA_ARGS environment variable to -autoproxy. This should use your OS's settings automatically, however it is known to have issues on some platforms.

  • Alternatively, you can manually set system properties via the QUOKKA_OPTS environment variable. e.g. QUOKKA_OPTS="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080".

  • Finally, if your proxy requires authentication you can set the following properties in the quokka.properties file in your preferences directory.

    q.proxy.host

    The proxy host. A value of "" disables http proxying.

    q.proxy.port

    The proxy port number. Defaults to 80

    q.proxy.nonProxyHosts

    A list of hosts to bypass the proxy on. These should be separated with the vertical bar character '|'. e.g. fozbot.corp.sun.com|*.eng.sun.com

    q.proxy.user

    The proxy user. Probably requires a password to accompany this setting. Defaults to ""

    q.proxy.password

    The password for the proxy. Used only if the user is set

    q.proxy.socksHost

    The name of a Socks server. A value of "" disables Socks proxying.

    q.proxy.socksPort

    The port of a Socks server. Defaults to 1080

For further information, see Ant's Proxy Configuration documentation. The q.proxy.* properties correspond to the Ant setproxy task attributes.

1.2. A Sample Project

1.2.1. Creating a project using archetypes

Quokka provides a mechanism for creating a new project based on an template, or archetype . Various archetypes are pre-defined, or you are free to define your own. In this case, we will use the quokka.archetype.jar archetype to create a project that builds a .jar file from Java sources. This archetype includes unit testing via jUnit and code coverage reporting via Cobertura.

Go to the command console and change to (or create) an empty directory for new project. Enter the following command:

$ quokka archetype -Darchetype=quokka.archetype.jar

You will then be prompted to enter several properties that define the group, name and version of the new project.

archetype:
Creating project based on artifact: quokka.archetype.jar:jar:archetype:0.3
    Properties can be used to configure this archetype. Those ending in * are mandatory.
    Choices are shown in brackets, defaults in square brackets.

[archetype] Enter group*: e.g. mycompany.myproject
mycompany.myproject
[archetype] Enter name*: e.g. myproject
myproject
[archetype] Enter version*: [0.1-ss]

The following properties have been set:
    group -> mycompany.myproject
    name -> myproject
    version -> 0.1-ss
[archetype] Do you want to continue? ([y], n)

Extracting the following archetype to /qtest:
    build-quokka.xml
    build.xml
    src/
        main/
            java/
                sample/
                    App.java
            resources/
        test/
            java/
                sample/
                    AppTest.java
            resources/

    [unjar] Expanding: /Users/andrew/Library/Preferences/Quokka/releases/quokka/archetype\
                /jar/0.3/jar_archetype.jar into /qtest
     [copy] Copying 4 files to /qtest
     [copy] Copied 9 empty directories to 2 empty directories under /qtest
   [delete] Deleting directory /qtest/META-INF

BUILD SUCCESSFUL

For now, it is not that important to understand how the archetype command works, other than it has created a new project based on the specified archetype in the current directory. See Archetypes for more information on using and defining archetypes.

If you examine the console output above, you'll see the structure of the project created. It consists of:

  • build-quokka.xml: This is the key project file. It defines what plugins are used by the project and therefore what targets are available

  • build.xml (optional): A standard Ant built file that is imported into the project, allowing custom targets. See Extending via Ant for more information.

  • src/: The default root directory for all source components.

  • src/main/: The default root for application source files. In this case it contains App.java under the sample package and a placeholder for resources

  • src/test/: The default root for test cases and associated resources.

1.2.2. Building the project

Now that we have our project, let's build a .jar file from it. From the console, enter the following:

$ quokka package
Buildfile: build-quokka.xml

stdlifecycle:generate-resources:
   [plugin] Generated artifact properties to /qtest/target/compile/META-INF/quokka\
                /mycompany.myproject_myproject_jar_artifacts.properties
    [mkdir] Created dir: /qtest/target/compile/META-INF/quokka
    [mkdir] Created dir: /qtest/target/compile/META-INF/quokka/mycompany.myproject\
                             _myproject_jar_0.1-ss
   [plugin] Generated repository file for mycompany.myproject:myproject:jar:0.1-ss:\ 
               /qtest/target/compile/META-INF/quokka\
               /mycompany.myproject_myproject_jar_0.1-ss/repository.xml

javac:compile:
    [javac] Compiling 1 source file to /qtest/target/compile

cobertura:instrument:
[cobertura-instrument] Cobertura 1.8 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
[cobertura-instrument] Instrumenting 1 file to /qtest/target/instrumented-compile
[cobertura-instrument] Cobertura: Saved information on 1 classes.
[cobertura-instrument] Instrument time: 217ms

javac:test-compile:
    [mkdir] Created dir: /qtest/target/test-compile
    [javac] Compiling 1 source file to /qtest/target/test-compile
    [javac] Since fork is false, ignoring memoryMaximumSize setting.

after-compile-before-test:
     [echo] Hello from "after-compile-before-test"

junit:test:
    [mkdir] Created dir: /qtest/target/test/junit
    [junit] Cobertura: Loaded information on 1 classes.
    [junit] Cobertura: Saved information on 1 classes.
    [junit] Test sample.AppTest FAILED

stdlifecycle:package:
    [mkdir] Created dir: /qtest/target/package
   [plugin] Generated repository file for mycompany.myproject:myproject:jar:0.1-ss: 
            /qtest/target/package/mycompany.myproject_myproject_jar_0.1-ss_repository.xml

jar:jar:
    [jar] Building jar: /qtest/target/package/mycompany.myproject_myproject_jar_0.1-ss.jar

BUILD SUCCESSFUL  

Congratulations! You now have a .jar file in your target/package directory ready for use. Looking at the console output, you can see that the build generated some resources (more on this later), compiled the source code, instrumented the code, copied some resources and packaged the classes and resources into a .jar file.

So what happened? Looking again at the output, you will notice a number of headings, from stdlifecycle:generate-resources to jar:jar. Each one of these banners represents a target, and the output below each target is generated by the tasks that make up the target. When you specified the package target, it automatically included its dependent targets, including those shown above.

Where's the package target itself? By default, quokka only shows targets when there is some console output relating to the target. This reduces a lot of clutter on the console as typical quokka projects consist of many targets, only some of which active in a particular build.

Try running the package target again. From the console:

$ quokka package
Buildfile: build-quokka.xml

after-compile-before-test:
     [echo] Hello from "after-compile-before-test"

junit:test:
    [junit] Cobertura: Loaded information on 1 classes.
    [junit] Cobertura: Saved information on 1 classes.
    [junit] Test sample.AppTest FAILED

BUILD SUCCESSFUL                    

Where's the rest of the output? Quokka tries to be very strict about what and when it logs to the console. At the default level of logging, it only shows events that result in a change to the build target. As the source files have not changed from the last build, quokka makes no changes to the build target and there is no output logged from compilation and packaging. Only the output from the test target and the sample after-compile-before-test targets are shown.

So how can you tell if it's doing anything? The -v (verbose) command line option enables verbose logging, giving detailed build information. Try it. From the console:

$ quokka package -v
...
javac:compile:
   [plugin] Executing 'javac:compile' from plugin 'quokka.plugin.javac:javac:plugin:0.3'
    [mkdir] Skipping /qtest/target/compile because it already exists.
    [javac] sample/App.java omitted as\
               /qtest/target/compile/sample/App.class is up to date.
...
BUILD SUCCESSFUL                    

Much of the output above has been omitted, but the sample shows the kind of information available with verbose logging enabled. Enabling verbose logging as you are learning quokka can provide a valuable insight into how quokka works.

The targets available depends entirely on what plugins have been specified for the project in the build-quokka.xml file. For now, we will stick to those plugins defined by the archetype when the project was created. To list them, type the following from the console:

$ quokka -projecthelp
Buildfile: build-quokka.xml
Main targets:

 after-compile-before-test  This is an ordinary ANT target that will run after compile...
 clean                      Cleans the project, deleting all generated files
 cobertura                  Generates a code coverage report
 compile                    Compile the source code of the project
 console                    Allows targets to be entered interactively...
 help                       Generates a detailed HTML help report for the current project
 install                    Install the package into the local repository...
 junitreport                Generates a jUnit HTML report containing test results
 list                       Lists the artifacts available in the repository
 list-plugins               Lists available plugins including analysis of compatibility...
 package                    Take the compiled code and package it...
 process-resources          Copy and process the resources...
 reports                    Generates all registered reports...
 resolve-dependencies       Forces all project dependencies to be resolved...
 stand-alone                This is an ordinary ANT target
 test                       Run tests using a suitable unit testing framework...
 test-compile               Compile the test source code...
 update-snapshots           Updates snapshots to the latest version available...
Default target: install                 

The output shows the available main targets. These are targets that actually perform some function in the current project. There are many other targets that are generally place holders for adding additional functionality not used by this particular project. If you really want to see all of the targets, use the -v (verbose) flag.

Multiple targets may be specified when launching quokka. For example, quokka clean package would delete all generated output before rebuilding the project.

The above list is fairly self explanatory. What isn't obvious is the dependencies between targets and how to configure them. Detailed help can be found via the help plugin (which is included in the archetype we are using). It includes a help target by default that generates a very detailed breakdown of all project targets and dependencies. Try it now:

$ quokka help

This should generate the report and launch it in your default browser automatically. Have a quick overview of the report now. Later sections will describe its contents in more detail.

1.2.3. Understanding how quokka works

Before getting into customising and extending our project, we'll go into some detail about how the package target we entered is executed. The following occurs when you type quokka package at the console:

  • Has a build file been specified? No, so defaults to build-quokka.xml in the current directory

  • Merges properties from the following sources if they exist (first is highest precedence if there is a conflict):

    • Properties specified on the command line with -D

    • Properties specified in quokka.properties from the Quokka preferences directory

    • Project properties (build-quokka.properties or property elements within build-quokka.xml)

  • Initialises the repository based on the above properties. The repository is one or more locations where plugins, jars and other resources can be retrieved. See below for more information, or Repositories for detailed information.

  • Parses the project file, in this case build-quokka.xml

    • Discovers all plugins used by the project

    • Adds the targets declared by the plugins to the project

    • Applies any aliases to the targets (aliases are usually shorthand forms of common targets)

    • Adds any default properties defined by the plugins to the project

    • Adds any default paths defined by the plugins to the project

  • Checks if there is an Ant extension file available (build.xml). If so, imports the targets declared into the project.

The key point from the above is that targets are defined by plugins which are declared in build-quokka.xml. So let's examine the project file in detail now. Here's our project file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project PUBLIC "quokka.ws/dtd/project-0.2" 
                         "http://quokka.ws/dtd/project-0.2.dtd">

<project default-target="install">
    <artifacts group="mycompany.myproject" version="0.1-ss">
        <!-- Defines a single artifact and exports the runtime path... -->
        <artifact name="myproject" paths="runtime"/>
    </artifacts>

    <!-- Ensures that the quokka version is >= 0.3 and < 0.4 -->
    <bootstrap core="[0.3,0.4)"/>

    <dependency-set>
        <profile id="skiptest" description="Skips tests..."/>

        <!-- ================================================================== -->
        <!-- The entries below add dependencies to project paths                -->
        <!-- ================================================================== -->
        <dependency group="junit" version="3.8.2" paths="test-compile"/>
        <dependency group="apache.log4j" version="1.2.15" paths="compile, runtime"/>

        <!-- ================================================================== -->
        <!-- The entries below add a number of plugins that introduce targets   -->
        <!-- to the project                                                     -->
        <!-- ================================================================== -->

        <!-- quokka.depset.jar includes the plugins necessary to process 
             resources, compile & package a .jar file -->
        <dependency-set group="quokka.depset.jar" version="0.3"/>

        <!-- Runs all developer reports and produces an HTML summary -->
        <plugin group="quokka.plugin.devreport" version="0.3"/>

        <!-- Adds jUnit support for running unit and integration tests -->
        <plugin group="quokka.plugin.junit" version="0.3" profiles="!skiptest"/>
        <plugin group="quokka.plugin.junitreport" version="0.3" profiles="!skiptest"/>

        <!-- Adds Cobertura support for producing code coverage reports -->
        <plugin group="quokka.plugin.cobertura" version="0.3" profiles="!skiptest"/>

        <!-- Adds the help plugin -->
        <plugin group="quokka.plugin.help" version="0.3"/>
        <plugin group="quokka.plugin.repository" version="0.1"/>

        <!-- ================================================================== -->
        <!-- Uncomment the following set of properties to store release         -->
        <!-- dependencies with the project in the 'lib' directory.              -->
        <!-- ================================================================== -->
        <!--
        <property name="q.repo.project.url" value="delegate:core,bundle,local,shared"/>
        <property name="q.repo.bundle.url" value="bundle:quokka.bundle.extensions:\
                        2008.1;snapshots=true;repository=shared"/>
        <property name="q.repo.local.url" value="file:${basedir}/lib;hierarchical=\
                        false;parents=shared"/>
        -->
    </dependency-set>
</project>

Notes on the elements:

DOCTYPE

The DOC TYPE is mandatory for quokka projects and is used for both validation of the XML itself and that the project version is supported by the currently executing quokka version.

artitfacts/artifact

Defines the artifacts produced by this project. Artifacts are files that will be installed into a repository for re-use by other projects. An artifact is usually a deployable unit such as a jar or war file

dependency-set

Each project has a single dependency set. The dependency set may contain dependencies, plugins and nested dependency sets

profile

Allows parts of the project to be enabled or disabled. In the above example, testing related targets can be disabled using -Dprofiles=skiptest on the command line.

dependency

Defines a dependency on an external artifact from the repository. Dependencies can be assigned to one or more paths. In this case we've included jUnit for testing and log4j as a compilation and runtime dependency.

plugin

Declares a plugin for the project. Plugins usually import targets by default. However, the defaults can be overridden with specific targets

In our sample project above, we see that it includes the quokka.depset.jar dependency set. This is a globally available dependency set that includes a number of plugins to build a jar file. If you were to extract the definition out of the dependency set, it looks like this:

<dependency-set>
    <plugin group="quokka.plugin.lifecycle" version="?"/>
    <plugin group="quokka.plugin.standard-lifecycle" version="?"/>
    <plugin group="quokka.plugin.resources" version="?"/>
    <plugin group="quokka.plugin.javac" version="?"/>
    <plugin group="quokka.plugin.jar" version="?"/>
</dependency-set>

In fact, you could replace the dependency-set entry in our project file with this definition and the project would perform exactly the same way. Later, you will learn additional capabilities of dependency sets and how they are the cornerstone of reusing build configurations amongst projects.

Each of the plugins above defines one or more targets. Some of the targets depend on one another. For example, the quokka.plugin.lifecycle defines a project life cycle for java projects, including a set of abstract targets such as compile, test-compile, test and package (and the dependencies between them). quokka.plugin.javac provides an implementation for the compile and test-compile targets. quokka.plugin.jar provides and implementation for the package target.

You can consult the documention for individual plugins for detailed information, or use the help target to provide an overview of the targets and interdependencies for your project. (Plugin help can be accessed via the project help report).

Now if you go back and re-examine the output from quokka package -v above you should have an understanding of where the targets came from and match them to the plugins declared within quokka.depset.jar.

1.2.4. Adding a dependency

A dependency in quokka is a reference to another artifact in the repository . Dependencies are commonly grouped together into paths . In our example, we've added the log4j library to our project to support decent logging as shown below:

<project>
    ...
    <dependency-set>
        ...
        <dependency group="apache.log4j" version="1.2.15" paths="compile, runtime"/>
        ...
    </dependency-set>
</project>                    

In the highlighted line above, group and version are enough to fully specify the dependency (name will default to log4j and type defaults to jar). The paths declaration essentially adds the log4j dependency to the compile and runtime paths. The paths themselves are actually defined by the Lifecycle Plugin.

There is nothing special about the lifecycle plugin in this regard. Any plugin can define paths for use in a project, or you can define your own paths within the project itself. In this case, the compile path is added to the class path when compiling java sources and the runtime path indicates that log4j is required at runtime when using the artifact generated by our project.

This raises the question of what happens when the dependency you add has its own dependencies (this is often referred to as transitive dependencies). Quokka fully supports transitive dependencies, giving fine control over exactly which transitive dependencies are included in a path using path specifications. In fact, the paths declaration above is a shorthand notation for path specifications. In this case, the default behaviour of the compile path is to just add the dependency declared, excluding transitive dependencies. However, transitive dependencies will be added to the runtime path. See Path Specifications and the Lifecycle Plugin for detailed information.

To find out what artifacts are available in the repository, you can use the repository plugin (already included) to list them.

$ quokka repo:list

There are various listing formats and options, although it's often simplest to just grep the output if searching. See the Repository Plugin for more information/

1.2.5. Adding a plugin

There are many plugins available for quokka, covering diverse functionality including doc book processing, version control management, unit testing and code analysis. In our example, we've added the help plugin as shown below:

<project>
    ...
    <dependency-set>
        ...
        <plugin group="quokka.plugin.help" version="0.3"/>
    </dependency-set>
</project>                   

Most plugins will automatically add targets to the project by default. In the case of the help plugin, it adds a target to generate the report, aliased as help.

For more information on plugins, see Plugins. For a list of available plugins, see available plugins. Note that plugins are all separate mini-projects in their own right and have their own release cycles and documentation.

With quokka you have to be explict regarding the version of plugin that you are going to use. This raises the problem of determining what plugins are available and of those which are compatible with your current version of quokka. To answer these questions, use the built-in list-plugins target.

$ quokka list-plugins

Available Plugins
=================
quokka.plugin.cobertura:           0.3 
    Quokka Cobertura plugin: performs code coverage analysis ...

quokka.plugin.devreport:           0.3 
    Quokka Developer Reports plugin: co-ordinates developer reports ...

quokka.plugin.fop:                 0.3 
    Quokka FOP (Formatting Objects Processor) plugin: transform FO XML ...

quokka.plugin.help:                0.3 
    Quokka Help plugin: supports viewing and generating help for projects ...

...

By default, it will list the latest version of all plugins available that are compatible with your quokka version or that can be coerced into being compatible using overrides.

If multiple versions are shown, select the version that does not have a trailing * character. You can also display information about a particular plugin, using the plugin option, and detailed information about any conflicts using the verbose option. e.g.

$ quokka list-plugins -Dplugin=quokka.plugin.help -Dverbose=true

Available Plugins
=================
quokka.plugin.help:                
    Quokka Help plugin: supports viewing and generating help for projects  ...
    0.3
...

Once you've added the help plugin to your project, you can also use it to view the help for a given extension or target. e.g. the following will display the XML plugin help in the browser (the format or the id is group:name:type:version).

$ quokka help -Did=quokka.plugin.xml:xml:plugin:0.3

Or, to display help for the repository list target, you can use:

$ quokka help -Dtarget=repo:list

1.2.6. Repositories and installation

Repositories are stores of artifacts and information about the dependencies between artifacts. Artifacts include jar files, quokka plugins, dependency sets, resource bundles and more. Indeed, our sample project generates a jar artifact. If we wished to share that artifact so it can be used by other projects, we need to install it into a repository. Before installing our artifact, we'll go through an overview of how repositories are resolved by quokka and what the defaults are.

On startup quokka will look for a project repository. If that doesn't exist it will use the shared repository. The locations and types of project and shared are is defined via properties. Project repositories are local to a project and should only be defined in properties local to a particular project. The shared repository is usually defined in quokka.properties in the user's preferences directory and is available to all projects. The following is a slightly simplified version of the default properties:

# Root shared repository that delegates to core, snapshot and release
q.repo.shared.url=delegate:core,snapshot,release

# Snapshot: Local snapshots
q.repo.snapshot.url=file:${q.preferencesDir}/snapshots;snapshots=true

# Release: Local cache of the global repository where any local releases are installed
q.repo.release.url=file:${q.preferencesDir}/releases;parents=quokka

# Global: the global quokka repository
q.repo.quokka.url=url:http://quokka.ws/repository/0.2

The definition above results in snapshots (versions of artifacts under development) being stored in snapshots within the preferences directory, and releases within the releases directory.Additionally, if releases are not found locally, they will be attempted to be downloaded from http://quokka.ws/repository automatically. See Repositories for more information.

The structure outlined above it just the defaults. Quokka can be configured to support any of the following scenarios:

  • All project dependencies are stored in version control with the project

  • All project dependencies are retrieved from the shared repository

  • Dependencies available in the shared repository are resolved from there, with only the subset not available stored with the project

  • A repository may be configured to only store artifacts that belong to a certain group. e.g. a plugin repository that only contains artifacts that start with quokka.plugin

If you are using quokka for your own development, it is strongly recommended you override the default repository configurations and at the very least have a corporate-wide repository under version control. See Repositories for more information on repositories, in particular Release Configurations for more information on configuring release repositories. Also note, quokka has been specifically designed to handle custom repositories. See Implementing a Repository for more information.

Now that we have an understanding of repositories, let's install the jar file artifact from our project to the repository.

$ quokka install
Buildfile: build-quokka.xml
...

stdlifecycle:install:
Installing 'mycompany.myproject:myproject:jar:0.1-ss' into repository 'snapshot' 
    at ~/Library/Preferences/Quokka/snapshots/mycompany/myproject/0.1-ss


BUILD SUCCESSFUL                    

Congratulations, your jar file should now be installed in your snapshot repository. It is now available for other projects to include as a dependency.

So that's it? Not quite. Repositories also store information about dependencies between artifacts. Remember that our project added log4j as a dependency. We want to indicate to users of our jar file that they must include log4j in their class path at runtime, or our jar file will not function. To do this, we export a path to the repository along with the artifact. This is done by a declaration in the project file:

<project>
    <artifacts group="mycompany.myproject" version="0.1-ss">
        <artifact name="myproject" paths="runtime"/>
    </artifacts>
    <dependency-set>
        ...
        <dependency group="apache.log4j" version="1.2.15" paths="compile, runtime"/>
    </dependency-set>
</project>                    

The paths attribute within the artifacts element declares that the runtime path will be exported to the repository along with the myproject artifact. The paths attribute within the dependency element adds log4j to the runtime path. Where did the runtime path come from? Like the compile path earlier, the runtime path is defined within the life cycle plugin. By default, the dependency will be considered mandatory and any mandatory transitive dependencies will also be included in the path. This can be overridden by configuring a path specification. See Path Specifications for more information.

1.2.7. Configuring the project and plugins

The project and plugins are configured using properties and build resources .

The location of properties was described earlier. The format of properties is essentially standard java properties with a few extensions to allow references to other properties, aliases and bulk copying from one prefix to another. See Properties for more information.

Below are a few important project properties

q.project.java.source

Defines the java source level for the project. Values may be 1.3 to 1.6. This value is used by default by all plugins that are aware of the source level, such as javac and javadoc.

q.project.java.target

Defines the java target level. Values may be 1.2 to 1.6. This applies in a similar fashion to the source level above.

q.project.forkMaxMemory

Defines the default maximum heap size for forked java processes, such as forked jUnit tests. Defaults to 1024m.

Applying the above to our project, we can set the source and target levels to 1.4. To do this, the following lines are added to the project's dependency set:

<property name="q.project.java.source" value="1.4"/>
<property name="q.project.java.target" value="1.4"/>                   

You can now rebuild the project with quokka clean package to recompile all classes for 1.4 compatibility.

Plugins generally add default targets to your project and are configured to reasonable default settings. However, the default settings can usually be overridden by setting properties and build resources. See the specific plugin help for configuration options.

Build resources are a hierarchy of files used for configuration. They are generally used by plugins when specifying configuration information that would be tedious or error prone using properties. For example, the Jalopy plugin uses a large xml file to specify the rules it uses to format source code. Instead of attempting to translate jalopy conventions into properties, the plugin includes it as a build resource with a key of jalopy-style.xml. However, the bundled configuration file in the plugin we be very unlikely to contain the rules that you want for you own project. So how do you override it?

Each project has a build resources directory that defaults to build/resources. Placing files under this directory will override build resources defined in plugins. So in our example above, creating your own configuration file and placing it in build/resources/jalopy-style.xml will enable your own customised settings. See Build Resources for more information.

1.2.8. Extending the project with Ant

Plugins are great, but what about those little one-off tasks specific to your project? As quokka is built on top of Ant, it is natural to use Ant for extensions and scripts. Quokka automatically looks for a build.xml file in the same directory as the build-quokka.xml file. If it exists the file is imported into the project using the same mechanism as ant's import task.

In fact, if you look at build.xml in our sample project, you will see there are already 2 targets defined using this mechanism. From build.xml:

<project name="mygroup.myname.ext">
    <target name="stand-alone" description="This is an ordinary Ant target">
        <echo>Hello from "stand-alone"</echo>
    </target>

    <target name="after-compile-before-test"
            description="This is an ordinary Ant target that will run after compile,
                         but before test"
            depends="compile">
        <dependency-of targets="lifecycle:pre-test"/>

        <echo>Hello from "after-compile-before-test"</echo>
    </target>
</project>
                   

The first target stand-alone, is a simple target that has no dependencies and just performs an echo.

The second target after-comple-before-test is more interesting. It inserts itself into the build life cycle, executing some time after compile, but before test. Note the special dependency-of task within the target. This has the effect of adding the current target to the depends list of the named targets. You may also notice, it adds it to the pre-test target, not the test target. This is required as test implementations (such as the jUnit test implementation) are inserted between test and pre-test in the build sequence.

See Extending via Ant for more information.

Another option for ad hoc targets is the script plugin. This allows targets to be written in various scripting languages, including Javascript. The scripts have full access to Ant core and optional tasks as well as the Quokka template targets. See the Script Plugin for examples and further information.

1.2.9. Reusing your build configuration

Most organisations have multiple projects, each of which has multiple modules. Using quokka plugins on their own goes a long way to providing re-use amongst those projects. However, the plugins only come with default configurations. What if you'd like to bundle up a set of configured plugins for reuse?

This is exactly what dependency sets do. In fact, we've already seen a dependency set in action, namely the quokka.depset.jar dependency set within our project. It bundles up a common set of plugins used to build a jar file.

As well as bundling plugins, dependency sets can bundle configuration information, including properties and build resources. This provides a very powerful unit of re-use. For example, you can easily create your own dependency set that bundles up your organisation's coding standards for jalopy and then include it in all your projects as a single unit.

Dependency sets may nest other dependency sets to any level, so you may make dependency sets as granular as you like. See Dependency Sets for more information.

1.3. Next Steps

By now, you should have an idea of what quokka is about. However, there is a lot more to quokka. The following documentation is considered recommended reading to help you get the most out of quokka.

Looking for examples or starting a new project? Check out the available archetypes at http://quokka.ws/extensions.html#archetypes. Each archetype provides a working example you can use to kick start your project.

Key sections about the quokka core in the user guide at http://quokka.ws/user-guide.html include:

  • Multi-project builds: How to build projects consisting of sub-projects automatically

  • Profiles: How to selectively enable or disable targets and other functionality

  • Dependency Sets: Read about dependency sets in detail, including path specifications

Check out the available plugins at http://quokka.ws/extensions.html#plugins. Highlights include:

  • Unit testing with jUnit

  • Code coverage using Cobertura

  • XML transformations, including doc book to html and pdf

  • Version control management with Subversion

If you'd like to write you own plugin, or implement a custom repository, check out the developer's guide at http://quokka.ws/dev-guide.html