So far in this chapter, we have discussed several applications of Maven archetypes. It's high time now to build our own custom archetype. Let's see how to develop a Maven archetype for an Apache Axis2 module/handler. Let's start with a simple Maven project:
$ mvn archetype:generate -DgroupId=com.packt.axis2 -DartifactId=com.packt.axis2.archetype.handler -Dversion=1.0.0 -Dpackage=com.packt.axis2.archetype.handler -DinteractiveMode=false
This command will generate the following directory structure:
com.packt.axis2.archetype.handler |-pom.xml |-src |-main/java/com/packt/axis2/archetype/handler/App.java |-test/java/com/packt/axis2/archetype/handler/AppTest.java
Before creating the archetype, first we need to build the project template. In this case, the project template itself is an Axis2 module/handler. Let's see how to improve the simple Maven project generated from the maven-archetype-quickstart
archetype into an Axis2 handler by performing the following steps:
pom.xml
file and add all of the required dependencies there. We also need two plugins to build the Axis2 module archive file. The value of packaging
is changed to mar
. After the modifications, pom.xml
will look as follows:<project> <modelVersion>4.0.0</modelVersion> <groupId>com.packt.axis2</groupId> <artifactId>com.packt.axis2.archetype.handler </artifactId> <packaging>mar</packaging> <version>1.0.0</version> <name>com.packt.axis2.archetype.handler</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.axis2</groupId> <artifactId>axis2</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>org.apache.neethi</groupId> <artifactId>neethi</artifactId> <version>2.0.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.axis2</groupId> <artifactId>axis2-mar-maven-plugin</artifactId> <version>1.2</version> <extensions>true</extensions> <configuration> <includeDependencies>false</includeDependencies> <moduleXmlFile>module.xml</moduleXmlFile> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> <version>1.0</version> <executions> <execution> <id>aar</id> <phase>package</phase> <goals> <goal>attach-artifact</goal> </goals> <configuration> <artifacts> <artifact> <file> target/${project.artifactId}-${project.version}.mar </file> <type>jar</type> </artifact> </artifacts> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
org.apache.axis2.engine.Handler
class. Here, we will rename the generated App.java
file to SampleAxis2Handler.java
and modify its code, as shown here:package com.packt.axis2.archetype.handler; import org.apache.axis2.AxisFault; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.HandlerDescription; import org.apache.axis2.description.Parameter; import org.apache.axis2.engine.Handler; public class SampleAxis2Handler implements Handler { private HandlerDescription handlerDesc; @Override public void cleanup() { // TODO Auto-generated method stub } @Override public void flowComplete(MessageContext arg0) { // TODO Auto-generated method stub } @Override public HandlerDescription getHandlerDesc() { return handlerDesc; } @Override public String getName() { return "SampleAxis2Handler"; } @Override public Parameter getParameter(String name) { return this.handlerDesc.getParameter(name); } @Override public void init(HandlerDescription handlerDesc) { this.handlerDesc = handlerDesc; } @Override public InvocationResponse invoke(MessageContext msgContext) throws AxisFault { return InvocationResponse.CONTINUE; } }
AppT
est.java
file to SampleAxis2HandlerTest.java
and modify its code, as shown here:package com.packt.axis2.archetype.handler; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Unit test for SampleAxis2Handler. */ public class SampleAxis2HandlerTest extends TestCase { /** * Create the test case * * @param testName name of the test case */ public SampleAxis2HandlerTest( String testName ) { super( testName ); } /** * @return the suite of tests being tested */ public static Test suite() { return new TestSuite(SampleAxis2HandlerTest.class ); } /** * Rigourous Test :-) */ public void testHandler() { assertTrue( true ); } }
src/main/java/com/packt/axis2/archetype/module
. You might need to create the archetype/module
directory, as it's not there by default:package com.packt.axis2.archetype.module; import org.apache.axis2.AxisFault; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.description.AxisDescription; import org.apache.axis2.description.AxisModule; import org.apache.axis2.modules.Module; import org.apache.neethi.Assertion; import org.apache.neethi.Policy; public class SampleAxis2Module implements Module { @Override public void applyPolicy(Policy arg0, AxisDescription arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public boolean canSupportAssertion(Assertion arg0) { // TODO Auto-generated method stub return false; } @Override public void engageNotify(AxisDescription arg0) throws AxisFault { // TODO Auto-generated method stub } @Override public void init(ConfigurationContext arg0, AxisModule arg1) throws AxisFault { // TODO Auto-generated method stub } @Override public void shutdown(ConfigurationContext arg0) throws AxisFault { // TODO Auto-generated method stub } }
module.xml
inside the root
directory (at the same level of the pom.xml
file), as shown here:<module name="sample-axis2-module" class="com.packt.axis2.archetype.module.SampleAxis2Module"> <Description>Sample Axis2 Module</Description> <OutFlow> <handler name="SampleOutHandler" class="com.packt.axis2.archetype.handler.SampleAxis2Handler"> <order phase="samplephase" /> </handler> </OutFlow> <InFlow> <handler name="SampleInHandler" class="com.packt.axis2.archetype.hanlder.SampleAxis2Handler"> <order phase="samplephase" /> </handler> </InFlow> <OutFaultFlow> <handler name="SampleOutFaultHandler" class="com.packt.axis2.archetype.hanlder.SampleAxis2Handler"> <order phase="samplephase" /> </handler> </OutFaultFlow > <InFaultFlow> <handler name="SampleInFaultHandler" class="com.packt.axis2.archetype.hanlder.SampleAxis2Handler"> <order phase="samplephase" /> </handler> </InFaultFlow > </module>
com.packt.axis2.archetype.hanlder |-pom.xml |-module.xml |-src |-main/java/com/packt/axis2/archetype/handler/SampleAxis2Handler.java |-main/java/com/packt/axis2/archetype/module/SampleAxis2Module.java |-test/java/com/packt/axis2/archetype/handler/SampleAxis2HandlerTest.java
mvn clean install
. Inside the target
directory, you will see the resultant module archive, com.packt.axis2.archetype.handler-1.0.0.mar
.Everything we have discussed so far is not directly related to building a custom archetype. It's all about building an Axis2 module. Now, let's see how to turn this into an archetype by performing the following steps:
com.packt.axis2.archetype.handler
directory and execute the following command:$ mvn archetype:create-from-project
com.packt.axis2.archetype.handler/target/generated-sources/archetype
directory. Let's have a look at the pom.xml
file created inside com.packt.axis2.archetype.handler/target/generated-sources/archetype
directory. By default, the artifactId
of the archetype is generated by appending -archetype
to the original artifactId
of the template project, which is shown as follows:<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt.axis2</groupId>
<artifactId>
com.packt.axis2.archetype.handler-archetype
</artifactId>
<version>1.0.0</version>
<packaging>maven-archetype</packaging>
<name>com.packt.axis2.handler.archetype-archetype</name>
<build>
<extensions>
<extension>
<groupId>org.apache.maven.archetype</groupId>
<artifactId>archetype-packaging</artifactId>
<version>2.2</version>
</extension>
</extensions>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-archetype-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<url>http://maven.apache.org</url>
</project>
local
repository, just type mvn install
in the command-line from com.packt.axis2.archetype.handler/target/generated-sources/archetype
.Now we've got our very first Maven archetype created and deployed into the local
repository. Let's use it to generate a skeleton Axis2 module/handler project, as follows:
$ mvn archetype:generate -B -DarchetypeGroupId=com.packt.axis2 -DarchetypeArtifactId=com.packt.axis2.archetype. handler-archetype -DarchetypeVersion=1.0.0 -DgroupId=com.packt.samples -DartifactId=my-axis2-handler -Dpackage=com.packt.samples.axis2 -Dversion=1.0.0
The previous command will create the following skeleton project. If you run mvn clean install
from the my-axis2-handler
directory, you will notice that themy-axis2-handler-1.0.0.mar
file is created under the my-axis2-handler/target
directory, which is shown as follows:
my-axis2-handler |-pom.xml |-module.xml |-src |-main/java/com/packt/samples/axis2/archetype/handler/SampleAxis2Handler.java |-main/java/com/packt/samples/axis2/archetype/module/SampleAxis2Module.java |-test/java/com/packt/samples/axis2/archetype/handler/SampleAxis2HandlerTest.java
You can find the complete Axis2 handler project at https://svn.wso2.org/repos/wso2/people/prabath/maven/chapter07/axis2-handler.
The archetype descriptor is generated by the archetype:create-from-project
goal. This is at the heart of the archetype and stores the metadata about it. The following configuration shows the archetype-metadata.xml
file (the archetype descriptor), which was generated for our custom archetype. The file is available at com.packt.axis2.archetype.handler/target/generated-sources/archetype/src/main/resources/META-INF/maven
:
<archetype-descriptor name="com.packt.axis2.handler.archetype " > <fileSets> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> <fileSet filtered="true" encoding="UTF-8"> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </fileSet> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/test/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> </fileSets> </archetype-descriptor>
According to the previous archetype-metadata.xml
file, all the *.java
files inside src/main/java and src/test/java
are copied into the archetype. Also, any XML files inside src/main/java
will be copied. During the template generation or while executing the archetype:generate
goal, the archetype
plugin reads archetype-metadata.xml
.
The following lists out the complete archetype-metadata.xml
file with all of the possible options:
<archetype-descriptor name=.. partial=.. >
The name
attribute carries the name of the archetype, while the partial
Boolean attribute indicates whether this archetype represents a complete Maven project or only a part of it.
<requiredProperties> <requiredProperty key=.. > <defaultValue/> </requiredProperty> </requiredProperties>
The requiredProperty
element carries the names of the properties required by the archetype to generate the template code. The defaultValue
element carries the default value of the corresponding property.
<fileSets> <fileSet filtered=.. packaged=.. encoding=.. > <directory/> <includes/> <excludes/> </fileSet> </fileSets>
Each fileSet
element inside the fileSets
parent element defines how the files located in the jar
archetype are used to generate the template. The filtered
Boolean attribute indicates whether the file set should be filtered or not. If set to true
, then the selected set of files will be treated as velocity templates; if not, these will be copied as they are without any modifications. We'll be talking about velocity templates later in this chapter.
The packaged
Boolean attribute indicates whether the file set should be packaged or not. If set to true
, then the directory structure, which contains the file set will be prepended by the value of the package
attribute (-Dpackage
set along with archetype:generate
); if not, the directory structure will be copied as it is. In our example, all XML files are copied without prepending the provided package name, as the packaged
attribute is not set, and this means that it's set to false
.
The encoding
attribute indicates which encoding to be used while filtering the content.
The directory
element indicates where the search is to be carried out and also the location to copy the files.
The includes
element indicates the pattern used to include files while the excludes
element indicates the pattern used to exclude files, as shown in the previous code snippet:
<modules> <module id=.. dir=.. name=.. > <fileSets> <fileSet filtered=.. packaged=.. encoding=.. > <directory/> <includes/> <excludes/> </fileSet> </fileSets> </module> </modules>
The modules
parent element is used as a container for multiple module
child elements. This is only used in cases where we need to generate a multimodule Maven project with a single archetype. Each module
element contains the definition of each Maven module. Next, in this chapter, we will see how to generate a multimodule Maven project from an archetype.
</archetype-descriptor>
The process of creating an archetype that generates a multimodule Maven project is no different from what we have done previously for a single module project. You need to go inside the root of the Maven project and run the following command. We will discuss multimodule projects in Chapter 9, Best Practices.
$ mvn archetype:create-from-project
Let's create a multimodule project with the following steps:
org.codehaus.mojo.archetypes:pom-root
archetype to generate the root POM file:$ mvn archetype:generate -DgroupId=com.packt.samples -DartifactId=com.packt.sample.multi.module.archetype -Dversion=1.0.0 -Dpackage=com.packt.sample.multi.module.archetype -DinteractiveMode=false -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=pom-root
com.packt.sample.multi.module.archetype
and then run the following command to create a child module under the parent Maven project:$ mvn archetype:generate -DgroupId=com.packt.samples -DartifactId=com.packt.sample.multi.module.archetype.mod1 -Dversion=1.0.0 -Dpackage=com.packt.sample.multi.module.archetype.mod1 -DinteractiveMode=false
This command will generate a new module with the name com.packt.sample.multi.module.archetype.mod1
and will also update the root POM file.
com.packt.sample.multi.module.archetype
and then run the following command to create another child module under the same parent Maven project:$ mvn archetype:generate -DgroupId=com.packt.samples -DartifactId=com.packt.sample.multi.module.archetype.mod2 -Dversion=1.0.0 -Dpackage=com.packt.sample.multi.module.archetype.mod2 -DinteractiveMode=false
Now we have the following project structure with a root POM file and two child modules:
com.packt.sample.multi.module.archetype |-pom.xml |-com.packt.sample.multi.module.archetype.mod1 |-pom.xml |-com.packt.sample.multi.module.archetype.mod2 |-pom.xml
The following configuration is the root POM file under com.packt.sample.multi.module.archetype
. This has references to all of its child projects under the modules
element:
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.packt.samples</groupId> <artifactId>com.packt.sample.multi.module.archetype </artifactId> <version>1.0.0</version> <packaging>pom</packaging> <name>com.packt.sample.multi.module.archetype</name> <modules> <module>com.packt.sample.multi.module.archetype.mod1 </module> <module>com.packt.sample.multi.module.archetype.mod2 </module> </modules> </project>
The following is the POM file under com.packt.sample.multi.module.archetype.mod1
. This has a reference to the parent POM file under the parent
element:
<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.packt.samples</groupId> <artifactId>com.packt.sample.multi.module.archetype </artifactId> <version>1.0.0</version> </parent> <groupId>com.packt.samples</groupId> <artifactId>com.packt.sample.multi.module.archetype.mod1 </artifactId> <version>1.0.0</version> <name>com.packt.sample.multi.module.archetype.mod1</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>
The following is the POM file under com.packt.sample.multi.module.archetype.mod2
. This also has a reference to the parent POM file under the parent
element:
<project> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.packt.samples</groupId> <artifactId>com.packt.sample.multi.module.archetype </artifactId> <version>1.0.0</version> </parent> <groupId>com.packt.samples</groupId> <artifactId>com.packt.sample.multi.module.archetype.mod2 </artifactId> <version>1.0.0</version> <name>com.packt.sample.multi.module.archetype.mod2</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>
com.packt.sample.multi.module.archetype
directory, and then run the following command:$ mvn archetype:create-from-project
com.packt.sample.multi.module.archetype/target/generated-sources/archetype
directory and then run the following command to install the new archetype in the local
repository:$ mvn install
Now we've got our multimodule Maven archetype created and deployed into the local
repository. Here, you can see the generated archetype-metadata.xml
file, which is inside com.packt.sample.multi.module.archetype/target/generated-sources/archetype/src/main/resources/META-INF/maven
:
<archetype-descriptor name="com.packt.sample.multi.module.archetype"> <modules> <module id="${rootArtifactId}.mod2" dir="__rootArtifactId__.mod2" name="${rootArtifactId}.mod2"> <fileSets> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/test/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> </fileSets> </module> <module id="${rootArtifactId}.mod1" dir="__rootArtifactId__.mod1" name="${rootArtifactId}.mod1"> <fileSets> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/main/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> <fileSet filtered="true" packaged="true" encoding="UTF-8"> <directory>src/test/java</directory> <includes> <include>**/*.java</include> </includes> </fileSet> </fileSets> </module> </modules> </archetype-descriptor>
Let's use the created multimodule archetype to generate a Maven project based on the template, as follows:
$ mvn archetype:generate -B -DarchetypeGroupId=com.packt.samples -DarchetypeArtifactId=com.packt.sample.multi.module.archetype-archetype -DarchetypeVersion=1.0.0 -DgroupId=com.packt.samples -DartifactId=my-multi-module-project -Dpackage=com.packt.samples.multi.module -Dversion=1.0.0
This command will create the following skeleton project. If you run mvn clean install
from my-multi-module-project
directory, all the child modules will be built, which is shown as follows:
my-multi-module-project |-pom.xml |-my-multi-module-project.mod1 |-my-multi-module-project.mod2
The create-from-project
goal of the archetype
plugin creates an archetype project from an existing Maven project. That is exactly what we have done in the previous section. When we execute mvn archetype:create-from-project
without any custom parameters, the plugin will use the default values and follow a convention.
Let's see how to create an archetype with a set of configured properties by performing the following steps:
com.packt.sample.multi.module.archetype
, which is the archetype project we created in the previous section, and create a file called archetype.properties
right under it with the following content:archetype.groupId=com.packt.archetypes archetype.artifactId=com.packt.archetypes.multi.module archetype.version=1.0.0
com.packt.sample.multi.module.archetype
directory:$ mvn archetype:create-from-project -Darchetype.properties=archetype.properties
com.packt.sample.multi.module.archetype/target/generated-sources/archetype
and then run mvn install
to deploy the archetype into the local
Maven repository. Unlike in the previous case, the plugin won't try to generate an artifactId
element for the archetype; it will simply use what is given in the archetype.properties
file. In the default scenario, artifactId
is com.packt.sample.multi.module.archetype-archetype
; however, now it is com.packt.archetypes.multi.module
.All these properties are standard ones. You can also define custom properties as follows:
com.packt.sample.multi.module.archetype
directory, which is the archetype project we created in the previous section, and create a file called archetype.properties
right under it with the following content. Make sure that there are no periods (.) in the name of the custom property. Here, we use the junit
version used in the project. The value of the custom property will be used as the default value:archetype.groupId=com.packt.archetypes
archetype.artifactId=com.packt.archetypes.multi.module
archetype.version=1.0.0
junit-version=3.8.1
com.packt.sample.multi.module.archetype/com.packt.sample.multi.module.archetype.mod1/pom.xml
and com.packt.sample.multi.module.archetype/com.packt.sample.multi.module.archetype.mod2/pom.xml
files and replace the value 3.8.1
with the $junit-version
place holder, which is shown as follows:<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>$junit-version</version>
<scope>test</scope>
</dependency>
com.packt.sample.multi.module.archetypedirectory
:$ mvn archetype:create-from-project -Darchetype.properties=archetype.properties
com.packt.sample.multi.module.archetype/target/generated-sources/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml
, you will notice that the following new section is added to the archetype-metadata.xml
file. This means that at the time you generate the template code, you have to pass a value to the custom property junit-version
, as follows:<requiredProperties>
<requiredProperty key="junit-version">
<defaultValue>3.8.1</defaultValue>
</requiredProperty>
</requiredProperties>
com.packt.sample.multi.module.archetype/target/generated-sources/archetype
directory and then type mvn install
to deploy the archetype into the local
Maven repository.-Djunit-version=4.11
as an argument. If you look at the generated POM files, you will notice that the version of the junit
dependency is set to 4.11
, shown as follows:$ mvn archetype:generate -B -DarchetypeGroupId=com.packt.archetypes -DarchetypeArtifactId=com.packt. archetypes.multi.module -DarchetypeVersion=1.0.0 -DgroupId=com.packt.samples -DartifactId=my-multi-module-project -Dpackage=com.packt.samples.multi.module -Dversion=1.0.0 -Djunit-version=4.11
More details about the create-from-project
goal is available at http://maven.apache.org/archetype/maven-archetype-plugin/create-from-project-mojo.html.
3.135.196.172