Friday, February 17, 2012

Advanced injection of Maven properties into Java application

In the last post I have shown how to inject Maven project informations into Java application. This topic describes the injection for more useful properties. Advantage: no needs to define then any project specific Java constants and change constants with each release. Current project infos already exist in pom.xml. In the PrimeFaces Extensions project we have defined some profile dependent properties like these
...
<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>${primefaces.core.version}</version>
</dependency> 
<dependency>
    <groupId>org.primefaces.extensions</groupId>
    <artifactId>primefaces-extensions</artifactId>
    <version>${pe.impl.version}</version>
</dependency>
...
<properties>
    <java.version.source>1.6</java.version.source>
    <java.version.target>1.6</java.version.target>
    <jetty.server.version>8.1.0.RC2</jetty.server.version>
    <pe.jsf.impl>mojarra</pe.jsf.impl>
    <pe.jsf.displayname>Mojarra</pe.jsf.displayname>
    <pe.jsf.group>com.sun.faces</pe.jsf.group>
    <pe.jsf.artifact>jsf</pe.jsf.artifact>
    <pe.jsf.version>2.1.6</pe.jsf.version>
    <pe.impl.version>0.3.0-SNAPSHOT</pe.impl.version>        
    <pe.webapp.filter>development</pe.webapp.filter>
    <pe.webapp.online>false</pe.webapp.online>
    <primefaces.core.version>3.1.1</primefaces.core.version>
    <primefaces.theme.version>1.0.3</primefaces.theme.version>
</properties>
And we also configured two Maven plugins which put more useful properties to Maven based applications.
<plugin>
    <groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
    <artifactId>maven-svn-revision-number-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <goals>
                <goal>revision</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <entries>
            <entry>
                <prefix>svn</prefix>
            </entry>
        </entries>
    </configuration>                    
</plugin>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <version>1.0</version>
    <executions>
        <execution>
            <id>generate-timestamp</id>
            <phase>validate</phase>
            <goals>
                <goal>create-timestamp</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <format>{0,date,yyyy-MM-dd HH:mm}</format>
        <items>
            <item>timestamp</item>
        </items>
    </configuration>
</plugin>
Let's start now. Property file under src/main/resources is called now pe-showcase.properties and has again only one line (surprise).
 
application.properties=${project.properties}
 
This line gets resolved at build time as follows:
application.properties={pe.jsf.impl=mojarra, pe.jsf.group=com.sun.faces, timestamp=1329486964505, svn.committedRevision=928, svn.revision=928, primefaces.theme.version=1.0.3, pe.impl.version=0.3.0-SNAPSHOT, pe.jsf.displayname=Mojarra, jetty.server.version=8.1.0.RC2, svn.committedDate=2012-02-17 01:48:44 +0100 (Fri, 17 Feb 2012), pe.jsf.version=2.1.6, primefaces.core.version=3.1.1, ...}
The task is now to parse this resolved line in a Java application. A good entry point for parsing in JSF is an application scoped bean noted with eager=true.
@ApplicationScoped
@ManagedBean(eager = true)
public class TechnicalInfo {

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

    private String primeFaces;
    private String primeFacesExt;
    private String jsfImpl;
    private String server;
    private String revision;
    private String buildTime;
    private boolean online = false;
    private boolean mojarra = true;

    @PostConstruct
    protected void initialize() {
        ResourceBundle rb;
        try {
            rb = ResourceBundle.getBundle("pe-showcase");

            String strAppProps = rb.getString("application.properties");
            int lastBrace = strAppProps.indexOf("}");
            strAppProps = strAppProps.substring(1, lastBrace);

            Map<String, String> appProperties = new HashMap<String, String>();
            String[] appProps = strAppProps.split("[\\s,]+");
            for (String appProp : appProps) {
                String[] keyValue = appProp.split("=");
                if (keyValue != null && keyValue.length > 1) {
                    appProperties.put(keyValue[0], keyValue[1]);
                }
            }

            primeFaces = "PrimeFaces: " + appProperties.get("primefaces.core.version");
            primeFacesExt = "PrimeFaces Extensions: " + appProperties.get("pe.impl.version");
            jsfImpl = "JSF-Impl.: " + appProperties.get("pe.jsf.displayname") + " " + appProperties.get("pe.jsf.version");
            server = "Server: Jetty " + appProperties.get("jetty.server.version");
            revision = "SVN-Revision: " + appProperties.get("svn.revision");

            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(Long.valueOf(appProperties.get("timestamp")));
            buildTime = "Build time: " + formatter.format(calendar.getTime());

            online = Boolean.valueOf(appProperties.get("pe.webapp.online"));
            mojarra = appProperties.get("pe.jsf.impl").contains("mojarra");
        } catch (MissingResourceException e) {
            LOGGER.warning("Resource bundle 'pe-showcase' was not found");
        }
    }

    ... getter ...

}
Access in JSF facelets:
<h:panelGrid columns="7" style="float: left;">
    <h:panelGroup styleClass="ui-icon ui-icon-info"/>
    <h:outputText value="#{technicalInfo.primeFaces},"/>
    <h:outputText value="#{technicalInfo.primeFacesExt},"/>
    <h:outputText value="#{technicalInfo.jsfImpl},"/>
    <h:outputText value="#{technicalInfo.server},"/>
    <h:outputText value="#{technicalInfo.revision},"/>
    <h:outputText value="#{technicalInfo.buildTime}"/>
</h:panelGrid>
And voilà. We have done this! Click on image to enlarge it.

No comments:

Post a Comment

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