Thursday, March 29, 2012

Mule Studio Hello World ESB Application

This note summarise the development of a Hello World ESB Application using Mule Studio.
Step 1 - Download and install Mule Studio
Download the Mule ESB Community Edition from www.mulesoft.org and save the distribution package zip file.
There is no installation required. Just unzip the package to local drive and we are ready to go.

Step 2 - Launching Mule Studio
Navigate to the directory that contains the muleStudio.exe executable.
Launch the muleStudio.exe to start the application.
Specify the workspace location on the Select a workspace screen.


Step 3 - First Steps
The First Steps screen is displayed if the selected workspace is a new one.
Click Go to Mule Studio to start using the application.


Step 4 - Create a new project
Go to the Studio application menu, click File > New > Mule Project


On the Mule Project screen, specify the project name and click Next.


On the New Mule Flow screen, select the Select to create a new message flow in the project checkbox, and specify the Name, then click Next.


On the Create a Java project screen, use default setting and click Next.


On the Java Settings screen, use default setting and click Finish.


Once the project is created, the Studio opens the Flow editor for the new message flow.


Step 5 - Build the Hello World message flow
Drag and drop a File endpoint from the Endpoints panel to the flow editor 

Right click the File endpoint in flow editor and click Properties

Specify the Path property.

This File endpoint works as the source endpoint, which reads files from the directory that specified in the Path property and puts the files into the flow.

Drag and drop another File endpoint from the Endpoints panel to the flow editor

The two file endpoints are linked with an arrow line that indicated the flow direction.
Right click the File endpoint in flow editor and click Properties


Specify the Path property.


This File endpoint works as the target endpoint, which receives files from the flow and writes them to the directory that specified in the Path property.

Step 6 - Run the Hello World application
Save the project first, then from the Package Explorer right click the current flow and select Run as > Mule Application


Wait for the application to start up, and check the Console shows "Started app..." message without any errors.

Once the application is started, copy a file to the directory specified in the source File endpoint path property. In few second, this file should be moved to the directory specified in the source File endpoint path property.

Now you have a simple Hello World ESB application running in Mule Studio.

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.

Thursday, March 8, 2012

File down with JSF applications

This note summarises different ways to implement file download with JSF applications.

Approach 1- File down using Servlet

This approach uses a servlet to serve file download request and the link to the servlet can be implemented by using various JSF components, e.g. commandLink and outputLink.

The servlet based approach is a simply and easy way to implement file down, however, the shortcoming here is the file serving process is outside the JSF life cycle, glue code is required when the download process needs to access JSF faces context and backing beans.

A detailed discussion of the approach can be found from here.

Approach 2- File down using JSF PhaseListener

This approach use a JSF PhaseListener to serving process, an example of such implementation can be found from the Mojarra Scales project, which provides a UI component that renders the download link and a PhaseListener that serves file content, sample usage is shown in below.

<sc:download id="downloadPdf" 
 method="download" 
 mimeType="application/pdf" 
 fileName="sample.pdf" 
 data="#{testBean.pdf}" 
 text="Download here">
</sc:download>

When the Mojarra Scales download component is used to create a download link, it renders a http link on the page with a specific URL format which the PhaseListener is used to identify the file request, once the link is clicked, the PhaseListener serves content in the beforePhase method at the RESTORE_VIEW phase.

By using a JSF PhaseListener, the file serving process is now part of the JSF lifecycle. However, the shortcoming here is the data for download is populated during page render, i.e. the evaluation of the #{testBean.pdf} expression in the above example, even the user has NOT click the download click.

Approach 3- File down using JSF Action/ActionListener

This approach use JSF Action/ActionListener that attaches to JSF commandLink or commandButton to serves file content.

Details discussion on Action based implementation can be found here, ActionListener based implementation can be found from the PrimeFaces FileDownload component.

This is the best approach from my point of view.

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)

Monday, March 5, 2012

Integrating m2eclipse-wtp with IBM Rational Application Developer for Portlet Development

This is a walkthrough for integrating Maven with IBM Rational Application Developer for portlet development using m2eclipse-wtp.

Step 1 - Install IBM Rational Application Developer V8.0.4

Refer my previous notes - Setup a Portlet Development Environment With IBM Rational Application Developer 8

