Sonatype

Previous: Chapter 5
Next: Chapter 7

Never confuse motion with action. -- Benjamin Franklin

Introduction

Plugins are the core of the Maven framework. At its heart, Maven is a plugin execution framework, with goals as the unit of execution. A plugin contains a set of goals with some theme, such as "ear" (with goals that package an ear, and generate-application-xml), or "resources" (with resources, testResources). Plugins may also manipulate the build lifecycle if they introduce a new packaging type, as shown in the previous chapter, but hijacking the lifecycle only scratches the surface of what plugins are capable.

A Quick Look at Plugin Name Resolution

Before we continue let us quickly cover a nagging point you may or may not have noticed. Up until we have simplified our treatment of plugin names for ease of discussion - but its grown-up time now and we need to raise our consciousness a little - to paraphrase Richard Dawkins. When we speak of the clean:clean goal, or the ear plugin, those are truncated versions of the actual plugin coordinates, and the plugin names. For example the clean:clean goal is actually named "org.apache.maven.plugins:maven-clean-plugin:clean", or you may even execute a specific verion of the goal by adding it after the plugin name, such as "org.apache.maven.plugins:maven-clean-plugin:2.1.1:clean".

If you execute "mvn org.apache.maven.plugins:maven-clean-plugin:clean" on the command line you will get the same results as "mvn clean:clean". This is due to two reasons. Reason one is: when no groupId is specified for a plugin Maven defaults to "org.apache.maven.plugins". In the POM plugin definition block, notice the lack of a groupId.

<project>
  ...
  <build>
    ...
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
        </configuration>
      </plugin>
    </plugins>

This also holds true on the command-line. By default org.apache.maven.plugins and org.codehaus.mojo are on a list of goals that need not be prefixed in the command-line. You can add more to that list - for example com.training.plugins - to your settings.xml pluginGroups element.

<settings>
  ...
  <pluginGroups>
    <pluginGroup>com.training.plugins</pluginGroup>
  </pluginGroups>
</settings>

You may now execute mvn maven-zip-plugin:zip

Note: The above information is correct as of Maven version 2.0.7, earlier versions would not honor plugin names that supercede found plugins in the two default plugin groups

from website: [The second reason the command-line is shortened is because <<<maven-${name}-plugin>> and ${name}-maven-plugin artifactId patterns are treated in a special way. If no plugin matches the artifactId specified on the command line, Maven will try expanding the artifactId to these patterns in that order. So in the case of our example, you can use mvn sample.plugin:hello:sayhi to run your plugin.]> Because of this the zip plugin execution can be even shorter: mvn zip:zip. All core Maven plugins and other official Maven project follow one of the two conventions.

Configuring Plugins

Using plugins in Maven seems trivial - you add them to the build element's plugins list and configure them. What can make this simple process seem complex is that each plugin has its own set of configurations (sometimes nested configurations). Before you get scared off, however, remember a core Maven principle is convention over configuration. This leads Maven's mojos to contain acceptable defaults. But there will be times where a goal actually requires a configuration to execute properly, for example the antrun plugin. Without an element configuring ant tasks or at least a file to execute, the run goal does nothing.

Plugins are configured under the "build" element. We know that plugin goals have default configurations, and that certain goals are bound by default bound certain phases of the build lifecycle, dependent upon the type of project being built. However, you will occasionally want to make certain changes to this default, some we have mentioned, and some not:

The first three items in the list all use the configuration element of the plugin, but to different ends. Configuring a plugin or goal that already exists in the lifecycle is the simplest. In the parent killerapp project you will notice the maven-compiler-plugin is configured to compile at JDK 1.4 (which is actually the default JDK).

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.4</source>
          <target>1.4</target>
        </configuration>
      </plugin>

You may wonder why the plugin is configured, rather than the goal. Do goals not do all of the actual work? Yes, they do. This is merely a shortcut for configuring all goals in the plugin with the same configuration. If we were to configure all of the compiler goals, the configuration would instead look like this:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>testCompile</goal>
            </goals>
            <configuration>
              <source>1.4</source>
              <target>1.4</target>
            </configuration>
          </execution>
        </executions>
      </plugin>

Notice that executions contain a set of goals? This is because, as shown above, a configuration may be shared between multiple goals, or because several goals may be bound to a single phase. Execution ids need not be unique, but executions with matching ids are merged - executing once on multiple phases if need be.

