Friday, June 22, 2012

Develop a Hello World ESB Java Service using WebSphere Integration Developer 7

This note summarise the development of a Hello World ESB Java service using WebSphere Integration Developer 7.0.

Step 1 - Build the ESB Java service

1.1) In WebSphere Integration Developer 7.0 workspace, switch to Business Integration Perspective.

1.2) In file menu, select File - New - Module, use HelloWorldServiceModule as the Module name and click Finish.

1.3) Under the HelloWorldServiceModule project, right click Interfaces, and select New - Integerface, use HelloWorldInterface as the interface name, then click Finish.

1.4) In the interface editor, right click and select Add Request Response Operation, use hello as operation name, and message as the input, response as the output, both with string type. Save the changes.

1.5) Switch to the Assembly Editor, drag and drop a Java component from the Palette to the Assembly Editor, name it HelloWorldService.

1.6) Right click the HelloWorldService and select Add - Interface, select HelloWorldInterface.

1.7) Right click the HelloWorldService and select Generate Implementation, create a new package demo.

1.8) In the HelloWorldServiceImpl Java editor, implemention the hello method as the code below, save changes.

/**
 * Method generated to support implementation of operation "hello" defined for WSDL port type 
 * named "HelloWorldInterface".
 * 
 * Please refer to the WSDL Definition for more information 
 * on the type of input, output and fault(s).
 */
public String hello(String message) {
 return "Hello:" + message;
}

1.9) Switch to the Assembly Editor, drag and drop a References component from the Palette to the Assembly Editor.

1.10) Right click the Stand-alone References, and select Add Reference, then select HelloWorldInterface

1.11) Link the Stand-alone References to HelloWorldService, save changes.

Step 2 - Build the ESB client

2.1) Switch the Java EE perspective.

2.2) Right click the HelloWorldServiceModuleWeb project, and select New - JSP, use client.jsp as the File name, then click Finish.

2.3) Add the code below to the client.jsp page, save changes.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ page import="com.ibm.websphere.sca.*,commonj.sdo.DataObject" %>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>

<%
String serviceOutput = "N/A";
String message = request.getParameter("message");
if(message != null){
 try{
  ServiceManager serviceManager = new ServiceManager();
  Service service = (Service) serviceManager.locateService("HelloWorldInterfacePartner");
  DataObject respObject = (DataObject) service.invoke("hello", message);
  serviceOutput = respObject.getString("response");
 }catch(Exception e){
  e.printStackTrace();
 }
}
%>

Service Output : <%= serviceOutput %>

<form method="post">
 <input type="text" NAME="message"/>
 <input TYPE="submit"/>
</form>

</body>
</html>

Step 3 - Build and run the application

3.1) Switch to Business Integration Perspective, right click the HelloWorldServiceModule, select Export and Integration modules and libraries - Files for server deployment

3.2) Deploy the generated EAR file to Websphere Process Server.

3.3) Access the client.jsp from browser to test the application.

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>

Spring MVC3 Portlets with Websphere Portal 7 Client Side Aggregation

This note summarises the Action ID missing issue and solution found when running Spring MVC3 portlets with Websphere Portal 7 Client Side Aggregation (CSA).

The issue can be reproduced with a simple Spring portlet as shown in below. When the form is submitted, the "This portlet is unavailable" message is displayed, and the ffdc log shows an Action ID missing error message.

<%@page
    language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1" session="false"%>
    
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>   
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%> 
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="portlet" uri="http://java.sun.com/portlet_2_0"%>

Hello ${demoBean.message}

<portlet:actionURL var="actionURL"/>

<div>

<form:form action="${actionURL}"  method="post" modelAttribute="demoBean">
 <form:input size="20" path="message" />
 <input type="submit"/>
</form:form>  

</div>

[30/05/12 16:53:06:418 EST] 0000004e PortletInvoke W com.ibm.wps.wsrp.producer.provider.pc.waspc.impl.PortletInvokerImpl 
 newBlockingInteractionResponse Action execution refused due to a security violation. Action ID missing.
[30/05/12 16:53:06:425 EST] 0000004e WSRPEngine    E com.ibm.wps.wsrp.producer.impl.WSRPEngine performBlockInteraction 
 EJPWC1109E: Normal execution of the operation failed.
 com.ibm.wps.wsrp.exception.WSRPException: EJPWC1109E: Normal execution of the operation failed.
 at com.ibm.wps.wsrp.producer.provider.pc.waspc.impl.PortletInvokerImpl.handleActionProtection(PortletInvokerImpl.java:1083)
 at com.ibm.wps.wsrp.producer.provider.pc.waspc.impl.PortletInvokerImpl.invokePerformBlockingInteraction(PortletInvokerImpl.java:833)
 at com.ibm.wps.wsrp.producer.provider.pc.impl.PortletInvokerImpl.invokePerformBlockingInteraction(PortletInvokerImpl.java:170)
 at com.ibm.wps.wsrp.producer.impl.WSRPEngine.performBlockingInteraction(WSRPEngine.java:833)
 at oasis.names.tc.wsrp.v2.bind.WSRP_v2_Markup_Binding_SOAPImpl.performBlockingInteraction(WSRP_v2_Markup_Binding_SOAPImpl.java:213)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at com.ibm.ws.webservices.engine.dispatchers.java.JavaDispatcher.invokeMethod(JavaDispatcher.java:178)
 at com.ibm.ws.webservices.engine.dispatchers.java.JavaDispatcher.invokeOperation(JavaDispatcher.java:141)
 at com.ibm.ws.webservices.engine.dispatchers.SoapRPCProcessor.processRequestResponse(SoapRPCProcessor.java:481)
 at com.ibm.ws.webservices.engine.dispatchers.SoapRPCProcessor.processMessage(SoapRPCProcessor.java:427)
 at com.ibm.ws.webservices.engine.dispatchers.BasicDispatcher.processMessage(BasicDispatcher.java:134)
 at com.ibm.ws.webservices.engine.dispatchers.java.SessionDispatcher.invoke(SessionDispatcher.java:204)
 at com.ibm.ws.webservices.engine.PivotHandlerWrapper.invoke(PivotHandlerWrapper.java:263)
 at com.ibm.ws.webservices.engine.handlers.jaxrpc.JAXRPCHandler.invoke(JAXRPCHandler.java:153)
 at com.ibm.ws.webservices.engine.handlers.WrappedHandler.invoke(WrappedHandler.java:64)
 at com.ibm.ws.webservices.engine.PivotHandlerWrapper.invoke(PivotHandlerWrapper.java:263)
 at com.ibm.ws.webservices.engine.PivotHandlerWrapper.invoke(PivotHandlerWrapper.java:263)

Look at the portlet page html source, the form action attribute values is a Websphere Portal javascript in which the portlet action URL is encoded.

<form method="post" action="javascript:
    com.ibm.portal.csa.PortletIWidget.Z7_EIH60VH40GNPF0ITR3BKO410I2.onActionLink(
      com.ibm.portal.csa.PortletIWidget.Z7_EIH60VH40GNPF0ITR3BKO410I2.urls.url0.tokens);" 
  id="demoBean">
 <input type="text" size="20" value="" name="message" id="message">
 <input type="submit">
</form>

This solution is to add a htmlEscape attribute to the spring form tag and set its value to false to disable html escape so that the portal engine can encode the action URL correctly.

<form:form action="${actionURL}"  method="post" modelAttribute="demoBean"
 htmlEscape="false">
  ...   
</form:form>

The solution is verified in Websphere Portal 7.0.0.2 with WAS Application Server 7.0.0.21 and Spring MVC 3.1.0.