Tuesday, July 19, 2011

Starting Glassfish 3.1 in debug mode using the Glassfish Maven plugin

I am documenting this for the sake of posterity. The Maven Glassfish plugin allows for starting and stopping Glassfish domains using Maven goals, apart from allowing for deployment, re-deployment and undeployment of applications.

Until now, I never found the need to start Glassfish in the debug mode, thanks to the unit tests that I've been writing. However there are those times where remote debugging does help. Starting Glassfish in the debug mode using the Maven plugin is quite easy, especially if one has already created a domain. All one needs to do is to create a separate Maven profile to start Glassfish in the debug mode; specifying the debug parameter in the start-domain goal is sufficient to start Glassfish in the debug mode, for Glassfish enables JDWP using the options specified in the Glassfish domain configuration file.

My Glassfish domain configuration file had the following debug-options attribute to enable remote debugging, and to allow for remote debuggers to connect onto port 9009:

Getting Glassfish to start in the debug mode from the maven plugin required passing in the true parameter, which automatically resulted in the debug options being used to start Glassfish. Under the hood, the asadmin start-domain command is executed with the --debug=true option which eventually results in Glassfish starting in the debug mode. Following is the snippet from my Maven POM file, containing the relevant configuration:

Note line 28 which triggers the debug mode and gets Glassfish to use the JDWP options. Apparently, the Maven Glassfish plugin also supports this curiously named "jvmOptions" parameter. This parameter is ignored for all practical purposes when starting a domain. In reality, it is used in the limited scenario of creating a new domain; the Maven Glassfish plugin uses the jvmOptions parameter to create a jvmOption for a domain in domain.xml; under the hood, the plugin executes the "asadmin create-jvm-options ..." command with the parameters to the create-jvm-options command being constructed from the jvmOptions parameter in the Maven POM.

Using the previously created Maven profile to start Glassfish is quite easy:

will do the needful activity of using the defined Maven profile.

Monday, July 18, 2011

Configure Hibernate logging on Glassfish with SLF4J

Glassfish 3.1 ships with EclipseLink as the default JPA provider. One can, however, install Hibernate 3.5 using the Glassfish Update Tool, which is the easiest means of installing Hibernate on Glassfish. The installation also installs the SLF4J-JDK14 wrapper, that will enable all SLF4J logging calls to be redirected to the java.util.logging logging implementation used by Glassfish. One would, therefore, find that SLF4J calls would be transparently redirected to the Glassfish domain log, without a lot of configuration.

In order to configure logging for Hibernate on Glassfish, the JDK logger configuration in the logging.properties file of the Glassfish domain must be modified, to include any desired configuration changes. Simply put, one need not install log4j and the slf4j-log4j12 module in Glassfish and also provide log4j.properties to get Hibernate logging to work.

The following lines were added in the logging.properties file of the Glassfish domain (usually located in $GLASSFISH_DOMAIN/config) to enable various loggers created by to provide a more verbose output:

To understand how those entries work, it is sufficient to understand that Hibernate uses SLF4J as a logging facade, delegating the actual writing of the log records to an underlying logger like log4j, logback or the JDK logger. Glassfish uses the JDK logger as the logging implementation, and to enable the calls on the SLF4J logger, to create entries in the Glassfish domain logs, one must have the SLF4J-JDK14 module (slf4j-jdk14-x.y.z.jar) installed in the classpath. The SLF4J-JDK14 module serves to adapt all SLF4J method calls to the JDK Logger interface, allowing any application (in this case, Hibernate) using SLF4J to have the log records written by the JDK logger. The adapter transforms the levels used by SLF4J to the ones known to the JDK logger as follows:

SLF4J Level JDK Logger Level

By inference, an invocation within Hibernate using Logger.trace() would be logged only if the JDK logger was configured to log messages at the FINEST level.

Saturday, July 09, 2011

Building a dynamic image based carousel with PrimeFaces 2.2.1

Time for another demonstration. This time, I needed to build a carousel with data including text and images. And, I chose to use the PrimeFaces carousel component for this purpose. The code presented here is available for download at my BitBucket repository.

Building a carousel with the PrimeFaces component is quite easy if you can not embedding rich and dynamic content within the carousel. The PrimeFaces User Guide downloadable off the PrimeFaces documentation page, does contain an example to get you started. I will extend that example to demonstrate how to use the StreamedContent class to enable display of images that could possibly be stored in a database or in a content management system.

The user interface layout of the desired final outcome is shown below.

The intent is to demonstrate how to display non-static content in the carousel. This is easy for text content as the carousel component supports the embedding of h:outputText tags and iteration through a collection using the var attribute. The example in the PrimeFaces user guide already covers this. We'll be looking at the use of the f:param tag to iterate through a collection of StreamedContent objects. To make things simple, we will be reading images off files instead of BLOB objects in a database, or similar binary input streams.

