Posts Tagged ‘Archetypes’

Working with Custom Maven Archetypes (Part 3)

February 25, 2010

In part 1 and part 2 of this series I was able to demonstrate how you can create a custom archetype and release it to a Maven repository. In this final part we’ll look at what you need to do to integrate it into your development process. This will involve the following steps:

  • Uploading the archetype and its associated metadata to a Maven Repository Manager.
  • Configuring an IDE to use the archetype.
  • Generating a skeleton project from the archetype.

Step 1 – Upload your archetype

In part 2 we covered releasing and deploying the archetype. For reasons of brevity I simply demonstrated deploying a release to the local file system, but if we wish to share our archetype we must deploy it to a remote repository that can be accessed by other developers. A remote Maven repository, in its simplest form, can be served up using a Http server such as Apache or Nginx. However, these days I would recommend that you use a Maven Repository Manager (MRM) instead, as these tools are purpose-built for serving (and deploying) Maven artefacts. There are basically three options for your MRM – Nexus, Artifactory or Archiva. A features matrix comparision is available here. All are available in open source flavours and both Nexus and Artifactory in particular are great tools. However, currently Artifactory is the only one that supports a Cloud-based service option which, as you might expect, integrates very well with our hosted Continuous Integration service. This allows you to provision yourself a fully-fledged MRM in very short order.

So, how do we add our archetype to the repository? This is a simple process using the built in Artifact Deployer of Artifactory which allows you to upload a file and supply its Maven GAV co-ordinates.

Artifactory Deployer

Artifactory Web-based Deployer

Next, we need to add some additional metadata about our archetype in the form of a ‘catalog’:


<?xml version="1.0" encoding="UTF-8"?>
<archetype-catalog>
  <archetypes>
    <archetype>
    <groupId>com.mikeci</groupId>
    <artifactId>mikeci-archetype-springmvc-webapp</artifactId>
    <version>0.1.4</version>
    <repository>http://mikeci.artifactoryonline.com/mikeci/libs-releases</repository>
    <description>Mike CI archetype for creating a Spring-Mvc web application.</description>
    </archetype>
  </archetypes>
</archetype-catalog>

This file should ideally be placed into an appropriate folder of a Maven repository and it contains information about all of the archetypes that live within the repository. We can simply add this file to our ‘libs-releases’ repository using Artifactory’s REST API:


curl -u username:password -f -d @archetype-catalog.xml -X PUT "http://mikeci.artifactoryonline.com/mikeci/libs-releases/archetype-catalog.xml"

Step 2 – Configure your IDE

Now that our archetype is deployed remotely, we can start to use it from within our IDE – in my case – Eclipse. To get good Maven integration inside Eclipse, you really should be using the latest release (0.10.0) of m2eclipse. Once m2eclipse is installed, it provides a handy feature that allows you to add and remove archetype catalogs. You will need to add your deployed archetypes catalog to the list of catalogs accessible from within m2eclipse. This ensures that you can access your custom archetypes when you run the Create a Maven Project wizard in Eclipse as we will see shortly.

Choose the menu item, Windows>Preferences, to open the Preferences dialog and drill down to the Maven>Archetypes preferences, as shown.


m2eclipse Archetype Prefs

Setting archetype preferences


Click Add Remote Catalog to bring up the Remote Archetype Catalog dialog. In the Catalog File text box, enter the path to your remote catalog file and in the Description text box, enter a name for your catalog:

m2eclipse Remote Catalog

Adding the catalog

Step 3 – Generate your project

You should now be ready to generate a skeleton Maven project inside Eclipse. Choose the menu item, File>New>Other, to open the Select a wizard dialog. From the scrollbox, select Maven Project and then click Next. Follow the wizard to configure your project location. Eventually, the wizard allows you to select the archetype to generate your Maven project. From the Catalog drop-down list, select your custom catalog. Then locate and select your archetype :

m2eclipse Select Archetype

Select the archetype

Click Next and enter the GAV values for your new project. Et voila – you should have just created a skeleton project based upon your custom archetype using a slick IDE wizard.

Pretty impressive, don’t you think?

Working with Custom Maven Archetypes (Part 1)

January 14, 2010

Late last year we announced support for Maven on our hosted CI platform. This was something we introduced earlier than anticipated as we discovered that the majority of our private beta participants wanted to use this increasingly popular tool for their builds. We also provide support for Apache Ant and Eclipse IDE based projects that don’t include a build.xml or POM file. The rationale behind the latter is to allow developers to get up and running with CI in no time at all. We also released an (open source) Eclipse plugin – mikeclipse – that in its current incarnation allows you to generate a ‘Mike-friendly’ web application project so you can quickstart your development effort. You can create a web app with Struts2 or Spring-Mvc based project flavours. No ‘Mike-specific’ hooks are written in to the generated apps, so you can just use it as a simple wizard to generate a skeleton project. We intend to expand the features of this plugin over the course of the coming months.

Those of you who are familiar with Maven will probably be aware that this generation of skeleton projects is already available via the maven-archetype-plugin. This plugin generates a project based upon a template – called an archetype of course – that you package as discreet Maven (jar) component. Once you have installed or deployed your archetype into a Maven repository it can then be processed by the maven-archetype-plugin. At execution time, if used interactively, the plugin will prompt you with a series of questions about which archetype you wish to use and what, using Maven-ese, the ‘GAV’ (GroupId/ArtifactId/Version) coordinates are for your skeleton project.

I’ve been a user of the plugin for some years now, buts its been a little while since i’ve created a custom archetype, so I thought it might be worth sharing the process I went through to create it. Along the way I discovered some nice features that, at time of writing, did not appear to be fully documented on the plugin site, so I’ve captured them here. I’ll look into creating a issue and/or submitting a patch to the Maven project for these omissions if required later.

Step 1 – Generate Your Archetype

This was a new one for me. Previously I had always hand crafted my custom archetypes, but the plugin supports a goal that allows you to create the basis of your archetype from an existing project – very handy. So I used mikeclipse to create myself a Spring-Mvc skeleton project, did some refactorings to mavenize it – create a POM basically – and executed the following command in my shell


~/foo/example$ mvn archetype:create-from-project
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ---------------------------------------------------------
[INFO] Building example
[INFO]    task-segment: [archetype:create-from-project] (aggregator-style)
[INFO] ---------------------------------------------------------
[INFO] Preparing archetype:create-from-project
[INFO] ---------------------------------------------------------
[...]
[INFO] Archetype created in target/generated-sources/archetype
[INFO] ---------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ---------------------------------------------------------

This created a first-cut archetype for me in target/generated-sources/archetype that i could now tweak.

Step 2 – Removing redundant files

First thing i needed to was make some small changes to remove some superfluous Eclipse metadata files. This is probably an oversight on my part as i could have generated the archetype after removing these, but since i wanted to view the results of the archetype generation in Eclipse, the plugin had hoovered them up. So I removed them from the archetype-resources sub-directory (under target/generated-sources/archetype) and also edited the two archetype descriptor files under archetype-resources/META-INF/maven. I believe that two files are created to ensure backward-compatability with earlier versions of the archetype plugin – i was using the 2.0-alpha-4 release which supports the new archetype-metadata.xml format descriptor. For example, I removed the following entry from archetype-metadata.xml after deleting the files:


  <fileSet filtered="true" encoding="UTF-8">
     <directory></directory>
     <includes>
        <include>.project</include>
        <include>.classpath</include>
     </includes>
  </fileSet>

Step 3 – Fixing Velocity warnings