The second type of configuration is a plugin or specific goal not in the lifecycle. This method of configuration is the same as the other two, but the use-case is different. A good example is the antrun plugin, since the run goal does not default to a specific lifecycle. When you configure the antrun plugin

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <configuration>
          <tasks>
            <echo>The JAVA_HOME var is ${env.JAVA_HOME}</echo>
          </tasks>
        </configuration>
      </plugin>

It will not be executed by running any phase. To run, you must execute the goal mvn antrun:run

If it is bound to phase, for example verify, then it becomes the third type of plugin configuration.

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <configuration>
          <tasks>
            <echo>The JAVA_HOME var is ${env.JAVA_HOME}</echo>
          </tasks>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>run</goal>
            </goals>
            <phase>verify</phase>
          </execution>
        </executions>
      </plugin>

The fourth type of plugin configuration is useful when the plugin itself may wish to use a dependency that is not required by default. Sticking with the maven-antrun-plugin in the killerapp-model project:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <id>file-exists</id>
            <phase>pre-clean</phase>
            <goals>
                                <goal>run</goal>
                        </goals>
            <configuration>
              <tasks>
                <!-- adds the ant-contrib tasks (if/then/else used below) -->
                <taskdef resource="net/sf/antcontrib/antcontrib.properties"/>

                <available 
                    file="${project.build.directory}/${project.build.finalName}.jar" 
                    property="file.exists" value="true" />
                        <if>
                              <not><isset property="file.exists" /></not>
                          <then><echo>No ${project.build.finalName}.${project.packaging} to delete</echo></then>
                          <else><echo>Deleting ${project.build.finalName}.${project.packaging}</echo></else>
                        </if>
              </tasks>
            </configuration>
          </execution>
        </executions>
                <dependencies>
          <dependency>
            <groupId>ant-contrib</groupId>
            <artifactId>ant-contrib</artifactId>
            <version>1.0b2</version>
          </dependency>
                </dependencies>
      </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

The last reason for plugin configuration was first explored in Chapter 4 when we created the zip packaging type. To understand precisely what it means to add a plugin extension requires us to understand the basics of Inversion of Control and how Maven uses Plexus to manage its dependency injection defined in the configuration.xml files. We will explore what this means later in this chapter, but for now suffice it to say that this element hints to Maven that it should add this plugin to its running classloader.

Gotcha: When executing a plugin from the command line, you must put the configuration tag outside of the <<<executions>> element, else you may get an error similar to:>

One or more required plugin parameters are invalid/missing for 'plugin:goal'

This make sense when you consider that the plugin element is the domain of direct interaction (such as, the command-line), while the execution is for a very specifically defined execution.

The examples above show the "why" of the configuration syntax. The following will show how to perform common configuration for commonly used plugins and goals.

Default Lifecycle Plugins

maven-resources-plugin - process-resource, process-test-resource

We have mentioned earlier that resources are non-source-code files used by your project. We have also relayed the notion of filtering resource text files. But text files come in several flavors, or encodings. Maven's resources plugin supports the types supported by Java, defaulting to the installed JRE's default, but changable to: US-ASCII, ISO-8859-1, UTF-8, UTF-16BE, UTF-16LE, and UTF-16.

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <configuration>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>

The management of resources is so integral to Maven that they are largely configured by more POM elements than just the configuration block. The resources and testResources have their own elements - which we have encountered before; resource and testResources, respectively. Beyond the simple configuration of adding new resource directories, the resources element can also set a specific output directory with the targetPath, and include/exclude specific files for processing by the resources goals.

<project>
  ...
  <build>
    <resources>
      <resource>
        <directory>src/my-properties</directory>
        <targetPath>META-INF</targetPath>
        <filtering>true</filtering>
        <excludes>
          <exclude>**/*test*.properties</exclude>
        </excludes>
      </resource>
    </resources>

    <testResources>
      <testResource>
        <directory>src/my-test-properties</directory>
        <targetPath>META-INF</targetPath>
        <filtering>true</filtering>
        <includes>
          <include>**/*.properties</include>
        </includes>
      </testResource>
    </testResources>
  </build>

maven-compiler-plugin - compile, test-compile

