Wednesday, February 15, 2012

Inject Maven project informations into Java application

Do you have a Maven project and would like to inject project informations from pom.xml into your application to avoid duplications? This is possible with resource filtering. This small guide will help you to achieve that. More funny advanced examples are coming soon in the next post. I have applied this approach for PrimeFaces Extensions project, so that all examples are related to this project.

Step 1. Create a property file under src/main/resources. In my case it's called primefaces-extensions.properties and consists of only one line.
 
application.version=${project.version}
 
Placeholder ${...} gets resolved at project build time. Maven also exposes other project properties like ${project.artifactId}, ${project.name}, etc. Please refer Maven properties guide. Not only Maven self exposes such properties. Various Maven plugins as buildnumber-maven-plugin and maven-svn-revision-number-plugin expose useful properties too.

Step 2. To get placeholders replaced you need to enable filtering in your pom.xml.
<build>
    <resources>
        <resource>src/main/resources</resource>
        <filtering>true</filtering>
    </resources>
    ...
</build>

Step 3. Access in Java is simple. I have created a singleton class VersionProvider for that (because I only have one placeholder for project version). Project version is cached after the first access.
public final class VersionProvider {

    private static final Logger LOGGER = Logger.getLogger(VersionProvider.class.getName());

    private static final VersionProvider INSTANCE = new VersionProvider();
    private String version;

    private VersionProvider() {
        ResourceBundle rb;
        try {
            rb = ResourceBundle.getBundle("primefaces-extensions");
            version = rb.getString("application.version");
        } catch (MissingResourceException e) {
            LOGGER.warning("Resource bundle 'primefaces-extensions' was not found or error while reading current version.");
        }
    }

    public static String getVersion() {
        return INSTANCE.version;
    }
}

Step 4. Using in any places is simple as well. Just call VersionProvider.getVersion(). For instance in the following JSF listener class
public class PostConstructApplicationEventListener implements SystemEventListener {

    private static final Logger LOGGER = Logger.getLogger(PostConstructApplicationEventListener.class.getName());

    @Override
    public boolean isListenerForSource(final Object source) {
        return true;
    }

    @Override
    public void processEvent(final SystemEvent event) {
        if (StringUtils.isNotBlank(VersionProvider.getVersion())) {
            LOGGER.log(Level.INFO, "Running on PrimeFaces Extensions {0}", VersionProvider.getVersion());
        }
    }
}
or in JSF resource handler
public class PrimeFacesExtensionsResource extends ResourceWrapper {

    private Resource wrapped;
    private String version;

    public PrimeFacesExtensionsResource(final Resource resource) {
        super();
        wrapped = resource;

        // get current version
        if (StringUtils.isNotBlank(VersionProvider.getVersion())) {
            version = "&v=" + VersionProvider.getVersion();
        } else {
            version = UUID.randomUUID().toString();
        }
    }

    @Override
    public String getRequestPath() {
        return super.getRequestPath() + version;
    }

    ...
}
With resource filtering you don't need to care about available current project infos in Java programs.

4 comments:

  1. I have no words for this great post such a awe-some information i got gathered. Thanks to Author.

    ReplyDelete
  2. I am using Maven 3.0.4 and it seems that resource dir should be inside src/main/resources otherwise you may get "Malformed POM" error.

    ReplyDelete
  3. At previous comment: inside "directory" XML tag

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

    ReplyDelete

Note: Only a member of this blog may post a comment.