Easy application versioning with AppInfo

Posted: 2010-12-20 in Tools
Tags: , , ,

AppInfo is a small library which provide the easy way to show always valid, automatic updated information about a version of running software in a web/desktop Java application. This is especially useful in connection with builds from Continuous Integration server which are automatically deployed on QA environment.

In this post I will show how easy is to setup versioning using AppInfo.

Besides AppInfo supports both web and desktop applications with or without Spring Framework in this example very simple console application with Spring is used to make post possible short and easy to understand. Maven is used as a build tool.

Our console application contains class which is run from main. In original version it only prints welcome banner on the console and initialize Spring context.

package net.sf.appinfo.spring.example;

//required imports

public class AppInfoSpringExample {

    protected final Logger log = LoggerFactory.getLogger(getClass());

    private ApplicationContext context;

    public static void main(String args[]) {
        AppInfoSpringExample app = new AppInfoSpringExample();
        app.start();
    }

    private void start() {
        initSpringContext();
        printAppInfo();
    }

    private void printAppInfo() {
        log.info("Welcome to AppInfo Spring Example");
    }

    private void initSpringContext() {
        context = new ClassPathXmlApplicationContext(
                "classpath:net/sf/appinfo/spring/example/applicationContext.xml");
    }
}

The output is:

[main] INFO  n.s.a.s.example.AppInfoSpringExample - Welcome to AppInfo Spring Example

It is not enough – we want to add version info. AppInfo to the rescue!

Step 1. Add AppInfo dependency in Maven.

        <dependency>
            <groupId>net.sf.appinfo</groupId>
            <artifactId>appinfo</artifactId>
            <version>0.5.1</version>
        </dependency>

AppInfo is available in Maven Central Repository, so it’s very easy to configure dependency using Maven (also Ivy or Grails). It will be automatically downloaded during the next build.

Step 2. Configure manifest reader from AppInfo in Spring configuration file (here applicationContext.xml) to get information from the main application JAR.

    <!-- the only bean required by AppInfo -->
    <bean id="applicationTypeSpecificManifestReader" class="net.sf.appinfo.reader.JarManifestReader">
        <!-- class from a JAR which is the application run from -->
        <constructor-arg value="net.sf.appinfo.spring.example.AppInfoSpringExample"/>
    </bean>

It’s required to configure that one bean with class from the application to allow AppInfo to get MANIFEST.MF from JAR in which application is packaged (there are many other JARs on a classpath).

Step 3. Modify Spring context configuration to attach one additional XML file from AppInfo package.

    private void initSpringContext() {
        context = new ClassPathXmlApplicationContext(
                "classpath:net/sf/appinfo/spring/example/applicationContext.xml",   //original application configuration
                "classpath:net/sf/appinfo/appInfoDefaultContext.xml");  //additional configuration from AppInfo
    }

Step 4. Add displaying information about current application version.

    private void printAppInfo() {
        log.info("Welcome to AppInfo Spring Example");  //original line
        String appInfoText = context.getBean("appInfoText", String.class);
        log.info("The application info is: {}", appInfoText);
    }

AppInfo in default configuration for Spring creates appInfoText bean which contains textural representation of current application version. It’s only required to inject into some other bean or fetch from Spring context and use in some other way (e.g. like presented above).

Step 5. Modify maven-jar-plugin to attach additional manifest entries.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>net.sf.appinfo.spring.example.AppInfoSpringExample</mainClass>
                        </manifest>
                        <!-- AppInfo related entries below -->
                        <manifestEntries>
                            <Specification-Title>${project.name}</Specification-Title>
                            <Specification-Version>${project.version}</Specification-Version>
                            <!-- Variables set by Hudson -->
                            <Build-Number>${BUILD_NUMBER}</Build-Number>
                            <Build-Date>${BUILD_ID}</Build-Date>
                            <SCM-Revision>${SVN_REVISION}</SCM-Revision>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

Build process has to store information about application version. In the default implementation MANIFEST.MF is used. When building automatically, CI server provides that data. Below sample configuration for Hudson CI server.

Step 6. Test run.

To simulate build from CI server it is required to set a few system variable which are normally set by Hudson. This can be done using following command:
$ BUILD_NUMBER=12 SVN_REVISION=12345 mvn clean package

After successful build the application need to be run:
$ java -jar target/appinfo-spring-example-0.5.1-SNAPSHOT.jar

The result is:

[main] INFO  n.s.a.s.example.AppInfoSpringExample - Welcome to AppInfo Spring Example
[main] INFO  n.s.a.s.example.AppInfoSpringExample - The application info is: AppInfo Spring Example - 0.5.1-SNAPSHOT - Build 12 - Rev. 12345 - devel

Build number and SCM revision is set. Build date wasn’t set, so have default value.

Integration with web application can be done in similar manner. For more information check the project home page.

Please let me know if you think that tutorial was helpful (and generally if AppInfo is useful for you – I’m also author of AppInfo library). Next time I could prepare some more complicated example. Sources for that example are available in AppInfo’s Git repository, which can be clonned by:

git clone git://appinfo.git.sourceforge.net/gitroot/appinfo/appinfo-spring-example
About these ads
Comments
  1. Kendoo says:

    And what is easy about this ?

    • emszpak says:

      Thanks for your reply Kednoo and sorry for a late reply.

      Imagine a situation when a software is built automatically using CI server. Available versions are downloaded by testers (desktop application) or automatically deployed to QA environment (web application). It’s required to unequivocally identify every version (for bug reporting and bug fixing). 1.0.0-SNAPSHOT from Maven is not enough. Releasing a new version for every build is often an overkill. I was in that situation and I wasn’t able to find existing flexible solution, so I wrote a few classes which help gather information from CI server and allow to display it to the user (with almost no modification in an application code). In the next project I had to copy that classes, do some further modifications and maintenance in that model wasn’t very comfortable (in every project different version, potential bugs has to be backported to many places). I decided to outsource it to external JAR called AppInfo. Since then I can add application versioning in every new project as simple as described in that tutorial. If you know easier solutions please let me know. Maybe I missed something when I tried to find something like that some time ago.

Leave a Reply

Fill in your details below or click an icon to log in:

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