We have already seen how to configure the compiler for a specific version of JDK. Note that you must be running Maven in at least that version. You cannot compile JDK 1.5 code if you are running Maven off of 1.4. However, you can configure the compiler plugin to use a javac other than the version Maven is currently running on (the default).

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <executable>/usr/bin/javac</executable>
          <compilerVersion>1.5</compilerVersion>
          <fork>true</fork>
        </configuration>
      </plugin>
    </plugins>

executable is the location of the javac version you wish to use. You must remember to always set fork to true to define your own compiler, otherwise it will not fork compile into a seperate process, thus using the default compiler inline.

The other commonly configured compiler property are arguments to the compiler, such as classpath. This setting only has relevence if the compiler is forked.

        <configuration>
          <compilerArguments>
            <classpath>${java.home}/lib/tools.jar</classpath>
          </compilerArguments>
        </configuration>

maven-surefire-plugin - test

Maven created the build lifecycle for a purpose... to give a well-defined sequence to every build. If you want to compile the source, you first need to verify that the project is kosher and generate and process sources and resources first.

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <skip>true</skip>
        </configuration>
      </plugin>

Sometimes it is necessary to turn off testing - almost every case is for development purposes. You can skip tests by setting the skip element to true, or by setting the maven.test.skip property. This property is useful through the command line via -Dmaven.test.skip=true. You should not normally turn off testing in a POM, so the command-line is the prefered method for development use.

surefire:test also has the ability to filter certain files for testing with includes and excludes elements, to add test scope system properties,

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>**/*Test.java</include> <!-- Only run tests ending with Test.java -->
          </includes>
          <systemProperties>
            <property>
              <name>sys.path</name>
              <value>${env.PATH}</value>
            </property>
          </systemProperties>
          <forkMode>pertest</forkMode>
          <argLine>-enableassertions</argLine>
        </configuration>
      </plugin>

Note that in order to use Surefire you must use one of its supported frameworks. By default this is junit, so in order to use it you must add it as a dependency:

  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifact>
    <version>3.8.1</version>
    <scope>test</scope>
  </dependency>

If you wish to use TestNG instead, add that as a dependency. The classifier must match the jdk version you wish to use, jdk14 or jdk15 (for Java 5 annotations).

  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>4.7</version>
    <scope>test</scope>
    <classifier>jdk15</classifier>
  </dependency>

maven-install-plugin - install

Installs files to the local repository. There is not much to configure in the install goal, but in the interest of completeness we will mention them here.

      <plugin>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <createChecksum>true</createChecksum>
          <updateReleaseInfo>true</updateReleaseInfo>
        </configuration>
      </plugin>

Set the createChecksum to true to generate some cryptographic hash checksum used to verify the integrity of all associated files (the pom file and artifacts). The updateReleaseInfo element is true if you want to update the local repository metadata file to set this as release. Both elements are false by default, and used mostly for development purposes.

These elements are almost never set permanently within the POM, but rather passed through to the command-line on occasion, by way of the -D flag (-DcreateChecksum=true).

maven-deploy-plugin - deploy

Deploy files using wagon, etc. Cover this in the repository section.

Packaging Types

maven-jar-plugin - jar, test-jar

The jar packaging type is the default for the POM, and is undoubtedly the most common type of Java project artifact. Simply running mvn package for a simple project will run this goal.

<project>
  <groupId>com.training.killerapp</groupId>
  <artifactId>killerapp-applet</artifactId>
  <version>1.0-SNAPSHOT</version>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <classifier>unsigned</classifier>
        </configuration>
      </plugin>
      ...
    </plugins>
  </build>
</project>

The classifier element is used to add an extra dimension to the jar coordinate. In the example above we create a jar with the classifier unsigned. This will simultaniously generate an artifact of the name ${project.build.finalName}-${classifier}.jar, as well as set the artifact's coordinate to be groupId:artifactId:packaging:classifier:version. This is useful when we have multiple similar artifacts available, generated from the same project but in slightly different ways. Perhaps we generate two jars for a project, one signed and one unsigned. When they are installed in the local repository, we may then use them by adding a classifier element to the dependency definition:

    <dependency>
      <groupId>com.training.killerapp</groupId>
      <artifactId>killerapp-applet</artifactId>
      <version>1.0-SNAPSHOT</version>
      <classifier>signed</classifier>
    </dependency>

The jar plugin goals generates a manifest file (META-INF/MANIFEST.MF) by default. There are several archive configuration elements for setting the desired values in the manifest file, such as the following example to give the JAR and entry point (making the jar executable).

        <configuration>
          <archive>
            <manifest>
              <mainClass>fully.qualified.MainClass</mainClass>
              <addClasspath>true</addClasspath>
            </manifest>
          </archive>
        </configuration>

Or use an existing one from the given location in your project structure:

        <configuration>
          <archive>
            <manifestFile>src/meta/MANIFEST.MF</manifestFile>
          </archive>
        </configuration>

As with all of the plugins we are going over, a more comprehensive list is in the Appendix B.

      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <executions>
           <execution>
              <goals>
                 <goal>sign</goal>
              </goals>
           </execution>
        </executions>
        <configuration>
           <keystore>/path/to/keystore</keystore>
           <alias>youralias</alias>
           <storepass>yourstorepassword</storepass>
           <signedjar>${project.build.finalName}-signed.jar</signedjar>
           <verify>true</verify>
        </configuration>
      </plugin>

If signedjar is not specified, then the plugin will generate the signedjar as your sole artifact. Setting "verify" to true automatically verifies the signed jar after generation. If this is set to false, you may still verify the jar at a later time via the jar:sign-verify goal.

maven-plugin-plugin - maven-plugin

Besides being just plain fun to say, this plugin defines the packaging type maven-plugin, and contains goals used for generating documents required for creating Maven plugins. Although it contains many goals, and it performs a fair amount of work, this plugin is not very configurable. About the only configuration you would wish to do it to specify the goal prefix.

      <plugin>
        <artifactId>maven-plugin-plugin</artifactId>
        <configuration>
          <goalPrefix>plugin</goalPrefix>
        </configuration>
      </plugin>

This specifies the string preceeding the goal name, before the colon (':') delimiter.

maven-ejb-plugin - ejb

Enterprise Java Beans (EJB) are commonly used Java EE data access framework which may split a single project into two parts, a client and server jar.

The most important (and required) configuration element is ejbVersion, which defaults to EJB version 2.1. If the version is less than 3.x (where x is any digit) the ejb-jar.xml file is required for packaging. The valid versions are 2.x and 3.x.

      <plugin>
        <artifactId>maven-ejb-plugin</artifactId>
        <configuration>
          <ejbVersion>3.0</ejbVersion>
        </configuration>
      </plugin>

Beyond that, the EJB configuration is fairly light. If you are running versions less than 3.0 you can generate a seperate client jar, but the default is false.

      <plugin>
        <artifactId>maven-ejb-plugin</artifactId>
        <configuration>
          <generateClient>true</generateClient>
          <clientIncludes>
            <clientInclude>**/**</clientInclude>
          </clientIncludes>
        </configuration>
      </plugin>