The Facelet

We will start by designing the facelet page that will use the carousel component. The code for the facelet is listed below:

The carousel definition contains:

  • a collection of items that used to render each individual item in the carousel. This is specified using the value="#{imageBean.images}" expression. For all practical purposes, the carousel is similar to a h:dataTable component as far as this attribute is concerned. Without specifying a value attribute that is referenced by a collection, one cannot render a collection of items in the carousel, whose size is unknown at design time. We'll see the definition of the managed bean class ImageBean later.
  • a name to reference an element in the above defined item collection. This is similar to the var attribute of the h:dataTable component. In the above facelet, var="image" is used to create a temporary reference to every item in the images collection of the ImageBean class.
  • a panel grid that is used to act as a container for the image, the title and the description of the image. It contains a style attribute whose usage is described later.
  • a PrimeFaces p:graphicImage component that is used to stream the image back to the browser. Note the use of the f:param tag. The p:graphicImage component cannot use the temporary reference created by the var attribute of the carousel component. The value attribute must evaluate to a StreamedContent object, but more importantly the p:graphicImage component will be rendered as a img tag with a src attribute containing a URL that will be used by the browser to fetch the image (present in a StreamedContent object). This URL does not change across the items in the carousel, and hence a parameter must be passed to identify the image being requested. This is done using the value="#{image.id}" attribute of the parameter that is used to pass a parameter of name photo_id. We shall see how this parameter is parsed by another Managed Bean, in a later section of the article.
  • a couple of h:outputText components that are used to display the title and description items. These use the reference created by the var attribute, and unlike the p:graphicImage component there are no issues involving the use of the temporary reference in this case.

The Managed Bean for the carousel component

The managed bean used to manage the collection of images is listed below:

The class is quite simple in design, in that it is used to store a reference to a list of Photo objects that contains merely the text content (title and description) of every image in the carousel. The Photo class is listed below. Again, it is quite simple in design, and is merely a bean class. Note the declaration of the id attribute of the class; this is used by the carousel component to provide the parameter to the p:graphicImage component.

The Managed Bean for the graphicImage component

The managed bean class that is responsible for serving image requests is listed below.

This is obviously the class that allows the carousel to obtain images dynamically, so a more descriptive explanation of it's behavior is provided.

Note that this class is a request scoped bean. Every image added in the carousel using the p:graphicImage tag will result in a separate GET request for the image. Once the image contents has been dispatched to the browser, the managed bean is no longer needed, unless the carousel needs to be rendered once again. It also not good design to store references to StreamedContent objects beyond a single request. Therefore, this class is not designed to be a session scoped class.

The following snippet is used to parse the parameter passed to the bean via the f:param tag.

It is important to know that the value of the photoId variable can be null, even if the browser has not issued a request with a null photoId. This needs to be handled by creating a StreamedContent object that points to a "default" image, as show in the following snippet.

The defaultFileContent variable is a static variable that is initialized on loading of the class. The initialization process isn't exactly production quality, and one might consider adding exception handling to address this in a better manner. But for now, it would suffice to know that the getFileContent method should not return null. Apparently, the method is invoked during the Render Response phase and it is quite possible that the value of photoId is null, thereby necessitating the need to return a non-null StreamedContent object. The "default" image is also returned in the event of an image Id being incorrect (out of bounds in this case).

Finally, if the image Id is valid, the context class loader is used to obtain a reference to a input stream that can be used to construct the StreamedContent object as demonstrated below:

In a production application, you would obviously be fetching the images from a database, a content management system, or from disk. In either case, you will need to obtain an InputStream object and use it to construct the StreamedContent object.

Styling the carousel

The carousel component uses the YUI carousel component to render the actual carousel in the browser. It relies on some JavaScript goodness to set the sizes of the individual items in the carousel on loading the document. If the height and width of the items is not specified, then it is quite possible that the items will not be displayed correctly; it is quite possible to have the items overflow each other. The YUI carousel requires that the height and width values be specified on each item (li0 in the list (ol) that is generated. Hence, it is necessary to set the style in the h:panelgrid component as follows:

Other interesting stuff

  • The carousel described above displays correctly in all modern browsers except IE 9 where it is quite horribly broken (even in compatibility mode, where the YUI carousel appears to work). This might require a revision to the posted code.
  • The PrimeFaces carousel automatically offers a drop down if the number of items exceeds 5 pages. At least that was my observation. Quite obviously, the carousel is not meant to be used in scenarios where a lot of items are present in a collection.
  • The images in the carousel are fetched upfront on initial document load, and not when pagination occurs. Other components would therefore be suitable if the number and size of the images exceeds a limit where performance becomes a problem; this would vary from application to application.
  • The icons used in the project are from the Polaroid icon set.