The WLM SE provides a simple Web based Worklist Manager that allows
users to review, Checkout and Complete Tasks assigned to them. This is
a very basic interface and in unlikely, although it can be modified, to
provide exactly what you want. Given that most users would like their
own Company specific interface linking in with their portal and access
control system they may well need to write their own interface.
This blog will take you through implementing a Visual Web Pack interface to the WLM SE processes. By its nature I intend to make this a simplistic implementation but hopefully show how it can be done. In my next blog I will repeat the process using the IceFaces interface.
Following on from this implementation I will integrate the pages with Open SSO to provide the Authentication and Authorisation functionality.
Resources
Application Overview
The Web Application defined below will provide a simple two page (excluding the login page) application that will display a list of User Assigned Tasks and allow the user to View (which will display the second page), Accept or reject a Task. Based on the response the application will call the appropriate TaskCommon operation. If the user decided to view the data then a second page will be displayed showing the actual message and a number of editable field where the user may change the values within the message before accepting the message.
WLMPOWebApp
We will now need to create a Web Service Client that is based on the TaskCommon.wsdl within the previously built WLMPOWorklistApp (see VRMP Part 3 blog entry). Therefore before proceeding make sure that you Clean & Build this project then create the client as follows:

For initial testing I quickly created a Logon Page and simple page Header Fragment which I do not intend documenting. In addition to these I also created two additional Session Properties that will be used throughout the project.
Before we can start accessing the WLM SE Task Database we will need to create a number of methods to access the appropriate Web Service Client calls. These methods can then be linked into the appropriate Visual Web Pack Data Providers. I will define these methods just prior to their use. The first method we will need is a getTaskList() which will be used to display the list of Tasks available for the use (as specified on the login page). Create the method in the SessionBean as follows:
Now we can create the TaskList Page as follows:
View Button
For the View Button we will simple access the Task Data and then display it on a new page. Because the data stored within the Task as an XML Node type I have copied the com.sun.workflow.xml.Util.java from the sample Web Application to allow me to format the XML within the Node. Once we have accessed the Task Input Data we will copy it into the SessionBean and then pass this the ViewTask Screen (Defined later). To facilitate this we need to create some additional properties in the SessionBean.
SessionBean
View Button Action
Reject Button
The Reject (and Accept) Button will combine a number of actions that will Claim the Task copy the Task Output to the modify the ApprovalResult to either Rejected or Approved (because we are not really doing anything) and then complete the task. This is achieved by creating the completeTask methods dragging methods from the Web Service client into it. The Reject Button action will call the completeTask passing false to the approve boolean.
This should then be modified to match the following:
Accept Button
The Accept Button action will call the completeTask passing false to the approve boolean.
We can now create the ViewTaskPage and link it to the appropriate SessionBean properties to display the data correctly. Create a new Page and add the Buttons, Grid Panels and fields so that it looks like the following:

Within the SessionBean we will create the following Methods that allow access to the Node information:
Finally we need to set the Page Navigation (Right Click on the page and select Page Navigation) up as follows.

Clean and Build the project and resolve any errors.
WLMPOWebCompositeApp
Running The Web Application
Now that the build process has been completed we can run the Web Application. I am assuming that the Business Process has been loaded with the appropriate Workflows. Once this has been done the application will look as follows:
Login

Task List

Task View
Select View from the Task List.

Revised Task List
Select Accept from the Task View,

You can try the various combinations of buttons. You will notice that both Accept and Reject mark the Task Status as completed because it has but when Reject is selected the BPEL process is terminated because we map Rejected into the XML Element.
If you used the previous set of WorkList Task you will need to remove the code for the Completed Action because we now do that mapping in the Web Pages.
This blog will take you through implementing a Visual Web Pack interface to the WLM SE processes. By its nature I intend to make this a simplistic implementation but hopefully show how it can be done. In my next blog I will repeat the process using the IceFaces interface.
Following on from this implementation I will integrate the pages with Open SSO to provide the Authentication and Authorisation functionality.
| WLM
SE Trail |
Resources
Application Overview
The Web Application defined below will provide a simple two page (excluding the login page) application that will display a list of User Assigned Tasks and allow the user to View (which will display the second page), Accept or reject a Task. Based on the response the application will call the appropriate TaskCommon operation. If the user decided to view the data then a second page will be displayed showing the actual message and a number of editable field where the user may change the values within the message before accepting the message.
WLMPOWebApp
We will now need to create a Web Service Client that is based on the TaskCommon.wsdl within the previously built WLMPOWorklistApp (see VRMP Part 3 blog entry). Therefore before proceeding make sure that you Clean & Build this project then create the client as follows:
- Right Click on the WLMPOWebApplication and select New->Web
Service Client.

