Install this theme

Posts tagged: maven

Database change management with Liquibase

Consult https://github.com/bigpuritz/javaforge-blog/tree/master/liquibase-sample for the sample project sources.

Quote:

Liquibase is an open source (Apache 2.0 Licensed), database-independent library for tracking, managing and applying database changes. 

It is built on a simple premise: All database changes are stored in a human readable yet trackable form and checked into source control.

This post is a simple tutorial demonstrating how to use Liquibase in a real world project. We’ll assume that our sample project lives through multiple phases, each of which adds diverse changes to the database.

Let’s prepare our sample project to use Liquibase within Maven build first. We need to define the liquibase-maven-plugin within the <plugins>…</plugins> block and point it to the liquibase.properties file, containing all properties required by the Liquibase at runtime. Both are demonstrated below.

Keep reading

Using XSDs or any other custom resources as Maven dependencies

Often it is required to put some custom resources (e.g. XSDs, WSDLs etc.) under dependency management control.

As soon as Maven is a de facto standard dependency management mechanism in the Java world, this post demonstrates how to use it to manage untypical custom resources as dependencies within the pom.xml.

Let’s assume we have some xsd file (test.xsd in this example), that we want to use as dependency in our POM.

First, we’ll deploy it to the local repository (alternatively you can deploy it to your company’s internal maven repository):

mvn install:install-file -Dfile=test.xsd -DgroupId=com.mycompany.app \
           -DartifactId=app-xsd -Dversion=1.0.0 -Dtype=xsd -Dpackaging=xsd

After installation you’ll find the xsd in your local maven repository within the following folder structure:

image

Next referencing this file as a dependency in your POM is quite simple. Just write:

<dependency>
	<groupId>com.mycompany.app</groupId>
	<artifactId>app-xsd</artifactId>
	<version>1.0.0</version>
	<type>xsd</type>
</dependency>	 

Furthermore if you want to add this file as a resource to the final artifact generated by Maven, you have to configure maven-dependency-plugin in your POM like this:

<build>
	<plugins>
		...
		<plugin>
			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-dependency-plugin</artifactId>
			<version>2.5.1</version>
			<executions>
				<execution>
					<id>copy-dependencies</id>
					<phase>generate-resources</phase>
					<goals>
						<goal>copy-dependencies</goal>
					</goals>
					<configuration>
						<outputDirectory>${project.build.directory}/${project.build.finalName}/META-INF</outputDirectory>
						<includeArtifactIds>app-xsd</includeArtifactIds>
						<includeTypes>xsd</includeTypes>
					</configuration>
				</execution>
			</executions>
		</plugin>
		...
	</plugins>		
</build> 

After executing the maven build the app-xsd-1.0.0.xsd file will land in the artifact’s META-INF folder.

Releasing maven artifacts using Ant and Maven Ant Tasks

In the current project one of my tasks was to simplify the maven release process. This should be a simple one click solution, that satisfies following requirements:

  • Release has to be executed either from IDE or from the command line.
  • Everyone (not only developer) should be able to execute release.
  • It should hide the pain of executing multiple maven goals (release:prepare, release:perform) after each other.
  • After releasing the software released artifacts for all profiles specified in the pom.xml should be deployed to the company’s maven repository.

I decided to write a simple Ant script that internally makes use of Maven Ant Tasks.

First a target asking user for all required release informations was born:

<?xml version="1.0" encoding="UTF-8"?>
<project name="myprj" default="release" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
	<property environment="env" />
	<path id="maven-ant-tasks.classpath" path="maven-ant-tasks-2.1.3.jar" />
	<typedef resource="org/apache/maven/artifact/ant/antlib.xml"
               uri="antlib:org.apache.maven.artifact.ant" classpathref="maven-ant-tasks.classpath" />
 
	<!-- - - - - - - - - - - - - - - - - - 
          target: prerequisites                      
         - - - - - - - - - - - - - - - - - -->
	<target name="prerequisites">
		<fail unless="env.MAVEN_HOME" 
		    		message="Environment variable MAVEN_HOME was not found on your system!" />
	</target>

	<!-- - - - - - - - - - - - - - - - - - 
          target: input                      
         - - - - - - - - - - - - - - - - - -->
	<target name="input">
		<artifact:pom id="local.pom" file="pom.xml" />
		<script language="javascript">
		<![CDATA[	
		    var before = project.getProperty("local.pom.version");
		    project.setProperty("tmp.release.version", before.replaceAll("-SNAPSHOT", ""));
			
		    var tmpVersion = project.getProperty("tmp.release.version");
		    var nextVersionNo = tmpVersion.substr( tmpVersion.lastIndexOf(".") + 1 );
		    project.setProperty("tmp.next.version", 
			      tmpVersion.substr(0, tmpVersion.lastIndexOf(".") + 1) + 
			      (parseInt(nextVersionNo)+1) + 
			      "-SNAPSHOT"
		    );
		]]>
		</script>

		<input message="Please enter the project release version?" 
			defaultvalue="${tmp.release.version}" addproperty="prj.release.version" />
		<input message="Please enter the svn tag name?" 
			defaultvalue="${local.pom.artifactId}-${prj.release.version}" addproperty="prj.release.tag" />
		<input message="Please enter the project next version?" 
			defaultvalue="${tmp.next.version}" addproperty="prj.next.version" />

		<fail unless="prj.release.version" message="Property 'prj.release.version' was not defined!" />
		<fail unless="prj.release.tag" message="Property 'prj.release.tag' was not defined!" />
		<fail unless="prj.next.version" message="Property 'prj.next.version' was not defined!" />
	</target>
</project> 

The “input”-target uses <artifact:pom … /> task and offers the POM structure to the ant script. 

Furthermore it makes use of Ant’s possibility to embed javascript, that reads current artifact version from the POM and pre-set some default variables like release version, release tag and next development version.

Finally the second target specifies the release procedure:

<target name="release" depends="prerequisites, input" description="project release ant script">
	<artifact:mvn mavenHome="${env.MAVEN_HOME}" fork="true">
		<arg value="--batch-mode" />
		<arg value="-Dtag=${prj.release.tag}" />
		<arg value="-DreleaseVersion=${prj.release.version}" />
		<arg value="-DdevelopmentVersion=${prj.next.version}" />
		<arg value="clean" />
		<arg value="release:prepare" />
		<arg value="release:perform" />
	</artifact:mvn>

	<available file="target/checkout" type="dir" property="checkout.dir.present" />
	<fail unless="checkout.dir.present" message="Checkout directory 'target/checkout' is not present!" />

	<!-- deploy 'test1' profile -->
	<artifact:mvn mavenHome="${env.MAVEN_HOME}" pom="target/checkout/pom.xml" fork="true">
		<arg value="-Ptest1" />
		<arg value="clean" />
		<arg value="deploy" />
	</artifact:mvn>

	<!-- deploy 'test2' profile -->
	<artifact:mvn mavenHome="${env.MAVEN_HOME}" pom="target/checkout/pom.xml" fork="true">
		<arg value="-Ptest2" />
		<arg value="clean" />
		<arg value="deploy" />
	</artifact:mvn>		
	
	<!-- deploy 'prod' profile -->
	<artifact:mvn mavenHome="${env.MAVEN_HOME}" pom="target/checkout/pom.xml" fork="true">
		<arg value="-Pprod" />
		<arg value="clean" />
		<arg value="deploy" />
	</artifact:mvn>
</target> 

Because it is just a simple ant script, it can be executed either directly from your favorite IDE

or from the command line tool by calling: ant -f release.xml


Note! maven-ant-tasks-2.1.3.jar file has to be commited to the SCM together with the release.xml

Generating boilerplate code with Maven and Groovy