Under the hood, the archetype plugin uses Apache Velocity to do its file filtering – for example, the substitution of the GAV values I discussed above. Those who have used Velocity will be aware that it can be quite verbose in its output, especially when it encounters syntax that resembles a filterable value. This manifests itself in warnings like the following when you generate a project using your archetype (I’ll cover that process shortly):


   [WARNING] ... : ${mvnVersion} is not a valid reference.

While this warning does not materially affect what gets generated it doesn’t build confidence in your archetype as it will be one of the first things your users will see. So lets see how we can fix this. In my case, its due to the fact that my template POM contains a number of properties that I don’t want to be filtered and should be left intact as part of the generation. This is not an uncommon problem with POM’s – they often contain properties that allow a runtime interpolated value to be changed in one place. We can use some simple Velocity syntactical sugar as follows. Declare the following directive at the top of your template pom.xml file under archetype-resources


  #set( $symbol_dollar = '$' )

Then, wherever you declared a property that you want to be ‘ignored’ by Velocity do something akin to the following


  <requireMavenVersion>
    <version>${symbol_dollar}{mvnVersion}</version>
  </requireMavenVersion>

Step 4 – Filtering a filename

One of the nice features in the latest version of the archetype plug-in is the ability to re-name files during the generation process. In my scenario, I want to use this feature to ensure that my Spring servlet descriptor matches up with the associated declaration in my web.xml file. However, I did have to do a little digging to find out how to do this via the plugin JIRA as when I looked it did’nt jump out from the plugin web site examples or usage pages. Anyways, its pretty simple to do. Just create the template file using the filterable property as part of its name, using double underscores as token separators. In my case:


  $ mv src/main/webapp/WEB-INF/example-servlet.xml \
  src/main/webapp/WEB-INF/__artifactId__-servlet.xml

Step 5 – Install and invoke the archetype

A quick local installation is simply accomplished by running an mvn install inside the target/generated-sources/archetype directory.

The install creates a metadata file under ~/.m2/ called archetype-catalog.xml.


~/.m2$ cat archetype-catalog.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <archetype-catalog>
   <archetypes>
    <archetype>
     <groupId>com.mikeci</groupId>
     <artifactId>example-archetype</artifactId>
     <version>1.0-SNAPSHOT</version>
     <description>example-archetype</description>
    </archetype>
   </archetypes>
  </archetype-catalog>


Once installed I can invoke it using the archetype:generate goal. By default this will search the public archetype catalog from the Maven central repositories and display all the available ones plus my local one. To tell the plugin to only search my local Maven repository I can use a simple mojo parameter as follows:


~/foo$ mvn archetype:generate -DarchetypeCatalog=local
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] --------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] --------------------------------------------------------------
[INFO] Preparing archetype:generate
[...]
Choose archetype:
1: local -> example-archetype (example-archetype)
Choose a number:  (1): 1
Define value for groupId: : com.acme
Define value for artifactId: : mywebapp
Define value for version:  1.0-SNAPSHOT: :
Define value for package:  com.acme: :
Confirm properties configuration:
groupId: com.acme
artifactId: mywebapp
version: 1.0-SNAPSHOT
package: com.acme
Y: :
[INFO] --------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] --------------------------------------------------------------

Then finally:


~/foo/mywebapp$ mvn package jetty:run -P mikeci,itest
[INFO] Scanning for projects...
[INFO] --------------------------------------------------------------
[INFO] Building example
[INFO]    task-segment: [package, jetty:run]
[INFO] --------------------------------------------------------------
[INFO] [enforcer:enforce {execution: enforce-versions}]
[...]
[INFO] Started Jetty Server

Et voila, my browser displays the simple landing page for the generated web app:

Obviously, I’ll need to subsequently take the generated archetype code and turn it into a proper project in its own right, add it to version control and ultimately deploy/release it to a Maven repository so it can be shared. I’m planning on using Github for the VCS (or SCM in maven-ese) as we are currently working on adding Git support to Mike. I also want to see how the maven-release-plugin handles Git. I’ll cover these topics in the next part of my blog.

Adam