- Navigate to the build directory of the WLMPOWorklistApp and
select TaskCommon.wsdl by selecting Browse for the Local File.


- Finish

For initial testing I quickly created a Logon Page and simple page Header Fragment which I do not intend documenting. In addition to these I also created two additional Session Properties that will be used throughout the project.
// Session Properties
private String username = null;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
private String currentPageName = "";
public String getCurrentPageName() {
return currentPageName;
}
public void setCurrentPageName(String currentPageName) {
this.currentPageName = currentPageName;
}
Before we can start accessing the WLM SE Task Database we will need to create a number of methods to access the appropriate Web Service Client calls. These methods can then be linked into the appropriate Visual Web Pack Data Providers. I will define these methods just prior to their use. The first method we will need is a getTaskList() which will be used to display the list of Tasks available for the use (as specified on the login page). Create the method in the SessionBean as follows:
- Open SessionBean.
- Create method public List<TaskType> getTaskList().
- Drag the GetTaskList operation from the Web Service Client and drop it between the {} of the Java Method. This will create an appropriate try-catch statement that calls the Web Service Operation.
- Modify the resultant code so it matches the following:
public List<TaskType> getTaskList() {
List<TaskType> taskList = new ArrayList<TaskType>();
try { // Call Web Service Operation
sun.com.jbi.wfse.wsdl.taskcommon.TaskCommonPortType port = service.getTaskCommonPort();
// TODO initialize WS operation arguments here
sun.com.jbi.wfse.wsdl.taskcommon.QueryType queryString = new sun.com.jbi.wfse.wsdl.taskcommon.QueryType();
java.lang.String userId = getUsername();
int start = 0;
int pageSize = 0;
// TODO process result here
sun.com.jbi.wfse.wsdl.taskcommon.TaskListType result = port.getTaskList(queryString, userId, start, pageSize);
taskList = result.getTask();
} catch (Exception ex) {
// TODO handle custom exceptions here
}
return taskList;
}
Clean and Build the project to generate the classes used in the next
part, if this is not done then you may not see the taskList property in
the SessionBean.Now we can create the TaskList Page as follows:
- Refactor and rename the default Page1 to TaskListPage or create a new Page.
- Drag a Table component onto the page.
- Right Click the table component and select "Table Layout"
- Change the "Get Data From" to be the taskList Property in the
SessionBean:

- Modify the Displayed Attributes as follows :

- Modify the Sort / Pagination Options as follows:

- This will create the following:

- Add the header fragment and test.