In every project, there are frequently code fragments, one would like to generate on builtime instead to code by hand. This post demonstrates how to generate Java sources with Groovy as part of the Maven build lifecycle without much effort.

As an example I’ll take the RestyGWT interfaces from one of the previous posts (see GWT: Creating REST Services with Jersey and RestyGWT) and show how to generate them on build time.

Note! Using Groovy scripts it is possible to generate nearly any kind of required project sources / resouces.

Keep reading

Generating project documentation with Docbook, Maven and Docbkx Maven Plugin

Out of the box Maven already provides facilities for generating project documentation, so called Maven Sites. Very often, however, it is desirable to create a good looking, “book-style” PDF document(s) that can be delivered to the end customers for example or as self-containing project documentation. To accomplish this task, Docbook would be a good choice.

This post describes how to create/generate docbook documents from the Maven project using  Docbkx Maven Plugin. Consult GitHub for the complete project sample: https://github.com/bigpuritz/javaforge-blog/tree/master/docbkx.

The sample project mentioned above is a maven artifact with a jar packaging type. It defines special profile docbkx in pom.xml, that activates docbkx-maven-plugin run (pdf generation) in the package phase. Furthermore build-helper-maven-plugin is added to this profile. It attaches (as zip) compressed pdf as artifact to the maven’s build lifecycle so that it can be installed in the maven repository on build.

Excerpt from pom.xml :

<profiles>
  <profile>
    <id>docbkx</id>
    <build>
      <plugins>
        <plugin>
          <groupId>com.agilejava.docbkx</groupId>
          <artifactId>docbkx-maven-plugin</artifactId>
          <version>2.0.14</version>
          <executions>
            <execution>
              <id>doc</id>
              <goals>
                <goal>generate-pdf</goal>
              </goals>
              <phase>package</phase>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>net.sf.xslthl</groupId>
              <artifactId>xslthl</artifactId>
              <version>2.0.2</version>
              <scope>runtime</scope>
            </dependency>
            <dependency>
              <groupId>net.sf.offo</groupId>
              <artifactId>fop-hyph</artifactId>
              <version>1.2</version>
              <scope>runtime</scope>
            </dependency>
          </dependencies>
          <configuration>
            <sourceDirectory>docs</sourceDirectory>
            <targetDirectory>target/docs</targetDirectory>
            <xincludeSupported>true</xincludeSupported>
            <useExtensions>1</useExtensions>
            <highlightSource>1</highlightSource>
            <highlightDefaultLanguage>java</highlightDefaultLanguage>
            <calloutsExtension>1</calloutsExtension>
            <paperType>A4</paperType>
            <fop1Extensions>1</fop1Extensions>
            <foCustomization>${basedir}/conf/customization-fopdf.xsl</foCustomization>
            <includes>manual.xml</includes>
            <postProcess>
              <zip
                destfile="${project.build.directory}/${project.artifactId}-${project.version}-docs.zip">
              <fileset dir="${project.build.directory}/docs"
                includes="**/*.pdf" />
              </zip>
            </postProcess>
          </configuration>
        </plugin>
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>build-helper-maven-plugin</artifactId>
          <version>1.7</version>
          <executions>
            <execution>
              <goals>
                <goal>attach-artifact</goal>
              </goals>
              <phase>package</phase>
              <configuration>
                <artifacts>
                  <artifact>
                    <file>${project.build.directory}/${project.artifactId}-${project.version}-docs.zip</file>
                    <type>zip</type>
                    <classifier>docs</classifier>
                  </artifact>
                </artifacts>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
</profiles>

Running a build with activated profile is quite easy:

mvn -Pdocbkx clean install

This will create following set of artifacts in the local maven repository:

image

And last but not least, take a look at the PDF document generated on the sample project build. This is how cool project documentation should look like :)

Note! In case of maven multi-module project it is probably a better idea to create a separate maven module with pom packaging type used for documentation only.