JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy
  • Contact Us

Unknown Lifecycle Phase Error in Maven Build

May 25, 2014 by Krishna Srinivasan Leave a Comment

If you are working with the maven build, there is more chance that you would have come across the error something like this:

[code lang=”java”]
[ERROR] Unknown lifecycle phase "test1". You must specify a valid lifecycle phase or a goal
in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-
version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources,
process-sources, generate-resources, process-resources, compile, process-classes, generate-
test-sources, process-test-sources, generate-test-resources, process-test-resources, test-
compile, process-test-classes, test, prepare-package, package, pre-integration-test,
integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean,
pre-site, site, post-site, site-deploy. -> [Help 1]

[/code]

If you look at the above error “Unknown lifecycle phase”, your build could not detect the pre-defined lifecycle phase used by Maven. Maven has the following phases:

  • validate – validate the project is correct and all necessary information is available
  • compile – compile the source code of the project
  • test – test the compiled source code using a suitable unit testing framework. These tests should not require the code be packaged or deployed
  • package – take the compiled code and package it in its distributable format, such as a JAR.
  • integration-test – process and deploy the package if necessary into an environment where integration tests can be run
  • verify – run any checks to verify the package is valid and meets quality criteria
  • install – install the package into the local repository, for use as a dependency in other projects locally
  • deploy – done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.

You have to specify any one of the above phase to resolve the above error. In most of the situations, this would have occurred due to running the build from the eclipse environment. Look at the below screenshot,

Spring MVC Build Maven Error

If you look at the above screenshot, you have to provide the lifecycle name in the “Goals” field. I hope this solution helps you to resolve this error.

Filed Under: Apache Maven

Create Web Application Project With Maven

October 13, 2013 by Krishna Srinivasan Leave a Comment

This is a simple tutorial explaining how to set up your Web Application Project With Maven and then how it can be converted to the eclipse project. If you have earlier used ANT tool for building the Java projects, it is little difficult to understand the working method for the Maven at first. Maven is not just for the building, it is used for managing the dependencies used in our projects.

In the current scenario, almost every project is moved to the Maven style plugin. Spring Framework is not distributing the binaries to download from their website, they are recommending to use the Maven repositories to get the latest packages. It becomes important for everyone understand how to set up maven project.

1. Install Maven

As a first step, you have to install the Maven tool in your system and set all the environment variables. You can find simple tutorials on setting up maven tools and Ubuntu and Windows. I personally write this tutorial on Ubuntu environment, all my examples are mostly tested in the Ubuntu environment. If you have issues on setting up the environment, please post your questions on comments section.

2. Create Web Project Using Maven

Once you have installed the Maven, it is time to create web project using the console. This tutorial is based on creating the projects in console, not using the eclipse IDE. If you become familiar with this idea, it is very easy for to understand how Maven works. Follow these steps:

  1. Open the console and enter the command “mvn archetype:generate -DgroupId=javabeat.net -DartifactId=MavenTestWebProject -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false”.
    • DgroupId – This parameter specifying the package path
    • DartifactId – This parameter specifies actual project name
    • DarchetypeArtifactId – This parameter specifies the type of project. maven-archetype-webapp is a standard command for creating the web projects. If you want to create simple Java project, then use the parameter maven-archetype-quickstart.
  2. Note that you have the write permission for the current folder when executing the command.
    • If you don’t have the proper right permission, you may get the error org.apache.maven.BuildFailureException: Error merging velocity templates. This error mostly occurs in the Linux environment. You have to change the write permission to 777 to make it work. Just execute the command sudo chmode 777 / in the current directory.
  3. You should see the console with BUILD SUCCESS message to confirm that set up is right.

You would see the below messages if the build is success.

[code lang=”java”]

krishna@krishna-desktop:~/workspace$ mvn archetype:generate -DgroupId=javabeat.net -DartifactId=MavenTestWebProject -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
[INFO] Scanning for projects…
[INFO]
[INFO] ————————————————————————
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ————————————————————————
[INFO]
[INFO] >>> maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] — maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom —
[INFO] Generating project in Batch mode
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] —————————————————————————-
[INFO] Parameter: groupId, Value: javabeat.net
[INFO] Parameter: packageName, Value: javabeat.net
[INFO] Parameter: package, Value: javabeat.net
[INFO] Parameter: artifactId, Value: MavenTestWebProject
[INFO] Parameter: basedir, Value: /home/krishna/workspace
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /home/krishna/workspace/MavenTestWebProject
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 28.279s
[INFO] Finished at: Sun Oct 13 07:56:57 IST 2013
[INFO] Final Memory: 9M/70M
[INFO] ————————————————————————

[/code]

3. Migrate To Eclipse Project

The above steps are only for creating the project in Maven. But, most of the developers are using Eclipse IDE to maintain the Java projects. It is necessary to make the Maven project compatible to Eclipse IDE. It is easily accomplished by executing a command as follows:

[code lang=”java”]
mvn eclipse:eclipse -Dwtpversion=2.0
[/code]

-Dwtpversion=2.0 is extra parameter to tell the Maven that it is a web project.

4. Project Structure in Maven

When you create Java projects in maven or want to work with Maven, the project structures has to be followed. Look at the figure below to know the typical project structure you would see once build is success.

Maven Project Structure

5. POM.xml

pom.xml is the build script for the Maven enabled projects. For our example, initially created file would look like this:

[code lang=”xml”]
<pre><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>javabeat.net</groupId>
<artifactId>SpringMVCTestFramework</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringMVCTestFramework Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringMVCTestFramework</finalName>
</build>
</project>
[/code]

It is done. You have successfully created the maven project in Eclipse. This tutorial explains only how to setup the project, not to run the projects. I would write few more articles about how to build and run the applications using Maven tools. Hope this article helped you to configure Maven in your system. If you have any questions, please write it in the comments section.

Filed Under: Apache Maven Tagged With: Maven

How To Install Maven On Windows?

October 3, 2013 by Krishna Srinivasan Leave a Comment

In my previous article I have written about how to install Maven in Ubuntu?. It is much easier in the Linux OS then setting up in the Windows OS. As we know, Linux does the installation through its package manager and there is no need for the mannual settings of path or anything else. In windows, it’s quite easy too but we need to alter the set of environment variables to make it work. It is very easy to set up using the following steps. (Read : What is Maven? and Custom Plug-In for Maven).

1. Install Maven

Download the maven package from here and extract the zip file to the appropriate location. The toot folder
D:\Softwares\apache-maven-3.1.0
is the M2_HOME values when you are setting the environment variables. There is nothing else to be done for installing the maven package.

2. Set M2_HOME

Open the environment variables for your computer and set the M2_HOME as the maven’s home folder. Be sure to omit any quotation marks around the path even if it contains spaces. Also add the M2 variable in the environemnt variables section as “%M2_HOME%\bin”. Using the same dialog, add the MAVEN_OPTS environment variable in the user variables section to pass the JVM properties, e.g. the value -Xms256m -Xmx512m. This environment variable can be used to supply extra options to Maven.
This is only optional parameter.

Maven Settings

3. Set Path

Add/ Update path variavles for environment and user sections. In the user variable, just append the %M2% to reflect the maven bin folder. In the environment variables section, update the path variable by appending %M2_HOME%\bin.

4. Verify the Maven Installation

The above steps ensure that all the required libraries are in the classpath. Now it is the time to check if the maven is installed properly. Open the command prompt and type mvn –version. If this results in the version details of the maven package, then it is installed properly. Otherwise verify the above steps if you have given the correct path for all the variables. mvn –version would out put the following details on your screen.

[java]

D:\>mvn –version
Apache Maven 3.1.0 (893ca28a1da9d5f51ac03827af98bb730128f9f2; 2013-06-28 07:45:3
2+0530)
Maven home: D:\Softwares\apache-maven-3.1.0
Java version: 1.6.0_25, vendor: Sun Microsystems Inc.
Java home: C:\Program Files\Java\jdk1.6.0_25\jre
Default locale: en_US, platform encoding: Cp1252
OS name: "windows 7", version: "6.1", arch: "x86", family: "windows"
D:\>

[/java]

Filed Under: Apache Maven Tagged With: Maven, Windows

How To Install Maven On Ubuntu?

October 1, 2013 by Krishna Srinivasan Leave a Comment

Apache Maven is project management tool which is following the concept of a project object model (POM). Maven can manage project’s build and documentation from a central place. Maven 1 actually was started as a sub project of Apache Turbine in 2002. It was released in July 2004 as v1.0. Maven 2 was released in Oct 2005. It was a complete rewrite of the previous project. It was not backward compatible. Maven 3 was released in October 2010 (Read : What is Apache Maven?).

This tutorial explains the steps to install the maven on Ubuntu 12.0.

1. Get Maven Package

Open the terminal and type the command $ apt-cache search maven. The command prompt will display the available packages which is matching the maven word. In the list, you also can see maven – Java software project management and comprehension tool. This package will always have the latest package.

Search Maven in Ubuntu

2. Install The Package

Run the command $ sudo apt-get install maven through the same above terminal. It will ask for the root password and some confirmation messages. Just follow and answer the questions till the installation is completed. Since the installation is done by downloading the entire package, it takes several minutes to download the entire mavan files. Note that you should have internet connection for installing the maven through the command prompt. It is the easiest way to install the package. Wait till the installation is completed.

3. Test The Maven Installation in Ubuntu

Run the command mvn -version to check if the maven is installed properly. You will see the below description on the command prompt.

[java]

krishna@krishna-desktop:~$ mvn -version
Apache Maven 3.0.4
Maven home: /usr/share/maven
Java version: 1.6.0_27, vendor: Sun Microsystems Inc.
Java home: /usr/lib/jvm/java-6-openjdk-i386/jre
Default locale: en_IN, platform encoding: UTF-8
OS name: "linux", version: "3.2.0-51-generic", arch: "i386", family: "unix"

[/java]

Maven is installed successfully. I found the installation on Ubuntu is much simpler than installing on Windows operating system. I would continue writing few more tips on using the various tools on Ubuntu OS. It is great experience on using Ubuntu for developing the Java applications. I would recommend you to try once, then you will never look back.

  • Apache Maven for Beginners
  • How to write a Custom Plugin for Maven?

If you are facing any issues, please write it in the comments section.

Filed Under: Apache Maven Tagged With: Maven, Ubuntu

Creating Simple Web Application Using Apache Maven

February 23, 2013 by Manisha Patil Leave a Comment

In the previous post we saw how to create simple Java project using Maven. We will create a simple web application. The goal of this post is to highlight the basic features Maven provides to develop web applications. This post covers the following :

  • Create simple web application using Maven Archetype plugin.
  • Prepare the Tomcat Manager application.
  • Define Tomcat Server in Maven settings.
  • Point POM to Tomcat Server.
  • Build and Deploy the web application to Tomcat server.

If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here.

  • Apache Maven 2.0 – Maven Plugins
  • Buy: Apache Maven Implementation from flipkart.com

apache maven

Create Simple Web Application using Maven

To create a web application we will use maven-archetype-webapp plugin. Run mvn archetype:generate with an artifactId and a groupId. Open command line window, point to the desired directory (here we are creating project under C:MVNProject project) and execute the following command:

[java]
C:MVNProject&amp;gt;mvn archetype:generate -DgroupId=net.javabeat -DartifactId=SampleWebapp
-DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
[/java]

Maven Commands

    • mvn : is the Maven command.
    • archetype:generate : is called a Maven goal, analogous to an ANT target. It describes a unit of work to be completed in a build. The purpose of this goal is to quickly create(goal) a project from an archetype(plugin).
    • -Dname=value pairs : (DgroupId, DartifactId, DarchetypeArtifactId, DinteractiveMode) These are the arguments which are passed to the goal.They take the form of -D properties, similar to the system property options which you pass to the Java Virtual Machine via the command line.

The output on executing the above command is:

[java]
C:MVNProject&amp;gt;mvn archetype:generate -DgroupId=net.javabeat -DartifactId=SampleWebapp
-DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
[INFO] Scanning for projects…
Downloading: https://www.javabeat.net/pluginrepo1/org/codehaus/mojo/maven-metadata.xml
Downloading: https://www.javabeat.net/pluginrepo1/org/apache/maven/plugins/maven-metadata.xml
[WARNING] Could not transfer metadata org.apache.maven.plugins/maven-metadata.xml from pluginrepo1
(https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
[WARNING] Could not transfer metadata org.codehaus.mojo/maven-metadata.xml from pluginrepo1
(https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
Downloading: https://www.javabeat.net/pluginrepo1/org/apache/maven/plugins/maven-archetype-plugin/maven-metadata.xml
[WARNING] Could not transfer metadata org.apache.maven.plugins:maven-archetype-plugin/maven-metadata.xml
from pluginrepo1 (https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
[INFO]
[INFO] ————————————————————————
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ————————————————————————
Downloading: https://www.javabeat.net/pluginrepo1/org/apache/maven/plugins/maven-metadata.xml
Downloading: https://www.javabeat.net/pluginrepo1/org/codehaus/mojo/maven-metadata.xml
[WARNING] Could not transfer metadata org.apache.maven.plugins/maven-metadata.xml from pluginrepo1
(https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
[WARNING] Could not transfer metadata org.codehaus.mojo/maven-metadata.xml from pluginrepo1
(https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
Downloading: https://www.javabeat.net/pluginrepo1/org/apache/maven/plugins/maven-archetype-plugin/maven-metadata.xml
[WARNING] Could not transfer metadata org.apache.maven.plugins:maven-archetype-plugin/maven-metadata.xml
from pluginrepo1 (https://www.javabeat.net/pluginrepo1/): Error transferring file: Connection reset
[INFO]
[INFO] &amp;gt;&amp;gt;&amp;gt; maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom &amp;gt;&amp;gt;&amp;gt;
[INFO]
[INFO] &amp;lt;&amp;lt;&amp;lt; maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom &amp;lt;&amp;lt;&amp;lt;
[INFO]
[INFO] — maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom —
[INFO] Generating project in Batch mode
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] —————————————————————————-
[INFO] Parameter: groupId, Value: net.javabeat
[INFO] Parameter: packageName, Value: net.javabeat
[INFO] Parameter: package, Value: net.javabeat
[INFO] Parameter: artifactId, Value: SampleWebapp
[INFO] Parameter: basedir, Value: C:MVNProject
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] project created from Old (1.x) Archetype in dir: C:MVNProjectSampleWebapp
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 10:01.500s
[INFO] Finished at: Fri Feb 22 21:32:54 IST 2013
[INFO] Final Memory: 8M/24M
[INFO] ————————————————————————
[/java]

Maven creates the complete web based java application project structure as in the screen below:
webapp_struct

We see that a default pom.xml has been created. POM file generated is:

[java]
&amp;lt;project xmlns=&amp;quot;http://maven.apache.org/POM/4.0.0&amp;quot; xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;
xsi:schemaLocation=&amp;quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&amp;quot;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&amp;lt;groupId&amp;gt;net.javabeat&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;SampleWebapp&amp;lt;/artifactId&amp;gt;
&amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;name&amp;gt;SampleWebapp Maven Webapp&amp;lt;/name&amp;gt;
&amp;lt;url&amp;gt;http://maven.apache.org&amp;lt;/url&amp;gt;
&amp;lt;dependencies&amp;gt;
&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;/dependencies&amp;gt;
&amp;lt;build&amp;gt;
&amp;lt;finalName&amp;gt;SampleWebapp&amp;lt;/finalName&amp;gt;
&amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;
[/java]

Here we notice that the packaging element has a value war. A project with a war packaging creates a WAR file in the target directory. Default name of this file is ${artifactId}-${version}.war. Hence our WAR generated would be in target/SampleWebapp-1.0-SNAPSHOT.war. The element finalName customizes the name of the generated WAR.

Maven also created a sample JSP Source file index.jsp:

[java]
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h2&amp;gt;Hello World!&amp;lt;/h2&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
[/java]

Prepare the Tomcat Manager application

We will deploy our web application to Tomcat server. We first need to ensure that we can access the Tomcat Manager application at: http://localhost:8080/manager/html. Just ensure that the <tomcat>/conf/tomcat-users.xml file has the following defined:(where <tomcat> is the Tomcat installed directory).

[java]
&amp;lt;?xml version=’1.0′ encoding=’utf-8′?&amp;gt;
&amp;lt;tomcat-users&amp;gt;
&amp;lt;role rolename=&amp;quot;manager&amp;quot;/&amp;gt;
&amp;lt;role rolename=&amp;quot;admin&amp;quot;/&amp;gt;
&amp;lt;user username=&amp;quot;admin&amp;quot; password=&amp;quot;admin&amp;quot; roles=&amp;quot;admin,manager&amp;quot;/&amp;gt;
&amp;lt;/tomcat-users&amp;gt;
[/java]

To login into Tomcat Manager app we will use:

[java]

Username=admin
Password=admin

[/java]

 

Define Tomcat Server in Maven settings

Edit the Maven settings.xml (e.g:C:Documents and SettingsManisha.m2settings.xml), add a server myserver. Add the credentials to log into the Tomcat Manager application:

[java]
&amp;lt;settings&amp;gt;
&amp;lt;servers&amp;gt;
&amp;lt;server&amp;gt;
&amp;lt;id&amp;gt;myserver&amp;lt;/id&amp;gt;
&amp;lt;username&amp;gt;admin&amp;lt;/username&amp;gt;
&amp;lt;password&amp;gt;admin&amp;lt;/password&amp;gt;
&amp;lt;/server&amp;gt;
&amp;lt;/servers&amp;gt;
…….
…..
[/java]

Point POM to Tomcat Server

Edit section in the the pom.xml file (under the directory C:MVNProjectSampleWebapppom.xml) as follows:

[java]
&amp;lt;build&amp;gt;
&amp;lt;finalName&amp;gt;SampleWebapp&amp;lt;/finalName&amp;gt;
&amp;lt;plugins&amp;gt;
&amp;lt;plugin&amp;gt;
&amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;tomcat-maven-plugin&amp;lt;/artifactId&amp;gt;
&amp;lt;configuration&amp;gt;
&amp;lt;server&amp;gt;myserver&amp;lt;/server&amp;gt;
&amp;lt;path&amp;gt;/SampleWebapp&amp;lt;/path&amp;gt;
&amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;
[/java]

We have added the Tomcat plugin for Maven. The <configuration> section points to the server we defined in settings.xml (‘myserver’). Through <finalName> and the <path> we define the web context we want to deploy to. We’ll be able to access our application at http://localhost:8080/SampleWebapp.

Build and Deploy the web application to Tomcat server

Open the command window console, and go to the directory where pom.xml is located (C:MVNProjectSampleWebapppom.xml). Execute the following command:
mvn tomcat:deploy
If “BUILD SUCCESS” message appears, then access the application at:
http://localhost:8080/SampleWebapp/.
If you want to deploy again, then use the following command:
mvn tomcat:redeploy

Summary

  • Apache Maven 2.0 – Maven Plugins
  • Buy: Apache Maven Implementation from flipkart.com

In this post we did learn how to create a simple webapp using the Maven archetype plugin. We checked the directory structure and the generated source code. We then did learn about how to build and deploy this simple web app in the Tomcat server using Maven command. If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here.

Filed Under: Apache Maven Tagged With: Apache Maven

Creating Simple Java Project Using Apache Maven

February 20, 2013 by Manisha Patil Leave a Comment

Maven is a build and project management tool for java based application development. In previous article(“Apache Maven for Beginners“), we talked about installing and configuring maven on windows operating system. In this article, we shall see how to create a simple Maven project, check the created directories and build the project.

If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here.

  • Buy: Apache Maven Implementation from flipkart.com

Maven uses archetype plugins to create projects. To create a simple java application, we’ll use maven-archetype-quickstart plugin from command line. In the example below, We’ll create a maven based java application project in C:\MVNProject folder.

Open the command line window and type the below command, Maven creates a blank java project with all default options.

[java]
C:\MVNProject>mvn archetype:generate -DgroupId=net.javabeat -DartifactId=
SampleJavaProject -DarchetypeArtifactId=maven-archetype-quickstart
-DinteractiveMode=false
[/java]

Note: If you have just installed Maven, and if its your first run, it may take a while, because Maven downloads the most recent artifacts (plugin jars and other files) into your local repository (to your .m2 directory). You may also need to execute the command a couple of times before it succeeds. This is because the remote server may time out before your downloads are complete.

Maven commands

    • mvn : is the Maven command.
    • archetype:create : is called a Maven goal, analogous to an ANT target. It describes a unit of work to be completed in a build. The purpose of this goal is to quickly create(goal) a project from an archetype(plugin)
    • -Dname=value pairs : (DgroupId, DartifactId, DarchetypeArtifactId, DinteractiveMode) These are the arguments which are passed to the goal.They take the form of -D properties, similar to the system property options which you pass to the Java Virtual Machine via the command line.

The output on executing the above command is

[java]
[INFO] Scanning for projects…
[INFO] ————————————————————————
[INFO] Building Maven Stub Project (No POM) 1
[INFO] ————————————————————————
[INFO]
[INFO] >>> maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom >>>
[INFO]
[INFO] <<< maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom <<<
[INFO]
[INFO] — maven-archetype-plugin:2.0:generate (default-cli) @ standalone-pom —
[INFO] Generating project in Batch mode
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0
[INFO] —————————————————————————-
[INFO] Parameter: groupId, Value: net.javabeat
[INFO] Parameter: packageName, Value: net.javabeat
[INFO] Parameter: package, Value: net.javabeat
[INFO] Parameter: artifactId, Value: SampleJavaProject
[INFO] Parameter: basedir, Value: C:\MVNProject
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] ********************* End of debug info from resources from generated POM ***********************
[INFO] project created from Old (1.x) Archetype in dir: C:\MVNProject\SampleJavaProject
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 13:03.812s
[INFO] Finished at: Sun Feb 17 08:37:52 IST 2013
[INFO] Final Memory: 8M/24M
[INFO] ————————————————————————
[/java]

Once the project is created, a directory structure is created as shown below. This directory structure adheres to the standard Maven directory layout.

dir_struct
The details of the basic directories is as follows:

    • SampleJavaProject: This directory contains src folder and pom.xml. Maven Archetype plugin creates this directory, value matching the artifactId SampleJavaProject
    • src/main/java: This directory contains java code files under the package structure (net/javabeat).
    • src/main/test: This directory contains test java code files under the package structure (net/javabeat).

We see that a default pom.xml has been created. POM file generated is:

[java]
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.javabeat</groupId>
<artifactId>SampleJavaProject</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>SampleJavaProject</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
[/java]

Maven Archetype plugin also created a sample Java Source file(C:\MVNProject\SampleJavaProject\src\main\java\net\javabeat\App.java) and Java Test file(C:\MVNProject\SampleJavaProject\src\test\java\net\javabeat\AppTest.java).

App.java, is a single 13-line Java class, with a static main function that prints a simple “Hello World!” message.

[java]
package net.javabeat;

/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
[/java]

AppTest.java

[java]
package net.javabeat;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}

/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}

/**
* Rigourous Test 🙂
*/
public void testApp()
{
assertTrue( true );
}
}

[/java]

Build project

Once the project is created with the Maven Archetype plugin as seen above, we can build and package the application. To do so, run mvn install from the directory that contains the pom.xml(in our case it is C:\MVNProject\SampleJavaProject):

[java]
C:\MVNProject\SampleJavaProject>mvn install
[INFO] Scanning for projects…
[INFO]
[INFO] ————————————————————————
[INFO] Building SampleJavaProject 1.0-SNAPSHOT
[INFO] ————————————————————————
[INFO]
[INFO] — maven-resources-plugin:2.4.3:resources (default-resources) @ SampleJavaProject —
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\MVNProject\SampleJavaProject\src\main\resources
[INFO]
[INFO] — maven-compiler-plugin:2.3.2:compile (default-compile) @ SampleJavaProject —
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\MVNProject\SampleJavaProject\target\classes
[INFO]
[INFO] — maven-resources-plugin:2.4.3:testResources (default-testResources) @ SampleJavaProject —
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory C:\MVNProject\SampleJavaProject\src\test\resources
[INFO]
[INFO] — maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ SampleJavaProject —
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\MVNProject\SampleJavaProject\target\test-classes
[INFO]
[INFO] — maven-surefire-plugin:2.5:test (default-test) @ SampleJavaProject —
[INFO] Surefire report directory: C:\MVNProject\SampleJavaProject\target\surefire-reports

