Saturday, June 23, 2012

Grails JSF 2 plugin with OpenFaces

Now that I have got Icefaces 3 working with the Grails JSF 2 plugin, I am now trying OpenFaces from www.openfaces.org. Since the plugin is compatible with JSF 2.0, I will be using the OpenFaces 3.0 libraries rather than the 2.0 libraries.

To start, you need to create the grails application (grails create-app) and install the JSF 2 plugin (grails install-plugin jsf2). You will also need to install the templates to modify the web.xml file (grails install-templates). Refer to my previous posts on examples of these steps.

For OpenFaces, you will need to copy these libraries into the lib directory:
  • openfaces.jar
  • cssparser.jar
  • jcommon.jar
  • jfreechart.jar
  • sac.jar

All these files can be found in the openfaces-3.0.zip file, which you can download from the OpenFaces website.

You will also need to make just one change to the web.xml file which is to add the following lines:

<context-param>
<param-name>org.openfaces.validation.clientValidation</param-name>
<param-value>onSubmit</param-value>
</context-param>

That's all that is needed. You can now start creating your OpenFaces app, using xhtml as the extension for the JSF files. You can use the grails create-bean command to create the backing bean for the JSF files.

UPDATE:
There are limitations with the above configuration.  The openfaces.jar library uses Class.forName to resolve some of the classes to unpack (deserialize) the objects.  However, if the classes are defined in the src directory which Grails allows for Dynamic Reloading, then it is NOT available to the jar file class loader (i.e the root classloader). Hence this results in a ClassNotFoundException. This problem occurs when using the run-app (which allows Dynamic Reloading) command.

I tried to unpack the source for the Openfaces components into the src/java directory and include 2 additional jars (portlet api and org.jboss.el).  This then allows the user-defined classes in src to be found since all of the source is dynamic, BUT the faces file parser now does not resolve the namespace for the Openfaces component.  So this is a dead-end.

Alternatively, if you don't need dynamic reloading, you can run the grails app by using run-war command instead.  This will compile all the sources and make it all available to the classloader.  However, there is problem running JSF2 plugin using run-war.  The GrailsResourceResolver.java resolver provided by the JSF2 plugin cannot work in run-war environment as it expects to look for the Grails GSP files like in the development environment instead of the war environment.  If you don't need to use the GSP files, you can make a copy of this file (from jsf2 plugin source directory and put into your project's src/java directory (keeping all the directory paths the same).  Then edit the file and remove all references and code calling the "resourceLoader" member.   Then then allows the run-war to work and you can now run your .xhtml files with the Openfaces components.

Icefaces 3 on Grails with JSF 2 Plugin

Continuing on the previous posts, I have managed to get the new Icefaces 3 libraries working with the Grails JSF 2 Plugin.

To get it working, just follow all the steps in the previous post for Icefaces 2.0.2. For Icefaces 3, download the libraries and replace the all the Icefaces jars on the lib directory with these files from Icefaces 3:
icefaces.jar
icefaces-ace.jar
icefaces-compat.jar
icepush.jar

However, there is one additional change that needs to be made to the web.xml file. Please add the following lines to the web.xml template file:

<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>

If you don't add these lines, when you click on a button (or do a post back), there a Server Error popup will appear and on the console, the system will raise a Java exception as follows:

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.sun.faces.application.view.StateHolderSaver

Please try it and let me know if all the Icefaces 3 features are working with this Grails JSF2 plugin. By the way, this has been tried on Grails 1.3.7.