Thursday, May 10, 2012

Building AJAX-enabled JSF Portlets in IBM WebSphere Portal 7

This note summarise different approaches to implement an AJAX-enabled JSF portlet in IBM WebSphere Portal 7. The portlet used in the demo has a simple UI that consists of two elements, one list box that has two items and one text label. When AJAX is enabled to the portlet, once the list box selected item changes, an AJAX request is sent to refresh the text label.

Implementation 1 - IBM JSF Portlet bridge 1.2 with IBM JSF Extension Components

IBM WebSphere Portal 7 comes with a JSF Portlet bridge 1.2 that supports JSF 1.2 based portlet development. As JSF 1.2 doesn't have built-in AJAX support, IBM JSF Extension Components are used to provide AJAX functionalities, as shown in the code below

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@taglib uri="http://www.ibm.com/jsf/html_extended" prefix="hx"%>

<%@taglib
  uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model"
  prefix="portlet-client-model"%>
<%@page language="java" contentType="text/html"
  pageEncoding="ISO-8859-1" session="false"%><portlet:defineObjects />
<portlet-client-model:init>
  <portlet-client-model:require module="ibm.portal.xml.*" />
  <portlet-client-model:require module="ibm.portal.portlet.*" />
</portlet-client-model:init>
<f:view>
  <hx:scriptCollector id="scriptCollector1">
    <h:form styleClass="form" id="form1">
      <h:selectOneListbox id="listbox1">
        <f:selectItem itemLabel="Label1" 
          itemValue="Value1" id="selectItem1" />
        <f:selectItem itemLabel="Label2" 
          itemValue="Value2" id="selectItem2" />
      </h:selectOneListbox>
      <hx:behavior event="onchange" target="listbox1" 
        behaviorAction="get" targetAction="group1"></hx:behavior>
    </h:form>
    <h:panelGroup styleClass="panelGroup" id="group1">
      <h:outputText styleClass="outputText" id="text1"
      value="Hello, #{param.listbox1} "></h:outputText>
    </h:panelGroup>
    <hx:ajaxRefreshRequest target="group1" 
      id="ajaxRefreshRequest1"
      params="listbox1">
    </hx:ajaxRefreshRequest>
  </hx:scriptCollector>
</f:view>

Implementation 2 - JSF 2.0 Portlet Bridge for IBM WebSphere Portal

There is a JSF 2.0 Portlet Bridge for IBM WebSphere Portal available from Greenhouse Lotus that allows developing portlets based on JSF 2.0 specifications with MyFaces 2.0. With JSF 2.0 build-in AJAX support, the demo can be implemented as JSF code shown in below.

<div xmlns="http://www.w3.org/1999/xhtml" 
 xmlns:ui="http://java.sun.com/jsf/facelets" 
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html" 
 xmlns:portlet="http://java.sun.com/portlet_2_0"  >
<f:view>
  <h:form> 
    <h:selectOneListbox styleClass="selectOneListbox" 
      id="listbox1" value="#{testBean.text}">
      <f:selectItem itemLabel="Label1" itemValue="Value1"/>
      <f:selectItem itemLabel="Label2" itemValue="Value2"/>
      <f:ajax render="text1" execute="@this"/> 
    </h:selectOneListbox>
    <h:outputText id="text1"
      value="Hello, #{testBean.text} ">
    </h:outputText>
  </h:form>
</f:view>
</div>

Implementation 3 - ICEfaces Enterprise Edition (EE) 3.0

ICEfaces Enterprise Edition 3.0 provides a PortletFaces Bridge Extensions library that supports JSF 2.0 based portlets on WebSphere Portal 7. The demo can be implemented using the same JSF code as Implementation 2 above with MyFaces 2.0 or Mojarra 2.1, additional change required is add the container runtime option below in portlet.xml.

<container-runtime-option>
  <name>javax.portlet.renderHeaders</name>
  <value>true</value> 
</container-runtime-option>

All three implementations are tested in WebSphere Portal 7.0.0.2 and WAS 7.0.0.19 with different theme and render modes, the results are summarised in the table below.

Implementation Page Builder theme - SSA Page Builder theme - CSA Portal theme - SSA only Notes
IBM JSF Portlet bridge 1.2 with IBM JSF Extension Components works as expected The portlet is rendered but AJAX doesn't work, no Javascript errors works as expected  
JSF 2.0 Portlet Bridge for IBM WebSphere Portal (MyFaces 2.0) works as expected works as expected works as expected The library is provided as is, with no support from IBM
ICEfaces Enterprise Edition 3.0 (MyFaces 2.0/Mojarra 2.1) works as expected The portlet is unable to render with exceptions from the bridge The portlet is rendered but AJAX doesn't work with Javascript errors Commercial license required

Monday, May 7, 2012

RAD Application Server Publishing settings and WTP based Maven Projects


The WebSphere Application Server publishing setting in RAD has two options: 1) Run server with resources within the workspace, and 2) Run server with resources on Server. When perform "Run/Debug on Server", with the "within the workspace" option, applications run from the workspace, while with the "on Server" option, applications are deployed to Application Server first and then run from the server.

When there is a local application server is available, the "within the workspace" option is the default and it takes less publishing time compare to the "on Server" option. However, it may not work with WTP based Maven projects that have "Workspace Resolution" enabled.

Given a Maven project that consists of two modules - core and web, when perform "Run/Debug on Server" with Maven "Workspace Resolution" enabled and the "within the workspace" option selected. RAD doesn't publish the core jar file to the workspace publishing folder (e.g. .metadata\.plugins\org.eclipse.wst.server.core\tmp1\), and uses two different class loaders to load the core jar and the web application, thus causes class loading related issues, examples include

- spring xml in the web module cannot import spring xml from core module using <import resource="classpath:com/test/resources/spring-core-beans.xml" />

- the web module cannot load resources from core module using ResourceBundle.getBundle(baseName)

An easy solution to these issues is to use the "Run server with resources on Server" publishing settings.

Friday, May 4, 2012

Using WAR File Name as uid in XMLAccess based Portlet Deployment

For portlets that don't have id attribute defined in <portlet-app> tag in portlet.xml, XMLAccess allows to use the WAR file name as uid in XMLAccess request.


<request
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="PortalConfig_7.0.0.xsd"
    type="update"
    create-oids="true">

    <portal action="locate">
        <web-app action="update" active="true" uid="WAR_NAME.webmod">
           <url>file:///PATH_TO_THE_WAR_FILE</url>
           <portlet-app action="update" active="true" uid="WAR_NAME">
              <portlet action="update" active="true" name="TestPortlet" objectid="theTestPortlet" />
            </portlet-app>
        </web-app>
    </portal>
</request>

The script works fine when install a new portlet, however when re-run the same script to update the portlet, it gives a DuplicateAppException that complains EJPPF0181E The id=XXX already exists for stored standard portlet application.


The solution to this problem is to add a uniquename attribute to the <web-app> in XMLAccess script, as shown in below


<request
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="PortalConfig_7.0.0.xsd"
    type="update"
    create-oids="true">

    <portal action="locate">
        <web-app action="update" active="true" uid="WAR_NAME.webmod" uniquename="SOME_UNIQUE_NAME">
           <url>file:///PATH_TO_THE_WAR_FILE</url>
           <portlet-app action="update" active="true" uid="WAR_NAME">
              <portlet action="update" active="true" name="TestPortlet" objectid="theTestPortlet" />
            </portlet-app>
        </web-app>
    </portal>
</request>

Now the script can be used to install a new portlet and also to update an existing portlet based on the uniquename attribute value.