Portlets with XForms in Liferay
This posting discusses how we integrated an web application with XForms as one of the main view technologies into a Liferay portal. We were using the Orbeon 3.8 XForms engine, which was introduced in the previous part of this series, and Spring Portlet MVC. Since we were facing quite a few problems and issues regarding Orbeon and Liferay, I go to great length discribing our working solution.
First of all, it is important to understand that our project uses the “separate deployment” approach of Orbeon integration. Here, Orbeon is only used as XForms renderer — neither the Orbeon Portlet nor the Formbuilder / Formrunner system was used.
Orbeon XForms supports two modes for a JSR-286 portal integration:
- The Orbeon Portlet uses the Orbeon Form Builder and Orbeon Form Runner, which are Orbeon’s own XForms editing and management toolkits. They allow you, to easily develop your own XForms and XForms screenflows with Orbeon. The catch is that you have to use the Orbeon framework and these toolkits for your whole XForms Application.
- With the “separate deployment” mode, Orbeon is only used as a XForms rendering engine, you have to create and mange the application by yourself. This gives you the ability to create 100% custom applications. As mentioned, this is the mode we chose.
Overview of our Integration Approach
Besides XForms, our existing web application was developed with Spring MVC, therefore the Spring Portlet MVC technology was used for the portlet implementation. The Spring application loads the XForms from a repository corresponding to the required business case. The specific architecture as well as Spring and Spring Portlet MVC were project technology decisions. They are not needed to integrate Orbeon with a portal server.
Orbeon is deployed as a normal web application besides Liferay, but is stripped down (Form Runner/Builder and samples removed). The JavaEE server is JBoss 5.1 with Liferay and Orbeon 3.8 installed on it, and configured with 1,5 GB RAM for the JVM.
Please note that Orbeon, as of October 2010, proclaims that the 3.8 stable version has various issues with the Portlet mode, so a Orbeon 3.8 nightly build from end of October 2010 was used. We also chose the stable release of Liferay 6, since the nightly build of Orbeon 3.8 is currently tested with this version only.
The Spring Portlet loads the XForms through some services invoked from the controller and uses an own XForms View to send the XForms directly to Orbeon through the portlet filter for further rendering. Other Spring MVC views like the JSTL view (a Spring view to display normal JSPs) are not affected, and can be used normally. The edit mode of this portlet is for example written as normal JSP Page.
The XForms XHTML Portlet Page
Spring MVC uses views to render models which are filled and created by controllers. (Ok, you might have guessed that;). There are many different included views for displaying Velocity templates, XML and JSPs. The “view resolvers” decide which View should be used, to render the requested page. So an own Spring ViewResolver was written, which reacts on our Spring convention that all View requests should start with “XForms::”. All other View requests are ignored by this resolver, so that the other resolvers can fetch it. As mentioned before, Spring is not needed in order to use XForms in Portlets; it was a general project requirement in our case.
Against your expectation, and not common when using Portlet page snippets, the XForms portlet page must be a complete XHTML page including all HTML Tags as shown below:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:n1="http://www.w3.org/2004/11/xmlmime" xmlns:xxf="http://orbeon.org/oxf/xml/xforms" xmlns:f="http://orbeon.org/oxf/xml/formatting" xmlns:c="http://java.sun.com/jsp/jstl/core"> <head> <xf:model> <xf:instance id="vu"> <repo:vu xmlns:repo="repos-ns" xmlns:partner="partner-ns" xmlns:allg="allg-bs"> <repo:Versicherungsunternehmen> <partner:Name>Versicherungsunternehmen</partner:Name> <partner:Anschrift> <allg:Strasse></allg:Strasse> <allg:Hausnummer>543</allg:Hausnummer> <allg:Postleitzahl>32430</allg:Postleitzahl> <allg:Ort>Stadt</allg:Ort> <allg:Land>D</allg:Land> [...] </repo:vu> </xf:instance> </xf:model> </head> <body> <h2>Adressdaten</h2> <xf:group ref="instance('vu')/repo:Versicherungsunternehmen"> <xf:label>Firma</xf:label> <xf:input ref="partner:Name"/> <br/> <xf:group ref="partner:Anschrift"> <xf:input ref="allg:Strasse"/> [...] </xf:group> [...] </body> </html>
A Liferay Bug and a Workaround for rendering XForms
Usually, Spring views act like a normal “view” Servlet or JSP, i.e. you can write to the output stream or forward to a JSP to render your model. However, there seems to be a problem with the portlet filtering mode in Liferay 6, so JSPs cannot be used as view technology. The filter only works for direct writing to the response stream, not when a redirection to a JSP happens.
The first work-around was to create the complete XForms pages in the Spring view and to send it out to the response via some Output Writer. But while debugging the bug described above, we discovered the request attribute “oxf.xforms.renderer.document”. Orbeon first checks this attribute in its filter initialization, and, it’s set, uses the content of the attribute to render the page.
In our case, the complete page was filled via a String into this attribute, which seems to be quite a bit faster then the normal response stream filter:
Receiving POST Data from the Browser
For receiving POST Data, no further configuration needed to be done. The binding URLs get rewritten automatically by the portlet filter. The following binding is sufficient to address the portlet correctly:
<xforms:submission id="gui-submission" method="post" ref="instance('getOffer')" resource="/" replace="all" />
With this binding, the submission resource URL (“/”) gets rewritten to the correct portlet action URL and the XForms model gets converted through the Orbeon filter. This filter is specified in the portlet configuration file “portlet.xml” as shown below:
<filter> <filter-name>orbeon-forms-portlet-xforms-filter</filter-name> <filter-class>org.orbeon.oxf.portlet.OrbeonPortletXFormsFilter</filter-class> <lifecycle>RENDER_PHASE</lifecycle> <lifecycle>ACTION_PHASE</lifecycle> <lifecycle>RESOURCE_PHASE</lifecycle> <init-param> <name>oxf.xforms.renderer.context</name> <value>/orbeon</value> </init-param> </filter> <filter-mapping> <filter-name>orbeon-forms-portlet-xforms-filter</filter-name> <portlet-name>xFormPortlet</portlet-name> </filter-mapping>
For this to work, the portlet filter JAR “Orbeon-xforms-filter.jar” must be included within the Portlet WAR archive. For greater detail, see the Orbeon Wiki on XForms – Separate Deployment with Portlets.
We have discussed our quick prototype to test whether portal integration could be achieved easily or not. The general impression was that this solution based on the “separate deployment” mode works quite nice. And it seemed faster than the operating mode “Orbeon Portlet”. This might be because, in the portal environment, the portal takes up most of the loading time. A quick JMeter test revealed an increase of 50% load time.
The rewriting of URLs to the portlet addresses works quite well and transparent. The downsides of using Orbeon with portlets using our approach are the following:
- limitations in your application design, through the portlet filter bug (no redirection and JSPs),
- bugs in the 3.8 release of Orbeon XForms,
- the current release of Orbeon Portlet Integration has been tested only with Liferay 6.x.
Another interesting approach using remote portlets (had the same idea) can be found in the Orbean Developer Wiki.
In conclusion, if you are planning to use Orbeon XForms with your portal server, you should use Liferay and also think about getting professional support from the Orbeon Team (which requires a commercial license), because further insight into the Orbeon system is of great advantage here. Other great sources are the Orbeon mailing list, the Development Overview, and the Liferay Forum.