Deploying Orbeon Forms as a Portlet into Liferay

Introduction

Availability

This is an Orbeon Forms PE feature.

Servlet vs. portlet deployment

In addition to deploying Orbeon Forms into a servlet container such as Tomcat, you can deploy it into the Liferay portal using the Orbeon Forms portlet component.

Portals provide features such as:
  • Content aggregation -  A single web page aggregates the output or user interface of several data sources or applications.
  • Personalization - Users or administrators of the portal can customize the user interface. This often means not only customizing the look and feel, but also selecting a certain set of available functionalities within the application.
  • Single sign-On - The user logs in only once to access several applications in the portal.

Bookshelf form deployed in Liferay

Status of portlet support in Orbeon Forms

Orbeon Forms supports deploying as portlets:
As of Orbeon Forms 4.0, portlet support was tested with Liferay 6.0 and 6.1. We recommend Liferay 6.1 GA2 or newer.

The following Form Runner limitations are known:
  • Form Builder is not supported within portlets (but you can run forms designed with Form Builder)
  • The Noscript mode is not supported within portlets

Deploying into Liferay

Configuration

The Orbeon Forms WAR can be directly deployed into the Liferay portal. By default, the Form Runner demo forms and XForms examples are immediately available within the portlet:

Orbeon Forms welcome page in Liferay


The following steps assume that:
  • Liferay is deployed on port 8080
  • the Orbeon Forms WAR is deployed under the name "orbeon" (which is the default if the WAR file is called orbeon.war)
Installation steps:

1. Set larger MaxPermSize - Depending on your system, you might get an error when starting Liferay, or later one when using Liferay, telling you that the Java VM ran out of PermGen space.

You can prevent this error by setting the value of MaxPermSize to a value larger than the default value, for instance by declaring the JAVA_OPTS environment variable in a way similar what is is done below. The declaration of JAVA_OPTS can be done at the beginning of bin/setclasspath.sh (or if on Windows, the equivalent line at the beginning of bin/setclasspath.bat):

JAVA_OPTS="-server -verbosegc -Xms386m -Xmx386m -Djava.awt.headless=true -XX:MaxPermSize=128m"

2. Deploy orbeon.war
- Start Liferay. When it is fully started move the orbeon.war into the Liferay deploy directory (e.g. ~/liferay/deploy). At this point, you should see message indicating that Orbeon is being deployed. Monitor the Liferay output as well as the logs/orbeon.log for possible errors.

3. Enable dynamic resource reloading (optional) - Remove the file webapps/orbeon/META-INF/context.xml and restart Liferay. For more information on what this does, see note 2 below.

4. Configuration for Form Runner (optional) - You can skip this step if you do not intend to use Form Runner or Form Builder in a portlet. Otherwise, create a file WEB-INF/resources/config/properties-local.xml which declares the following properties (and other properties you might want to override):

<properties xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:oxf="http://www.orbeon.com/oxf/processors">

    <!-- This is the property for Orbeon Forms 3.8/3.9 -->
    <property as="xs:anyURI"  name="oxf.fr.persistence.service.exist.uri"
              value="http://localhost:8080/orbeon/exist/rest/db/orbeon/fr"/>

    <!-- This is the property for Orbeon Forms 4.0 -->
    <property as="xs:anyURI"  name="oxf.fr.persistence.exist.exist-uri"
              value="http://localhost:8080/orbeon/exist/rest/db/orbeon/fr"/>

    <!-- Configure authentication properties through headers -->
    <property as="xs:string" name="oxf.fr.authentication.method"
              value="header"/>

    <!-- If you want the Liferay user email used for Form Runner authentication -->
    <property as="xs:string"  name="oxf.fr.authentication.header.username"
              value="Orbeon-Liferay-User-Email"/>

    <!-- If you want Liferay roles used -->
    <property as="xs:string" name="oxf.fr.authentication.header.roles"
              value="Orbeon-Liferay-User-Roles"/>

    <!-- To propagate username/roles to the persistence layer, if using authentication -->
    <property as="xs:string"  name="oxf.xforms.forward-submission-headers"
              value="Orbeon-Username Orbeon-Roles"/>

    <!-- Form Runner CSS file that doesn't impact the global Liferay layout -->
    <property as="xs:string"  name="oxf.fr.css.uri.*.*"
              value="/ops/yui/grids/grids.css
                     /ops/yui/datatable/assets/skins/sam/datatable.css
                     /apps/fr/style/form-runner-base.css
                     /apps/fr/style/form-runner-orbeon.css"/>
    <property as="xs:string"  name="oxf.fr.css.uri.orbeon.*"
              value="/ops/yui/grids/grids.css
                     /ops/yui/datatable/assets/skins/sam/datatable.css
                     /apps/fr/style/form-runner-base.css
                     /apps/fr/style/form-runner-orbeon.css"/>

</properties>

The host name (localhost), port (8080), and context path (orbeon) must be updated to match your local configuration.

5. Add the Orbeon Forms portlet - Log into the portal, go to the Add menu:


Create a new page, for example Orbeon Page:

Go to the Add menu again and select More…:

Select the Orbeon Forms Portlet entry:

Drag the portlet to the page. The Orbeon Forms home page will show.
NOTES:
  1. While Liferay 4 lazy loads portlets, but, because of performance related issues, Liferay 5 is aggressively loading portlets when the web application is being deployed. So with Liferay 5, the initialization order is as follows:

    1. Servlet context listeners are initialized.
    2. Portlets are initialized.
    3. Servlets are initialized.

    For the Orbeon Forms portlet to be able to run, code which is executed by either the Orbeon Forms servlet context listener, or the Orbeon Forms servlet needs to run first. Since servlets are initialized after portlets, the only option is to have this code executed from the servlet context listener.

    NOTE: By default, the Orbeon Forms servlet context listener is enabled for Orbeon Forms builds after Febuary 4, 2009.

  2. When Liferay deploys Orbeon Forms, it changes some of the descriptors and adds a META-INF/context.xml which is not present in the distribution of Orbeon Forms. This file contains:

    <Context antiJARLocking="true" antiResourceLocking="true"/>

    which causes Tomcat to, on startup, make a copy of the Orbeon web application into its temp directory and use that copy instead of the files under webapps/orbeon. That copy is removed when the server shuts down, and will be done again the next time the server is started. This makes starting Liferay slower, but more importantly this means that changes you make to files under webapps/orbeon after the server started will never be picked up. So any modification to the resources (WEB-INF/resources) of your application will require a restart of Liferay. This  can be quite very time consuming and annoying, hence our recommendation to remove the META-INF/context.xml generated by Liferay.

Accessing liferay users and roles

[SINCE: 2011-05-11]

When running in Liferay, you can access some specific user and roles information from XForms.

Getting the current user's email:

xxforms:get-request-header('orbeon-liferay-user-email')

Example: 'test@liferay.com'

Getting the current user's full name:

xxforms:get-request-header('orbeon-liferay-user-full-name')

Example: 'Joe Bloggs'

Getting the current user's role names:

xxforms:get-request-header('orbeon-liferay-user-roles')

This returns a sequence of strings, with one string per role. Example: ('Administrator', 'Power user', 'User')

Alternatively, you can use the standard Orbeon-Username and Orbeon-Roles headers. See also: Access control

Enabling asynchronous portlet content loading

[SINCE: 2011-10-07]

Enabling the following property allows loading of portlet content asynchronously via Ajax after the portal has shown the page:

<property as="xs:boolean" name="oxf.xforms.async-portlet-load" value="true"/>

This allows Orbeon Forms to start producing the page in the background, while the portal page is loading.

You might find that enabling this property helps performance, especially with older browsers such as IE 6/7.

Performance tuning

For large pages, we have found that the Liferay strip filter can take an extremely long time to process a response. You can disable that filter in your portal-ext.properties with:

com.liferay.portal.servlet.filters.strip.StripFilter=false

Creating a new landing page for the portlet

By default, the portlet shows a list of Orbeon Forms sample forms and apps.

To change this, you need to:
  1. Modify WEB-INF/resources/page-flow-portlet.xml.
  2. Create a new landing page in XHTML format.
  3. Change the default Orbeon theme so that no custom Orbeon CSS is added.
A simple way do implement this is as follows:

First, replace this line in page-flow-portlet.xml:

<page id="home" path-info="/home/" model="apps/home/page-flow.xml"/>

with:

<page id="home" path-info="/home/" view="home.xhtml"/>

Second, create a new file, WEB-INF/resources/home.xhtml, with content such as:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Form Runner Home</title>
    </head>
    <body>
        <a href="/fr/">Link to the Form Runner home page</a>
        <a href="/fr/acme/form1/summary">Link to summary page of form acme/form1</a>
        <a href="/fr/acme/form2/new">Link to new page of form acme/form2</a>
    </body>
</html>

This is the landing page itself, and it can contain any XHTML you like. Typically would include links to specific Form Runner paths as shown in the example above.

Finally, to change the Orbeon portlet theme to the plain theme, set this property:

<property
  as="xs:anyURI"
  name="oxf.epilogue.theme.embeddable"
  value="oxf:/config/theme-embeddable.xsl"/>

Other portals

Deploying into Jetspeed 2 based portals

NOTE: Orbeon Forms 3.9 and 4.0 have not been tested with Jetspeed 2 portals.