If you choose to generate a client, then you can set the clientInclude and clientExcludes elements to filter those specific files you wish included into the generated client EJB JAR. The defaults are:

  • clientIncludes: **/**
  • clientExcludes: **/*Bean.class, **/*CMP.class, **/*Session.class, **/package.html

Beyond the client generation information, the archive configuration element is available and the same as the archive element in the maven-jar-plugin goals.

maven-war-plugin - war

The most common Java web artifact is the Web Archive, or WAR.

The war packaging type looks to src/main/webapp for the web application files such as JSPs, but still looks for non-code files in the standard src/main/resources directory. Where you place files such as *.properties files is of personal choice, however, if you think you may filter the resources it is suggested that you place them in resources, not webapp.

Like the jar and ear plugins goals, the archive configuration element is available via the same MavenArchiveConfiguration settings. One important item of note is that many web containers use the classpath defined in the manifest in classloading. By default this is false, but you can set the value with the following:

      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
            </manifest>
          </archive>
        </configuration>
      </plugin>

The manifest classpath is constructed by the war project's compile and runtime scope dependencies and transitive dependencies which will appear in WEB-INF/lib.

        <configuration>
          <dependentWarIncludes>**/images</dependentWarIncludes>  
          <dependentWarExcludes>WEB-INF/web.xml,index.*</dependentWarExcludes>  
          <workDirectory>target/war/work</workDirectory>
        </configuration>

