I recently investigated the Worklist Manager in GlassFish ESB and want to share some of the details here. GlassFish is based on the Java Business Integration (JBI) specification and includes service engines for Java EE, BPEL and so on. The Worklist Manager is one of these service engines. It is not based on BPEL4People as far as I know but basically meets the same need -- providing a way to integrate human/workflow tasks into a business-process environment.
Note that there is a Wiki for this service engine at
http://wiki.open-esb.java.net/Wiki.jsp?page=WLMSE. My goal when investigating the WLMSE was to demonstrate accessing it from a web service client external to the GlassFish environment. The documentation in this area is rather spotty, and hence this post. I started at the above Wiki and took things from there.
An important consideration here is that there are a number of versions of GlassFishESB, OpenESB, NetBeans, and so on, and the combination makes a difference. If you peruse enough online tutorials, you'll finally begin wondering what version, exactly, you need to download to see the same functionality as you are seeing in the tutorial. For example, the latest release, recommended on the WorkList Manager Service Engine (WLMSE) Wiki, is GlassFish ESB V2.1 Milestone 1. The download for this release includes NetBeans 6.5. It does not include the WLMSE, however, which the Wiki recommends obtaining as a separate download. The only problem with the provided download is that it is only compatible with the latest patch of NetBeans 6.1, and lower. So you will need an earlier version of NetBeans in order to install the WLMSE!
For reference, I used GlassFish V2 UR2 and NetBeans 6.1 Patch 4. It does not appear feasible at this time to use V2.1M1 with the WLMSE based on the above issue, so I recommend trying something a little older. My pre-requisites below send you to the older version that I used to develop this post.
Pre-requisites:
- Get NetBeans 6.1 at http://www.netbeans.org/downloads/6.1/index.html, selecting the "All" column, which includes SOA support.
- Java SE 6 installed: http://java.sun.com/javase/downloads/index.jsp. Be sure to get the JDK, not the JRE, as there are utilities you will need from the JDK.
- Maven 2 installed: http://maven.apache.org/download.html
- The following environment variables:
- JAVA_HOME: top-level Java SE 6 directory
- M2_HOME: top-level Maven 2 directory
- M2: $M2_HOME/bin or %M2_HOME%\bin
- MAVEN_OPTS: -Xms256m -Xms512m (optional)
- PATH: $JAVA_HOME/bin:$M2:$PATH or %JAVA_HOME%\bin;%M2%;%PATH%
The Java SE JDK, Maven 2 and the environment-variable settings are for the Java-based web-service client we'll be building after we deploy an instance of the Worklist Manager.
Create a Worklist Application
Start NetBeans. Once the IDE is up, select the Services tab, expand "Servers", then right-click on "GlassFish V2" and select "Start". Once the GlassFish server has started, select the Projects tab.
From the "File" menu, select "New Project...", then select category "SOA", then select "Worklist Module". Enter "TutorialWorklistApp" for the project name and click "Finish".
Our worklist application will start with a single operation. Just as an example, assume this is an ETL system and we want to create a trouble ticket on failure of a file to load. The creation of the application will be a lot smoother if we first create the XML Schema for the request and response messages, then create the WSDL definition to define the operation, then create the worklist Task itself.
The XML Schema
Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "XML Schema...". If "XML Schema..." is not listed, select "Other...", then "XML", then "XML Schema", then "Next". Name the schema tutorial_worklist (NetBeans will supply an .xsd extension) and click "Finish". The schema will open in a graphical schema editor. Provide elements for the request and response messages and base them on complexTypes containing information that might be needed for this application. An example schema is below:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://xml.netbeans.org/schema/tutorial_worklist"
xmlns:tw="http://xml.netbeans.org/schema/tutorial_worklist"
elementFormDefault="qualified">
<xsd:element name="loadFailureActionRequest" type="tw:LoadFailureActionRequestType"/>
<xsd:element name="loadFailureActionResponse" type="tw:LoadFailureActionResponseType"/>
<xsd:complexType name="LoadFailureActionRequestType">
<xsd:sequence>
<xsd:element name="feedName" type="xsd:string"/>
<xsd:element name="fileName" type="xsd:string"/>
<xsd:element name="timestamp" type="xsd:date"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LoadFailureActionResponseType">
<xsd:sequence>
<xsd:element name="troubleTicketID" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
Save the schema and check it with the "Validate XML" button.
The WSDL definition
Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "WSDL Document...". If "WSDL Document..." is not listed, select "Other...", then "XML", then "WSDL Document", then "Next". Name the WSDL document "tutorial_worklist" (NetBeans will supply a .wsdl extension) and click "Finish". Select "Concrete WSDL Document", then "SOAP" Binding and "Document Literal" for the Type. Click "Next".
In the "Abstract Configuration" panel, clean up some of the names a little. Change the port type name to worklistPortType, the operation name to processLoadFailure, then click the ellipses ("...") for the Input and Output messages to select the input and output messages we defined in the XML Schema above (namely, loadFailureActionRequest and loadFailureActionResponse; you will need to scroll up in the dialog to find the definition, and expand the "Elements" node). Leave the "Generate partnerlinktype automatically" box checked. Click "Next".
On the "Concrete Configuration" panel, clean up the names a little, using worklistBinding, worklistService, and worklistPort for Binding Name, Service Name, and Port Name, respectively. Click "Finish".
The Task definition
Right-click on the "WorklistFiles" directory under "TutorialWorklistApp", select "New" -> "Worklist Task Definition...". If "Worklist Task Definition..." is not listed, select "Other...", then "SOA", then "Worklist Task Definition", then "Next". Name the file processLoadFailure (no need for an extension), click the ellipsis by the empty Operation name, expand the WSDL definition down to the processLoadFailure operation, and click "OK". Click "Finish". The Task definition will now open in a graphical editor.
Build
Right click on the name of the Worklist Application ("TutorialWorklistApp") and select "Build". You should get a successful build. This application is now a JBI module which can be deployed to a composite application, which is our next step.
Create a Composite Application
From the "File" menu, select "New Project...", then project category "SOA", then "Composite Application". Click "Next". Name the project TutorialCompositeApp. Click Finish. The Service Assembly file TutorialCompositeApp.casa will open in a graphical editor containing three sections:
- WSDL Ports
- JBI Modules
- External Modules
Drag the Worklist Application (TutorialWorklistApp) over to the "JBI Modules" section of the service assembly and drop it. At this point, your service assembly will look as follows:
Right-click on the project name and select "Build". You will see the service-assembly view reload, with the following results:

Note that the processLoadFailure operation has a configured SOAP/HTTP binding, as we expected (we just configured it in some detail), but notice that we also have a TaskCommonPort, with no binding. This is the Worklist Manager. We will add a SOAP/HTTP binding for this port so that we will be able to access the items in the Worklist from a simple demonstration Java client.
Create the Worklist Manager binding
From the "WSDL Bindings" section of the Palette, drag and drop a "soap" binding on the "WSDL Ports" section of the service assembly. You will see an additional binding similar to the one already configured for the Worklist application. Select the purple (right-pointing) arrow in the binding and drag over to and connect to the TaskCommonPort port. Now, right-click on this binding and select "Properties". Change casaPort1 to worklistManagerPort, then click on the ellipsis ("...") by the soap:address Location. You should see the following:
http://localhost:${HttpDefaultPort}/casaService1/worklistManagerPort
Simplify this a little by changing it to
http://localhost:${HttpDefaultPort}/worklistManager
Note that the URL for the Worklist application is similarly wordy. If you want to shorten it, you can in similar manner, but you'll have to first right-click on the binding and select "Clone WSDL Port to edit...". Confirm on the dialog which follows, then right-click and select "Properties" to edit, and change the soap:address Location from
http://localhost:${HttpDefaultPort}/tutorial_worklistService/tutorial_worklistPort
to
http://localhost:${HttpDefaultPort}/worklistApp
then click "Close" to save. Your service assembly should now look as follows:

Deploy the Composite Application
Before we deploy the application, you're probably wondering what ${HttpDefaultPort} means. You might guess that it is the default port of the GlassFish web services, but actually each of the binding components in GlassFish has their own unique default port. This can be a problem if you are trying to access a binding component from outside of GlassFish and don't know the port number, but these can be found in the Admin console. For more information, see "Understanding the ${HttpDefaultPort} Token" at
http://wiki.open-esb.java.net/Wiki.jsp?page=ClusteringSupportForHTTPBindingComponent. But I will walk you through the process here.
To determine what the default port is for a binding component (in this case, the HTTP BC):
- Open the Admin console (in Netbeans, open Services tab, expand "Servers", right click on Glassfish, select "View Admin Console". Unless you changed values, the username/password pair is "admin"/"adminadmin".
- Under "Common Tasks", expand "JBI", "Components", "sun-http-binding".
- Select the "Configuration" tab.
- Second entry is "Default HTTP Port Number". If you did not change this on installation, it will probably be 9080.
If you choose to, you can always select an unused port number and hard-code it into the bindings before you deploy. If you're like me, all you care about is being able to find out where the service is deployed!
Now, right-click on the composite application name in the "Projects" tab, select "Build", then again right-click on the application name and select "Deploy". The project should deploy successfully.
To verify that the two services are correctly deployed, and assuming you used the soap:address Locations I used above, navigate to the following:
where I have substituted the HTTP default port for my deployment. Note you may have to view the page source to see the WSDL definition, but you should see both. Note the worklistApp has a single operation available (processLoadFailure), while the worklistManager has a number of operations related to the processing of tasks, as we might expect. For example, GetTaskList, RevokeTask, CompleteTask, and so on. We will be calling these operations from the simple Java web-service client which we will create next.
Create a simple Java client
All we'll be doing here is generating the minimal Java client necessary to exercise some operations on the Worklist Manager. The steps involved are almost identical to those under the heading "Create a client for the web service" at my earlier post
Java-SE-Based Web Services . The only difference will be the URL of the web service, of course. Because the WSDL definition of the Worklist Manager contains a URL to the TaskCommon.wsdl file (the latter is the abstract WSDL, and the former imports it and contains the necessary information to make the WSDL definition concrete), we will copy both files to a
wsdl directory in our client build.
Expand the NetBeans project directory for the composite application and retrieve the following files:
src/JbiServiceUnits/TutorialCompositeApp.wsdl
src/JbiServiceUnits/TutorialWorklistApp/TaskCommon.wsdl
Copy these files into the wsdl directory (under your Maven project src directory). Open the TutorialCompositeApp.wsdl file and change the import path for TaskCommon.wsdl to reflect the fact that it is now in the same directory as TutorialCompositeApp.wsdl:
<import namespace="http://jbi.com.sun/wfse/wsdl/TaskCommon" location="TaskCommon.wsdl">
Also, edit the soap:address, replacing ${HttpDefaultPort} with the actual port number (defaults to 9080, or use whatever value you hard-coded, if any).
Then, instead of configuring a WSDL URL in your pom.xml file, configure a WSDL file as follows:
<configuration>
<wsdlFiles>
<wsdlFile>TutorialCompositeApp.wsdl</wsdlFile>
</wsdlFiles>
<packageName>com.example.webservice.service</packageName>
</configuration>
The client of course instantiates a different service and invokes different operations than in my previous post. Here is an example Java client that exercises a couple of operations on the Worklist Manager:
package com.example.webservice.client;
import com.example.webservice.service.QueryType;
import com.example.webservice.service.CasaService1;
import com.example.webservice.service.TaskCommonPortType;
import com.example.webservice.service.TaskFaultMsg;
import com.example.webservice.service.TaskListType;
import com.example.webservice.service.TaskType;
public class WLMClient
{
public static void main(String[] args) throws TaskFaultMsg
{
CasaService1 service = new CasaService1();
TaskCommonPortType port = service.getWorklistManagerPort();
System.out.println("Getting Task List:");
QueryType qt = new QueryType();
QueryType.Users users = new QueryType.Users();
users.getUser().add("john");
qt.setUsers(users);
QueryType.Groups groups = new QueryType.Groups();
groups.getGroup().add("CustomerServiceRep");
qt.setGroups(groups);
TaskListType tasks = port.getTaskList(qt, "john", 0, 100);
System.out.println(" Total record count: " + tasks.getTotalRecords());
System.out.println(" Returned record count: " + tasks.getReturnedRecords());
for (TaskType nextTask: tasks.getTask())
{
System.out.println("Task ID: " + nextTask.getTaskId() + "; title: " + nextTask.getTitle() + "; " +
"Claimed by: " + nextTask.getClaimedBy() + "; Assigned to: " + nextTask.getAssignedTo());
}
}
}
Build and run this application and you should see output like the following:
C:\Users\wayne.adams\Blogger\GlassfishWLMJavaClient>java -cp target\glassfishWLMJavaClient.jar com.example.webservice.client.WLMClient
Getting Task List:
Total record count: 0
Returned record count: 0
In this case, there are no tasks, but we can create some by exercising the other service, the worklistApp service. More on that in a subsequent post!