Orbeon's war distribution can easily be deployed on any Jetspeed-2 based portal. If you don't have a Jetspeed portal yet, you may want to get started with the Jetspeed 2 installer, see http://portals.apache.org/jetspeed-2/getting-started-installer.html.

Deployment:
  1. Deploy Orbeon.war

    a) On Tomcat - If your Jetspeed portal runs on Tomcat (like when having used the installer), the easiest way is to let Jetspeed deploy Orbeon by copying orbeon.war to Jetspeed's deploy directory  webapps/jetspeed/WEB-INF/deploy.  Auto-deployment will take place directly if the portal is running, otherwise at startup.

    b) Other - On application servers other than Tomcat, use your application server's own deployment mechanism to deploy Orbeon as web application.

    The following servlet is to be inserted into Orbeon's web.xml

    <servlet>
       <servlet-name>JetspeedContainer</servlet-name>
       <display-name>Jetspeed Container</display-name>
       <description>MVC Servlet for Jetspeed Portlet Applications</description>
       <servlet-class>org.apache.jetspeed.container.JetspeedContainerServlet</servlet-class>
       <init-param>
         <param-name>contextName</param-name>
         <param-value>orbeon</param-value>
       </init-param>
       <load-on-startup>[your-value]</load-on-startup>
    </servlet>
    <servlet-mapping>
       <servlet-name>JetspeedContainer</servlet-name>
       <url-pattern>/container/*</url-pattern>
    </servlet-mapping>


    With this setup Orbeon will register itself as portlet application to Jetspeed.

  2. Add Orbeon's portlet on your page

    To add Orbeon's portlet called OrbeonFormsPortlet to a page, adjust the desired .psml page to incorporate this portlet in a fragment, e.g.

    <fragment id="yourId" type="portlet" name="orbeon::OrbeonFormsPortlet">

    This can also be accomplished using a UI with the Edit page functionality when logged in as admin.
More information on Jetspeed 2 available at http://portals.apache.org/jetspeed-2/guides.

Deploying into IBM WebSphere Portal 6

NOTE: Orbeon Forms 3.9 and4.0 have not been tested with WebSphere Portal 6.

Deploying into JBoss Portal

NOTE: Orbeon Forms 3.9 and 4.0 have not been tested with JBoss Portal.

This instructions have been reported to work with JBoss Portal 2.6.5-SP1.
  1. First setup and run the portal normally and check that you get the portal first page OK at http://localhost:8080/portal.
  2. Download a nightly build of Orbeon Forms, and add the following files inside the WEB-INF directory:

    portlet-instances.xml:

    <?xml version="1.0" standalone="yes"?>
    <!DOCTYPE deployments PUBLIC
      "-//JBoss Portal//DTD Portlet Instances 2.6//EN"
      "
    http://www.jboss.org/portal/dtd/portlet-instances_2_6.dtd">
    <deployments>
      <deployment>
         <instance>
            <instance-id>OrbeonPortletInstance</instance-id>
            <portlet-ref>OrbeonFormsPortlet</portlet-ref>
         </instance>
      </deployment>
    </deployments>


    orbeon-object.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE deployments PUBLIC
      "-//JBoss Portal//DTD Portal Object 2.6//EN"
      "
    http://www.jboss.org/portal/dtd/portal-object_2_6.dtd">
    <deployments>
      <deployment>
         <parent-ref>default.default</parent-ref>
         <if-exists>overwrite</if-exists>
         <window>
            <window-name>Orbeon Forms</window-name>
            <content>
            
    <content-type>portlet</content-type>
            
    <content-uri>OrbeonPortletInstance</content-uri>
            </content>
            <region>center</region>
            <height>1</height>
         </window>
      </deployment>
    </deployments>


  3. Uncomment the following in the web.xml, since resource is present in jboss-web.xml file:

       <!-- Uncomment this for the SQL examples -->
       <resource-ref>
           <description>DataSource</description>
           <res-ref-name>jdbc/db</res-ref-name>
           <res-type>javax.sql.DataSource</res-type>
           <res-auth>Container</res-auth>
       </resource-ref>


  4. Deploy modified WAR to $JBOSS_PORTAL_DIR/server/default/deploy
  5. The deployer should automatically deploy the WAR and if you refresh the first page on the portal, you will see that the orbeon portlet view has appeared on the page. Check the terminal or logs for issues during deployment if you have some problems.

Technical information

What is a portlet?

Orbeon Forms achieves deployment into portals by supporting a standard, namely the Java Portlet specification version 2 (also known as JSR-286).

According to the Java Portlet Specification, a portlet is a "Java technology based Web component, managed by a portlet container that processes requests and generates dynamic content. Portlets are used by portals as pluggable user interface components that provide a presentation layer to Information Systems". An implementation agnostic definition can be found in the Web Services for Remote Portals (WSRP) White Paper of 22 September 2002 "Portlets are user-facing, interactive Web application components rendering markup fragments to be aggregated and displayed by the portal."

In other words, a portlet is usually a web application that can be embedded within a portal, and shares web page real estate with other portlets. Traditionally portlets available in public portals have provided simple features such as stock quotes, news feeds, weather reports, etc. In particular thanks to the Java Portlet specification, there is no limit to the extent of the features provided by a portlet, and it is expected that complex interactive portlets will become more and more widespread.

Orbeon Forms and portlets

Orbeon Forms hides the complexity of the Portlet API to allow most Orbeon Forms applications to work unmodified within portlet container. For the curious, the Portlet API requires:
  • Separation of faceless actions from rendering - Orbeon Forms allows actions to generate output while still adhering to the Java Portlet specification. Developers are obviously free to only write faceless actions. In the Page Flow Controller, such actions end with a <result page="some-page-id"> directive.
  • Getting rid of the familiar concept of URL path - Orbeon Forms abstracts this behavior and provides Orbeon Forms Portlet developers with the notion of a path, implicitly in the Web Application Controller, or explicitly with the Request Generator, while still adhering to the Java Portlet specification.
  • Getting rid of the familiar concept of URL redirection - Instead, portlet actions can set parameters to use in subsequent portlet rendering. Orbeon Forms abstracts this behavior and provides, indirectly in the Page Flow Controller, or explicitly with the Redirect Processor, the notion of redirecting to another page within the portlet.
  • Calling APIs to generate URLs - Orbeon Forms handles this by providing automatic URL rewriting.
  • Generating markup fragments - The default Orbeon Forms epilogue automatically extracts a fragment from an HTML document. This allows pages to remain unmodified for both servlet and portlet deployment.

Portlet application configuration file

Configuration of portlets is done in a standard file called portlet.xml that sits in the same directory (WEB-INF) as your web.xml. The portlet-class element must always be:
  • org.orbeon.oxf.portlet.OrbeonPortlet2Delegate (for Portlet 2 (JSR-286) Orbeon Forms portlets)
You can also configure non-Orbeon Forms portlets within the same portlet.xml.The main processor URI and optional inputs are specified with the oxf.main-processor.name and oxf.main-processor.input.* initialization parameters.


It is possible to configure several Orbeon Forms Portlets within the same portlet.xml, with the same or a different configuration. The portlet-name element however must be different for each portlet, as per the Java Portlet specification.

NOTE: It is possible to deploy Orbeon Forms Servlets, Servlet Filters, Servlet Context Listeners, and Portlets within the same application:


Portlet output

The type of the portlet output is determined by the serializer. With the default Orbeon Forms epilogue in config/epilogue-portlet.xpl, the HTML serializer is used.

Preferences

Portlet preferences can be retrieved with the oxf:portlet-preferences-generator processor.

To retrieve the preferences of your current portlet, use the following code:

<p:processor name="oxf:portlet-preferences">
    <p:output name="data" id="portlet-preferences"/>
</p:processor>

The generator outputs a document containing name / values in the following format:

<portlet-preferences>
    <preference>
        <name>name1</name>
        <value>value1</value>
    </preference>
    <preference>
        <name>name2</name>
        <value>value1</value>
        <value>value2</value>
        <value>value3</value>
    </preference>
</portlet-preferences>

For example:

<portlet-preferences>
    <preference>
        <name>max-items</name>
        <value>10</value>
    </preference>
    <preference>
        <name>url</name>
        <value>http://xml.newsisfree.com/feeds/42/1842.xml</value>
    </preference>
</portlet-preferences>

Portlet preferences can be saved with the oxf:portlet-preferences-serializer processor. [TODO: document]

Portlet security

Portlet security can be configured in portlet.xml as per the Portlet specification. The Request Security processor provides security information like in the case of Servlets.

Limitations of Orbeon Forms portlets

The Orbeon Forms Portlet developer should be aware of the following limitations:
  • Redirection - In the Page Flow Controller, pages that are the target of a portlet render URL cannot end with a redirection. This in particular applies to the default portlet page ("/"). Developers have to make sure that a page exists for "/" that produces content and does not end in a redirect. Other pages can end with redirects by making sure that they are targeted by action URLs (by default, only the target of HTML or XHTML form submissions generate action URLs).
  • Portlet Mode and Window State hints - It is currently not possible to set a portlet mode or window state hint in a URL. 
  • Content Type Hints - It is not possible for an Orbeon Forms Portlet to know which content types are supported by the portal.
  • Preferences - It is currently not possible to modify portlet preferences or store them from within a portlet.

Comments