« Ubuntu 10.4, Glassfi... | Main | OpenID and Yahoo »

Liferay, JSF and Glasssfish

Developing a JSF portlet in Liferay 6.0.4 running on Glassfish 3 is not as easy as it sounds like. I investigated several days (and nights) to found a working solution. I think the reason why it takes so much time for me was the fact that there are to many examples spread over the last two years. And as more you mix them up as more problems occur.   

Running Liferay on top of Glassfish 3 is a good choice as the Glassfish application server supports a powerful platform for EJB and Web development. For the portlet development there are different APIs and specifications which need to be separated with care.

After my personal journey through the portlet/jsf world I come to the conclusion that the best combination of all portlet technologies is the Portlet API 2.0 (JSR 286) and JSF 2.0 (JSR 314). To fit them together you need a JSF-Portlet Bridge.

The best working solution for now seems to be the portletfaces-bridge from portletfaces.org. This bridge is not yet final but it works well with Liferay and Glassfish. ?The portletfaces bridge supports development of JSF 2.0 apps that run inside a Portlet 2.0 compliant portlet container, such as the one provided by Liferay Portal. In addition, the bridge facilitates the deployment of ICEfaces 2.0 applications.

The two artifacts "portletfaces-bridge-api" and portletfaces-bridge-impl"are not available through an official maven repository.So you need to add the Maven repository 'http://repo.portletfaces.org/mvn/maven2/' to your maven settings.xml file. Then you can use them in your projects using maven2.

The current alpha releases are:

  • portletfaces-bridge-api-2.0.0-ALPHA4.jar
  • portletfaces-bridge-impl-2.0.0-ALPHA4.jar

You can checkout an example portlet form the Imixs Workflow Portlet Project at the following location:

https://imixs-workflow.dev.java.net/svn/imixs-workflow/imixs-workflow-portlet-sample/tags/0.0.3

Note: To get access you simply need an account on dev.java.net.

I will post the interesting parts of the example here:

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">

<description>Imixs RichFacesPortlet</description>
<context-param>
<param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.expressionFactory</param-name>
<param-value>org.jboss.el.ExpressionFactoryImpl</param-value>
</context-param>
<!--
Although the FacesServlet will not be invoked by any portlet requests,
it is required to initialize JSF.
-->
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>


<security-constraint>
<web-resource-collection>
<web-resource-name>Page Sources</web-resource-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>nobody</role-name>
</auth-constraint>
</security-constraint>
<security-role>
<role-name>nobody</role-name>
</security-role>
</web-app>

portlet.xml

 <?xml version="1.0"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
    <portlet>
        <portlet-name>1</portlet-name>
        <display-name>Imixs Portlet Sample RichFaces</display-name>
        <portlet-class>org.portletfaces.bridge.GenericFacesPortlet</portlet-class>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.view</name>
            <value>/pages/echo.xhtml</value>
        </init-param>
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
        </supports>           
        <portlet-info>
            <title>ImixsRichFacesEchoPortlet</title>
            <short-title>ImixsRichFacesEchoPortlet_Short</short-title>
            <keywords>Sample</keywords>
        </portlet-info>
          <security-role-ref>
            <role-name>administrator</role-name>
        </security-role-ref>
        <security-role-ref>
            <role-name>guest</role-name>
        </security-role-ref>
        <security-role-ref>
            <role-name>power-user</role-name>
        </security-role-ref>
        <security-role-ref>
            <role-name>user</role-name>
        </security-role-ref>       
</portlet>
</portlet-app>


 liferay-plugin-package.properties

 

name=ImixsPortletSample
module-group-id=liferay
module-incremental-version=1
tags=sample
short-description=This plugin leverages the Sun OpenPortal JSF Portlet Bridge and shows how to use the JSF 1.2 Sun RI and the Facelets view-handler within Liferay.
change-log=
page-url=http://www.liferay.com
author=Liferay, Inc.
licenses=MIT

portal-dependency-jars=

 

faces-config.xml

 <?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
 
   <application>
 
   </application>
   
   <managed-bean>
      <description>Echo Bean</description>
      <managed-bean-name>echo</managed-bean-name>
      <managed-bean-class>com.imixs.portlet.test.EchoBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
        <managed-property>
            <property-name>text</property-name>
            <value>Hello Liferay</value>
        </managed-property>
   </managed-bean>

    
</faces-config>