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.
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:goalnotation. - @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.
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.
Example 11.9. 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.
Example 11.10. 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.
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 Example 11.11, “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.
Example 11.11. 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.
Example 11.12. 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.
