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.

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.

Tuesday, January 31, 2012

Cron Job to restart Jetty Server

If you have an Java hosting on a virtual server, you normally have limited resources for that. That means you only have a certain amount of RAM. This leads to memory problems when deploying large applications. Restart the server by hand is annoying. Fortunately there are cron jobs. A cron job is a task in Linux which is to be executed at specific times automatically. The simplest way to start a cron job in Linux is to place a shell script below one of the following folders:
/etc/cron.daily
/etc/cron.weekly
/etc/cron.monthly

I intend to show a shell script for Jetty 8 server which is installed in /opt/jetty-distribution-8.1.0.RC2/ (path on my virtual server). The script checks the process id of the running Jetty server, kills it if it was found and restarts the server with the command "nohup java -jar start.jar".
#! /bin/sh

jettyPid='pgrep -f "java -jar start.jar"'

if [ "$jettyPid" != "" ]
then
kill -9 $jettyPid
fi

jettyHome="/opt/jetty-distribution-8.1.0.RC2/"
cd $jettyHome
nohup java -jar start.jar

exit
Alternative shorter variant:
#! /bin/sh

pgrep -f "java -jar start.jar" | xargs -i kill {}

cd /opt/jetty-distribution-8.1.0.RC2/
nohup java -jar start.jar

exit

Sunday, January 1, 2012

New release of web resource optimization plugin

I have released a new 0.3 version of the Maven plugin for web resource optimization. As I mentioned in the last posts this plugin was created as a part of the PrimeFaces Extensions project. It produces better compression results than YUI Compressor and has some nice features. The current release fixes only one issue. Release notes are here. The plugin is available in the Maven central repository.

If you have any questions regarding to the configuration, ask me please in the PrimeFaces Extensions forum. This forum is also a good place for all questions to the components and more. Unfortunately, but PrimeFaces lead doesn't like to see any discussions related to our extensions in the main PrimeFaces forum. He considers such topics as advertisement and locks / removes them. That hurts and is weird because if it would be an advertisement, it would be an advertisement for PrimeFaces. We have "PrimeFaces" in the name "PrimeFaces Extensions". The aim was never to do an advertisement or get money. This project is just for fun, everybody can participate in.

Currently we are working on the last use cases for our showcase and plan to do a release in the middle of January. Next releases will be published at frequent intervals and include less stuff - approximately 2-4 new components, client behaviors, converters or similar JSF 2 related artefacts. Some stuff is amazing, so stay tuned.

Best wishes for the New Year!

Friday, December 30, 2011

Efficient component tree traversal in JSF

Everybody knows about findComponent() and invokeOnComponent() methods in JSF to find a component and doing something with it. The first method expects a special search expression and the second one component's clientId. They belong to UIComponent class, so that any UIComponent can acts as a start point in the view hierarchy. But what is about if we want to find many components at some start point in the view hierarchy which match certain conditions? We can apply getChildren() rekursive, but we wish us a convenient method for tree traversal. Tree traversal refers to the process of visiting each node in a component tree data structure. There is an efficient method in JSF accomplishing this task - visitTree()
public boolean visitTree(VisitContext context, VisitCallback callback)
context is an instance of VisitContext class that is used to hold state relating to performing a component tree visit. callback is an instance of VisitCallback whose visit method will be called for each node visited. Let's start with a practical example. Our task is to find and gather all components implementing EditableValueHolder. Such components implement resetValue() method which allows to reset component's submitted, locale values, etc. to an un-initialized state. Furthermore, another requirement is to skip sub-tree traversal for a component which should be not rendered (don't visit sub-components). In other words we want to find only editable components to be rendered. Assume, the start component calls target
UIComponent target = ...
It can be got in an action / event listener by event.getComponent() or somewhere else by findComponent().

We are ready now to create a special EditableValueHoldersVisitCallback in order to find all mentioned above sub-components and call visitTree on the target component with this callback. EditableValueHoldersVisitCallback gathers sub-components we want to reset.
EditableValueHoldersVisitCallback visitCallback = new EditableValueHoldersVisitCallback();
target.visitTree(VisitContext.createVisitContext(FacesContext.getCurrentInstance()), visitCallback);

// iterate over found sub-components and reset their values
List<EditableValueHolder> editableValueHolders = visitCallback.getEditableValueHolders();
for (EditableValueHolder editableValueHolder : editableValueHolders) {
    editableValueHolder.resetValue();
}
Callback looks like this one
public class EditableValueHoldersVisitCallback implements VisitCallback {

    private List<EditableValueHolder> editableValueHolders = new ArrayList<EditableValueHolder>();

    @Override
    public VisitResult visit(final VisitContext context, final UIComponent target) {
        if (!target.isRendered()) {
            return VisitResult.REJECT;
        }

        if (target instanceof EditableValueHolder) {
            editableValueHolders.add((EditableValueHolder) target);
        }

        return VisitResult.ACCEPT;
    }

    public List<EditableValueHolder> getEditableValueHolders() {
        return editableValueHolders;
    }
}
Result VisitResult.REJECT indicates that the tree visit should be continued, but should skip the current component's subtree (remember our requirement?). VisitResult.ACCEPT indicates that the tree visit should descend into current component's subtree. There is also VisitResult.COMPLETE as return value if the tree visit should be terminated.

Some components extending UINamingContainer override the behavior of visitTree(). For instance, UIData overrides this method to handle iteration correctly.