views:

1089

answers:

5

I am using Maven 2 to build my Java project and I am looking for a way to present the current version number of the pom.xml to the user (using a Servlet or JSP for example).

As far as I can see, the best way would be that Maven packages the version number as a text file into the WAR. This allows me to read the version from that file and present it the way I want.

Does anyone know of a plugin that can do something like that for me? Maybe the WAR plugin can be configured to do so? Or maybe using some other approach all together?

+3  A: 

You're looking to do filtering of resources. This is done even before the war-plugin creates the file. I'm pretty sure the war-plugin packs the version in the web.xml and manifest, but I'm not sure how to access those through servlet APIs, but it might also be a valid approach.

Have a look at the Maven resource plugin documentation, it'll tell you how it's done. I think you should be able to just substitue the version using ${version}. Haven't got a working maven installation to test it here though.

roe
Thank you. I hope you can figure it out!
Tom van Zummeren
I just checked it and indeed it works like you suggested! If you set the <filtered> property of a resource to "true", you can use placeholders in text files. In my case the placeholder ${version} does the trick.
Tom van Zummeren
+2  A: 

Of course, variables can be included in resources and filtered wih the maven-resource-plugin by adding a <filtering> tag to the POM and set it to true like this:

...
<resource>
  <directory>src/main/resources</directory>
  <filtering>true</filtering>
</resource>
...

And you could use this feature to read and replace ${version} (or ${project.version} or ${pom.version} which are equivalent) in a properties file for example.

But, actually, the information you are looking for is available by default by Maven (unless you configured it to not do so which is very unlikely if you are not aware of that). If you unpack the WAR that Maven created for you and take a look at it you would see the following:

|-- META-INF
|   |-- MANIFEST.MF
|   `-- maven
|       `-- com.mycompany.app
|           `-- my-app
|               |-- pom.properties
|               `-- pom.xml
|-- WEB-INF
|   |-- classes
|   |   |-- ...
|   |-- lib
|   |   |-- ...
|   `-- web.xml
|-- bar.jsp
|-- ...
`-- foo.jsp

As you can see, you'll find a pom.xm and pom.properties file in it and, as explained in How do I add resources to my JAR?:

The pom.xml and pom.properties files are packaged up in the JAR so that each artifact produced by Maven is self-describing and also allows you to utilize the metadata in your own application if the need arises. One simple use might be to retrieve the version of your application. Operating on the POM file would require you to use some Maven utilities but the properties can be utilized using the standard Java API and look like the following:

#Generated by Maven
#Tue Oct 04 15:43:21 GMT-05:00 2005
version=1.0-SNAPSHOT
groupId=com.mycompany.app
artifactId=my-app

So you could just load this pom.properties file with something like this (pseudo code):

// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/META-INF/maven/com.mycompany.app/my-app/pom.properties" );

// Do something with the resource, e.g. load it as Properties
Properties prop = new Properties();
prop.load(is);
String version = prop.get("version");
Pascal Thivent
Thanks! I wasn't aware of that. Thanks for the very long and clear explanation! And yes this would also work. But in my case I also needed the build number which was produced by another plugin and could be accessed using ${buildNumber}. Your solution can only provide me with a version.
Tom van Zummeren
Oh, this was not my understanding of your initial question and comment to the other answer but, indeed, if you need more information such as the `${buildnumer}` produced by the maven-buildnumber-plugin (http://commons.ucalgary.ca/projects/maven-buildnumber-plugin/howto.html), `pom.properties` won't contain everything.
Pascal Thivent
+1  A: 

I solved this problem a little differently, as I had a desire to display version, svn revision, etc. on the index page of a service. I used the buildnumber-maven-plugin and the war-plugin to store the values in the manifest.

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <executions>
      <execution>
        <phase>validate</phase>
        <goals>
          <goal>create</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
  <plugin>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
        </manifest>
        <manifestEntries>
          <Implementation-Environment>${env}</Implementation-Environment>
          <Implementation-Build>${buildNumber}</Implementation-Build>
        </manifestEntries>
      </archive>
    </configuration>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>war</goal>
        </goals>
        <configuration>
          <classifier>${env}</classifier>
        </configuration>
      </execution>
    </executions>
  </plugin>

The JSP to pull them out was fairly trivial:

<%@ page language="java" pageEncoding="UTF-8"%>
<% 
java.util.jar.Manifest manifest = new java.util.jar.Manifest();
manifest.read(pageContext.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
java.util.jar.Attributes attributes = manifest.getMainAttributes();

%>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <title>Health Check</title>
  </head>
  <body>
    <h1>Health Check</h1>
    <h2>Version: <%=attributes.getValue("Implementation-Version")%>-<%=attributes.getValue("Implementation-Environment")%></h2>
    <h2>SVN Revision: <%=attributes.getValue("Implementation-Build")%></h2>
  </body>
</html>

This displayed something like

Version: 2.0.1-SNAPSHOT-QA

SVN Revision: 932

Mike Cornell
A: 

how to do this with ant?

Skirulau
A: 

My solution for the standard Maven WAR plugin

Add a resources tag to you build section which enables filtering (aka "search and replace"):

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
....
<build>

Then in your src/main/resources add a version.properties file containing any filter variables that matches one of the standard maven build variables (you can also use filtering feature to load your own custom variables):

pom.version=${pom.version}

Now when you do a "maven package" or a maven install it will copy the version.properties file into the WEB-INF/classes and do a search and replace to add the pom version into the file.

To get at this with Java use a class such as:

public class PomVersion {
    final private static Logger LOGGER = LogManager.getLogger(PomVersion.class);

    final static String VERSION = loadVersion();

    private static String loadVersion() {
        Properties properties = new Properties();
        try {
            InputStream inStream = PomVersion.class.getClassLoader().getResourceAsStream("version.properties");
            properties.load(inStream);
        } catch (Exception e){
            LOGGER.warn("Unable to load version.properties using PomVersion.class.getClassLoader().getResourceAsStream(...)", e);
        }
        return properties.getProperty("pom.version");
    }

    public static String getVersion(){
        return VERSION;
    }
}

Now you can just call PomVersion.getVersion() to put the version number of the pom file into the page. You can also have the WAR file be given the same number by using a filter variable in the finalName within the pom.xml:

<build>
    <finalName>my-killer-app-${pom.version}</finalName>
...
</build>

so now if you set your application version in your pom to be 01.02.879:

<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"&gt;
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.killer.app</groupId>
    <artifactId>my-killer-app</artifactId>
    <packaging>war</packaging>
    <name>This App Will Rule The World</name>
    <version>01.02.879</version>
    ...
</project>

when you do an "mvn install" the war file name include the version number also:

my-killer-app-01.02.879.war

finally if you use Spring heavily such as with SpringMVC/SpringWebFlow you can make a singleton service bean which uses that class to avoid having to reference the low level class by name:

@Service("applicationVersion")
public class ApplicationVersion {
    final static String VERSION = PomVersion.getVersion();

    public String getVersion() {
        return VERSION;
    }
}
simbo1905