13
Feb
13

Create Custom Maven Plugin


This page describes how to create a custom maven plugin.

Full downloadable source for this page is available here. Corrections and enhancements are welcome, fork, change and push back to GitHub.

Problem Statement

This site contains hundreds pages with small demo java projects embedded in its pages.

While working on this site I came across a few problems.

  1. How to reduce typo errors on the pages source code.
  2. How to keep the blog page up to date after code fixes.

The solution: Have a custom maven plugin generate the blog page with source code automatically. The plugin uses velocity template that contain the text of the blog page along with “#include” velocity directives that bring in the source code from the project.

Implementation

Follow these steps to create a custom plugin to generate HTML content from velocity templates.

Start by editing the pom.xml file to look like this.

vi pom.xml

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>github.numberformat</groupId>
	<artifactId>blog-plugin</artifactId>
	<version>1.0-SNAPSHOT</version>
	<packaging>maven-plugin</packaging>

	<properties>
		<mavenVersion>2.0.6</mavenVersion>
	</properties>

	<pluginRepositories>
	  <pluginRepository>
	    <id>numberformat-releases</id>
	    <url>https://raw.github.com/numberformat/20130213/master/repo</url>
	  </pluginRepository>
	</pluginRepositories>

	<dependencies>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-plugin-api</artifactId>
			<version>2.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.velocity</groupId>
			<artifactId>velocity</artifactId>
			<version>1.7</version>
		</dependency>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-model</artifactId>
			<version>${mavenVersion}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-artifact</artifactId>
			<version>${mavenVersion}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-project</artifactId>
			<version>${mavenVersion}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-core</artifactId>
			<version>${mavenVersion}</version>
		</dependency>
	</dependencies>
	<name>Wordpress Page Generation Plugin</name>
	<description>Generates a wordpress page for the project.</description>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
	 		<plugin> 			
	 			<groupId>github.numberformat</groupId>
	 			<artifactId>blog-plugin</artifactId>
	 			<version>1.0-SNAPSHOT</version>
	 			<configuration>
				<gitUrl>https://github.com/numberformat/20130213</gitUrl>
	 			</configuration>
	        <executions>
	          <execution>
	            <id>1</id>
	            <phase>site</phase>
	            <goals>
	              <goal>generate</goal>
	            </goals>	            
	          </execution>
	        </executions>
	 		</plugin>
		</plugins>
	</build>
</project>

The following file is the plugin implementation class.

BlogMojo.java

package github.numberformat.plugin;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;

/**
 * This is a simple plug-in that generates a blog page from a velocity
 * template. This allows developers to create very simple project documentation
 * pages for their projects. Developers would typically create a blog entry by
 * copying and pasting the HTML directly into the blog site.
 * 
 * @goal generate
 */
public class BlogMojo extends AbstractMojo {
	/**
	 * @parameter default-value="${basedir}"
	 * @required
	 * @readonly
	 */
	private File basedir;

	/**
	 * Represents the date first published.
	 * 
	 * @parameter default-value="https://github.com/numberformat"
	 * @required
	 * @readonly
	 */
	private String gitUrl;
	
	
	public void execute() throws MojoExecutionException {
		
		final File templateDir = basedir;
		final File targetBlog = new File(basedir, "target/blog");

		if(new File(templateDir, "src/blog/wordpress.vm").canRead()) {
			if(!targetBlog.exists()) {
				targetBlog.mkdirs();
			} else if(!targetBlog.isDirectory()) {
				throw new MojoExecutionException("Must be a directory: " + targetBlog.getAbsolutePath());
			}
	
	        VelocityEngine ve = new VelocityEngine();
	        ve.setProperty("file.resource.loader.path", templateDir.getAbsolutePath());
	        ve.init();
        
	        Template t = ve.getTemplate( "src/blog/wordpress.vm" );
	        VelocityContext context = new VelocityContext();
	        context.put("blog_header", getHeader());
	        context.put("blog_footer", getFooter());
	        context.put("blog_git_url", gitUrl);
	        
	        FileWriter writer = null;
			try {
				writer = new FileWriter(new File(targetBlog, "wordpress.html"));
		        t.merge( context, writer );				
			} catch (IOException e) {
				throw new MojoExecutionException(e.getMessage());
			} finally {
				try{writer.close();}catch(Exception e){}				
			}
		}
	}


	private Object getFooter() {
		return "<div style=\"font-size:13px;border:1px solid gray; " +
				"padding:5px;line-height:120%\">Full downloadable source for " +
				"this page is <a href=\""+gitUrl+"\">available here</a>. " +
				"</div>";
	}

	private Object getHeader() {
		return "<div style=\"font-size:13px;border:1px solid gray; " +
				"padding:5px;line-height:120%\">Full downloadable source for " +
				"this page is <a href=\""+gitUrl+"\">available here</a>. " +
				"Corrections and enhancements are welcome, fork, change and push " +
				"back to GitHub.</div>";
	}
}

Publish to Nexus or Website

You may deploy the plugin into a nexus repository a simple website.

Example Usage

For demonstration purposes I have published the plugin to the following URL, you may use it in your project by including it in your pom.xml.

vi pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test</groupId>
  <artifactId>testProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <pluginRepositories>
    <pluginRepository>
      <id>numberformat-releases</id>
      <url>https://raw.github.com/numberformat/20130213/master/repo</url>
    </pluginRepository>
  </pluginRepositories>
  
  <build>
  	<plugins>
  		<plugin> 			
  			<groupId>github.numberformat</groupId>
  			<artifactId>blog-plugin</artifactId>
  			<version>1.0-SNAPSHOT</version>
	        <executions>
	          <execution>
	            <id>1</id>
	            <phase>site</phase>
	            <goals>
	              <goal>generate</goal>
	            </goals>	            
	          </execution>
	        </executions>
  		</plugin>
  	</plugins>
  </build>
</project>

As you can see from the above the plugin to generate the wordpress page is hooked into the “site” phase of the build lifecycle.

Velocity Template

Save the file into:

src/blog/wordpress.vm

#set( $foo = "Velocity" )
Hello $foo World!

(include sourcecode tag in square brackets around the include line below)
#include("src/main/java/App.java")
(include /sourcecode tag in square brackets around the include line above)

Run the Plugin

To run the plugin and you have specified the executions tag above just type

mvn site

As an alternative if you don’t want to hook it into the maven lifecycle then just delete the “executions” tag above and run the plugin by typing:

To run the plugin just type

mvn blog:generate

If you get a WARNING about plexus ignore it.

Upon successful build you can view the generated wordpress page in the target/blog folder of the project.

Next Steps

blog-plugin improvements:

  1. Enhance the plugin to generate pages in formats other than wordpress.
  2. Have plugin insert headers or footers on the generated pages. (done)
  3. Enhance the plugin to have blog pages contain a link to GitHub where visitors can simply checkout the project instead of copying and pasting source from the page. (done)
Full downloadable source for this page is available here.
Advertisements

0 Responses to “Create Custom Maven Plugin”



  1. Leave a Comment

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 77 other followers

February 2013
S M T W T F S
« Jan   May »
 12
3456789
10111213141516
17181920212223
2425262728  

Blog Stats

  • 830,829 hits

%d bloggers like this: