Maven: The Complete Reference

11.6. Plugins and the Maven Lifecycle

In the Chapter 4, The Build Lifecycle chapter, you learned that lifecycles can be customized by packaging types. A plugin can both introduce a new packaging type and customize the lifecycle. In this section, you are going to learn how you can customize the lifecycle from a custom Maven plugin. You are going to learn how to execute a parallel lifecycle.

11.6.1. Executing a Parallel Lifecycle

Let’s assume you write some goal that depends on the output from a previous build. Maybe the ZipMojo goal can only run if there is output to include in an archive. You can specify something like a prerequisite goal by using the @execute annotation on a Mojo class. This annotation will cause Maven to spawn a parallel build and execute a goal or a lifecycle in a parallel instance of Maven that isn’t going to affect the current build.

@execute goal="<goal>"
This will execute the given goal before execution of this one. The goal name is specified using the prefix:goal notation.
@execute phase="<phase>"
This will fork an alternate build lifecycle up to the specified phase before continuing to execute the current one. If no lifecycle is specified, Maven will use the lifecycle of the current build.
@execute lifecycle="<lifecycle>" phase="<phase>"
This will execute the given alternate lifecycle. A custom lifecycle can be defined in META-INF/maven/lifecycles.xml.

11.6.2. Creating a Custom Lifecycle

A custom lifecycle must be packaged in the plugin under the META-INF/maven/lifecycles.xml file. You can include a lifecycle under src/main/resources in META-INF/maven/lifecycles.xml. The following lifecycle.xml declares a lifecycle named zipcycle that contains only the zip goal in a package phase.

Define a Custom Lifecycle in lifecycles.xml. 

<lifecycles>
    <lifecycle>
        <id>zipcycle</id>
        <phases>
            <phase>
                <id>package</id>
                <executions>
                    <execution>
                        <goals>
                            <goal>zip</goal>
                        </goals>
                    </execution>
                </executions>
            </phase>
        </phases>
    </lifecycle>
</lifecycles>

If you wanted to execute the zipcycle lifecycle within another build, you could then create a ZipForkMojo which uses the @execute annotation to tell Maven to step through the zipcycle lifecycle when the ZipForkMojo is executed.

Forking a Custom Lifecycle from a Mojo. 

/**
* Forks a zip lifecycle.
* @goal zip-fork
* @execute lifecycle="zipcycle" phase="package"
*/
public class ZipForkMojo extends AbstractMojo
{
public void execute()
throws MojoExecutionException
{
getLog().info( "doing nothing here" );
}
}

Running the ZipForkMojo will fork the lifecycle. If you’ve configured your plugin to execute with the goal prefix zip, running zip-fork should produce something similar to the following output.

$ mvn zip:zip-fork
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'zip'.
[INFO] ----------------------------------------------------------------------
[INFO] Building Maven Zip Forked Lifecycle Test
[INFO]task-segment: [zip:zip-fork]
[INFO] ----------------------------------------------------------------------
[INFO] Preparing zip:zip-fork
[INFO] [site:attach-descriptor]
[INFO] [zip:zip]
[INFO] Building zip: \
~/maven-zip-plugin/src/projects/zip-lifecycle-test/target/output.zip
[INFO] [zip:zip-fork]
[INFO] doing nothing here
[INFO] ---------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ---------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Sun Apr 29 16:10:06 CDT 2007
[INFO] Final Memory: 3M/7M
[INFO] ---------------------------------------------------------------------

Calling zip-fork spawned another lifecycle, Maven executed the zipcycle lifecycle then it printed out the message from ZipFormMojo's execute method.

11.6.3. Overriding the Default Lifecycle

Once you’ve created your own lifecycle and spawned it from a Mojo. The next question you might have is how do you override the default lifecycle? How do you create custom lifecycles and attach them to projects? In Chapter 4, The Build Lifecycle, we saw that the packaging of a project defines the lifecycle of a project. There’s something different about almost every packaging type; each packaging type attaches different goals to the default lifecycle. When you create a custom lifecycle, you can attach that lifecycle to a packaging type by supplying some Plexus configuration in your plugin’s archive.

To define a new lifecycle for a new packaging type, you’ll need to configure a LifecycleMapping component in Plexus. In your plugin project, create a META-INF/plexus/components.xml under src/main/resources. In components.xml add the content from Overriding the Default Lifecycle. Set the name of the packaging type under role-hint, and the set of phases containing the coordinates of the goals to bind (omit the version). Multiple goals can be associated with a phase using a comma delimited list.

Overriding the Default Lifecycle. 

<component-set>
    <components>
        <component>
            <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
            <role-hint>zip</role-hint>
            <implementation>
                org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping
            </implementation>
            <configuration>
                <phases>
                    <process-resources>
                        org.apache.maven.plugins:maven-resources-plugin:resources
                    </process-resources>
                    <compile>
                        org.apache.maven.plugins:maven-compiler-plugin:compile
                    </compile>
                    <package>org.sonatype.mavenbook.plugins:maven-zip-plugin:zip</package>
                </phases>
            </configuration>
        </component>
    </components>
</component-set>

If you create a plugin which defines a new packaging type and a customized lifecycle, Maven won’t know anything about it until you add the plugin to your project’s POM and set the extensions element to true. Once you do this, Maven will scan your plugin for more than just Mojos to execute, it will look for the components.xml under META-INF/plexus, and it will make the packaging type available to your project.

Configuring a Plugin as an Extension. 

<project>
    ...
    <build>
        ...
        <plugins>
            <plugin>
                <groupId>com.training.plugins</groupId>
                <artifactId>maven-zip-plugin</artifactId>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>

Once you add the plugin with the extensions element set to true, you can use the custom packaging type and your project will be able to execute the custom lifecycle associated with that packaging type.