- Edit the Table Layout and add 3 extra columns (no title). These should be Button Types with the Text as follows:
- View.
- Reject.
- Accept.
- For each of these new column types add an Action to the Buttons follows:
View Button
For the View Button we will simple access the Task Data and then display it on a new page. Because the data stored within the Task as an XML Node type I have copied the com.sun.workflow.xml.Util.java from the sample Web Application to allow me to format the XML within the Node. Once we have accessed the Task Input Data we will copy it into the SessionBean and then pass this the ViewTask Screen (Defined later). To facilitate this we need to create some additional properties in the SessionBean.
SessionBean
private String inputXML = "";
public String getInputXML() {
return inputXML;
}
public void setInputXML(String inputXML) {
this.inputXML = inputXML;
}
private Long taskId = new Long(0);
public Long getTaskId() {
return taskId;
}
public void setTaskId(Long taskId) {
this.taskId = taskId;
}
private String taskTitle = "";
public String getTaskTitle() {
return taskTitle;
}
public void setTaskTitle(String taskTitle) {
this.taskTitle = taskTitle;
}
private Long taskPriority = new Long(0);
public Long getTaskPriority() {
return taskPriority;
}
public void setTaskPriority(Long taskPriority) {
this.taskPriority = taskPriority;
}
View Button Action
/*We will create the page navigation for the View Task Page later.
* Methods
*/
private Node getTaskInput() {
Node taskInputNode = null;
// Get TaskId
Long taskIdLong = (Long) getValue("#{currentRow.value['taskId']}");
System.out.println("*** APH-I1 : getTaskInput() TaskId " + taskIdLong);
if (taskIdLong != null) {
try {
sun.com.jbi.wfse.wsdl.taskcommon.TaskCommonPortType port = service.getTaskCommonPort();
// TODO initialize WS operation arguments here
long taskId = taskIdLong.longValue();
java.lang.String userId = getSessionBean1().getUsername();
// TODO process result here
java.lang.Object result = port.getTaskInput(taskId, userId);
if (result != null && result instanceof Node) {
taskInputNode = (Node) result;
String xml = Util.toXml(taskInputNode, "UTF-8", true);
System.out.println("*** APH-I3 getTaskInput: " + xml);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
return taskInputNode;
}
/*
* Action Event Handlers
*/
public String viewBtn_action() {
Node taskOutputNode = getTaskOutput();
getSessionBean1().setOutputNode(taskOutputNode);
getSessionBean1().setInputXML(Util.toXml(taskOutputNode, "UTF-8", true));
getSessionBean1().setTaskId((Long) getValue("#{currentRow.value['taskId']}"));
getSessionBean1().setTaskTitle((String) getValue("#{currentRow.value['title']}"));
getSessionBean1().setTaskPriority((Integer) getValue("#{currentRow.value['priority']}"));
return "view";
}
Reject Button
The Reject (and Accept) Button will combine a number of actions that will Claim the Task copy the Task Output to the modify the ApprovalResult to either Rejected or Approved (because we are not really doing anything) and then complete the task. This is achieved by creating the completeTask methods dragging methods from the Web Service client into it. The Reject Button action will call the completeTask passing false to the approve boolean.
This should then be modified to match the following:
public String rejectBtn_action() {
completeTask(false);
return null;
}
private void completeTask(boolean approve) {
Node outputMsgNode = null;
// Get TaskId
Long taskIdLong = (Long) getValue("#{currentRow.value['taskId']}");
System.out.println("*** APH-I1 : TaskId " + taskIdLong);
if (taskIdLong != null) {
try { // Call Web Service Operation
sun.com.jbi.wfse.wsdl.taskcommon.TaskCommonPortType port = service.getTaskCommonPort();
// TODO initialize WS operation arguments here
long taskId = taskIdLong.longValue();
java.lang.String userId = getSessionBean1().getUsername();
// TODO process result here
sun.com.jbi.wfse.wsdl.taskcommon.ResultCodeType result = port.claimTask(taskId, userId);
java.lang.Object outputMsg = port.getTaskOutput(taskId, userId);
if (outputMsg != null && outputMsg instanceof Node) {
outputMsgNode = (Node) outputMsg;
String xml = Util.toXml(outputMsgNode, "UTF-8", true);
System.out.println("*** APH-I3 getTaskOutput: " + xml);
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
Node newChildNode = null;
boolean approvalResultFound = false;
for (int i=0;i<childNodeList.getLength();i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("ApprovalResult")) {
approvalResultFound = true;
newChildNode = oldChildNode.cloneNode(true);
if (approve)newChildNode.setNodeValue("Approved");
else newChildNode.setTextContent("Rejected");
outputMsgNode.replaceChild(newChildNode, oldChildNode);
i = childNodeList.getLength();
}
}
outputMsg = outputMsgNode;
xml = Util.toXml(outputMsgNode, "UTF-8", true);
System.out.println("*** APH-I3 getTaskOutput: " + xml);
} else {
warn("outputMsg is not a Node");
}
result = port.setTaskOutput(taskId, outputMsg, userId);
result = port.completeTask(taskId, userId);
} catch (Exception ex) {
ex.printStackTrace();
error(ex.getMessage());
}
}
}
Accept Button
The Accept Button action will call the completeTask passing false to the approve boolean.
public String acceptBtn_action() {
completeTask(true);
return null;
}
We can now create the ViewTaskPage and link it to the appropriate SessionBean properties to display the data correctly. Create a new Page and add the Buttons, Grid Panels and fields so that it looks like the following:

Within the SessionBean we will create the following Methods that allow access to the Node information:
/*To display the data correctly we will need to bind the fields on the page as follows:
* Node Processing methods
*/
private Node outputNode = null;
public Node getOutputNode() {
return outputNode;
}
public void setOutputNode(Node outputNode) {
this.outputNode = outputNode;
}
private String poNumber = "";
private String supplier = "";
private String description = "";
private boolean approve = false;
public boolean isApprove() {
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("ApprovalResult")) {
if (oldChildNode.getTextContent().equals("Approved")) {
approve = true;
} else {
approve = false;
}
System.out.println("*** APH-I1 : Approved " + approve + " (" + oldChildNode.getTextContent() + ")");
i = childNodeList.getLength();
}
}
}
return approve;
}
public void setApprove(boolean approve) {
this.approve = approve;
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
Node newChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("ApprovalResult")) {
newChildNode = oldChildNode.cloneNode(true);
if (approve) {
newChildNode.setTextContent("Approved");
} else {
newChildNode.setTextContent("Rejected");
}
System.out.println("*** APH-I1 : Approved " + approve + " (" + oldChildNode.getTextContent() + ")");
outputMsgNode.replaceChild(newChildNode, oldChildNode);
i = childNodeList.getLength();
}
}
}
}
public String getDescription() {
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("PODescription")) {
description = oldChildNode.getTextContent();
i = childNodeList.getLength();
}
}
}
return description;
}
public void setDescription(String description) {
this.description = description;
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
Node newChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("PODescription")) {
newChildNode = oldChildNode.cloneNode(true);
newChildNode.setTextContent(description);
outputMsgNode.replaceChild(newChildNode, oldChildNode);
i = childNodeList.getLength();
}
}
}
}
public String getPoNumber() {
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("PONumber")) {
poNumber = oldChildNode.getTextContent();
i = childNodeList.getLength();
}
}
}
return poNumber;
}
public void setPoNumber(String poNumber) {
this.poNumber = poNumber;
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
Node newChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("PONumber")) {
newChildNode = oldChildNode.cloneNode(true);
newChildNode.setTextContent(poNumber);
outputMsgNode.replaceChild(newChildNode, oldChildNode);
i = childNodeList.getLength();
}
}
}
}
public String getSupplier() {
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("SupplierName")) {
supplier = oldChildNode.getTextContent();
i = childNodeList.getLength();
}
}
}
return supplier;
}
public void setSupplier(String supplier) {
this.supplier = supplier;
Node outputMsgNode = getOutputNode();
if (outputMsgNode != null) {
// Iterate through child nodes
NodeList childNodeList = outputMsgNode.getChildNodes();
Node oldChildNode = null;
Node newChildNode = null;
for (int i = 0; i < childNodeList.getLength(); i++) {
oldChildNode = childNodeList.item(i);
if (oldChildNode.getNodeName().endsWith("SupplierName")) {
newChildNode = oldChildNode.cloneNode(true);
newChildNode.setTextContent(supplier);
outputMsgNode.replaceChild(newChildNode, oldChildNode);
i = childNodeList.getLength();
}
}
}
}
- Task Id Static Text : #{SessionBean1.taskId}
- Title Static Text : #{SessionBean1.taskTitle}
- Priority Static Text : #{SessionBean1.taskPriority}
- Message Text Area : #{SessionBean1.inputXML}
- tfPONumber : #{SessionBean1.poNumber}
- tfSupplierName : #{SessionBean1.supplier}
- tfDescription : #{SessionBean1.description}
private void completeTask(boolean approve) {
// Get TaskId
Long taskIdLong = getSessionBean1().getTaskId();
System.out.println("*** APH-I1 : TaskId " + taskIdLong);
if (taskIdLong != null) {
try { // Call Web Service Operation
sun.com.jbi.wfse.wsdl.taskcommon.TaskCommonPortType port = service.getTaskCommonPort();
// TODO initialize WS operation arguments here
long taskId = taskIdLong.longValue();
java.lang.String userId = getSessionBean1().getUsername();
// TODO process result here
sun.com.jbi.wfse.wsdl.taskcommon.ResultCodeType result = port.claimTask(taskId, userId);
getSessionBean1().setApprove(approve);
result = port.setTaskOutput(taskId, getSessionBean1().getOutputNode(), userId);
result = port.completeTask(taskId, userId);
} catch (Exception ex) {
ex.printStackTrace();
error(ex.getMessage());
}
}
}
public String listBtn_action() {
// TODO: Process the action. Return value is a navigation
// case name where null will return to the same page.
return "list";
}
public String rejectBtn_action() {
completeTask(false);
return "reject";
}
public String acceptBtn_action() {
completeTask(true);
return "accept";
}
Finally we need to set the Page Navigation (Right Click on the page and select Page Navigation) up as follows.