——————————————————-
T E S T S
——————————————————-
Running net.javabeat.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.453 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO]
[INFO] — maven-jar-plugin:2.3.1:jar (default-jar) @ SampleJavaProject —
[INFO] Building jar: C:\MVNProject\SampleJavaProject\target\SampleJavaProject-1.0-SNAPSHOT.jar
[INFO]
[INFO] — maven-install-plugin:2.3.1:install (default-install) @ SampleJavaProject —
[INFO] Installing C:\MVNProject\SampleJavaProject\target\SampleJavaProject-1.0-SNAPSHOT.jar to C:\Documents and Settings\Manisha\.m2\repository\net\javabeat\SampleJavaProject\1.0-SNAPSHOT\SampleJavaProject-1.0-SNAPSHOT.jar
[INFO] Installing C:\MVNProject\SampleJavaProject\pom.xml to C:\Documents and Settings\Manisha\.m2\repository\net\javabeat\SampleJavaProject\1.0-SNAPSHOT\SampleJavaProject-1.0-SNAPSHOT.pom
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 37.375s
[INFO] Finished at: Sun Feb 17 12:17:10 IST 2013
[INFO] Final Memory: 11M/27M
[INFO] ————————————————————————
[/java]

Executing the mvn install, we have just created, compiled, tested, packaged and installed the simple java project by Maven. We can also clean the target directories by using the clean command as mvn clean install.

Execute the program from command line as follows:

[java]
C:\MVNProject\SampleJavaProject\target\classes>java net.javabeat.App
Hello World!
[/java]

Summary

  • Buy: Apache Maven Implementation from flipkart.com

In this article we saw how to create a simple Java project using Maven archetype plugins. We checked the directory structure, the generated source code.We then did learn about how to build this simple Java project using Maven command.In the next article we shall create a web application project using Maven.

If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here.

Filed Under: Apache Maven Tagged With: Apache Maven

Apache Maven for Beginners

February 13, 2013 by Manisha Patil Leave a Comment

What is Maven?

Apache Maven is project management tool which is following the concept of a project object model (POM). Mavan can manage project’s build and documentation from a central place. Maven 1 actually was started as a sub project of Apache Turbine in 2002 (by Sonatype’s Jason van Zyl). It was released in July 2004 as v1.0. Maven 2 was released in Oct 2005. It was a complete rewrite of the previous project. It was not backward compatible.
Maven 3 was released in October 2010. It is same as Maven 2 but more stable. This article explores the very basic concepts needed for the beginners who want to learn and get started with the Maven. Before the popularity of using Maven, most of the projects used Ant Script for the projects build which is used only for the build purpose.

If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here.

apache maven

Maven Definition