Step 2 - Install m2eclipse-wtp release 1.0.100

1) In RAD open the menu Window - Preferences - Install/Update - Available Software Sites, enable sites listed below,

* http://download.eclipse.org/eclipse/updates/3.6
* http://download.eclipse.org/webtools/repository/helios

2) In RAD open the menu Help -> Install New Software, add this new location:

http://download.jboss.org/jbosstools/updates/m2eclipse-wtp

and select the following check boxes:

* Maven Integration for Eclipse
* Maven Integration for WTP
* Expand Maven Integration for Eclipse Extras folder and select only m2e connector for maven archiver pom properties

Step 3 - Install m2e connectors for software configuration management (SCM)

In my case SVN is used as SCM, I first installed Subclipse V1.6.X from update site http://subclipse.tigris.org/update_1.6.x, then in RAD open the menu Window - Preferences - Maven - Discovery, click the Open Catalog button, and select/install the m2e-subclipse connector.

Step 4 - Setup Java EE and Maven preference

1)In RAD open the menu Window - Preferences - Java EE - Project, uncheck the "Add project to an EAR" checkbox.

2)In RAD open the menu Window - Preferences - Maven - WTP integration, uncheck the "Generate application.xml under the build directory" checkbox.

Step 5 - Add Maven projects into RAD workspace

Use RAD "Checkout Maven projects from SCM" or "Import Existing Maven Projects" wizard to add your Maven projects into RAD workspace.

In my demo project, I have a Maven project that consists of three modules: core, webapp and ear. When the projects are imported into RAD, the m2eclipse-wtp plugin apply appropriate facets to the projects based on the maven project types

Step 6 - Setup EAR project properties

This step is important to use RAD Portlet development features include debug/run on server, and edit WAS deployment descriptor.

1) Right click the ear project and select Properties - Project Facets, select the "Websphere Application(Co-existence)" and the "Websphere Application(Extended)" checkboxes, change the version based on your WAS server version

2) Right click the ear project and select Properties - Targeted Runtimes, select the "Websphere Portal" checkbox.

Congratulations! now you have set up a Maevn based portlet development environment in RAD.

Issues and Solutions

Issue - The EAR project popup menu doesn't show the option Open WebSphere Application Deployment

Solution - ensure in the ear module POM file, the maven-ear-plugin/configuration/version property is set to 5 or up.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-ear-plugin</artifactId>
  <version>2.6</version>
  <configuration>
    <!-- generate application.xml version 5, to enable RAD to edit WAS deployment descriptor -->
    <version>5</version>  
    <modules>
      <webModule>
        <groupId>${project.groupId}</groupId>
        <artifactId>demo-webapp</artifactId>
        <contextRoot>MavenDemoPortlet</contextRoot>
      </webModule>
    </modules>
  </configuration>
</plugin>

Issue - Open WebSphere Application Deployment for the EAR project shows error Could not open the editor: An unexpected exception was thrown.

Solution - check the ear project settings/org.eclipse.wst.common.component file, ensure the deploy-name attribute of wb-module has the same value as the Eclipse project name. This can be achieved by two different ways.

1) In ear module POM file, add the build/finalName property, and set the value as the ear module artifactId,

<build>
  <!-- 
    same as the artifactId, which is the RAD project name, and also the    
    deploy-name defined in settings/org.eclipse.wst.common.component    
  -->
  <finalName>demo-ear</finalName>
  ...
</build>

2) During the project import, use the [artifactId]-[version] Name template in Advanced setting.

Issue - Run/Debug the portlet on Server shows error EJPPG0024I: Web application with context root XXX is deployed in the application server but not registered with portal.

Solution - check the webapp project settings/org.eclipse.wst.common.component file, ensure the context-root property of wb-module has the same value as the contextRoot defined in the ear maven-ear-plugin. If they are different, either update the ear POM file, or set the m2eclipse.wtp.contextRoot or the build/finalNameproperty in webapp module POM to update the webapp project settings/org.eclipse.wst.common.component file.

<properties>
  <!-- this must be same as the contextRoot defined in the ear module-->
  <m2eclipse.wtp.contextRoot>MavenDemoPortlet</m2eclipse.wtp.contextRoot>
</properties>