Pls Subscribe this channel Subscribe ® Registered teknosys.in
Get link
Facebook
X
Pinterest
Email
Other Apps
Creating a maven Plugin Project
Get link
Facebook
X
Pinterest
Email
Other Apps
-
169---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
170---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
171---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
172---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
173---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
174---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
175---->
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
11.4. Writing a Custom Plugin
When you write a custom plugin, you are going to be writing a series of Mojos (goals). Every Mojo is a single Java class which contains a series of annotations that tell Maven how to generate the Plugin descriptor described in the previous section. Before you can start writing Mojo classes, you will need to create Maven project with the appropriate packaging and POM.
11.4.1. Creating a Plugin Project
To create a plugin project, you should use the Maven Archetype plugin. The following command-line will create a plugin with a groupId of org..mavenbook.plugins and the artifactId of first-maven-plugin:
$ mvn archetype:create \
-DgroupId=org..mavenbook.plugins \
-DartifactId=first-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-mojo
The Archetype plugin is going to create a directory named my-first-plugin which contains the following POM.
The most import element in a plugin project?s POM is the packaging element which has a value of maven-plugin. This packaging element customizes the Maven lifecycle to include the necessary goals to create a plugin descriptor. The plugin lifecycle was introduced in Section 4.2.3, ?Maven Plugin?, it is similar to the Jar lifecycle with three exceptions: plugin:descriptor is bound to the generate-resources phase, plugin:addPluginArtifactMetadata is added to the package phase, and plugin:updateRegistry is added to the install phase.
The other important piece of a plugin project?s POM is the dependency on the Maven Plugin API. This project depends on version 2.0 of the maven-plugin-api and it also adds in JUnit as a test-scoped dependency.
11.4.2. A Simple Java Mojo
In this chapter, we?re going to introduce a Maven Mojo written in Java. Each Mojo in your project is going to implement the org.apache.maven.plugin.Mojo interface, the Mojo implementation shown in the following example implements the Mojo interface by extending the org.apache.maven.plugin.AbstractMojo class. Before we dive into the code for this Mojo, let?s take some time to explore the methods on the Mojo interface. Mojo provides the following methods:
void setLog( org.apache.maven.monitor.logging.Log log )
Every Mojo implementation has to provide a way for the plugin to communicate the progress of a particular goal. Did the goal succeed? Or, was there a problem during goal execution? When Maven loads and executes a Mojo, it is going to call the setLog() method and supply the Mojo instance with a suitable logging destination to be used in your custom plugin.
protected Log getLog()
Maven is going to call setLog() before your Mojo is executed, and your Mojo can retrieve the logging object by calling getLog(). Instead of printing out status to Standard Output or the console, your Mojo is going to invoke methods on the Log object.
void execute() throws org.apache.maven.plugin.MojoExecutionException
This method is called by Maven when it is time to execute your goal.
The Mojo interface is concerned with two things: logging the results of goal execution and executing a goal. When you are writing a custom plugin, you?ll be extending AbstractMojo. AbstractMojo takes care of handling the setLog() and getLog() implementations and contains an abstract execute() method. When you extend AbstractMojo, all you need to do is implement the execute() method. A Simple EchoMojo shows a trivial Mojo implement which simply prints out a message to the console.
/**
* Echos an object string to the output screen.
* @goal echo
* @requiresProject false
*/
public class EchoMojo extends AbstractMojo
{
/**
* Any Object to print out.
* @parameter expression="${echo.message}" default-value="Hello World..."
*/
private Object message;
public void execute()
throws MojoExecutionException, MojoFailureException
{
getLog().info( message.toString() );
}
}
If you create this Mojo in ${basedir} under src/main/java in org//mavenbook/mojo/EchoMojo.java in the project created in the previous section and run mvn install, you should be able to invoke this goal directly from the command-line with:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo
That large command-line is mvn followed by the groupId:artifactId:version:goal. When you run this command-line you should see output that contains the output of the echo goal with the default message: "Hello Maven World?". If you want to customize the message, you can pass the value of the message parameter with the following command-line:
$ mvn org..mavenbook.plugins:first-maven-plugin:1.0-SNAPSHOT:echo \
-Decho.message="The Eagle has Landed"
The previous command-line is going to execute the EchoMojo and print out the message "The Eagle has Landed".
11.4.3. Configuring a Plugin Prefix
Specifying the groupId, artifactId, version, and goal on the command-line is cumbersome. To address this, Maven assigns a plugin a prefix. Instead of typing:
$ mvn org.apache.maven.plugins:maven-jar-plugin:2.2:jar
You can use the plugin prefix jar and turn that command-line into mvn jar:jar. How does Maven resolve something like jar:jar to org.apache.mven.plugins:maven-jar:2.3? Maven looks at a file in the Maven repository to obtain a list of plugins for a specific groupId. By default, Maven is configured to look for plugins in two groups: org.apache.maven.plugins and org.codehaus.mojo. When you specify a new plugin prefix like mvn hibernate3:hbm2ddl, Maven is going to scan the repository metadata for the appropriate plugin prefix. First, Maven is going to scan the org.apache.maven.plugins group for the plugin prefix hibernate3. If it doesn?t find the plugin prefix hibernate3 in the org.apache.maven.plugins group it will scan the metadata for the org.codehaus.mojo group.
When Maven scans the metadata for a particular groupId, it is retrieving an XML file from the Maven repository which captures metadata about the artifacts contained in a group. This XML file is specific for each repository referenced, if you are not using a custom Maven repository, you will be able to see the Maven metadata for the org.apache.maven.plugins group in your local Maven repository (~/.m2/repository) under org/apache/maven/plugins/maven-metadata-central.xml. Maven Metadata for the Maven Plugin Group shows a snippet of the maven-metadata-central.xml file from the org.apache.maven.plugin group.
As you can see in Maven Metadata for the Maven Plugin Group, this maven-metadata-central.xml file in your local repository is what makes it possible for you to execute mvn surefire:test. Maven scans org.apache.maven.plugins and org.codehaus.mojo: plugins from org.apache.maven.plugins are considered core Maven plugins and plugins from org.codehaus.mojo are considered extra plugins. The Apache Maven project manages the org.apache.maven.plugins group, and a separate independent open source community manages the Codehaus Mojo project. If you would like to start publishing plugins to your own groupId, and you would like Maven to automatically scan your own groupId for plugin prefixes, you can customize the groups that Maven scans for plugins in your Maven Settings.
If you wanted to be able to run the first-maven-plugins echo goal by running first:echo, add the org..mavenbook.plugins groupId to your '~/.m2/settings.xml as shown in Customizing the Plugin Groups in Maven Settings. This will prepend the org..mavenbook.plugins to the list of groups which Maven scans for Maven plugins.
Customizing the Plugin Groups in Maven Settings.
... org..mavenbook.plugins
You can now run mvn first:echo from any directory and see that Maven will properly resolve the goal prefix to the appropriate plugin identifiers. This worked because our project adhered to a naming convention for Maven plugins. If your plugin project has an artifactId which follows the pattern maven-first-plugin or first-maven-plugin. Maven will automatically assign a plugin goal prefix of first to your plugin. In other words, when the Maven Plugin Plugin is generating the Plugin descriptor for your plugin and you have not explicitly set the goalPrefix in your project, the plugin:descriptor goal will extract the prefix from your plugin?s artifactId when it matches the following patterns:
${prefix}-maven-plugin, OR
maven-${prefix}-plugin
If you would like to set an explicit plugin prefix, you?ll need to configure the Maven Plugin Plugin. The Maven Plugin Plugin is a plugin that is responsible for building the Plugin descriptor and performing plugin specific tasks during the package and load phases. The Maven Plugin Plugin can be configured just like any other plugin in the build element. To set the plugin prefix for your plugin, add the following build element to the first-maven-plugin project?s pom.xml.
Configuring a Plugin Prefix sets the plugin prefix to blah. If you?ve added the org..mavenbook.plugins to the pluginGroups in your ~/.m2/settings.xml, you should be able to execute the EchoMojo by running mvn blah:echo from any directory.
11.4.4. Logging from a Plugin
Maven takes care of connecting your Mojo to a logging provider by calling setLog() prior to the execution of your Mojo. It supplies an implementation of org.apache.maven.monitor.logging.Log. This class exposes methods that you can use to communicate information back to the user. This Log class provides multiple levels of logging similar to that API provided by Log4J. Those levels are captured by a series of methods available for each level: debug, info, error and warn. To save trees, we?ve only listed the methods for a single logging level: debug.
void debug( CharSequence message)
Prints a message to the debug logging level.
void debug( CharSequence message, Throwable t)
Prints a message to the debug logging level which includes the stack trace from the Throwable (either Exception or Error)
void debug( Throwable t )
Prints out the stack trace of the Throwable (either Exception or Error)
Each of the four levels exposes the same three methods. The four logging levels serve different purposes. The debug level exists for debugging purposes and for people who want to see a very detailed picture of the execution of a Mojo. You should use the debug logging level to provide as much detail on the execution of a Mojo, but you should never assume that a user is going to see the debug level. The info level is for general informational messages that should be printed as a normal course of operation. If you were building a plugin that compiled code using a compiler, you might want to print the output of the compiler to the screen.
The warn logging level is used for messages about unexpected events and errors that your Mojo can cope with. If you were trying to run a plugin that compiled Ruby source code, and there was no Ruby source code available, you might want to just print a warning message and move on. Warnings are not fatal, but errors are usually build-stopping conditions. For the completely unexpected error condition, there is the error logging level. You would use error if you couldn?t continue executing a Mojo. If you were writing a Mojo to compile some Java code and the compiler wasn?t available, you?d print a message to the error level and possibly pass along an Exception that Maven could print out for the user. You should assume that a user is going to see most of the messages in info and all of the messages in error.
11.4.5. Mojo Class Annotations
In first-maven-plugin, you didn?t write the plugin descriptor yourself, you relied on Maven to generate the plugin descriptor from your source code. The descriptor was generated using your plugin project?s POM information and a set of annotations on your EchoMojo class. EchoMojo only specifies the @goal annotation, here is a list of other annotations you can place on your Mojo implementation.
@goal
This is the only required annotation which gives a name to this goal unique to this plugin.
@requiresDependencyResolution
Flags this mojo as requiring the dependencies in the specified scope (or an implied scope) to be resolved before it can execute. Supports compile, runtime, and test. If this annotation had a value of test, it would tell Maven that the Mojo cannot be executed until the dependencies in the test scope had been resolved.
@requiresProject (true|false)
Marks that this goal must be run inside of a project, default is true. This is opposed to plugins like archetypes, which do not.
@requiresReports (true|false)
If you were creating a plugin that relies on the presence of reports, you would need to set requiresReports to true. The default value of this annotation is false.
@aggregator (true|false)
A Mojo with aggregator set to true is supposed to only run once during the execution of Maven. It was created to give plugin developers the ability to summarize the output of a series of builds; for example, to create a plugin that summarizes a report across all projects included in a build. A goal with aggregator set to true should only be run against the top-level project in a Maven build. The default value of aggregator is false.
@requiresOnline (true|false)
When set to true, Maven must not be running in offline mode when this goal is executed. Maven will throw an error if one attempts to execute this goal offline. Default: false.
@requiresDirectInvocation
When set to true, the goal can only be executed if it is explicitly executed from the command-line by the user. Maven will throw an error if someone tries to bind this goal to a lifecycle phase. The default for this annotation is false.
@phase
This annotation specifies the default phase for this goal. If you add an execution for this goal to a pom.xml and do not specify the phase, Maven will bind the goal to the phase specified in this annotation by default.
@execute [goal=goalName|phase=phaseName [lifecycle=lifecycleId]]
This annotation can be used in a number of ways. If a phase is supplied, Maven will execute a parallel lifecycle ending in the specified phase. The results of this separate execution will be made available in the Maven property ${executedProperty}.
The second way of using this annotation is to specify an explicit goal using the prefix:goal notation. When you specify just a goal, Maven will execute this goal in a parallel environment that will not affect the current Maven build.
The third way of using this annotation would be to specify a phase in an alternate lifecycle using the identifier of a lifecycle.
@execute phase="package" lifecycle="zip"
@execute phase="compile"
@execute goal="zip:zip"
If you look at the source for EchoMojo, you?ll notice that Maven is not using the standard annotations available in Java 5. Instead, it is using Commons Attributes. Commons Attributes provided a way for Java programmers to use annotations before annotations were a part of the Java language specification. Why doesn?t Maven use Java 5 annotations? Maven doesn?t use Java 5 annotations because it is designed to target pre-Java 5 JVMs. Because Maven has to support older versions of Java, it cannot use any of the newer features available in Java 5.
11.4.6. When a Mojo Fails
The execute() method in Mojo throws two exceptions MojoExecutionException and MojoFailureException. The difference between these two exception is both subtle and important, and it relates to what happens when a goal execution "fails". A MojoExecutionException is a fatal exception, something unrecoverable happened. You would throw a MojoExecutionException if something happens that warrants a complete stop in a build; you re trying to write to disk, but there is no space left, or you were trying to publish to a remote repository, but you can?t connect to it. Throw a MojoExecutionException if there is no chance of a build continuing; something terrible has happened and you want the build to stop and the user to see a "BUILD ERROR" message.
A MojoFailureException is something less catastrophic, a goal can fail, but it might not be the end of the world for your Maven build. A unit test can fail, or a MD5 checksum can fail; both of these are potential problems, but you don?t want to return an exception that is going to kill the entire build. In this situation you would throw a MojoFailureException. Maven provides for different "resiliency" settings when it comes to project failure. Which are described below.
When you run a Maven build, it could involve a series of projects each of which can succeed or fail. You have the option of running Maven in three failure modes:
mvn -ff
Fail-fast mode: Maven will fail (stop) at the first build failure.
mvn -fae
Fail-at-end: Maven will fail at the end of the build. If a project in the Maven reactor fails, Maven will continue to build the rest of the builds and report a failure at the end of the build.
mvn -fn
Fail never: Maven won?t stop for a failure and it won?t report a failure.
You might want to ignore failure if you are running a continuous integration build and you want to attempt a build regardless of the success of failure of an individual project build. As a plugin developer, you?ll have to make a call as to whether a particular failure condition is a MojoExecutionException or a MojoFailureExeception.
Prev : 11.3. Plugin Descriptor
TOC
Next : 11.5. Mojo Parameters
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
176---->
Prev : 11.2. Programming Maven
TOC
Next : 11.4. Writing a Custom Plugin
11.3. Plugin Descriptor
A Maven plugin contains a road-map for Maven that tells Maven about the various Mojos and plugin configuration. This plugin descriptor is present in the plugin JAR file in META-INF/maven/plugin.xml. When Maven loads a plugin, it reads this XML file, instantiates and configures plugin objects to make the Mojos contained in a plugin available to Maven.
When you are writing custom Maven plugins, you will almost never need to think about writing a plugin descriptor. In Chapter 4, The Build Lifecycle, the lifecycle goals bound to the maven-plugin packaging type show that the plugin:descriptor goal is bound to the generate-resources phase. This goal generates a plugin descriptor off of the annotations present in a plugin?s source code. Later in this chapter, you will see how Mojos are annotated, and you will also see how the values in these annotations end up in the META-INF/maven/plugin.xml file.
Plugin Descriptor shows a plugin descriptor for the Maven Zip Plugin. This plugin is a contrived plugin that simply zips up the output directory and produces an archive. Normally, you wouldn?t need to write a custom plugin to create an archive from Maven, you could simply use the Maven Assembly Plugin which is capable of producing a distribution archive in multiple formats. Read through the following plugin descriptor to get an idea of the content it contains.
Plugin Descriptor.
com.training.plugins maven-zip-plugin 1-SNAPSHOT zip false true zip Zips up the output directory. false true false false false true package com.training.plugins.ZipMojo java per-lookup once-per-session baseDirectory java.io.File false true Base directory of the project.
buildDirectory java.io.File false true Directory containing the build files.
${project.build.directory}
${basedir}
org.codehaus.plexus.archiver.Archiver zip zipArchiver
org.apache.commons commons-io 1.3.2
There are three parts to a plugin descriptor: the top-level configuration of the plugin which contains elements like groupId and artifactId, the declaration of mojos, and the declaration of dependencies. Let?s examine each of these sections in more detail.
11.3.1. Top-level Plugin Descriptor Elements
The top-level configuration values in the plugin element are:
description
This element contains a short description of the plugin. In the case of the Zip plugin, this description is empty.
groupId, artifactId, version
As with everything else in Maven, plugins need to have a unique set of coordinates. The groupId, artifactId, and version are used to locate the plugin artifact in a Maven repository.
goalPrefix
This element controls the prefix used to reference goals in a particular plugin. If you were to look at the Compiler plugin?s descriptor you would see that goalPrefix has a value of compiler. If you look at the descriptor for the Jar plugin, it would have a goalPrefix of jar. It is important that you choose a distinct goal prefix for your custom plugin.
isolatedRealm (deprecated)
This is a legacy property which is no longer used by Maven. It is still present in the system to provide backwards compatibility with older plugins. Earlier versions of Maven used to provide a mechanism to load a plugin?s dependencies in an isolated ClassLoader. Maven makes extensive use of a project called ClassWorlds from the Codehaus community to create hierarchies of ClassLoader objects which are modeled by a ClassRealm object. Feel free to ignore this property and always set it to false.
inheritedByDefault
If inheritedByDefault is set to true, any mojo in this plugin which is configured in a parent project will be configured in a child project. If you configure a mojo to execute during a specific phase in a parent project and the Plugin has inheritedByDefault set to true, this execution will be inherited by the child project. If inheritedByDefault is not set to true, then an goal execution defined in a parent project will not be inherited by a child project.
11.3.2. Mojo Configuration
Next is the declaration of each Mojo. The plugin element contains an element named mojos which contains a mojo element for each mojo present in the Plugin. Each mojo element contains the following configuration elements:
goal
This is the name of the goal. If you were running the compiler:compile goal, then compiler is the plugin?s goalPrefix and compile would be the name of the goal.
description
This contains a short description of the goal to display to the user when they use the Help plugin to generate plugin documentation.
requiresDirectInvocation
If you set this to true, the goal can only be executed if it is explicitly executed from the command-line by the user. If someone tries to bind this goal to a lifecycle phase in a POM, Maven will print an error message. The default for this element is false.
Prev : 11.2. Programming Maven
TOC
Next : 11.4. Writing a Custom Plugin
11.3. Plugin Descriptor
A Maven plugin contains a road-map for Maven that tells Maven about the various Mojos and plugin configuration. This plugin descriptor is present in the plugin JAR file in META-INF/maven/plugin.xml. When Maven loads a plugin, it reads this XML file, instantiates and configures plugin objects to make the Mojos contained in a plugin available to Maven.
When you are writing custom Maven plugins, you will almost never need to think about writing a plugin descriptor. In Chapter 4, The Build Lifecycle, the lifecycle goals bound to the maven-plugin packaging type show that the plugin:descriptor goal is bound to the generate-resources phase. This goal generates a plugin descriptor off of the annotations present in a plugin?s source code. Later in this chapter, you will see how Mojos are annotated, and you will also see how the values in these annotations end up in the META-INF/maven/plugin.xml file.
Plugin Descriptor shows a plugin descriptor for the Maven Zip Plugin. This plugin is a contrived plugin that simply zips up the output directory and produces an archive. Normally, you wouldn?t need to write a custom plugin to create an archive from Maven, you could simply use the Maven Assembly Plugin which is capable of producing a distribution archive in multiple formats. Read through the following plugin descriptor to get an idea of the content it contains.
Plugin Descriptor.
com.training.plugins maven-zip-plugin 1-SNAPSHOT zip false true zip Zips up the output directory. false true false false false true package com.training.plugins.ZipMojo java per-lookup once-per-session baseDirectory java.io.File false true Base directory of the project.
buildDirectory java.io.File false true Directory containing the build files.
${project.build.directory}
${basedir}
org.codehaus.plexus.archiver.Archiver zip zipArchiver
org.apache.commons commons-io 1.3.2
There are three parts to a plugin descriptor: the top-level configuration of the plugin which contains elements like groupId and artifactId, the declaration of mojos, and the declaration of dependencies. Let?s examine each of these sections in more detail.
11.3.1. Top-level Plugin Descriptor Elements
The top-level configuration values in the plugin element are:
description
This element contains a short description of the plugin. In the case of the Zip plugin, this description is empty.
groupId, artifactId, version
As with everything else in Maven, plugins need to have a unique set of coordinates. The groupId, artifactId, and version are used to locate the plugin artifact in a Maven repository.
goalPrefix
This element controls the prefix used to reference goals in a particular plugin. If you were to look at the Compiler plugin?s descriptor you would see that goalPrefix has a value of compiler. If you look at the descriptor for the Jar plugin, it would have a goalPrefix of jar. It is important that you choose a distinct goal prefix for your custom plugin.
isolatedRealm (deprecated)
This is a legacy property which is no longer used by Maven. It is still present in the system to provide backwards compatibility with older plugins. Earlier versions of Maven used to provide a mechanism to load a plugin?s dependencies in an isolated ClassLoader. Maven makes extensive use of a project called ClassWorlds from the Codehaus community to create hierarchies of ClassLoader objects which are modeled by a ClassRealm object. Feel free to ignore this property and always set it to false.
inheritedByDefault
If inheritedByDefault is set to true, any mojo in this plugin which is configured in a parent project will be configured in a child project. If you configure a mojo to execute during a specific phase in a parent project and the Plugin has inheritedByDefault set to true, this execution will be inherited by the child project. If inheritedByDefault is not set to true, then an goal execution defined in a parent project will not be inherited by a child project.
11.3.2. Mojo Configuration
Next is the declaration of each Mojo. The plugin element contains an element named mojos which contains a mojo element for each mojo present in the Plugin. Each mojo element contains the following configuration elements:
goal
This is the name of the goal. If you were running the compiler:compile goal, then compiler is the plugin?s goalPrefix and compile would be the name of the goal.
description
This contains a short description of the goal to display to the user when they use the Help plugin to generate plugin documentation.
requiresDirectInvocation
If you set this to true, the goal can only be executed if it is explicitly executed from the command-line by the user. If someone tries to bind this goal to a lifecycle phase in a POM, Maven will print an error message. The default for this element is false.
Prev : 11.2. Programming Maven
TOC
Next : 11.4. Writing a Custom Plugin
11.3. Plugin Descriptor
A Maven plugin contains a road-map for Maven that tells Maven about the various Mojos and plugin configuration. This plugin descriptor is present in the plugin JAR file in META-INF/maven/plugin.xml. When Maven loads a plugin, it reads this XML file, instantiates and configures plugin objects to make the Mojos contained in a plugin available to Maven.
When you are writing custom Maven plugins, you will almost never need to think about writing a plugin descriptor. In Chapter 4, The Build Lifecycle, the lifecycle goals bound to the maven-plugin packaging type show that the plugin:descriptor goal is bound to the generate-resources phase. This goal generates a plugin descriptor off of the annotations present in a plugin?s source code. Later in this chapter, you will see how Mojos are annotated, and you will also see how the values in these annotations end up in the META-INF/maven/plugin.xml file.
Plugin Descriptor shows a plugin descriptor for the Maven Zip Plugin. This plugin is a contrived plugin that simply zips up the output directory and produces an archive. Normally, you wouldn?t need to write a custom plugin to create an archive from Maven, you could simply use the Maven Assembly Plugin which is capable of producing a distribution archive in multiple formats. Read through the following plugin descriptor to get an idea of the content it contains.
Plugin Descriptor.
com.training.plugins maven-zip-plugin 1-SNAPSHOT zip false true zip Zips up the output directory. false true false false false true package com.training.plugins.ZipMojo java per-lookup once-per-session baseDirectory java.io.File false true Base directory of the project.
buildDirectory java.io.File false true Directory containing the build files.
${project.build.directory}
${basedir}
org.codehaus.plexus.archiver.Archiver zip zipArchiver
org.apache.commons commons-io 1.3.2
There are three parts to a plugin descriptor: the top-level configuration of the plugin which contains elements like groupId and artifactId, the declaration of mojos, and the declaration of dependencies. Let?s examine each of these sections in more detail.
11.3.1. Top-level Plugin Descriptor Elements
The top-level configuration values in the plugin element are:
description
This element contains a short description of the plugin. In the case of the Zip plugin, this description is empty.
groupId, artifactId, version
As with everything else in Maven, plugins need to have a unique set of coordinates. The groupId, artifactId, and version are used to locate the plugin artifact in a Maven repository.
goalPrefix
This element controls the prefix used to reference goals in a particular plugin. If you were to look at the Compiler plugin?s descriptor you would see that goalPrefix has a value of compiler. If you look at the descriptor for the Jar plugin, it would have a goalPrefix of jar. It is important that you choose a distinct goal prefix for your custom plugin.
isolatedRealm (deprecated)
This is a legacy property which is no longer used by Maven. It is still present in the system to provide backwards compatibility with older plugins. Earlier versions of Maven used to provide a mechanism to load a plugin?s dependencies in an isolated ClassLoader. Maven makes extensive use of a project called ClassWorlds from the Codehaus community to create hierarchies of ClassLoader objects which are modeled by a ClassRealm object. Feel free to ignore this property and always set it to false.
inheritedByDefault
If inheritedByDefault is set to true, any mojo in this plugin which is configured in a parent project will be configured in a child project. If you configure a mojo to execute during a specific phase in a parent project and the Plugin has inheritedByDefault set to true, this execution will be inherited by the child project. If inheritedByDefault is not set to true, then an goal execution defined in a parent project will not be inherited by a child project.
11.3.2. Mojo Configuration
Next is the declaration of each Mojo. The plugin element contains an element named mojos which contains a mojo element for each mojo present in the Plugin. Each mojo element contains the following configuration elements:
goal
This is the name of the goal. If you were running the compiler:compile goal, then compiler is the plugin?s goalPrefix and compile would be the name of the goal.
description
This contains a short description of the goal to display to the user when they use the Help plugin to generate plugin documentation.
requiresDirectInvocation
If you set this to true, the goal can only be executed if it is explicitly executed from the command-line by the user. If someone tries to bind this goal to a lifecycle phase in a POM, Maven will print an error message. The default for this element is false.
Prev : 11.2. Programming Maven
TOC
Next : 11.4. Writing a Custom Plugin
11.3. Plugin Descriptor
A Maven plugin contains a road-map for Maven that tells Maven about the various Mojos and plugin configuration. This plugin descriptor is present in the plugin JAR file in META-INF/maven/plugin.xml. When Maven loads a plugin, it reads this XML file, instantiates and configures plugin objects to make the Mojos contained in a plugin available to Maven.
When you are writing custom Maven plugins, you will almost never need to think about writing a plugin descriptor. In Chapter 4, The Build Lifecycle, the lifecycle goals bound to the maven-plugin packaging type show that the plugin:descriptor goal is bound to the generate-resources phase. This goal generates a plugin descriptor off of the annotations present in a plugin?s source code. Later in this chapter, you will see how Mojos are annotated, and you will also see how the values in these annotations end up in the META-INF/maven/plugin.xml file.
Plugin Descriptor shows a plugin descriptor for the Maven Zip Plugin. This plugin is a contrived plugin that simply zips up the output directory and produces an archive. Normally, you wouldn?t need to write a custom plugin to create an archive from Maven, you could simply use the Maven Assembly Plugin which is capable of producing a distribution archive in multiple formats. Read through the following plugin descriptor to get an idea of the content it contains.
Plugin Descriptor.
com.training.plugins maven-zip-plugin 1-SNAPSHOT zip false true zip Zips up the output directory. false true false false false true package com.training.plugins.ZipMojo java per-lookup once-per-session baseDirectory java.io.File false true Base directory of the project.
buildDirectory java.io.File false true Directory containing the build files.
${project.build.directory}
${basedir}
org.codehaus.plexus.archiver.Archiver zip zipArchiver
org.apache.commons commons-io 1.3.2
There are three parts to a plugin descriptor: the top-level configuration of the plugin which contains elements like groupId and artifactId, the declaration of mojos, and the declaration of dependencies. Let?s examine each of these sections in more detail.
11.3.1. Top-level Plugin Descriptor Elements
The top-level configuration values in the plugin element are:
description
This element contains a short description of the plugin. In the case of the Zip plugin, this description is empty.
groupId, artifactId, version
As with everything else in Maven, plugins need to have a unique set of coordinates. The groupId, artifactId, and version are used to locate the plugin artifact in a Maven repository.
goalPrefix
This element controls the prefix used to reference goals in a particular plugin. If you were to look at the Compiler plugin?s descriptor you would see that goalPrefix has a value of compiler. If you look at the descriptor for the Jar plugin, it would have a goalPrefix of jar. It is important that you choose a distinct goal prefix for your custom plugin.
isolatedRealm (deprecated)
This is a legacy property which is no longer used by Maven. It is still present in the system to provide backwards compatibility with older plugins. Earlier versions of Maven used to provide a mechanism to load a plugin?s dependencies in an isolated ClassLoader. Maven makes extensive use of a project called ClassWorlds from the Codehaus community to create hierarchies of ClassLoader objects which are modeled by a ClassRealm object. Feel free to ignore this property and always set it to false.
inheritedByDefault
If inheritedByDefault is set to true, any mojo in this plugin which is configured in a parent project will be configured in a child project. If you configure a mojo to execute during a specific phase in a parent project and the Plugin has inheritedByDefault set to true, this execution will be inherited by the child project. If inheritedByDefault is not set to true, then an goal execution defined in a parent project will not be inherited by a child project.
11.3.2. Mojo Configuration
Next is the declaration of each Mojo. The plugin element contains an element named mojos which contains a mojo element for each mojo present in the Plugin. Each mojo element contains the following configuration elements:
goal
This is the name of the goal. If you were running the compiler:compile goal, then compiler is the plugin?s goalPrefix and compile would be the name of the goal.
description
This contains a short description of the goal to display to the user when they use the Help plugin to generate plugin documentation.
requiresDirectInvocation
If you set this to true, the goal can only be executed if it is explicitly executed from the command-line by the user. If someone tries to bind this goal to a lifecycle phase in a POM, Maven will print an error message. The default for this element is false.
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
11.2. Programming Maven
Most of this book has dealt with using Maven, and for a book on Maven, you haven?t seen too many code examples dealing with Maven customization. In fact, you haven?t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven?s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you?ve found the proper starting line.
11.2.1. What is Inversion of Control?
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn?t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we?ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you?ve just performed dependency injection, and you?ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a Java Bean both provide an interface. The Playstation 3 has two inputs: power and network, and one output to the TV. Your JavaBean has three properties: power, network, and tvOutput. When you open the box of your Playstation 3, it didn?t provide you with detailed pictures and instructions for how to connect it to every different kind of TV that might be in every different kind of house. When you look at your Java Bean, it just provides a set of properties, not an explicit recipe for creating and managing an entire system of components. In an IoC container like Plexus, you are responsible for declaring the relationships between a set of components which simply provide an interface of inputs and outputs. You don?t instantiate objects, Plexus does; your application?s code isn?t responsible for managing the state of components, Plexus is. Even though it sounds very cheesy, when you start up Maven, it is starting Plexus and managing a system of related components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
11.2.2. Introduction to Plexus
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
Constructor Injection
Constructor injection is populating an object?s values through its constructor when an instance of the object is created. For example, if you had an object of type Person which had a constructor Person(String name, Job job), you could pass in values for both name and the job via this constructor.
Setter Injection
Setter injection is using the setter method of a property on a Java bean to populate object dependencies. For example, if you were working with a Person object with the properties name and job, an IoC container which uses setter injection, would create an instance of Person using a no-arg constructor. Once it had an instance of Person, it would proceed to call the setName() and setJob() methods.
Field Injection
Both Constructor and Setter injection rely on a call to a public method. Using Field injection, an IoC container populates a component?s dependencies by setting an object?s fields directly. For example, if you were working with a Person object that had two fields name and job, your IoC container would populate these dependencies by setting these fields directly (i.e. person.name = "Thomas"; person.job = job;)
11.2.3. Why Plexus?
Spring does happen to be the most popular IoC container at the moment, and there?s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn?t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn?t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you?ve have an idea of how Plexus works. If you already use an IoC container you?ll notice similarities and differences between Plexus and the container you currently use.
Note
Just because Maven is based on Plexus doesn?t mean that the Maven community is "anti-Spring" (we?ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn?t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don?t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
11.2.4. What is a Plugin?
A Maven Plugin is a Maven artifact which contains a plugin descriptor and one or more Mojos. A Mojo can be thought of as a goal in Maven, and every goal corresponds to a Mojo. The compiler:compile goal corresponds to the CompilerMojo class in the Maven Compiler Plugin, and the jar:jar goal corresponds to the JarMojo class in the Maven Jar Plugin. When you write your own plugin, you are simply grouping together a set of related Mojos (or goals) in a single plugin artifact. [1]
Note
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
[1] "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
Most of this book has dealt with using Maven, and for a book on Maven, you haven?t seen too many code examples dealing with Maven customization. In fact, you haven?t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven?s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you?ve found the proper starting line.
11.2.1. What is Inversion of Control?
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn?t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we?ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you?ve just performed dependency injection, and you?ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a Java Bean both provide an interface. The Playstation 3 has two inputs: power and network, and one output to the TV. Your JavaBean has three properties: power, network, and tvOutput. When you open the box of your Playstation 3, it didn?t provide you with detailed pictures and instructions for how to connect it to every different kind of TV that might be in every different kind of house. When you look at your Java Bean, it just provides a set of properties, not an explicit recipe for creating and managing an entire system of components. In an IoC container like Plexus, you are responsible for declaring the relationships between a set of components which simply provide an interface of inputs and outputs. You don?t instantiate objects, Plexus does; your application?s code isn?t responsible for managing the state of components, Plexus is. Even though it sounds very cheesy, when you start up Maven, it is starting Plexus and managing a system of related components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
11.2.2. Introduction to Plexus
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
Constructor Injection
Constructor injection is populating an object?s values through its constructor when an instance of the object is created. For example, if you had an object of type Person which had a constructor Person(String name, Job job), you could pass in values for both name and the job via this constructor.
Setter Injection
Setter injection is using the setter method of a property on a Java bean to populate object dependencies. For example, if you were working with a Person object with the properties name and job, an IoC container which uses setter injection, would create an instance of Person using a no-arg constructor. Once it had an instance of Person, it would proceed to call the setName() and setJob() methods.
Field Injection
Both Constructor and Setter injection rely on a call to a public method. Using Field injection, an IoC container populates a component?s dependencies by setting an object?s fields directly. For example, if you were working with a Person object that had two fields name and job, your IoC container would populate these dependencies by setting these fields directly (i.e. person.name = "Thomas"; person.job = job;)
11.2.3. Why Plexus?
Spring does happen to be the most popular IoC container at the moment, and there?s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn?t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn?t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you?ve have an idea of how Plexus works. If you already use an IoC container you?ll notice similarities and differences between Plexus and the container you currently use.
Note
Just because Maven is based on Plexus doesn?t mean that the Maven community is "anti-Spring" (we?ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn?t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don?t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
11.2.4. What is a Plugin?
A Maven Plugin is a Maven artifact which contains a plugin descriptor and one or more Mojos. A Mojo can be thought of as a goal in Maven, and every goal corresponds to a Mojo. The compiler:compile goal corresponds to the CompilerMojo class in the Maven Compiler Plugin, and the jar:jar goal corresponds to the JarMojo class in the Maven Jar Plugin. When you write your own plugin, you are simply grouping together a set of related Mojos (or goals) in a single plugin artifact. [1]
Note
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
[1] "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
Most of this book has dealt with using Maven, and for a book on Maven, you haven?t seen too many code examples dealing with Maven customization. In fact, you haven?t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven?s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you?ve found the proper starting line.
11.2.1. What is Inversion of Control?
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn?t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we?ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you?ve just performed dependency injection, and you?ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a Java Bean both provide an interface. The Playstation 3 has two inputs: power and network, and one output to the TV. Your JavaBean has three properties: power, network, and tvOutput. When you open the box of your Playstation 3, it didn?t provide you with detailed pictures and instructions for how to connect it to every different kind of TV that might be in every different kind of house. When you look at your Java Bean, it just provides a set of properties, not an explicit recipe for creating and managing an entire system of components. In an IoC container like Plexus, you are responsible for declaring the relationships between a set of components which simply provide an interface of inputs and outputs. You don?t instantiate objects, Plexus does; your application?s code isn?t responsible for managing the state of components, Plexus is. Even though it sounds very cheesy, when you start up Maven, it is starting Plexus and managing a system of related components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
11.2.2. Introduction to Plexus
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
Constructor Injection
Constructor injection is populating an object?s values through its constructor when an instance of the object is created. For example, if you had an object of type Person which had a constructor Person(String name, Job job), you could pass in values for both name and the job via this constructor.
Setter Injection
Setter injection is using the setter method of a property on a Java bean to populate object dependencies. For example, if you were working with a Person object with the properties name and job, an IoC container which uses setter injection, would create an instance of Person using a no-arg constructor. Once it had an instance of Person, it would proceed to call the setName() and setJob() methods.
Field Injection
Both Constructor and Setter injection rely on a call to a public method. Using Field injection, an IoC container populates a component?s dependencies by setting an object?s fields directly. For example, if you were working with a Person object that had two fields name and job, your IoC container would populate these dependencies by setting these fields directly (i.e. person.name = "Thomas"; person.job = job;)
11.2.3. Why Plexus?
Spring does happen to be the most popular IoC container at the moment, and there?s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn?t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn?t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you?ve have an idea of how Plexus works. If you already use an IoC container you?ll notice similarities and differences between Plexus and the container you currently use.
Note
Just because Maven is based on Plexus doesn?t mean that the Maven community is "anti-Spring" (we?ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn?t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don?t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
11.2.4. What is a Plugin?
A Maven Plugin is a Maven artifact which contains a plugin descriptor and one or more Mojos. A Mojo can be thought of as a goal in Maven, and every goal corresponds to a Mojo. The compiler:compile goal corresponds to the CompilerMojo class in the Maven Compiler Plugin, and the jar:jar goal corresponds to the JarMojo class in the Maven Jar Plugin. When you write your own plugin, you are simply grouping together a set of related Mojos (or goals) in a single plugin artifact. [1]
Note
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
[1] "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
Most of this book has dealt with using Maven, and for a book on Maven, you haven?t seen too many code examples dealing with Maven customization. In fact, you haven?t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven?s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you?ve found the proper starting line.
11.2.1. What is Inversion of Control?
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn?t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we?ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you?ve just performed dependency injection, and you?ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a Java Bean both provide an interface. The Playstation 3 has two inputs: power and network, and one output to the TV. Your JavaBean has three properties: power, network, and tvOutput. When you open the box of your Playstation 3, it didn?t provide you with detailed pictures and instructions for how to connect it to every different kind of TV that might be in every different kind of house. When you look at your Java Bean, it just provides a set of properties, not an explicit recipe for creating and managing an entire system of components. In an IoC container like Plexus, you are responsible for declaring the relationships between a set of components which simply provide an interface of inputs and outputs. You don?t instantiate objects, Plexus does; your application?s code isn?t responsible for managing the state of components, Plexus is. Even though it sounds very cheesy, when you start up Maven, it is starting Plexus and managing a system of related components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
11.2.2. Introduction to Plexus
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
Constructor Injection
Constructor injection is populating an object?s values through its constructor when an instance of the object is created. For example, if you had an object of type Person which had a constructor Person(String name, Job job), you could pass in values for both name and the job via this constructor.
Setter Injection
Setter injection is using the setter method of a property on a Java bean to populate object dependencies. For example, if you were working with a Person object with the properties name and job, an IoC container which uses setter injection, would create an instance of Person using a no-arg constructor. Once it had an instance of Person, it would proceed to call the setName() and setJob() methods.
Field Injection
Both Constructor and Setter injection rely on a call to a public method. Using Field injection, an IoC container populates a component?s dependencies by setting an object?s fields directly. For example, if you were working with a Person object that had two fields name and job, your IoC container would populate these dependencies by setting these fields directly (i.e. person.name = "Thomas"; person.job = job;)
11.2.3. Why Plexus?
Spring does happen to be the most popular IoC container at the moment, and there?s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn?t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn?t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you?ve have an idea of how Plexus works. If you already use an IoC container you?ll notice similarities and differences between Plexus and the container you currently use.
Note
Just because Maven is based on Plexus doesn?t mean that the Maven community is "anti-Spring" (we?ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn?t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don?t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
11.2.4. What is a Plugin?
A Maven Plugin is a Maven artifact which contains a plugin descriptor and one or more Mojos. A Mojo can be thought of as a goal in Maven, and every goal corresponds to a Mojo. The compiler:compile goal corresponds to the CompilerMojo class in the Maven Compiler Plugin, and the jar:jar goal corresponds to the JarMojo class in the Maven Jar Plugin. When you write your own plugin, you are simply grouping together a set of related Mojos (or goals) in a single plugin artifact. [1]
Note
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
[1] "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
Most of this book has dealt with using Maven, and for a book on Maven, you haven?t seen too many code examples dealing with Maven customization. In fact, you haven?t yet seen any. This is by design, 99 out of 100 Maven users will never need to write a custom plugin to customize Maven; there is an abundance of configurable plugins, and unless your project has particularly unique requirements, you will have to work to find a reason to write a new plugin. An even smaller percentage of people who end up writing custom plugins will ever need to crack open the source code for Maven and customize a core Maven component. If you really need to customize the behavior of Maven, then you would write a plugin. Modifying the core Maven code is as far out of scope for most developers as modifying the TCP/IP stack on an operating system, it is that abstract for most Maven users.
On the other hand, if you are going to start writing a custom plugin, you are going to have to learn a bit about the internals of Maven: How does it manage software components? What is a Plugin? How can I customize the lifecycle? This section answers some of those questions, and it introduces a few concepts at the core of Maven?s design. Learning how to write a custom Maven plugin is the gateway to customizing Maven itself. If you were wondering how to start understanding the code behind Maven, you?ve found the proper starting line.
11.2.1. What is Inversion of Control?
At the heart of Maven is an Inversion of Control (IoC) container named Plexus. What does it do? It is a system for managing and relating components. While there is a canonical essay about IoC written by Martin Fowler, the concept and term have been so heavily overloaded in the past few years it is tough to find a good definition of the concept that isn?t a self-reference (or just a lazy reference to the aforementioned essay). Instead of resorting to a Wikipedia quote, we?ll summarize Inversion of Control and Dependency Injection with an analogy.
Assume that you have a series of components which need to be wired together. When you think about components, think stereo components not software components. Imagine several stereo components hooked up to a Playstation 3 and a Tivo that have to interface with both an Apple TV box and a 50-inch flat panel LCD TV. You bring everything home from the electronics store and you purchase a series of cables that you are going to use to connect everything to everything else. You unpack all of these components, put them in the right place, and then get to the job of hooking up fifty thousand coaxial cables and stereo jacks to fifty thousand digital inputs and network cables. Step back from your home entertainment center and turn on the TV, you?ve just performed dependency injection, and you?ve just been an inversion of control container.
So what did that have to do with anything? Your Playstation 3 and a Java Bean both provide an interface. The Playstation 3 has two inputs: power and network, and one output to the TV. Your JavaBean has three properties: power, network, and tvOutput. When you open the box of your Playstation 3, it didn?t provide you with detailed pictures and instructions for how to connect it to every different kind of TV that might be in every different kind of house. When you look at your Java Bean, it just provides a set of properties, not an explicit recipe for creating and managing an entire system of components. In an IoC container like Plexus, you are responsible for declaring the relationships between a set of components which simply provide an interface of inputs and outputs. You don?t instantiate objects, Plexus does; your application?s code isn?t responsible for managing the state of components, Plexus is. Even though it sounds very cheesy, when you start up Maven, it is starting Plexus and managing a system of related components just like your stereo system.
What are the advantages of using an IoC container? What is the advantage of buying discrete stereo components? If one component breaks, you can drop in a replacement for your Playstation 3 without having to spend $20,000 on the entire system. If you are unhappy with your TV, you can swap it out without affecting your CD player. Most important to you, your stereo components cost less and are more capable and reliable because manufacturers can build to a set of known inputs and outputs and focus on building individual components. Inversion of Control containers and Dependency Injection encourage Disaggregation and the emergence of standards. The software industry likes to imagine itself as the font of all new ideas, but dependency injection and inversion of control are really just new words for the concepts of Disaggregation and interchangeable machinery. If you really want to know about DI and IoC, learn about the Model T, the Cotton Gin, and the emergence of a railroad standard in the late 19th century.
11.2.2. Introduction to Plexus
The most important feature of an IoC container implemented in Java is a mechanism called dependency injection. The basic idea of IoC is that the control of creating and managing objects is removed from the code itself and placed into the hands of an IoC framework. Using dependency injection in an application that has been programmed to interfaces, you can create components which are not bound to specific implementations of these interfaces. Instead, you program to interfaces and then configure Plexus to connect the appropriate implementation to the appropriate component. While your code deals with interfaces, you can capture the dependencies between classes and components in an XML file that defines components, implementation classes, and the relationships between your components. In other words, you can write isolated components, then you can wire them together using an XML file that defines how the components are wired together. In the case of Plexus, system components are defined with an XML document that is found in META-INF/plexus/components.xml.
In a Java IoC container, there are several methods for injecting dependencies values into a component object: constructor, setter, or field injections. Although Plexus is capable of all three dependency injection techniques, Maven only uses two types: field and setter injection.
Constructor Injection
Constructor injection is populating an object?s values through its constructor when an instance of the object is created. For example, if you had an object of type Person which had a constructor Person(String name, Job job), you could pass in values for both name and the job via this constructor.
Setter Injection
Setter injection is using the setter method of a property on a Java bean to populate object dependencies. For example, if you were working with a Person object with the properties name and job, an IoC container which uses setter injection, would create an instance of Person using a no-arg constructor. Once it had an instance of Person, it would proceed to call the setName() and setJob() methods.
Field Injection
Both Constructor and Setter injection rely on a call to a public method. Using Field injection, an IoC container populates a component?s dependencies by setting an object?s fields directly. For example, if you were working with a Person object that had two fields name and job, your IoC container would populate these dependencies by setting these fields directly (i.e. person.name = "Thomas"; person.job = job;)
11.2.3. Why Plexus?
Spring does happen to be the most popular IoC container at the moment, and there?s a good argument to be made that it has affected the Java "ecosystem" for the better forcing companies like Sun Microsystems to yield more control to the open source community and helping to open up standards by providing a pluggable, component-oriented "bus". But, Spring isn?t the only IoC container in open source. There are many IoC containers (like PicoContainer).
Years and years ago, when Maven was created, Spring wasn?t a mature option. The initial team of committers on Maven were more familiar with Plexus because they invented it, so they decided to use it as an IoC container. While it might not be as popular as the Spring Framework, it is no less capable. And, the fact that it was created by the same person who created Maven makes it a perfect fit. After reading this chapter you?ve have an idea of how Plexus works. If you already use an IoC container you?ll notice similarities and differences between Plexus and the container you currently use.
Note
Just because Maven is based on Plexus doesn?t mean that the Maven community is "anti-Spring" (we?ve included a whole chapter with a Spring example in this book, portions of the Spring project are moving to Maven as a build platform). The question, "Why didn?t you use Spring?" comes up often enough it did make sense to address it here. We know it, Spring is a rock star, we don?t deny it, and it is on our continuing to-do list to introduce people to (and document) Plexus: choice in the software industry is always a good thing.
11.2.4. What is a Plugin?
A Maven Plugin is a Maven artifact which contains a plugin descriptor and one or more Mojos. A Mojo can be thought of as a goal in Maven, and every goal corresponds to a Mojo. The compiler:compile goal corresponds to the CompilerMojo class in the Maven Compiler Plugin, and the jar:jar goal corresponds to the JarMojo class in the Maven Jar Plugin. When you write your own plugin, you are simply grouping together a set of related Mojos (or goals) in a single plugin artifact. [1]
Note
Mojo? What is a Mojo? The word mojo is defined as "a magic charm or spell", "an amulet, often in a small flannel bag containing one or more magic items", and "personal magnetism; charm". Maven uses the term Mojo because it is a play on the word Pojo (Plain-old Java Object).
A Mojo is much more than just a goal in Maven, it is a component managed by Plexus that can include references to other Plexus components.
[1] "mojo." The American Heritage® Dictionary of the English Language, Fourth Edition. Houghton Mifflin Company, 2004. Answers.com 02 Mar. 2008
Prev : 11.1. Introduction
TOC
Next : 11.3. Plugin Descriptor
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
While this chapter covers an advanced topic, don?t let the idea of writing a Maven plugin intimidate you. For all of the theory and complexity of this tool, the fundamental concepts are easy to understand and the mechanics of writing a plugin are straightforward. After you read this chapter, you will have a better grasp of what is involved in creating a Maven plugin.
Prev : Chapter 11. Writing Plugins
TOC
Next : 11.2. Programming Maven
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
186---->
Prev : 10.8. Tips and Tricks
TOC
Next : 11.1. Introduction
Chapter 11. Writing Plugins
11.1. Introduction
11.2. Programming Maven
11.2.1. What is Inversion of Control?
11.2.2. Introduction to Plexus
11.2.3. Why Plexus?
11.2.4. What is a Plugin?
11.3. Plugin Descriptor
11.3.1. Top-level Plugin Descriptor Elements
11.3.2. Mojo Configuration
11.3.3. Plugin Dependencies
11.4. Writing a Custom Plugin
11.4.1. Creating a Plugin Project
11.4.2. A Simple Java Mojo
11.4.3. Configuring a Plugin Prefix
11.4.4. Logging from a Plugin
11.4.5. Mojo Class Annotations
11.4.6. When a Mojo Fails
11.5. Mojo Parameters
11.5.1. Supplying Values for Mojo Parameters
11.5.2. Multi-valued Mojo Parameters
11.5.3. Depending on Plexus Components
11.5.4. Mojo Parameter Annotations
11.6. Plugins and the Maven Lifecycle
11.6.1. Executing a Parallel Lifecycle
11.6.2. Creating a Custom Lifecycle
11.6.3. Overriding the Default Lifecycle
Prev : 10.8. Tips and Tricks
TOC
Next : 11.1. Introduction
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
187---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
188---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
189---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
190---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
191---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
192---->
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
10.8. Tips and Tricks
This section lists some useful tips and tricks you can use when creating a Maven site.
10.8.1. Inject XHTML into HEAD
To inject XHTML into the HEAD element, add a head element to the body element in your project?s Site descriptor. The following example adds a feed link to every page in the sample-project web site.
If you are working on a project which is being developed by an organization, you may want to add links under your project?s logo. Assume that your project is a part of the Apache Software Foundation, you might want to add a link to the Apache Software Foundation web site right below your logo, and you might want to add a link to a parent project as well. To add links below your site logo, just add a links element to the body element in the Site descriptor. Each item element in the links element will be rendered as a link in a bar directly below your project?s logo. The following example would add a link to the Apache Software Foundation followed by a link to the Apache Maven project.
Adding Links Under Your Site Logo.
...
...
...
10.8.3. Add Breadcrumbs to Your Site
If your hierarchy exists within a logical hierarchy, you may want to place a series of breadcrumbs to give the user a sense of context and give them a way to navigate up the tree to projects which might contain the current project as a subproject. To configure breadcrumbs, add a breadcrumbs element to the body element in the site descriptor. Each item element will render a link, and the items in the breadcrumbs element will be rendered in order. The breadcrumb items should be listed from highest level to lowest level. In the following site descriptor, the Codehaus item would be seen to contain the Mojo item.
Configuring the Site?s Breadcrumbs.
...
...
...
10.8.4. Add the Project Version
When you are documenting a project that has multiple versions, it is often very helpful to list the project?s version number on every page. To display your project?s version on the website, simply add the version element to your site descriptor:
Positioning the Version Information.
...
...
This will position the version (in the case of the sample-project project, it will say "Version: 1.0-SNAPSHOT") in the upper left-hand corner of the site, right next to the default "Last Published" date. Valid positions for the project version are:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the version entirely
10.8.5. Modify the Publication Date Format and Location
In some cases, you may wish to reformat or reposition the "Last Published" date for your project website. Just like the project version tip above, you can specify the position of the publication date by using one of the following:
left
Left side of the bar just below the site logo
right
Right side of the bar just below the site logo
navigation-top
Top of the menu
navigation-bottom
Bottom of the menu
none
Suppress the publication entirely
Positioning the Publish Date.
...
...
By default, the publication date will be formatted using the date format string MM/dd/yyyy. You can change this format by using the standard notation found in the JavaDocs for SimpleDateFormat (see JavaDoc for SimpleDateFormat for more information). To reformat the date using yyyy-MM-dd, use the following publishDate element.
Configuring the Publish Date Format.
...
...
10.8.6. Using Doxia Macros
In addition to its advanced document rendering features, Doxia also provides a macro engine that allows each input format to trigger injection of dynamic content. An excellent example of this is the snippet macro, which allows a document to pull a code snippet out of a source file that?s available via HTTP. Using this macro, a small fragment of APT can be rendered into XHTML. The following APT code calls out to the snippet macro. Please note that this code should be on a single continuous line, the black slash character is inserted to denote a line break so that this code will fit on the printed page.
%{snippet|id=modello-model|url=http://svn.apache.org/repos/asf/maven/\
archetype/trunk/maven-archetype/maven-archetype-model/src/main/\
mdo/archetype.mdo}
Output of the Snippet Macro in XHTML.
archetypeArchetype
]]>packageorg.apache.maven.archetype.modelArchetypeModelDescribes the assembly layout and packaging.1.0.0id1.0.0trueString
...
Warning
Doxia macros MUST NOT be indented in APT source documents. Doing so will result in the APT parser skipping the macro altogether.
For more information about defining snippets in your code for reference by the snippet macro, see the Guide to the Snippet Macro on the Maven website, at http://maven.apache.org/guides/mini/guide-snippet-macro.html.
Prev : 10.7. Customizing Site Appearance
TOC
Next : Chapter 11. Writing Plugins
Nexus Professional
Access a live demo of the Pro Suite Install a trial version of Nexus Professional on your own machine Purchase a license for Nexus Professional
Recent Posts
Last Chance To Register: Insight for CI Demo
Insight for CI Demo: Additional Session Added
When Licenses Meet Reality, the Result is Often Confusing
How does Insight handle conflicting OSS licenses?
New Webinar: Gain Visibility & Control At Build Time with Insight for CI
"What is eCPM? What affects my eCPM? What can I do to earn a higher eCPM?" Effective cost per thousand impressions (eCPM) is the amount of revenue you can expect to earn from AdSense for every 1000 impressions shown on your site. Since eCPM helps you measure how well your ads are performing, we often hear questions from publishers about the factors that impact this metric and how it relates to their earnings. If you're using the new interface, you'll see that your reports show RPM (revenue per thousand impressions); RPM is just another term for eCPM, and it's calculated the same way, so we use these two terms interchangeably. To help provide some clarity, we're kicking off a two-part video series with more insights into how eCPM is calculated in order to help you maximize earnings. With the help of AdSense optimization specialist, Matthew Carpenter Arevalo, we'll show you the factors that affect eCPM, how to track user behavior and traffic patterns, and ...
Comments