Definition of Maven from the Maven site(http://maven.apache.org/):
“Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.

Maven is an open source software engineering platform. The intent of Maven is to make intra-project development highly manageable in the hopes of providing more time for cross-project development. You may say it as sharing of project development knowledge. The core functionality of Maven is automated project building, distribution and website creation.

Maven features

  • Dependency System: Superior dependency management including automatic updating, dependency closures (also known as transitive dependencies). Maven encourages the use of a central repository of JARs and other dependencies. Maven has a mechanism which helps your project’s clients to download any required JARs for building your project from a central JAR repository.This allows reuse of JARs across projects for Maven users.This also helps in dealing with backward compatibility issues.
  • Multi-module builds: Able to easily work with multiple projects at the same time
  • Consistent project structure: Consistent structure across all projects means no ramp up time for new developers coming onto a project
  • Consistent build model: Maven is able to build any number of projects into predefined output types such as a JAR, WAR, or distribution based on metadata about the project, without the need to do any scripting in most cases.
  • Plugin oriented: The Maven functionality is implemented in terms of plugins.
  • Project generated sites: Maven generates a website or a PDF file using the same metadata as for the build process.You can include any documentation to this site and the standard report about the state of development of the project.Examples of this information can be seen at the bottom of the left-hand navigation of this site under the “Project Information” and “Project Reports” sub menus.

Comparison of Maven with Apache ANT:

Major differences between Maven and ANT are:

  1. Maven is description of a project whereas ANT is development of a build script per project.
  2. Maven follows conventions like a common project directory structure whereas ANT needs to be told about the exactly where to find the source and where to put the output.
  3. Maven has invocation of defined goals (targets) whereas in ANT script you have invocation of project specific targets.
  4. Maven has build life cycle, standard project layout where as ANT doesn’t and it has too complex scripts(You have to define goals and goal dependencies). You have to attach a sequence of tasks to each goal manually.
  5. Maven has reusable plugins, repositories whereas ANT scripts are not reusable.
  6. Maven is declarative.All you have to do is create a pom.xml file and put your source in the default directory. Maven takes care of the rest.ANT is procdeural which means you need to tell it to compile,copy and then compress.

Maven POM

POM stands for Project Object Model.It describes following data about a project:

  1. Metadata: Location of Directories, Developers/Contributors, Dependencies, Repositories
  2. Dependencies (Transitive Dependencies), Inheritance, and Aggregation
  3. Key Elements
    • Project
    • Model Version
    • Group ID
    • Packaging
    • Artifact ID
    • Version
    • Name
    • URL
    • Description
    • Plugins
    • Profiles (Alternate build configurations)

(Note:Transitive Dependencies definition- A dependency that should be included when declaring project itself is a dependency.Example: ProjectA depends on ProjectB. If ProjectC depends on ProjectA then ProjectB is automatically included. Only compile and run time scopes are transitive)

POM has four categories

  1. General project information-this includes project information like name,URL for project,sponsor organization,list of developers,license for the project.
  2. Build settings-This include customization of default Maven build behaviour.
  3. Build environment-This inlcudes profiles that can be used and activated for working in different environments(example development server,production server).
  4. POM relationships-This includes inheritance of POM settings of parent projects.

Standard Directory Layout
structure

Install Maven

  1. Download the latest Maven from http://maven.apache.org/download.cgi.
    • The installed file is:apache-maven-3.0-bin.zip
    • Extract the archive to the directory you wish to install Maven.We have extracted to the following folder:
    • C:\tools\apache-maven-3.0
  2. Test Maven
    In order to test Maven setup,you need Java installed/configured on your machine.Assuming you have JDK installed at C:\Program Files\Java\jdk1.7.0_11\bin, execute the following commands which sets your System Environment with Java and Maven paths.[java]
    set MAVEN_HOME=C:\tools\apache-maven-3.0
    set MAVEN_OPTS=-Xms256m -Xmx512m
    set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_11
    set path=%path%,%JAVA_HOME%\bin;%MAVEN_HOME%\bin
    [/java]
  3. Verify Maven installation
    Open the command prompt and execute the following command:[java]c:\> mvn –version[/java]

    This should give the current installed version of Maven.

    [java]
    Apache Maven 3.0 (r1004208; 2010-10-04 17:20:56+0530)
    Java version: 1.7.0_11
    Java home: C:\Program Files\Java\jdk1.7.0_11\jre
    Default locale: en_US, platform encoding: Cp1252
    OS name: "windows xp" version: "5.1" arch: "x86" Family: "windows"
    [/java]

Basic User specific Maven Configuration

Now that you have installed Maven, it is a good idea to setup the .m2 directory, where Maven creates its local repository. To create .m2 directory, assuming “Manisha” is logged in user, open the command console and execute the following command, to create the .m2 directory.

[java]
mkdir C:\Documents and Settings\Manisha\.m2
[/java]

The settings.xml file(under the .m2 directory) contains user-specific configuration for authentication, repositories,and other information to customize the behavior of Maven. Sample settings file is:

[java]
<settings>
<servers>
<server>
<id>server1</id>
<username>user1</username>
<password>password1</password>
</server>
<server>
<id>server2</id>
<username>user2</username>
<password>password2</password>
</server>
<!– Server settings for repositories Ends –>
</servers>

<!– Mirror settings for repositories Starts –>
<mirrors>
<mirror>
<id>mirror1</id>
<name>Internal network access to any repository</name>
<mirrorOf>repo1</mirrorOf>
<url>https://www.javabeat.net/repo1/</url>
</mirror>
</mirrors>
<!– Mirror settings for repositories Ends –>
<!– Profiles settings for repositories Starts –>
<profiles>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>repo1</id>
<url>https://www.javabeat.net/repo1/</url>
</repository>
<pluginRepositories>
<pluginRepository>
<id>pluginrepo1</id>
<name>Repos (public/proxied)</name>
<url>https://www.javabeat.net/pluginrepo1/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</pluginRepository>
</profile>
</profiles>
<!– Profiles settings for repositories Ends –>
</settings>
[/java]

Summary

In this article we saw basic overview about Apache Maven, its installation and basic configuration.The next article would deal with creating a simple Java project using Maven. I would write the series of tutorials on Apache Maven and how to use Apache Maven in your projects. If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on  Java topics, please subscribe here.

Filed Under: Apache Maven Tagged With: Apache Maven

Apache Maven 2.0 – Maven Plugins

July 19, 2010 by Krishna Srinivasan Leave a Comment

This book offers a comprehensive look at using Maven on a project, covering not only the build system itself, but how it is best used in concert with other development infrastructures such as source control, continuous integration and build servers, and an artifact repository. We cover this territory using Subversion, Apache Continuum, and Apache Archiva, respectively, though the concepts learned should apply to other comparable systems.

In many ways, this is the book we’ve always wanted to write about Maven, and it takes a different approach to the existing Maven titles. Rather than being a reference or documentation for the software, it takes the approach of walking through a single example application and associated infrastructure in the same way that you would develop your own projects. For this purpose, we have crafted the example application Centrepoint—a simple but functional web application composed of several modules that itself interacts with Maven, Continuum, and Archiva.

apache maven

also read:

  • Buy: Apache Maven Implementation from flipkart.com
  • Ant Script
  • Creating Simple Java Project Using Apache Maven
  • Creating Simple Web Application Using Apache Maven

We believe this book will not only show you how to use Maven, but how to use it effectively, covering concepts and best practices that should endure beyond the current versions of Maven and apply to your development infrastructure and teams in general.

Apache Maven 2 Effective Implementation

What This Book Covers

Chapter 1: Maven in a Nutshell is a quick overview of the fundamentals of Maven—from creating a simple Maven project to basic plugin configuration to generating sites and reports. These are demonstrated in an easy to follow step-by-step process. By the end of the chapter, you should be able to apply and use the skills that you have learned to your own project.

Chapter 2: Staying in Control with Archiva introduces you to Archiva and its role in building software. You will learn the basics of installing and configuring it for internal use. It also shows you how Archiva complements Maven and how they can be used together efficiently.

Chapter 3: Building an Application Using Maven delves into the details on how to accurately set up and build an application using Maven. The Centrepoint project is introduced in this chapter. This is the sample application that will be used for the hands-on demonstrations throughout the book. You will see how Maven enforces convention over configuration while building the Centrepoint project.

Chapter 4: Application Testing with Maven goes through the various types of automated tests that can be executed from Maven. This includes unit testing, integration testing, and testing web applications using Selenium to name a few. Instrumenting tests, implementing test coverage, and reporting of test results are also covered.

Chapter 5: Reporting and Checks shows how to configure Maven to generate project reports and incorporate them in the generated site. This chapter also tackles the basics on enforcing certain rules or checks on your code such as conforming to code styles and standards, and finding common bugs in the code while building your application.

Chapter 6: Useful Maven Plugins discusses some of the Maven plugins, both from Apache Maven and from the Codehaus Mojo project, that may be of great help in your Maven builds. The functionality of these plugins range from keeping track of the source revision number for the build to executing external applications as part of the build. You will learn to identify when to use each plugin and how to configure them properly to address your need.

Chapter 7: Maven Best Practices illustrates the effective usage of Maven. You will learn tips and tricks for setting up your development environment to managing your project dependencies to making your builds portable and reproducible. By the end of this chapter, you should be able to apply what you’ve learned to your next project, or even to your current one.

Chapter 8: Continuum: Ensuring the health of your source code highlights the importance of continuous integration in software development through Continuum. It covers basic installation and set up, adding projects to Continuum, and effective configuration and build scheduling, at the same time demonstrating how it works in accordance with Maven and also with Archiva.

Chapter 9: Continuum in Depth deals with releasing projects using both Maven and Continuum. The different phases involved in the release process will be covered along with a bit of troubleshooting on the side. You will also learn about building multiple projects simultaneously in Continuum through parallel and distributed builds.

Chapter 10: Archiva in a Team gives you the more advanced features of Archiva and demonstrates how to configure it for use in a team. You will learn how to control access to a repository, how to take advantage of repository groups, how to make use of its reporting feature, and how to maintain your Archiva repositories.

Chapter 11: Archetypes covers Maven archetypes. It discusses some of the archetypes available—what their purpose is and what the generated project from each archetype looks like. You will also create a custom archetype specifically for the Centrepoint application, which will be used in the last chapter.

Chapter 12: Maven, Archiva, and Continuum in the Enterprise shows how to configure Archiva and Continuum effectively for use in the corporate environment. Tips on how to set up projects and repositories across multiple projects with respect to controlling who and what can be accessed by different teams covers the first half of the chapter. The second part demonstrates the web services feature of both applications by creating plugins for the Centrepoint application and using them to get information from Archiva and Continuum.

Appendix A: Troubleshooting Maven provides techniques for troubleshooting Maven. Incorrect POM or settings configuration, and dependency and download problems are a few of the usual suspects that will be covered here.

Appendix B: Recent Maven Features discusses the new features in Maven 2.1 and above. These features include password encryption, reactor project selection, and parallel downloads of dependencies.

Appendix C: Migrating Archiva and Continuum Data illustrates how to migrate data in Archiva and Continuum when upgrading to a higher version. How to switch to a different database from the built-in one is also discussed.

Useful Maven Plugins

Nobody can tell exactly how many Maven plugins exist today—since, like dependencies they can be retrieved from any specified remote repository, there are likely hundreds to choose from, and likely even more that have been custom written for use within the infrastructure of particular organizations. A common practice for frameworks and tools that require build integration is to publish a Maven plugin to accomplish the task—and it is becoming increasingly common to encounter this as a standard part of the getting started section of a project you might hope to use. However, there are also a number of plugins that would be considered general purpose and handle some extended build cases in a wider variety of projects.

In this chapter, we will take a closer look at some of these plugins from two locations: those hosted as part of the Apache Maven project (http://maven.apache.org/ plugins/), and a number of plugins from the Codehaus Mojo project (http://mojo.codehaus.org/plugins.html), which is oriented directly towards Maven plugin development. Some of these have been covered already in this book, so this will be an opportunity to examine their use in more depth, while others are new.

Where possible, we will apply the plugins to our example application to see how they can be used in practice, and then cover some of the other use cases and best practices for their use. While this won’t come close to covering all the plugins you are likely to encounter, with these common tools in your arsenal it will cover many of your Maven build needs, reducing the need for you to write your own plugins.

The Remote Resources plugin

Most projects will use the Resources plugin at some point, even if it isn’t configured directly—it is standard in the default life cycle for any packaging that produces some type of artifact, bundling the resources found in src/main/resources. However, what if you wanted to share those resources among multiple projects? The best approach to doing that is to store the resources in the repository and retrieve them for use in multiple builds—and that is where the Remote Resources plugin comes in.

First, we should note that this is not the only alternative for handling the scenario. The Dependency plugin’s unpack goal is also quite capable of unpacking an artifact full of resources directly into the location that will be packaged.

However, the Remote Resources plugin offers several advantages:

  1. Re-integration with the resources life cycle so that retrieved resources will automatically be processed in any goals in the process-resources phase.
  2. The ability to perform additional processing on the resources (including the optional use of Velocity templates to generate the resources) before inclusion.
  3. A specific bundle generation goal for creating the resource artifact in the
    first place.

These advantages can make the plugin very effective at dealing with some common scenarios. For example the inspiration for the creation of the plugin, and one of its more common uses, is to place aggregated license files within the final artifact.

[java]
There are other scenarios where the dependency:unpack goal
remains more suitable—for example, the bundling of plugin
configuration as seen in Chapter <i>5, Reporting and Checks</i>. It is
best to select the Remote Resources plugin when the files will be
incorporated into the resources life cycle and the Dependency
plugin when the files will be utilized independently.
[/java]

Let’s look at how to create a license file for our Centrepoint application. We will do this in two steps—the creation of the resource bundle that provides the generic resources for any project by the same organization, and the processing of the module resources.

Creating a Remote Resource bundle

Remote Resource bundles are regular JAR files packaged with additional information generated by the remote resource plugin’s bundle goal. Creating a module follows the same process as with other JAR files. In the example application, we will create the module outside of the Centrepoint
multi-module hierarchy, so that it could (theoretically) be used by other projects from the same organization. This could be anywhere in source control, but we will assume it sits side-by-side with the effectivemaven-parent module in the workspace.

[java]<b>
$ mvn archetype:generate -DartifactId=license-resources \
-DgroupId=com.effectivemaven
</b>[/java]

As this is not going to be a code project, the src/main/java and src/test directories can be removed from the generated content. We then continue to
add the parent project to the POM, so the result looks like the following:

[java] <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.effectivemaven</groupId>
<artifactId>effectivemaven-parent</artifactId>
<version>1-SNAPSHOT</version>
<relativePath>../effectivemaven-parent/pom.xml</relativePath>
</parent>
<artifactId>license-resources</artifactId>
<version>1.0-SNAPSHOT</version>
<name>License Resource Bundle</name>
</project>

[/java]

We will add the Remote Resources plugin shortly, but first let’s create the resources that will be bundled. These are added to the src/main/resources
like regular resources. Consider the following Velocity template file, src/main/resources/LICENSE.vm:

[java] ## License Generator
#macro(showUrl $url)
#if($url)
($url)
#end
#end
This software is distributed under the following license(s):
#foreach ($l in $project.licenses)
– $l.name #showUrl ($l.url)
#end
#if (!$projectsSortedByOrganization.isEmpty())
The software relies on a number of dependencies. The individual
licenses are outlined below.
#set ($keys = $projectsSortedByOrganization.keySet())
#foreach ($o in $keys)
From: ‘$o.name’ #showUrl($o.url)
#set ($projects = $projectsSortedByOrganization.get($o))
#foreach ($p in $projects)
– $p.name #showUrl ($p.url)
$p.artifact
#foreach ($l in $p.licenses)
License: $l.name #showUrl ($l.url)
#end
#end
#end
#end
[/java]

For those not familiar with Velocity, the purpose of this is to first iterate through the project’s licenses and list them, then secondly iterate through the project’s dependencies (grouped by the organization they are from) and list their license. The $projectsSortedByOrganization variable is a special one added by the Remote Resources plugin to assist in this task.

Before we can move on to use the bundle, we need to add the plugin to the bundle project like so:

[java]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<goals>
<b><goal>bundle</goal></b>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
[/java]

This goal is required to generate a bundle manifest, the contents of which tell the plugin which resources to process when it is later called on to do so.

With this all in place, we can now install the bundle into the local repository, ready for use:

[java]<b>
license-resources$ mvn install
</b>[/java]

If you were to inspect the contents of the generated JAR file, you would see both the LICENSE.vm file in the root, and the bundle manifest in META-INF/maven/remoteresources. xml. You would also find that the Velocity template is unmodified—the contents will be executed when the bundle is later processed in the target project, which we will proceed to look at now.

Processing Remote Resources in a project

Using the resource bundle we have created is now quite straightforward. We start by adding the folllowing to the build section of modules/pom.xml file of Centrepoint:

[java] <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<b><goals>
<goal>process</goal>
</goals></b>
</execution>
</executions>
<b><configuration>
<resourceBundles>
<resourceBundle>
com.effectivemaven:license-resources:1.0-SNAPSHOT
</resourceBundle>
</resourceBundles>
</configuration></b>
</plugin>
[/java]

Here we have added a list of resource bundle artifacts to the configuration for the process goal, in the familiar shorthand artifact notation of groupId:artifactId: version. It has been added to the modules POM so that the license is included in the JAR files, but not included in the other non-code modules such as the documentation (which already generates a copy of the license from the reporting plugins).

[java]
Normally, you should use a released version of the license bundle,
not a snapshot as we have here (as we have not yet covered the
release process!). Since the bundle is configured directly and not
through a dependency, the Release plugin will not detect this
unresolved snapshot later.
[/java]

Now, if we build a module such as store-api, we will see the license included in the root directory of the JAR file with the following content:

[java]
This software is distributed under the following license(s):
– The Apache Software License, Version 2.0
(http://www.apache.org/licenses/LICENSE-2.0.txt)
The software relies on a number of dependencies. The individual
licenses are outlined below.
From: ‘Apache Maven 2: Effective Implementations Book’
(http://www.effectivemaven.com/)
– Centrepoint Data Model
com.effectivemaven.centrepoint:model:jar:1.0-SNAPSHOT
License: The Apache Software License, Version 2.0
(http://www.apache.org/licenses/LICENSE-2.0.txt)
From: ‘Google’
(http://www.google.com/)
– Guice
(http://code.google.com/p/google-guice/)
com.google.code.guice:guice:pom:1.0
License: The Apache Software License, Version 2.0
(http://www.apache.org/licenses/LICENSE-2.0.txt)
[/java]

This is a good start, but we don’t really need to include our own artifacts in the list, so we go back to the plugin declaration in modules/pom.xml and add another line of configuration:

[java] <configuration>
<excludeGroupIds>${project.groupId}</excludeGroupIds>
<resourceBundles>
…
[/java]

Regenerating the above artifact will alter the license to remove the dependencies from the project’s group.

A different case is the final distribution. As this is not part of the modules hierarchy, first we need to include the plugin definition identical to the one added previously.

[java]
In the sample code for this chapter, you will notice that this has been
taken a step further with the version and common configuration pushed
into a pluginManagement section of the Centrepoint parent POM,
and just the execution of the plugin goal remains in the modules and
distribution POM files.
[/java]

We can now build the assembly as usual:

[java]<b>
distribution$ mvn clean install
</b>[/java]

Upon inspecting the generated assemblies, you will not see the license file included yet. This is because the Assembly plugin does not pick up Maven resources by default, as it does not participate in the normal life cycle.

To include the license file, we must alter the assembly descriptor distribution/src/main/assembly/bin.xml and add the following file set:

[java]
<fileSet>
<b><directory>target/maven-shared-archive-resources</directory></b>
<outputDirectory>/</outputDirectory>
</fileSet>
[/java]

The directory given is the standard location in which the Remote Resources plugin stores the resources it has processed, so if you decide to configure that differently in your own projects you would need to change this to the corresponding location.

Upon building the assembly again we will see that the license has been generated, and that it includes the licenses of dependencies outside of the Centepoint application. As you can see, the distributed application depends on Jetty (also under the Apache License 2.0), which includes some portions of Glassfish (under the CDDL 1.0 License).

[java]
While the above technique can be very helpful in constructing some
useful information about your project and its dependencies, it cannot be
guaranteed to produce complete licensing information for a project. The
method relies on accurate information in the POMs of your dependencies,
and this can sometimes be inaccurate (particularly when using
public repositories such as the Maven Central Repository). If you are
redistributing your files, always confirm that you have correctly recorded
any necessary licensing information that must accompany them!
[/java]

The Remote Resources plugin is also capable of covering other scenarios that are particularly suited to license handling or more generally recording information about the project it is being processed for. These include:

  1. The supplementalDataModels configuration option that allows you to fill in incomplete or incorrect metadata for a project dependency before the resources are processed (to avoid particular problems as described above).
  2. The appendedResourcesDirectory, which allows you to store the above models in a separate file.
  3. The properties configuration , which allows the injection of other build properties into the Velocity templates.

However, with this in mind, remember that the Remote Resources plugin is often just as suitable for any type of reusable resource, even if it is a static file.

The Build Number plugin

In Maven Mojos, the goals within a plugin are always designed to be simple tasks. Their aim is to do one thing, and do it well. A good example of this is the Build Number plugin. This simple plugin has one goal (create), with one purpose—to obtain a suitable build number and expose it to the build through properties or a file.

[java]
While the plugin focuses on exposing the current Subversion revision, it is
capable of generating an incremented build number (stored in a specified
properties file), and a representation of the current system date and
time. This feature can be very useful in identifying the exact heritage of
a particular build. The build number generated by the plugin is different
to that used by Maven to identify snapshots or artifact versions. While
it is possible that you might mark your version using the information
it generates, this plugin is typically used to record information about a
particular build—whether it is a snapshot, or a release—within the artifact
itself as a permanent record.
[/java]

Using the plugin is straightforward. By adding the goal to the project, the Subversion revision and a timestamp property will be exposed from the point
that it is run onwards.

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-1</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
[/java]

In this example, we execute the plugin in the generate-resources phase so that the properties are available to any resource processing. Note that the values could be used with the Remote Resources plugin that we have just seen.

There are two things to take into consideration with this configuration, however. Firstly, not all source builds will be Subversion checkouts, but the plugin does not verify that. To work around this potential problem, you can put the goal into a profile:

[java]
<profile>
<id>buildnumber</id>
<b><activation>
<file>
<exists>.svn</exists>
</file>
</activation></b>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
…
[/java]

This particular activation check will cause the profile to be used within a Subversion checkout (that is, if .svn exists in the current directory), and to skip the plugin if not. In this case, the properties will not be set (or the file will not be created), so the code using these must take that into account.

Secondly, how the values will be accessed needs to be given careful consideration. For example, it is unlikely that you want to create a convoluted build processing step to filter the value into a particular JSP file to appear in a web application. For the sake of keeping the build simple (and speedy), it is best to write the values into a single file that the application can then load from its classpath.

This can be achieved by creating a filtered resource that contains references to the values. The advantage of this method is that it is automatic if you have already configured filtered resources, and automatically ends up in the classpath of the application code that can load the file as a resource.

The plugin also supports a number of formatting options, in the event that you do not wish to use the raw build number and timestamp integers. These options are also used to trigger the manual build number increment feature of the plugin in the event that Subversion is not used.

As our example application is one such case, let’s apply this technique ourselves. We will only need to include the build number plugin in one location—if it were to be run on every module, the number would end up being different for each. Some seemingly sensible options may not actually be appropriate here:

  • The parent project will cause the build number to be included in every module, and executing it just in the parent may result in it not being
    executed at all.
  • The final distribution might be the best place in some situations, but what if you needed to reference the build number from the
    application itself?

Considering these factors, the best location is the web application module, as this will be the code which will eventually display the build number. In another application where multiple modules were to require it, it might be best generated in a common dependency instead.

The modules/webapp/pom.xml file requires two modifications. First, to enable filtering, we must add both the new filtered resources location and the original resources location to the build section (as Maven inheritance overrides resources instead of adding to them). This will look like the following:

[java]
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/filtered-resources</directory>
<filtering>true</filtering>
</resource>
</resources>
[/java]

Depending on what resources you have in src/main/resources, you may choose to do away with it and include them in the filtered-resources directory instead. However, if some resources may be corrupted by filtering (such as images and other binary files), you will need to retain both.

Next, the addition of the build number plugin is needed with some particular configuration:

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.0-beta-1</version>
<configuration>
<b><format>Build: #{0} ({1,date})</format>
<items>
<item>buildNumber\d*</item>
<item>timestamp</item>
</items></b>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
[/java]

Note the formatting options being used. The first, format, specifies what the configured property (by default called buildNumber) will look like, using the Java MessageFormat syntax. The items configuration provides a list of variables to substitute into the message format for {0}, {1}, and so on. Here, the first configured variable is buildNumber\d*, which is used to trigger the automatic number generation. The second is the integer timestamp that represents the current system date and time.

[java]
You may also configure the location of the file to be generated that
contains the incremented build number, with the default being
buildNumber.properties in the current directory. It is important to
place this in a location that will not be purged over time—for example, in
the target directory, as this is regularly cleaned!
[/java]

The exposed property is referenced from the resource files using the normal filtering syntax, so we can create src/main/filtered-resources/build.
properties like so:

[java]
build.message=${buildNumber}
[/java]

When we build the application, we will see the build number generated and incremented each time:

[java]<b>
[INFO] Storing buildNumber: Build: #1 (27/03/2009) at timestamp:
1238074038389
</b>[/java]

All that is left to do is to access the build number from the application, which you can see in the BuildNumber class:

[java]
ResourceBundle bundle = ResourceBundle.getBundle( "build" );
msg = bundle.getString( "build.message" );
[/java]

As you can see, if you are using Subversion it is likely a simpler option to use the revision number instead of creating a new build number, or perhaps passing the build number in from your build server using its own build numbering scheme. Using an incremented number as we have above can be inconsistent depending on the build order and build successes, with the additional requirement of maintaining the separate tracking file.

The Shade plugin

Maven’s dependency-based nature promotes the practice of proper compartmentalization of a build and producing a set of discrete artifacts that can be
aggregated into an application. Throughout a dependency tree, dependencies may appear multiple times and can be mediated to the correct version so that a single version can be used. However, circumstances will occur where, rather than the discrete list of dependencies, it is necessary to merge, hide, or alter the parts of a number of dependencies into a single artifact. This is the purpose for which the Shade plugin was developed, and in this section we will look at two use cases in more detail.

Building a standalone artifact

In Chapter 3, Building an Application Using Maven, we learned how to build a suitable distribution for our example application. This was a suitable set up for a server where there are multiple configuration files, startup scripts, as well as the application itself. But for some Java applications, all that is needed is to run static void main().

Distributing such applications if they have dependencies on other JAR files has always been problematic. Java has a mechanism to run a JAR on its own through the Main-Class manifest attribute, providing us with a simple command such as the following:

[java]<b>
client$ java -jar centrepoint-client-1.0-SNAPSHOT.jar
</b>[/java]

However, this will generally fail as the dependencies required are not present on the classpath. From here, you might add the Class-Path element to the manifest. However, this requires that the JARs be placed in a particular location relative to the other files, and we are back to distributing a complete archive.

To make this easier, the Assembly plugin contains a pre-built descriptor called jar-with-dependencies. This simply collapses the JAR and all it’s dependencies into one large JAR so that the above type of execution can work. In some cases, this configuration will work correctly, and no more work needs to be done.

One of the issues with the naïve approach of the assembly plugin is that many of the dependencies will house files with identical names, and it is given little choice but to pick just the last file that it encounters rather than dealing with the overlap properly.

This is where the Shade plugin can be useful, by providing hooks to transform these resources into a single resource as appropriate.

[java]
This is similar in intent to the Uberjar plugin that you may have used in
Maven 1, however the technique is improved. In the assembly plugin
and the shade plugin, the resulting artifact collapses the dependency
JARs and corrects references instead of having to unpack and construct
classloaders, making it a much faster alternative.

[/java]

For example, consider the following configuration:

[java]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.
resource.ComponentsXmlResourceTransformer" />
</transformers>
<artifactSet>
<excludes>
<exclude>xerces:xercesImpl</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
[/java]

Here we have the shade goal bound to the package phase to produce the collapsed JAR file as we might expect. In the transformers section, a transformer
is added that merges all encountered Plexus descriptor files under META-INF/plexus/components.xml. Finally, we have the ability to configure the transitive dependencies that are included and excluded from the final artifact using the artifactSet configuration.

As of Shade version 1.2, the following transformers are supplied with the plugin:

  • ApacheLicenseResourceTransformer and ApacheNoticeResourceTransformer: Specific to Apache license files such as those we created with the remote resources plugin earlier
  • AppendingTransformer: To concatenate plain text resources
  • ComponentsXmlResourceTransformer: For merging Plexus descriptors
  • ManifestResourceTransformer: For merging Java JAR file manifests
  • ServicesResourceTransformer: For merging Java services metadata in META-INF/services
  • XmlAppendingTransformer: To concatenate XML resource files with appropriate nesting

These transformers will cover many of your needs when using the Shade plugin. You may eventually need your own custom transformer if there are certain types of resources that must be merged between two artifacts that are not accommodated by the above. In that case, a transformer can be written in a separate artifact and added as a plugin dependency, then referenced directly from the configuration. This is similar to the technique illustrated for sharing other build resources such as the reporting configuration files in Chapter 5, Reporting and Checks.

Shading dependencies

Another interesting use case of the Shade plugin is to hide or alter the dependencies of an artifact. This can be helpful in several situations, such as:

  • Distributing classes from JARs that are difficult to access as dependencies (as long as such redistribution is allowed). For example, you may need to use a patched version of a common library and not want to cause conflict for projects that might depend on both your library and the original version.
  • Avoiding confl icts with other instances of the dependency within a classloader or to work around incompatible versions in a dependency tree.
  • Reducing the amount of code shipped by selectively including code from a particular dependency.

These situations are all similar and boil down to including some or all of the classes from a set of dependencies into the current artifact and altering the transitive dependency tree to compensate.

Let’s consider this example within the context of the example application. In the example code for this chapter, we have extended the model to use commons-lang, which is used to construct the equals and hashCode methods. Now, if we were to share the APiand model with third party developers to create their own store implementations, it would raise the same issues:

    • Requiring the dependency of commons-lang (about 260K in size) for just a couple of classes.
    • Introducing a dependency with a potentially stricter requirement than the rest of the application may later require (for example, if an incompatible, Java 5 enabled, commons-lang 3.0 is made available), again for very few classes.

In this situation, shading in just the portions of commons-lang that are needed may be a viable alternative. It is important to note that we can only do this if the license of the dependency allows such a combination, which in this case is true.

[java]
An important part of this scenario is that the dependency is being shared
outside of the current application. Inside an application, where you have
full control of the dependency tree, you are less likely to benefit from
shading dependencies for this purpose.
[/java]

To start with, we will add the Shade plugin configuration to the model/pom.xml file:

[java]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>commons-lang:commons-lang</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
[/java]

Running the package command with this in place will show the following:

[java]<b>
[INFO] [jar:jar]
[INFO] Building jar: /Users/brett/code/06/centrepoint/modules/model/
target/model-1.0-SNAPSHOT.jar
[INFO] [shade:shade {execution: default}]
[INFO] Including commons-lang:commons-lang:jar:2.3 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /Users/brett/code/06/centrepoint/modules/model/target/
model-1.0-SNAPSHOT.jar with /Users/brett/code/06/centrepoint/modules/
model/target/model-1.0-SNAPSHOT-shaded.jar
</b>[/java]

Multiple things are happening here. First, we can see that the normal JAR is produced as usual, and then the shade goal runs (consistent with the execution we added to the project). The plugin next shows that because of the artifact Set that we gave, commons-lang will be included in the JAR. If there were other dependencies, they would remain a regular dependency and not be included. Finally, we see that using the Shade plugin’s default configuration, the original artifact is replaced with the shaded artifact so that this version will be installed or used in the reactor instead.

However, we still have some work to do. Notice the size and contents of the JAR for the model now—so far, we have added all of commons-lang. We would only like to include the builder classes, so for that purpose we add artifact filters to the Shade plugin configuration:

[java]
<filters>
<filter>
<artifact>commons-lang:commons-lang</artifact>
<includes>
<include>org/apache/commons/lang/builder/**</include>
</includes>
</filter>
</filters>
[/java]

f we rebuild the project, we see that the JAR has reduced in size and upon inspection would find that only the files under the given path are included. This also ensures other files that might cause confusion (such as the pom.properties file under META-INF from commons-lang) are not included.

Of course, some caution is required here—these classes may well have required some of the now-excluded classes that are no longer present. In your own projects, ensure that your integration test cases adequately exercise the code being used; so that inadvertent runtime errors don’t occur later.

[java]
Beware the catch here that unit tests won’t exercise this change! Unit tests
run before the shading process occurs, so the tests need to occur in the
integration test phase or in a separate testing module.

[/java]

The next thing that we might notice about the contents of the JAR file is that the classes are still in their original packages under org/apache/commons/lang. This poses a potential problem for other projects that use commons-lang and depend on this API. There will now be two copies of these classes on the classloader that contains both JARs, and depending on the order, either copy of the classes could be used. If the wrong version is silently picked up, confusion will ensue on the part of the developer that appears to be getting the right version of the dependency, but the wrong behavior.

To prevent this, the Shade plugin allows us to encapsulate the use of commons-lang entirely by using the relocations feature.

[java]
<relocations>
<relocation>
<pattern>org.apache.commons.lang</pattern>
</relocation>
</relocations>
[/java]

Now when we build the artifact, we will see that the class names have changed, for example:

[java]<b>
hidden/org/apache/commons/lang/builder/EqualsBuilder.class
</b>[/java]

This is more than a simple renaming—the Shade plugin has also adjusted the bytecode of these classes and the references in our own Java classes to rename the package to include hidden at the start. This will now avoid any confl ict with other instances of commons-lang!

[java]
Though this confl ict is removed, you may still need to consider the
converse case, if a class depends on only being instantiated once to
operate correctly, or is accessed by a string using Class.forName
for example, shading may not work.
[/java]

One slight adjustment should be made here, as the default pattern of prepending hidden is not always a good choice. This can be confusing to see in stack traces, and if two different dependencies shade the same classes in the same way then the likelihood of confl ict occurs again. Instead, we can choose to include them within the namespace of our own package instead by a slight adjustment to the relocation configuration:

[java]
<relocation>
<pattern>org.apache.commons.lang</pattern>
<b><shadedPattern>
com.effectivemaven.centrepoint.model.shaded.lang
</shadedPattern></b>
</relocation>

[/java]

A final thing is worth noting about the configuration we have used so far. Initially, the shaded artifact replaces the original artifact and is installed in the local repository. In addition to replacing the original artifact, you may notice that the POM file installed in the local repository is also replaced with a different version that removes the commons-lang dependency. This is what we would expect as we have completely incorporated our commons-lang needs within the classes of the JAR through the shading process. This is thanks to the createDependencyReducedPom configuration option being enabled by default.

In some scenarios, you may not wish to replace the artifact, but instead create an additional artifact, with a different classifier, that contains the shaded alternative. This can be a good middle ground to give users the choice between an all-in-one artifact, or the default artifact that allows Maven to manage the dependencies normally. In this case, the createDependencyReducedPom option should be set to false, and the shadedArtifactAttached option set to true. Bear in mind, however, that the dependency representation for the classified artifact in this instance will be incorrect as the main artifact POM is used for classified artifacts as well.

The Shade plugin configuration contains a number of other configuration options for altering inclusions and exclusions at each step of the process that we have seen here and in particular for altering the technique and naming of artifacts that are attached with a classifier. Refer to the Shade plugin documentation for more information: http://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html

Before we move on, you may have observed a potential side effect of this change; that there will now be two instances of each class in the application should another use commons-lang. If multiple dependencies shade in the same classes, there may be multiple copies so even though this is powerful it is worth being judicious about using the technique, particularly if you have good control over how your artifact will be used as a dependency. Maven’s dependency mechanism and version management is there for a reason. If it is possible to continue using discreet artifacts as they are, then that may be the best and simplest alternative too!

The Build Helper plugin

Within Maven, there are a number of common tasks which plugins can perform to alter the current project for changes occurring during the build. We have seen the inclusion of new resources in the Remote Resources plugin, and the attachment of a new artifact from the Shade plugin. It is also possible to have a plugin generate new source code and include it for compilation, even though the directory is not included in the POM file.

The role of the Build Helper plugin is to provide a set of goals that can help achieve a collection of small but common tasks for which it would not be worth writing a custom plugin.

Adding source directories

Maven’s inability to have multiple source directories in the project model has often been called into question. However, as time has progressed the request has died down as the idea of a standardized source structure took hold.

The Build Helper plugin offers the ability to add another source directory or test source directory to that configured in the POM. This is not necessarily to allow a workaround for the deliberate limitation in the project model, but rather to facilitate other use cases that require it. The most common need to use this technique is to assist with the migration of a project in an existing layout to Maven temporarily.

[java]
Even with this capability it is still recommended not to add multiple
source directories without a particular reason—apart from breaking with
convention, you may find that some tools that operate based on the values
in the POM will not recognize the additional directories as containing
source code.
[/java]

The following example illustrates the addition of a source directory:

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/more-java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
[/java]

The need to use the Build Helper plugin for adding sources is now becoming more rare. Maven plugins that generate source code would be likely to add the extra directory to the project internally without the need for additional configuration. If some other means is used to generate the sources—for example, from a scripting plugin—it is common for the scripting plugin to have a way to add the source directory with fewer configurations than using the Build Helper plugin. However, if the need does arise, the Build Helper plugin will prove itself useful.

Attaching arbitrary artifacts

A similar scenario that can occur is the generation of additional artifacts that need to be attached to the build process. This means they use the same POM to define them, but are different types of related build artifacts, with their own classifier. The artifacts are installed and deployed to the repository alongside the original.

Typically, this will be in the form of another JAR file, possibly generated by one of the scripting plugins that did not attach the artifact itself.

However, it could be used for any number of files that need to be stored in the repository alongside the main artifact. Consider the example of deploying the license to the repository—if you were to run the install phase on the given project, you would be able to have the license installed into the local repository alongside the main artifact and its POM.

In reality, this particular configuration may be overkill, especially if the licenses are identical across many projects, or can be derived from the POM. However, depending on your deployment needs this possibility can be helpful in ensuring the repository contains the information about an artifact that you need, at the time it was deployed, in addition to any extra build artifacts that might be generated.

In our example application, we generated the license in two places—in all the Java modules, and the final distribution. Deploying it along with the final distribution makes some sense, so let’s add it to the distribution/pom.xml file:

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<artifacts>
<artifact>
<file>
target/maven-shared-archive-resources/LICENSE
</file>
<type>txt</type>
<classifier>license</classifier>
</artifact>
</artifacts>
</configuration>
<executions>
<execution>
<goals>
<goal>attach-artifact</goal>
</goals>
</execution>
</executions>
</plugin>
[/java]

This goal will execute after the packaging has occurred, but before installation so that it can be attached to the installation (and deployment) process. The file to attach is the license generated earlier by the Remote Resources plugin and is given an extension of .txt and classifier of -license. When running the install phase, we now see the file being processed:

[java]<b>
[INFO] [build-helper:attach-artifact {execution: default}]</b>[/java]

[INFO] [enforcer:enforce {execution: default}]

[INFO] [install:install]

[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
pom-transformed.xml to /Users/brett/.m2/repository/com/effectivemaven/
centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT.pom

[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
centrepoint-1.0-SNAPSHOT-bin.zip to /Users/brett/.m2/repository/com/
effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-
SNAPSHOT-bin.zip

[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
centrepoint-1.0-SNAPSHOT-bin.tar.gz to /Users/brett/.m2/repository/com/
effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-
SNAPSHOT-bin.tar.gz

[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
maven-shared-archive-resources/LICENSE to /Users/brett/.m2/repository/
com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-
1.0-SNAPSHOT-license.txt

Other goals

The Build Helper plugin also contains some other goals in the latest release at the time of writing (v1.1) of more specific interest:

    • remove-project-artifact: To clean the local repository of artifacts from the project being built to preserve space and remove outdated files. This may occur if the build no longer produces those files, or if it is necessary to remove older versions.
    • reserve-network-port: Many networked applications may want to use a network port that doesn’t confl ict with other test cases. This goal can help reserve unique ports to use in the tests. This is useful for starting servers in integration tests and then referencing them in the test cases. However, note that it won’t be available when running such tests in a non-Maven environment such as the IDE.

The goals available in the Build Helper plugin may increase over time, so if you have some small, common adjustments to make it is a good place to look to first for those utilities.

The AntRun plugin and scripting languages

Maven was designed to be extended through plugins. Because of the fact that this is so strongly encouraged, there are now many plugins available for a variety of tasks, and the need to write your own customizations, particularly for common tasks, is reduced. However, no two projects are the same, and in some projects, there are likely to be some customizations that will need to be made that are not covered by an existing plugin.

While it is virtuous to write a plugin for such cases so that it can be reused in multiple projects, it is also very reasonable to use some form of scripting for short, one off customizations.

One simple option is to use the AntRun plugin. Ant still contains the largest available set of build tasks to cover the types of customizations that you might need in your build, and through this plugin you can quickly string together some of these tasks within the Maven life cycle to achieve the outcome that you need.

Running simple tasks

We have already used the AntRun plugin in the distribution module of the example application. This snippet was used to copy some configuration files into place and create a logs directory, ready for the Assembly plugin to create the archive from:

[java]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>config</id>
<phase>process-resources</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/generatedresources/
appassembler/jsw/centrepoint/conf">
<fileset dir="src/main/conf" />
</copy>
<mkdir dir="${project.build.directory}/generatedresources/
appassembler/jsw/centrepoint/logs" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
[/java]

This shows how quick and useful the AntRun plugin can be for simple tasks. However, it also contains a number of other features that can be of benefit to the build for more significant tasks.

Interacting with the Maven project

As we mentioned in the section, The Build Helper plugin, you can tell the plugin to map some directories to new source directories. This functionality is identical to that of the Build Helper plugin, but is more conveniently located when the directories are being generated by Ant tasks.

This can be useful because even though tools are increasingly supplying native Maven plugins in addition to Ant tasks, you might come across a source generation tool that only has an Ant task. In this scenario, you can use the AntRun plugin to run the tool, generate the source code, and use the sourceRoot parameter to have that directory added back into the build life cycle.

In addition to injecting source directories back into the life cycle, the AntRun plugin also injects Maven project information into Ant’s context. Probably the most important of these is the availability of the project’s and plugin’s dependencies as Ant path references:

    • maven.compile.classpath: The dependencies in the compile scope (this syntax will look familiar to those that used Maven 1’s built in Ant-based files)
    • maven.runtime.classpath: The dependencies in the runtime scope (including the above)
    • maven.test.classpath: The dependencies in the test scope (including both of the above)
    • maven.plugin.classpath: The dependencies of the AntRun plugin itself, including any added via the POM

Though we have not needed it in the example application, to illustrate how these two options would work, consider if you needed to use the XJC Ant task from JAXB to generate some sources.

[java]
<b>JAXB</b> is a <b>Java-to-XML</b> binding framework that can be used to generate
Java source code from XML schema (among many other things), using its
XJC tool. Though it serves as a suitable example here, you would not be
faced with this issue with JAXB itself, as it now offers a Maven plugin.

[/java]

In this example, you might add the following configuration to an AntRun execution in a POM file:

[java]
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>xjc</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<taskdef name="xjc"
classname="com.sun.tools.xjc.XJCTask"
<b>classpathref="maven.plugin.classpath" /></b>
<xjc destdir="${project.build.directory}/xjc"
schema="src/main/jaxb/schema.xsd">
<b><classpath refid="maven.compile.classpath" /></b>
</xjc>
</tasks>
<b><sourceRoot>${project.build.directory}/xjc</sourceRoot></b>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.1.9</version>
</dependency>
</dependencies>
</plugin>
[/java]

We see here that the XJC Task is defined using the plugin classpath to locate the task and its dependencies (and that task’s artifact is added as a plugin dependency to accommodate this). Additional built-in Ant tasks would also be added as plugin dependencies (such as ant-nodeps).

[java]
<b>AntRun and Ant versions</b>
While in some cases they might be compatible, generally you should use
the same version of the Ant optional tasks as the version of Ant itself. The
version of Ant used by the plugin is predetermined by what it has been
built against. In AntRun v1.3, that is Ant 1.7.1. To use a different version
of Ant, consider a different version of the AntRun plugin.

[/java]

Next, the task is run—being passed the project’s dependencies and schema to generate the source code from. The source code is output to target/xjc, which is also added as a source directory by the AntRun plugin because of the configuration specified. As the task runs in the generate-sources phase, it is available for compilation in the same way as any other source code.

Again, the configuration of AntRun here has been relatively simple, and is completely integrated with the Maven artifact handling and build life cycle such that it would not likely be needed to write a plugin to wrap the tool completely if you were faced with this decision in your environment.

Converting Ant or Maven 1 builds

The AntRun plugin can be most useful when it comes to converting an existing build from Ant or Maven 1 (if it used custom Ant-based plugins or maven.xml heavily).

The approach to converting such a build varies depending on the project. For some projects, it is easier to start over on the build and map in modules one by one, interacting via the repository. For others, it might be a matter of gradually turning the existing script into a POM file and using AntRun to execute the existing code for the unconverted parts, keeping the fl ow wrapped in the new Maven life cycle.

[java]
The topic of build conversion is covered in more depth in the
Better Builds with Maven section in Chapter 8, available at
http://www.maestrodev.com/better-build-maven.
[/java]

Let’s look at another example. The following execution might be added to the
AntRun plugin, with the same pattern repeated for other such examples in different
parts of the life cycle:

[java]
<execution>
<id>gen-src</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<b><ant antfile="build-migration.xml" target="gen-src" /></b>
</tasks>
</configuration>
<sourceRoot>${project.build.directory}/gen-src</sourceRoot>
<goals>
<goal>run</goal>
</goals>
</execution>
[/java]

In this source generation example, the previous build file is executed to perform a certain task. As before, the resultant directory is added back into the Maven project so that Maven can continue to control the build.

You will notice that the original script (perhaps broken up) is retained and called rather than pasting the script fragment into the POM. While either is acceptable (as long as the script does not contain multiple targets), it is a good idea to keep the POM as trim as possible. Unless the Ant script is just one or two lines long, it is better to put those commands into an external build file to execute.

[java]
This advice applies even if not performing a build conversion. If your
Maven build contains script fragments that are longer than a few lines,
consider placing them outside of the POM file. However, bear in mind
that in doing so it will not be available when reading the POM from the
repository later.
[/java]

In some conversions, a particular task may be reusable in multiple places or projects (particularly if migrating a Maven 1 plugin). In this case, instead of the Ant Run plugin, you may consider writing your own plugin for the task. Luckily, to reduce the work involved Maven also offers the ability to run plugins written in Ant.

Maven plugins written in Ant

While the AntRun plugin offers a convenient way to string some simple tasks together, as with any part of the build process in Maven it is worth taking into consideration a simple rule of thumb: if you might use it twice, consider writing a plugin.

Of course, if you do take that step, it is not required to write the plugin in Ant. However, having the option available is useful as:

    • It will be easier to use for converting from a previous Ant/Maven 1 build
    • Ant tasks may be more familiar to your team than writing Maven plugins in another language
    • It can be easier to put together a set of Ant tasks for certain procedures than to write the corresponding code in another language such as Java

The process for creating Ant plugins involves the following steps:

    1. Create a Maven project of type maven-plugin.
    1. Add the maven-plugin-plugin to the build section, including a plugin dependency on maven-plugin-tools-ant.
    1. Add an Ant build script for each goal to src/main/scripts directory under the name goalName.build.xml. This should be a completely executable Ant script containing one target definition.
    1. Add a Mojo definition for each goal to src/main/scripts directory under the name goalName.mojo.xml. This defines the mapping of Maven
      information to the Ant target.

Plugin authoring (in Ant or other languages) is not something we will go into detail on in this chapter. For more information on writing plugins in Ant, see the documentation: http://maven.apache.org/guides/plugin/guide-ant-plugindevelopment. html.

Other scripting languages

While this section has focused on Ant as one of the most common scripting tools for builds, it is worth noting that other scripting languages can be used both for executable fragments (such as the fragments that AntRun is used for) and whole plugins (such as the Ant plugin tools are used for).

If you have expertise in a particular scripting language, and would like to use that for your own plugins or to add fragments to the build, you might consider one or more of the following projects:

    • GMaven: This is a mature solution for writing plugins in Groovy, and running Groovy scripts from the POM. For more information, see
      http://groovy.codehaus.org/GMaven.
    • JRuby Maven Plugin: This is an early but functional tool for writing plugins in JRuby, or running Ruby scripts from the POM. For more information, see http://mojo.codehaus.org/jruby-maven-plugin/howto.html.
    • Script Maven Plugin: This uses BSF (Bean Scripting Framework) for running scripts in other languages directly from the POM. Supports a larger number of languages, but does not allow the creation of native Maven plugins from the source. For more information, see http://mojo.codehaus.org/scriptmaven-plugin.

[java]
At the time of writing, the Script Maven Plugin has not
had an official release and needs to be built from source.

[/java]

The Exec plugin

In some build situations, the best (or only!) way to get something done might be to run an external application, or a piece of Java code. It was for this purpose that the Exec plugin was created.

The plugin contains two goals: exec:exec and exec:java. They are similar in purpose, however the java goal sets up an easier way to pass Java configuration and execution parameters to a forked JVM instance, whereas the exec goal simply runs any executable available on the system.

To use the exec goal, you pass the path of the executable program in the executable configuration option, and optionally can add the environment Variables or arguments configuration to run the command as desired.

[java]
<b>Portability</b>
Keep in mind the question of portability when using the exec goal.
Some executables may not be available on all platforms that the build
will run on. You may need to clearly state the requirement in the build’s
documentation, gracefully degrade the functionality, or use a profile to
run a different executable on a different platform.
[/java]

In contrast, the java goal automatically locates the JVM executable to run, and instead you provide the mainClass configuration option. The arguments
configuration can again be given, but can also include a classpath option that helps construct Java -classpath arguments from the Maven build (though it is also possible to pass this to the exec goal if you happen to be running a particular java executable with it). You may also configure systemProperties for the plugin to pass to the forked JVM instance.

By default, the java goal will construct its base classpath from the current project’s dependencies, though it is also possible to have it pass the plugin’s dependencies as well or instead of the project dependencies. For more information on configuring either of the plugin goals, refer to the plugin website at: http://mojo.codehaus. org/exec-maven-plugin.

Both of these goals provide a useful way to run external processes, depending on what type of application it is. However, the context that it will be used in is also important. For execution there are often two scenarios—integrating the external process into the build life cycle (much like the examples we have seen with AntRun previously), or pre-configuring the plugin to be able to be run from the command line for a given project.

Adding the Exec plugin to the Build life cycle

In the first scenario, there may be an external tool or Java application that needs to be run at a certain point in the build for which the plugin should be configured. This occurs in the same way as for any other plugin, using a particular execution.

In The AntRun plugin and scripting languages, we looked at running the XJC tool from Ant. Another alternative could be to run the tool from the command line (assuming it had been pre-installed in the path):

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>xjc</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<b><executable>xjc</executable>
<arguments>
<argument>-d</argument>
<argument>${project.build.directory}/xjc</argument>
<argument>src/main/jaxb/schema.xsd</argument>
</arguments></b>
<sourceRoot>${project.build.directory}/xjc</sourceRoot>
</configuration>
</execution>
</executions>
</plugin>
[/java]

For this particular scenario of source generation, the Exec plugin also contains a sourceRoot and testSourceRoot parameter for adding any generated sources into the build for later—exactly like the AntRun plugin.

Notice in the example that the configuration is inside the execution element, and therefore will not be able to be run from the command line. This is usually the best course of action when binding to the life cycle so that multiple instances are possible.

Running the Exec plugin standalone

There are also a number of uses for running the Exec plugin directly from the command line. This might be used with a particular project, or run independently.

A common reason to use this approach is if a particular Maven project produces an executable JAR—we looked at such an example with the Shade plugin earlier. By pre-configuring the Exec plugin with the necessary information, the JAR can be easily run by Maven itself. The following POM snippet from the Archiva XMLRPC Client illustrates this:

[java]
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<mainClass>
org.apache.archiva.web.xmlrpc.client.SampleClient
</mainClass>
<arguments>
<argument>http://127.0.0.1:8081/xmlrpc</argument>
<argument>admin</argument>
<argument>${password}</argument>
</arguments>
</configuration>
</plugin>
[/java]

Here, the project dependencies are included and the given arguments passed to the main function of the class specified. Notice that in contrast to the previous example, the configuration is not in an execution, both because it is not bound to the life cycle, but also so that it can be run from the command line.

Executing this is now a matter of running the following command:

[java]<b>
$ mvn exec:java -Dpassword=ADMIN_PASSWORD

</b>[/java]

Clearly, this is much easier to remember than the full set of arguments!

In similar scenarios, the Exec plugin can become very useful in being able to give a simple demonstration or quick use of an application while in development. In some ways, it can be compared to jetty:run for web applications as bringing the same functionality to executable standalone applications.

Summary

As we learned early in the first chapter, once you have the right framework in place with Maven, it is a matter of finding and selecting the right combination of plugins to assemble your build from there on. Here, we have seen a selection of such plugins to help achieve some common builds goals.

The list doesn’t stop here though. If you are looking to integrate a particular tool or framework into your build, see if a plugin is already available for it. A number of plugins such as the Dependency plugin, Enforcer plugin, Assembly and App Assembler plugins, discussed elsewhere in the book, have more goals and configurations that are worth investigating as well. If you have some other needs that might apply to multiple builds, search for a plugin to serve that case, or beyond that write one yourself in a scripting language, as a set of Ant tasks, or your own Maven plugin. Online Maven repository search engines can be helpful in finding other plugins to use.

also read:

  • Buy: Apache Maven Implementation from flipkart.com
  • Ant Script
  • Creating Simple Java Project Using Apache Maven
  • Creating Simple Web Application Using Apache Maven

In the first half of this book, we have covered all the pieces of the build puzzle needed to build an application with Maven—from the basics to dependency
management, multi-module applications, distribution, reporting, and now a variety of plugins to augment build functionality.

With this in place, in the next chapter we are going to review what we have learned about Maven so far and lay out some best practices to keep in mind as you write or review your own builds.

Filed Under: Apache Maven Tagged With: Apache Maven

How to write a Custom Plugin for Maven?

July 8, 2010 by Krishna Srinivasan Leave a Comment

In this article, we will learn about Maven which is a project management framework that provides a configurable approach for managing software projects. Maven covers all the necessary phases that happen right from project creation, building, documentation, reporting, installation and deployment. This article begins with the basics of Maven along with the concepts like Project Object Model (aka POM), the various life-cycles in Maven etc. Then it continues with using Maven for creating a project till installation of the project in a local repository. The latter part of the article provides details about creating custom Maven plugins that can be executed in stand-alone mode as well as part of some Maven life-cycle.

Maven Custom Plug-In (Example Code)

  • Download Sample Program for Maven Custom Plug-In

Maven Concepts

In this section, we will see the basics of Maven concepts like Project Object Model, the standard lifecycles available in Maven as well as the dependency scope that comes up while dealing with dependency with projects.

  • How to install maven on Ubuntu

Project Object Model

Project information, its dependencies and the artifacts that can be built are described in POM which is essentially a configuration file in XML. POM basically contains instructions on what needs to be done during the various life-cycles that happen during a build. Note that the POM is not coupled to java projects, in fact the project can be written in any language like C, C# etc. For example, consider the sample minimal POM,

[java]
<project>

<modelVersion>4.0.0</modelVersion>

<name>adder</name>
<url>https://javabeat.net/adder</url>
<groupId>net.javabeat.adder</groupId>
<artifactId>adder</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

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

</project>
[/java]

Have a look at the above POM. It defines the information about the project and its dependant projects. We will look into more details about the various POM elements.

  • modelVersion – This defines the version of the POM.
  • name – The name of the project.
  • groupId – This identifies the group (or the organization) that created the project. This property usually takes the domain address which represents the group or the organization so that uniqueness is maintained across the groups.
  • artifactId – This identifies the artifact (output component) name that comes from a project. Artifacts can be anything like a JAR, WAR, EAR etc
  • version – This property identifies the version of the artifact. Usually the version takes the format as “majorVersion.minorVersion-qualifier”. For example, “1.1-alpha”, “1.2-beta”, “1.3-SNAPSHOT”.
    packaging – Represents the type of artifact, for example – jar, war, ear etc.

In the next section in the POM, we have included the dependencies of the project. Note that this section is optional. If there are no dependencies for a project (which is unlikely the case), this can be omitted. However, in this example case, we have declared a dependency to junit and it is expected that the project will contain some test resources. It is always a good idea to define the version of the artifact while defining a dependency, so that during runtime, we are not facing any issues because of version match. We have mentioned the scope as test, more details about this element will follow in the forthcoming section.

  • Log4j configurations

Dependency Scope

A project can depend on a number of dependent projects and Maven provides a way for defining the dependencies among projects through configuration. One can control the level of dependency through scope and the default being ‘compile’. The following scopes are available.

  • Compile – This being the default scope will be available at the classpath during the compilation as well as during runtime.
  • Runtime – The presence of this scope ensures that the dependency will be available at the runtime and not during the compile-time. For example, one may use the Servlet API during the compilation phase, however the Servlet implementation (from Sun, Oracle, IBM etc) will be required during the runtime only.
  • Test – This scope ensures that the dependency is available during the compilation of the test resources as well as during the execution of the test resources.
  • Provided – This dependency is mostly used while developing J2EE applications where the dependency is available as part of the J2EE container (or any Container) and it is not necessary for the project to package the dependency as part of the artifact. For example, while developing Enterprise bean applications, as part of the project, we will be using EJB jar for compilation; however, we never package this jar as part of the project because the EJB container will provide this jar.

Build Life-cycle

A life-cycle defines the execution for achieving a set of goals. Each life-cycle defines a sequence of phases for achieving the goals. There are three standard life-cycles defined in Maven and this section provides a brief summary about them.

  • Clean
  • Build (the default life-cycle)
  • Site

Clean life-cycle

The clean life-cycle accomplishes the goal of deleting the output directory, if present. It in-turn accomplishes this goal by running the phases, pre-clean, clean and post-clean. It is possible to configure custom actions/operations in the pre-clean and the post-clean phases.

Build life-cycle

This is the default life-cycle that maven executes uses during the build process. It has a sequence of phases namely validate, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install and deploy. As you can see the list is huge, in general in this cycle, the necessary resources and sources are generated, processed, compiled and various test steps are executed before package and deployment.

Site life-cycle

This life-cycle is used to generate the documentation and reports pertaining to the project. It is also possible to customize the various aspects during site generation like the content, image, layout etc. This life-cycle contains pre-site, site, post-site and site-deploy phases.

Using Maven

In this section, we will see how to use maven for creating, compiling, building, packaging and installing a project. Download the latest version of Maven from here. Installation of maven will be as simple as un-zipping the downloaded file into a desired directory. In this example, we will be seeing the usage of various maven plugins and goals that contributes to the entire project life-cycle. Before proceeding with the sample, create an environment variable MAVEN_HOME that points to the Maven installation directory and ensure that the PATH variable contains %MAVEN_HOME/bin.

Creating a project

Execute the following command which is used to create the initial project structure.

[java]mvn archetype:create -DgroupId=net.javabeat.emailservice -DartifactId=emailservice[/java]

Note that in archetype:create, archetype represents the plugin prefix and create represents the goal. This goal creates a project with the name emailservice. As soon as this command is executed, one can see a directory called emailservice which has the src folder for holding the main java files, along with java files representing test-cases. The POM file with the name pom.file will also be created with the structure as follows,

pom.xml

[java]
<project>
<modelVersion>4.0.0</modelVersion>

<groupId>net.javabeat.emailservice</groupId>
<artifactId>emailservice</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>emailservice</name>
<url>http://maven.apache.org</url>

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

</project>
[/java]

Importing the project in Eclipse

This step is optional for those who are not working with Eclipse being the IDE for developing the project. Change the current directory to emailservice and issue the following command. This goal eclipse creates the project metadata files that are complaint with Eclipse. As soon as the following goal is executed there will be two files generated in the current directory which are .project and .classpath. This is for Eclipse to understand so that the newly created project can be imported in Eclipse IDE to work with.

[java]mvn eclipse:eclipse[/java]

Now, for importing the project into Eclipse, Open Eclipse, go to File -> Import -> Existing Projects into Workspace and navigate to the directory containing the .project and .classpath files and Click OK. Now this project gets imported into Eclipse workspace.

Adding files to project

To make the project meaningful, we will add the following files into the main source folder.

EMail.java

[java]package net.javabeat.emailservice;

public class EMail {

private String fromAddress;
private String toAddress;
private String subject;
private String message;
private String status;

public String getFromAddress() {
return fromAddress;
}

public void setFromAddress(String fromAddress) {
this.fromAddress = fromAddress;
}

public String getToAddress() {
return toAddress;
}

public void setToAddress(String toAddress) {
this.toAddress = toAddress;
}

public String getSubject() {
return subject;
}

public void setSubject(String subject) {
this.subject = subject;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}
}[/java]

The above class represents the Email model object that will be used by EmailService class for sending email. Given below is the code listing for EMailService class.

EMailService.java

[java]package net.javabeat.emailservice;

public class EMailService {

public EMail sendEmail(String fromAddress, String toAddress, String subject, String message){

EMail emailObject = new EMail();
emailObject.setFromAddress(fromAddress);
emailObject.setToAddress(toAddress);
emailObject.setSubject(subject);
emailObject.setMessage(message);
emailObject.setStatus("SUCCESS");

System.out.println("Sending email from " + fromAddress + " to " + toAddress + "with subject "
+ subject + " having the message contents " + message);
return emailObject;
}
}[/java]

Note that there is no real functionality in the above, all it does is to accept the various user inputs and constructs an email object before returning it.

Compiling the project

The next step is to compile to project, by default the compilation process will create a folder called target and it will place the java class files along with any resource files, if present.

[java]mvn compile[/java]

Note that the location of the target folder as well as the location of the target folder is also configurable.

Packaging the project

This step will package the project with the packaging type mentioned in POM, which is JAR. Before packaging it will also execute the test cases (if specified) in the test folder and the packaged jar will be placed in the target folder.

[java]mvn package[/java]

Installing the project

The final step is to install the jar in a local repository so that other projects, if they are dependant on this project can make references to this project. The following command will install (i.e copy the jar) to the local repository.

[java]mvn install[/java]

Note that, by default, the local repository path will be %USER_HOME%/.m2/repository.

Writing Custom Maven plugins

In this section we will see how to write custom maven plugins. It is possible that the custom maven can be made to run outside the standard life-cycle phase or it can be made to be executed as part of the standard life-cycle phase. We will see how to accomplish both of these items in the following sections.

Creating standalone plugins

In this section, we will write a custom plugin and will see how to write it in stand-alone mode – i.e running the plugin directly without establishing any dependencies on any of the standard life-cycles available in Maven.

Creating the project

The first step is to create the project containing the custom maven plugin. This project is quite different from the regular java project because it is not a regular java artifact like JAR, WAR etc. Instead it is going to be a maven plugin. Issue the following command to create the maven plugin project.

[java]mvn archetype:create -DgroupId=net.javabeat.maven -DartifactId=environment-info -DarchetypeArtifactId=maven-archetype-mojo[/java]

The above command creates a project with the name environment-info with the standard directory layout containing the source and test resources. If you look into the POM file, the package type will be maven-plugin to indicate that this is a maven plugin project.

Importing the project into Eclipse

This step is optional and this is for someone who wishes to work with the project in Eclipse IDE. Issuing the following with the current directory being environment-info creates the Eclipse .project and .classpath files. Now, open Eclipse and go to File -> Import -> Existing Project into Workspace and specify the directory to <<path to environment-info>> directory.

[java]mvn eclipse:eclipse[/java]

Creating the plugin

In Maven, the plugin that achieves a specific task is called by the name MOJO (Maven Old Java Object similar to POJO). A MOJO defines the goal which is nothing but the custom action which is executed upon user’s request. In this example, we will see a custom MOJO that will define the goal of storing all the environmental properties in a text file upon execution. Have a look at the following code,

EnvironmentInfoTask.java

[java]package net.javabeat.maven;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Iterator;
import java.util.Map;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

/**
* @goal env-info
*/
public class EnvironmentInfoTask extends AbstractMojo{

/**
* @parameter
* default-value="log.txt"
* expression="${environment.filename}"
*/
private String fileName;

/**
* @parameter
* default-value="C:\\temp"
* expression="${environment.base_dir}"
*/
private File baseDirectory;

/**
* @parameter
* default-value="true"
* expression="${environment.loggingRequired}"
*/
private boolean loggingRequired;

public void execute() throws MojoExecutionException, MojoFailureException {

StringBuilder fileContents = new StringBuilder();

if (baseDirectory.exists()){
baseDirectory.mkdirs();
log("Created base directory ‘" + baseDirectory.getAbsolutePath() + "’");
}

Map&lt;String, String&gt; environment = System.getenv();
Iterator&lt;Map.Entry&lt;String, String&gt;&gt; entries = environment.entrySet().iterator();

fileContents.append("Environment Information:" + newLine());
fileContents.append("———————————————————–" + newLine());

while (entries.hasNext()){

Map.Entry&lt;String, String&gt; entry = entries.next();
fileContents.append(entry.getKey() + "————-&gt;" + entry.getValue() + newLine());
}

fileContents.append("———————————————————–" + newLine());
writeToFile(fileContents);
log("File contents written");
}

private void log(String message){

if (loggingRequired){
System.out.println(message);
}
}

private static String newLine(){
return System.getProperty("line.separator");
}

private void writeToFile(StringBuilder fileContents){

FileWriter fWriter = null;
BufferedWriter bWriter = null;

try{
fWriter = new FileWriter(baseDirectory + File.separator + fileName);
bWriter = new BufferedWriter(fWriter);
bWriter.write(fileContents.toString());
}catch (Exception e){
log("Error in writing the contents to file -&gt;" + e.getMessage());
}finally{
try{
if (bWriter != null){
bWriter.close();
}
if (fWriter != null){
fWriter.close();
}
}catch (Exception e){
log("Error in closing the resources -&gt;" + e.getMessage());
}
}
}
}[/java]

The first thing to notice is the class EnvironmentInfoTask which is going to persist the environmental information into a file extends AbstractMojo class which in turn extends the Mojo interface. Note that the goal for this MOJO is annotated using XDoclet using goal attribute with the name env-info. The method that will be called during execution of the MOJO is execute(). This method does the job of persisting the environmental properties by taking information from the various properties .

  • Base Directory – the directory under which the log file name will be created which is of type ‘java.io.File’. Note that we have used XDoclet ‘parameter’ for annotating this property. This property has the default value ‘C:\\temp’ which means the this is the default location for the log file. However, this value can be overridden at runtime by specifying the property ‘environment.base_dir’ which is an expression and its value will be resolved at runtime
  • Filename – the name of the log file into which the environmental properties will be written. Note that the default value for the log file name is ‘log.txt’. However, during runtime, the value can be overridden through the property ‘environment.filename’
  • Logging Required – whether logging information on what this MOJO is doing has to be shown. The default value being true can be overridden by specifying the value false to the property ‘environment.loggingRequired’.

Compiling the project

Issue the following command for compiling the maven plugin project.

[java]mvn compile[/java]

Packaging the project

The following command is used to package the plugin project.

[java]mvn package[/java]

Installing the project

For installing the project into the local Maven repository, issue the following command.

[java]mvn install[/java]

Usually, on Windows, the local repository is %USER_HOME%/.m2/repository. On Windows XP, USER_HOME will expand to "C:\\Document and Settings\\<<UserName>>", however in Windows Vista it is "C:\\Users\\<<UserName>>".

Running the project

There are several ways to run the maven plugin. We will see them one by one. Generally running a Maven plugin takes the following form,

[java]mvn groupId:artifactId:version:goalName[/java]

In our case, the group id is net.javabeat.maven, artifact id is environment-info, version is 1.0-SNAPSHOT and goal name is env-info. So running the following command will run the custom plugin

[java]mvn net.javabeat.maven:environment-info:1.0-SNAPSHOT:env-info[/java]

Running the above command will create a directory C:\\temp (if not present) and create a file name with log.txt with the environment information. Because logging is enabled by default, the text ‘Created base directory C:\temp‘ and ‘File contents are written’ will be displayed in the console.

It is also possible to configure the plugin by passing alternate input values. Have a look at the following command. This command specifies an alternate base directory C:\\temp-new for the log file newLog.txt with logging turned off. Note that for passing a property to a plugin the standard way is –DpropertyName=propertyValue.

[java]mvn net.javabeat.maven:environment-info:1.0-SNAPSHOT:env-info -Denvironment.base_dir=
C:\temp-new -Denvironment.filename=newLog.txt -Denvironment.loggingRequired=false[/java]

It is also possible to omit the version information while running the plugin in which case, Maven tries to find the recent version for the plugin by comparing the version strings. In our case, this wouldn’t happen, because we have only one version which is 1.0-SNAPSHOT. So the following command will also work.

[java]mvn net.javabeat.maven:environment-info:env-info[/java]

Another approach to run the plugin is by omitting the group id and just specifying the artifact id along with the goal name. However, for this to happen, we have to add the group id to the default list of groups that Maven will look for. Open the file %MAVEN_HOME%/conf/settings.xml and add the following line under the element pluginsGroup.

[java]<pluginGroup>net.javabeat.maven</pluginGroup>[/java]

This ensures that we have added the group net.javabeat.maven to the list of default groups that Maven will search for, because of which the following command will work.

[java]mvn environment-info:env-info[/java]

Attaching plugins to existing life-cycle

So far, we have seen how to run a custom plugin in stand-alone mode. This is not of much-use and Maven provides a way for binding the goals of any custom plugin into existing build cycle. For example, let us consider that we have written a custom plugin which will simply print the current date and we want this plugin to be executed during the compilation phase and the installation phase of a project. We will see how to accomplish this goal in this section.

The following listing shows the custom plugin which will simply emit the date information.

DateInfo.java

[java]package net.javabeat.maven;

import java.util.Date;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

/**
* @goal date-info
*/
public class DateInfo extends AbstractMojo {

public void execute() throws MojoExecutionException, MojoFailureException {

Date currentDate = new Date();
getLog().info("Current date is " + currentDate);
}
}[/java]

Follow the same process of creating the project, then creating the plugin, compilation, packaging and installation as we have discussed before. We will see how to attach this custom plugin during the compile and the install phase. Open POM.xml file and add the following after the project dependencies element,

[java]
<build>
<plugins>
<plugin>
<groupId>net.javabeat.maven</groupId>
<artifactId>environment-info</artifactId>
<version>1.0-SNAPSHOT</version>

<executions>
<execution>
<id>date-info-compile</id>
<phase>compile</phase>
<goals>
<goal>date-info</goal>
</goals>
</execution>

<execution>
<id>date-info-install</id>
<phase>install</phase>
<goals>
<goal>date-info</goal>
</goals>
</execution>

</executions>

</plugin>
</plugins>
</build>
[/java]

Though the above XML fragment is big, it is fairly simple. First thing is, it defines the execution element where we can define goals for executions. We have defined two execution elements one for the compile phase and the other for the install phase and we have given appropriate id for each execution element. Have a note at the goals section. We have included our custom goal date-info which will display the current date information. Note that where to search for the goal’s group id and the artifact id along with optional version is defined just above the executions element.

After this whenever we run mvn compile and mvn install for any project that contains the above definition we will see that the goal date-info getting invoked during the phases.

Conclusion

In this article, we have seen how to use Maven for creating projects and to manage dependencies between projects. We have seen Maven simplifying the task of creating, compiling, packaging, installing projects thereby reducing the pain from developers and build managers. Also discussed in the article are the extension capabilities provided by Maven for pluging-in custom plugins in the form of MOJOs.

Filed Under: Apache Maven Tagged With: Maven

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved