Showing posts with label WebSphere. Show all posts
Showing posts with label WebSphere. Show all posts

Thursday, August 30, 2012

Apache Tiles 2.2 error handling in Websphere Application Server 7

When using Apache Tiles 2.2 in Websphere 7 application, by default the JSP engine renders the response tile-by-tile. When exception happens in one tile and there is error page defined, only the offending tile is rendered with the error page, the others are just rendered fine.

To change this behaviour to allow exceptions to bubble up to the including JSP and forwad to the error page, there are two things need to be done:

1) Set the container custom property com.ibm.ws.webcontainer.dispatcherRethrowSError to true. This property is avaiable from WAS Fixpack 7.0.0.15. Details can be found from http://www-01.ibm.com/support/docview.wss?uid=swg1PM22919 and http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=%2Fcom.ibm.websphere.express.doc%2Finfo%2Fexp%2Fae%2Frweb_custom_props.html.

2) Define an errorPage for the template jsp, as shown in below.

<%@ page errorPage="/jsp/general/error.jsp" %>

<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>

<tiles:insertAttribute name="header" />

<tiles:insertAttribute name="body" />

<tiles:insertAttribute name="footer" /> 

Thursday, June 14, 2012

Develop a Hello World Business Integration Application using WebSphere Integration Developer 7

This note summarise the development of a Hello World Business Integration application using WebSphere Integration Developer 7.0. The demo application reads simple CSV files from the input directory and then writes the data to the output directory in XML format.

Step 1 - Install WebSphere Integration Developer 7.0

Install IID 7.0.0.4 and local Websphere Process server test environment.

Step 2 - Build the Hello World Business Integration application

2.1) Create a new module, from menu select File - New - Module, and uses SimpleFileModule as module name.

2.2) Use the default Business Object Parsing Mode, and click Finish. Once the module is created, the Assemble Diagram view is displayed

2.3) Under the SimpleFileModule, right click the Data Types node to create a new Business Object.

2.4) Enter Customer as the Business Object name, click Next

2.5) Click Finish on the Derived Business Object screen

2.6) Now the Business Object editor screen is displayed

2.7) Click the Add Field icon to add fields to the Customer Business Object.

2.8) Add a string field name and an int field age, then save changes.

2.9) Right click the SimpleFileModule and select New - External Service

2.10) Select Simple inbound Flat File service to read from a local file, click Next.

2.11) Use the default values on the Flat File service name screen and click Next.

2.12) Now the CWYFF_FlatFile project is imported to the workspace. On the Business object and directory screen, select the Customer Business object and the input directory. Click Next.

2.13) Select Other as the input format and select the CSVDataHandler

2.14) Use "\n" as the file split delimiter, click Next.

2.15) Select the local archive directory, click Finish.

2.16) The FlatFileExport interface is now added to the Assemble Diagram.

2.17) Right click the SimpleFileModule and select New - External Service to add a Simple outbound Flat File service to write to a local file, click Next.

2.18) Use the default values on the Flat File service name screen and click Next.

2.19) On the Business object and directory screen, select the Customer Business object and the output directory, click Next.

2.20) Set the output file to Customer.xml and use other default values on the Output file name screen, click Next.

2.21) Select XML output format, click Finish.

2.22) The FlatFileImport interface is now added to the Assemble Diagram.

2.23) Drag and drop a Mediation Flow from the Assemble Diagram Palette to the Assemble Diagram editor.

2.24) Name the Mediation Flow to SimpleFileFlow

2.25) Double click the SimpleFileFlow and click Yes on the confirmation message box.

2.26) Use the default value on the Generate Implementation screen and click OK.

2.27) Now the SimpleFileFlow editor is open.

2.28) Click the Add an interface link and select FlatFileExport.

2.29) Click the Add a reference link and select FlatFileImport.

2.30) Save changes.

2.31) Click the emit link from FlatFileExport, then select Operation Map.

2.32) Select the default values on the Select Reference Operation screen, click OK.

2.33) The Mediation Flow Request editor is open.

2.34) Double click the input_map node, use default values on the Create an XML Map screen and click Next.

2.35) Use default values on the Specify Message Types screen and click Finish.

2.36) Now the map editor is open, expand the emit link and the create link.

2.37) Link the emitInput and the createInput with a Move transformation.

2.38) Save all changes and back to the Assemble Diagram editor, link the FlatFileExport to SimpleFileFlow, then SimpleFileFlow to FlatFileImport, save changes.

Step 3 - Testing the module

To run the module, right click the local Process Server and select Add and Remove Projects.