...Creating Skinny Wars, from the maven-war-plugin doc...

      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <configuration>
           <warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>
           <archive>
             <manifest>
               <addClasspath>true</addClasspath>
               <classpathPrefix>lib/</classpathPrefix>
             </manifest>
           </archive>
         </configuration>      
      </plugin>

Of course you will have to include these jars in the containing EAR, which leads us to the next plugin.

maven-ear-plugin - ear

The Enterprise Archive (EAR) is the last common packaging type configuration that we will cover. EARs are packages of other packaging types along with configuration files. The application.xml file is required, and can either be provided or generated via configuration of the generate-application-xml goal. For JBoss, the jboss-app.xml can also optionally be generated.

When generating application.xml, the most important piece is inclusion of modules.

      <plugin>
        <artifactId>maven-ear-plugin</artifactId>
        <configuration>
          <modules>
            <jarModule>
              <groupId>com.training.killerapp</groupId>
              <artifactId>killerapp-ejb</artifactId>
            </jarModule>
            <warModule>
              <groupId>com.training.killerapp</groupId>
              <artifactId>killerapp-war</artifactId>
              <contextRoot>/killerapp</contextRoot>
            </warModule>
            <artifactTypeMappings>
              <artifactTypeMapping type="zip" mapping="zip" />
            </artifactTypeMappings>
          </modules>
        </configuration>
      </plugin>

Above we show the jarModule (generated as javaModule in the descriptor file) and warModule with its context root (the access-point to the WAR model).

  • ejbClientModule
  • ejbModule
  • jarModule
  • parModule
  • rarModule
  • sarModule
  • webModule
  • wsrModule
  • harModule

Notice the artifactTypeMappings element, allowing the addition of new mapping types not defined by default.

...Using Skinny Wars, from the maven-war-plugin doc...

      <plugin>
        <artifactId>maven-ear-plugin</artifactId>
        <configuration>
          <defaultJavaBundleDir>lib</defaultJavaBundleDir>
        </configuration>
      </plugin>

From the maven-ear-plugin doc...

JBoss Support

The EAR plugin can generate the jboss-app.xml automatically. To do so, the 'jboss' element must be configured and takes the following child elements:

  • version: the targeted JBoss version to use (3.2 or 4 which is the default).
  • security-domain: the JNDI name of the security manager (JBoss 4 only)
  • unauthenticated-principal: the unauthenticated principal (JBoss 4 only)
  • jmx-name: the object name of the ear mbean.

Hibernate archives (HAR) and Service archives (SAR) will be recognized automatically and added the the jboss-app.xml file.

You can take a look at the examples for more information on the JBoss support.

      <plugin>
        <configuration>
          <jboss>
            <version>4</version>
            <unauthenticated-principal>guest</unauthenticated-principal>
          </jboss>
        </configuration>
      </plugin>

Non-Lifecycle Tools (Stand-Alone Goals)

The following goals are not meant to be attached to any phase, so it goes without saying that they are not bound by default.

maven-install-plugin:install-file

This is a command-line only goal to manually install a project to the local repository. You may wish to install a jar manually for several reasons, but the most common is for licensing issues, which make the artifact unable to be deployed to a remote repository. Or simply because the artifact is not a "Mavenized" project.

mvn install:install-file  -Dfile=/path/to/commercial.jar \
                          -DgroupId=com.training.killerapp \
                          -DartifactId=killerapp-commercial \
                          -Dversion=1.0 \
                          -Dpackaging=jar \
                          -DgeneratePom=true

Rather than have the pom file be generated by the goal, you may instead set the path to a custom pom file, which sets the coordinate elements.

mvn install:install-file  -Dfile=/path/to/commercial.jar \
                          -DpomFile=/path/to/pom.xml

maven-deploy-plugin:deploy-file

The install-file goal has a corrosponding goal in deploy-file for deployment. The difference being that a URL must be given so the goal knows where and how to deploy to the remote repository.

mvn deploy:deploy-file -Durl=file:///path/to/repo \
                          -DrepositoryId=my-local-repo \
                          -Dfile=/path/to/commercial.jar \
                          -DgroupId=com.training.killerapp \
                          -DartifactId=killerapp-commercial \
                          -Dversion=1.0 \
                          -Dpackaging=jar \
                          -DgeneratePom=true