Clean and Build the project and resolve any errors.
WLMPOWebCompositeApp
- New Project -> SOA -> Composite Application

- Next
- New Composite Application Project
- Finsh
- Add JBI Module WLMPOWebApplication.war

- Clean & Build
- Open Service Assembly

- Add External Service Unit
- Drag Provider EndPoint onto External

- Select EndPoint Properties and edit as follows:
- Interface Name : Click ellipsis TaskCommonPortType

- Service Name : Click ellipsis TaskCommonService

- Endpoint Name : TaskCommonPort

- Connect the javaee_TaskCommonPort in the JBI Module to the
TaskCommonPort in the External.

- Select the Provide on the existing WSDL Port SOAP interface and
then check the "Disable in BC" property.

- Clean & Build
- Deploy
Running The Web Application
Now that the build process has been completed we can run the Web Application. I am assuming that the Business Process has been loaded with the appropriate Workflows. Once this has been done the application will look as follows:
Login

Task List

Task View
Select View from the Task List.

Revised Task List
Select Accept from the Task View,

You can try the various combinations of buttons. You will notice that both Accept and Reject mark the Task Status as completed because it has but when Reject is selected the BPEL process is terminated because we map Rejected into the XML Element.
If you used the previous set of WorkList Task you will need to remove the code for the Completed Action because we now do that mapping in the Web Pages.