Then add the SimpleFileModuleApp to the Configured projects list, and click Finish.

Start the Process Server, and check the SimpleFileModuleApp is started and synchronized.

Copy a CSV file to the input directory, the file should have a format as shown in below

Peter,20
Tom,21
Emma,22
Julia,23

After a few seconds, the application reads the input CSV file and output few output XML files to the output directory, the input file is archived to the archive directory with a .success or .fail extension. The generated XML file has a format as shown in below.

<?xml version="1.0" encoding="UTF-8"?>
<p:Customer xsi:type="p:Customer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:p="http://SimpleFileModule">
 
 <name>Tom</name>
 <age>21</age>
</p:Customer>

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.

Tuesday, April 3, 2012

Using URL Rewrting for Session Tracking in IBM WebSphere Application Server

My recent application has two access interfaces; the first one in a normal Web interface that end users access to using browsers, the second one is a servlet based B2B interface that business partners access to using their in-house applications. Session tracking is required for both the interface, for Web interface, normal cookies based session tracking mechanism is used; while for B2B interface, as the client applications don't support cookie, URL rewriting based session tracking mechanism is used.
In order to use URL rewriting, B2B client applications must include jsessionid in its request URL. In the current implementation, when a B2B client applicaiton access the application first time, a jsessionid is output to the client, then the jsessionid is used in following requests.

The implementation of the URL rewriting in WAS consists of two parts.
Firstly, the URL rewriting must be enabled in the application session management. When both cookie and URL rewriting are enabled, WAS by default will use cookie when requests come from clients that have cookie enabled.



Secondly, the application must include the jsessionid in the response. Through the HttpSession interface provides a getId method that returns a unique identifier assigned to this session, but in WAS, the return value is only part of the jsessionid string. Currently I use the response.encodeURL method to generate a encoded URL that has a format like ...;jsessionid=0000qA9CUpmesNP-MLxR3KoXeaM:-1, from which the jsessionid is extracted using substring methods.

Monday, March 12, 2012

JSF Portlet File Download using WebSphere JSF 1.2 Portlet Bridge

This note summarise my experience of JSF portlet file download using WebSphere JSF 1.2 Portlet Bridge.

One approach to implement file download from portlets is to use the JSR 286 resource serving mechanism. In order to make it working in JSF portlets, one needs to mix portlet and JSF programming as there is no direct support of the mechanism from JSF 1.2 Portlet Bridge.

The implementation consists of three components: a portlet class that extends FacesPortlet and overrides the serveResource method; a JSF page that provides use the download link; and a JSF managed bean that provides the file content.

The portlet class

package demo;

import java.io.IOException;
import java.io.OutputStream;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
import javax.faces.lifecycle.Lifecycle;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

import com.ibm.faces.portlet.FacesPortlet;
import com.ibm.faces.portlet.httpbridge.PortletRequestWrapper;
import com.ibm.faces.portlet.httpbridge.PortletResponseWrapper;
import com.ibm.faces.portlet.httpbridge.ResourceRequestWrapper;
import com.ibm.faces.portlet.httpbridge.ResourceResponseWrapper;

public class JSFPortlet extends FacesPortlet {

 @Override
 public void serveResource(ResourceRequest request, ResourceResponse response)
   throws PortletException, IOException {

  super.serveResource(request, response);

  TestBean testBean = (TestBean) getJSFManagedBean(
    request, response, TestBean.BEAN_NAME, TestBean.class);

  final OutputStream out = response.getPortletOutputStream();
  byte[] bytes = testBean.getCsv();
  response.setContentType("text/csv");
  response.setProperty("Content-Disposition",
    "attachment; filename=download.csv");
  response.setProperty("Content-length", String.valueOf(bytes.length));

  out.write(bytes);
  out.flush();
  out.close();
 }

 public Object getJSFManagedBean(ResourceRequest request,
   ResourceResponse response, String beanName, Class beanClass)
   throws PortletException {

  PortletSession portletSession = request.getPortletSession();

  Object jsfBean = (TestBean) portletSession.getAttribute(beanName);

  if (jsfBean == null) {
   PortletRequestWrapper requestWrapper = new ResourceRequestWrapper(
     request);
   requestWrapper.setPortletContext(getPortletContext());
   PortletResponseWrapper responseWrapper = new ResourceResponseWrapper(
     response);
   Lifecycle lifecycle = getLifecycle(requestWrapper);
   FacesContext context = getFacesContext(requestWrapper,
     responseWrapper, lifecycle);

   final ExpressionFactory expressionFactory = context
     .getApplication().getExpressionFactory();

   final ValueExpression valueExpression = expressionFactory
     .createValueExpression(context.getELContext(), 
       "#{" + beanName + "}", beanClass);
   jsfBean = (TestBean) valueExpression.getValue(context
     .getELContext());
  }

  return jsfBean;
 }
}

The JSF page

<%@ 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/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>
  
  <portlet:resourceURL var="resourceUrl" >
  <portlet:param name="action" value="csv" />
  </portlet:resourceURL>

  <a href="<%=resourceUrl%>">Download CSV</a>
  
</f:view>

The JSF managed bean

package demo;
import java.util.Date;

public class TestBean {
 public static final String BEAN_NAME = "testBean";
 
 public byte[] getCsv() {
     return new Date().toString().getBytes();
   }
 
 public String getText() {
  return "Hello";
 }
}

Some notes are:

- The IBM JSF 1.2 Portlet Bridge doesn't provide a Facelet taglib xml for the <portlet:resourceURL> tag, so the tag cannot be used in Facelet based JSF pages. This issue has been addressed in IBM JSF 2 Portlet Bridge.

- The <portlet:resourceURL> tag provides a var attribute that can be used to export the resource URL. Based on the JSR 286 spec, the exported variable is created in JSP page scope. As JSF code has no access to JSP page scope, the exported variable can not be used in JSF code.

- In traditional Servlet programming, the response.setHeader method is used to set HTTP response heads like Content-Disposition and Content-length, but in portlet, the ResourceResponse.setProperty method is used.

- There are two ways to access JSF managed beans from the portlet code: if the managed bean is a session scope bean and it's already exists in the session, the portletSession.getAttribute(BEAN_NAME) call can be used; otherwise, JSF value expression can be used to get and/or create the bean from FacesContext, as the IBM JSF 1.2 Portlet Bridge doesn't provide any method that the portlet implementation class can directly access FacesContext, some internal code must be used to achieve this.

Tuesday, March 6, 2012

Use WebSphere wsadmin Jython to customise Web module context root for WAR/EAR deployment

This note explain how to use wsadmin Jython to customise Web module context root for WAR/EAR deployment in WebSphere Application Server.

To deploy WAR/EAR file in WAS WebSphere Application Server, wsadmin Jython provides the AdminApp.install method, where the archivePath parameter gives the full path of the war/ear file, and the options parameter gives various options for deployment, including the context root setting.

AdminApp.install(archivePath, options)

For WAR deployment, the -contextroot option is used, the option value is the given context root.

options = []
...
options.append("-contextroot")
options.append(contextRoot)
...
AdminApp.install(warPath, options)

For EAR deployment, the -CtxRootForWebMod option is used, the option value is a list consists of three items: Web module name, Web module URI, and the given context root. The Web module name and URI values can be set in two ways, using specific values, or using pattern matching:

#Set Web module name and URI with specific values
options = []
...
options.append("-CtxRootForWebMod")
options.append([['My Web Applicaiton', 'my_app.war,WEB-INF/web.xml', contextRoot]])
...
AdminApp.install(earPath, options)

#Set Web module name and URI using pattern matching
options = []
...
options.append("-CtxRootForWebMod")
options.append([['.*', '.*', contextRoot]])
...
AdminApp.install(earPath, options)

Friday, February 24, 2012

Setup a Portlet Development Environment With IBM Rational Application Developer 8

This is a walkthrough for setting up a portlet development environment With IBM Rational Application Developer (RAD) 8.

Step 1 - Verify you meet the System requirements for Rational Application Developer 8.
Reference: http://www-01.ibm.com/support/docview.wss?rs=2042&uid=swg27019500

Step 2 - Download RAD 8 install package
Trial version can be found from http://www.ibm.com/developerworks/downloads/r/rad/?S_CMP=rnav

Step 3 - Install RAD 8
Lunch the IBM Installation Manager to install Rational Application Developer for WebSphere, in Features screen, select Portlet and Portal development tool. If you don't have a local portal server installed, make sure the "Tools for developing applications without a local server installation" option is selected, as shown in below.

Step 4 - Setup a Portal Server in RAD
1) From the RAD menu, Window -> Show View -> Servers
2) Right-click the server view and click New -> Server.
3) On the Define a New Server page, select WebSphere Portal Server
4) Follow the New Server wizard and provide the WebSphere Settings, WebSphere Portal Settings and Properties Publishing Settings.

Step 5 - Verify the setup
Right-click the Portal server in the server view then do a start and stop to verify the server setup.

Congratulations! Now you have set up a portlet development environment in RAD, and you are ready to start portlet development.