There is actually much more involved with the creation and deployment of a remote repository, and will be covered in the next chapter.

maven-ant-plugin:ant

Ant does not need to be seen as a competing tool to Maven. In fact, Maven can handle Ant build scripts quite well through the maven-antrun-plugin. The converse of this plugin is the maven-ant-plugin that actually generates an Ant maven-build.xml file which may be imported into any build.xml file. This goal is a good example of a goal that is not configurable (in any interesting way). This goal places the generated file in the ${basedir} directory.

maven-assembly-plugin:assembly

When no packaging type exists that creates the type of zipped artifact bundle you desire, the assembly plugin is a decent solution. Although it is almost always preferable to use an existing plugin, sometimes it is not feasable or desired to create an entire plugin simply to create a zip file (which is why there is no zip packaging type by default - if you were wondering).

The assembly:assembly goal, unlike the assembly:attached goal shown below, will fork its own lifecycle, so it is necessary to run assembly:assembly, and never bind the goal to a phase.

Note: There is plenty of information on the assembly plugin in Chapter 10: Assemblies.

Lifecycle-Bound Tools

maven-jar-plugin:test-jar

There are occasions where you may wish to re-use test cases in multiple places. This is the purpose of the test-jar goal which packages the test artifacts into a test-jar type. This goal is meant to be bound to be bound to the package phase, which it does by default.

     <plugin>
       <artifactId>maven-jar-plugin</artifactId>
       <executions>
         <execution>
           <goals>
             <goal>test-jar</goal>
           </goals>
         </execution>
       </executions>
     </plugin>

Like any other type any project may use the project's test-jar artifact by adding it to its dependency list.

    <dependency>
      <groupId>com.training.killerapp</groupId>
      <artifactId>killerapp-api</artifactId>
      <version>1.0-SNAPSHOT</version>
      <type>test-jar</type>
      <scope>test</scope>
    </dependency>

Isn't Maven swell?

maven-source-plugin:jar, test-jar

The sources plugin packages the sourcecode (as well as generated sourcecode from the generate-sources phase, or generate-test-sources) into a jar suffixed with the -sources flag, or -test-source by default for the goals jar and test-jar, respectively. They default to being bound to the package phase. By default the source artifacts attach themselves to the project, but that can be surpressed via the attach flag (though the use-cases for such behavior are rare).

    <plugin>
      <artifactId>maven-source-plugin</artifactId>
      <executions>
        <execution>
          <id>source-jar</id>
          <goals>
            <goal>jar</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <finalName>${project.build.finalName}-my-sources.jar</finalName>
        <attach>false</attach>
      </configuration>
    </plugin>

maven-antrun-plugin:run

The maven-antrun-plugin is diametric to maven-ant-plugin. Where the ant:ant goal creates a build file from an existing project, the antrun:run goal executes either tasks inline the POM configuration, or external to a build.xml file.

maven-assembly-plugin:attached

The definition of this goal is the same as the assembly:assembly goal shown above, with an important cavet. Where assembly spawns a seperate build lifecycle when executed, the attached goal is meant to be attached to a phase manually.

    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>attached</goal>
          </goals>
          <phase>package</phase>
        </execution>
        <configuration>
        </configuration>
      </executions>
    </plugin>

If you were to attempt to bind the assembly:assembly goal to a lifecycle phase, the results could be surprising. Once Maven reached the specified phase bound to assembly, the assembly goal would then fork a new build lifecycle, effectively executing all of the goals twice. This is rarely what is desired.

Look to configurations. Since plugins are released on their own schedules and not bound to the Maven core, changes can and do happen often. Although the Appendix B of this book is a good reference for goal configuration values, the Maven website plugin documentation should be considered the definitive documentation on the subject.

Summary

Plugins are the core of Maven's ability to perform actions. Plugins are, at their heart, just like any other Maven artifacts complete with dependencies and parents. The big difference is that, with a packaging type of maven-plugin and some annotated Mojos - they are recognized within Maven as special artifacts that can be executed to perform whatever action the Mojo was written to perform. We call the action that a Mojo performs a "goal" - these goals form the backbone of all executions that Maven performs. The ability to manipulate and manage goals forms the backbone of Maven - turning it from a simple project mangement system, to a full-blown convention-over-configuration-based build system.


Previous: Chapter 5
Next: Chapter 7