This chapter introduces the Simple API for Workflow (SAW) and explains how to implement SAW in Portal server 7.2 release. SAW is a generic workflow API to perform human workflow interaction with various workflow engines. SAW provides a framework to plug-in any business process specific implementation that implements SAW interfaces. SAW is shipped with a default implementation for Sun Java Composite Application Platform Suite. You can have similar SAW implementations for other business processes such as JBoss Business Process Management (jBPM), Open Enterprise Service Bus (OpenESB) and so on.
This chapter includes the following sections:
Before you implement SAW in Portal Server 7.2, you need to install the following components:
JDK version 1.5 or above.
Sun Java Composite Application Platform Suite.
For more information on prerequisites to install Sun Java Composite Application Platform Suite and how to create a simple Business Process, refer the article http://developers.sun.com/portalserver/reference/techart/workflow.html.
For more information on using SAW plug-in to create you applications, refer the Adding the Workflow Portlet to the Sun Java System Portal Server 7.2 Desktop.
The application that you create using SAW to manage tasks, should have accessibility to the Sun Java Composite Application Platform Suite installation.
Follow the steps to configure SAW.
Create a new Java project.
Ensure that client stubs generated out of the workflow service of Sun Java Composite Application Platform Suite is in the classpath.
Add the saw-api-0.7.jar and saw-impl-jcaps-0.8.jar files to the classpath of the project.
Ensure that the javaee.jar is in classpath.
The saw-api-0.7.jar file should be in compile time and runtime classpath, whereas the saw-impl-jcaps-0.8.jar, WorkflowServiceClient.jar, and javaee.jar files should be only in runtime classpath.
All these .jar files are available at https://saw.dev.java.net/
Add WorkflowConfig.properties file in the project classpath.
Sample entries for WorkflowConfig.properties file:
sawworkflowimplclass = com.sun.saw.impls.jcaps.JCAPSWorkflow (This entry means that you are using SAW Workflow implementation class, JCAPSWorkflow.)
Sample entries for WorkflowConfig.properties file:
com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverhost = points to the machine where the Java CAPS Business Process is deployed.
com.sun.saw.impls.jcaps.JCAPSWorkflow.iiopserverport = port on which the IIOP lookup for the EJB happens.
com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverusername = admin user id and password for the server on which Java CAPS Business Process is running.
com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverpassword = admin user id and password for the server on which Java CAPS Business Process is running.
com.sun.saw.impls.jcaps.JCAPSWorkflow.contextfactory = com.sun.jndi.cosnaming.CNCtxFactory
com.sun.saw.impls.jcaps.JCAPSWorkflow.serviceJndi = Java Naming and Directory Interface (JNDI) name of the deployed Java CAPS Business Process.
The ImplementationType.properties file is required to run SAW Application, when you create using NetBeans plug-in. The ImplementationType.properties file should contain the keyword, ImplementationType=JCAPS.
The client of the SAW API should get the reference of the workflow implementation object (in this case the JCAPSWorkflow) through the WorkflowFactory class. The client should call the getWorkflowInstance() or getWorkflowInstance(java.util.Properties) method on the WorkflowFactory to get an instance of the SAW Workflow Implementation class. The WorkflowFactory reads the sawworkflowimplclass key from the WorkflowConfig.properties file and finds out which SAW Workflow Implementation class to use. The getWorkflowInstance() looks for the WorkflowConfig.properties in classpath. This properties file will have the values for the necessary attributes that are required. The getWorkflowInstance(java.util.Properties) uses the properties object is provided to it as the argument and does not look for the WorkflowConfig.properties. Once the client has the reference to the SAW Workflow Implementation class, the client can call methods on that instance.
In order to explain how to use SAW APIs, you can consider the following Business Process use case, where a user wants to do the following tasks:
Create a task.
A task is a unit of execution that requires human interaction. The task id created in this use case is 4ce71ee0:11420e51eca:-6388.
Check out the task.
The user name in this use case is CPina.
Modify and save (execute) the task attributes.
Complete the task.
Create a test class. For example, TestClient.java in this use case.
Ensure that the WorkflowConfig.Properties file is in classpath. The sample WorkflowConfig.properties file is shown below:
# the business process to use. sawworkflowimplclass = The SAW Workflow Implementation class to use. For example, com.sun.saw.impls.jcaps.JCAPSWorkflow # Properties that are needed by the JCAPS Implementation of SAW. com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverhost = machine name or IP where Sun Java Composite Application Platform Suite business process is running. For example, abc.india.sun.com com.sun.saw.impls.jcaps.JCAPSWorkflow.iiopserverport = Port on which the IIOP lookup for the EJB happens. For example, 18002 com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverusername = Administrator user name. For example, Administrator com.sun.saw.impls.jcaps.JCAPSWorkflow.appserverpassword = Administrator password. For example, STC com.sun.saw.impls.jcaps.JCAPSWorkflow.contextfactory = The context factory. For example, com.sun.jndi.cosnaming.CNCtxFactory com.sun.saw.impls.jcaps.JCAPSWorkflow.serviceJndi = The JNDI look up name. For example, WorkflowService |
Add the following code to your test class, to check out a task.
private com.sun.saw.vo.OutputVO checkoutTasks (String userId,java.util.List taskIdList,Workflow workflowImpl) throws com.sun.saw.WorkflowException { com.sun.saw.vo.CheckoutTaskVO checkoutTaskVO = new com.sun.saw.vo.CheckoutTaskVO(); checkoutTaskVO.setTaskIdList(taskIdList); checkoutTaskVO.setUserId(userId); com.sun.saw.vo.OutputVO outputVO = null; outputVO = workflowImpl.checkoutTasks(checkoutTaskVO); return outputVO; } //Call the above method from the main(). For example public static void main(String args) { TestClient client = new TestClient(); List taskIdList = new ArrayList(); taskIdList.add("4ce71ee0:11420e51eca:-6388"); Workflow workflowImpl = this.getWorkflowImpl(); try { client.checkoutTasks("CPina", taskIdList,workflowImpl); } catch (com.sun.saw.WorkflowException e) { e.printStackTrace(); } } private com.sun.saw.Workflow getWorkflowImpl() throws com.sun.saw.WorkflowException{ // This assumes that the property file is there in classpath. com.sun.saw.Workflow workflow = null; com.sun.saw.WorkflowFactory workflowFactory = WorkflowFactory.getInstance(); workflow = workflowFactory.getWorkflowInstance(); return workflow; } |
The above code does the following functions:
The main() calls the getWorkflowImpl() to get the reference of the SAW Workflow Implementation object, which is JCAPSWorkflow class.
The getWorkflowImpl() gets reference to the WorkflowFactory, and calls the getWorkflowInstance() on the factory.
The factory looks for the WorkflowConfig.properties in the classpath, reads the sawworkflowimplclass key and instantiates that.
The main() then calls the checkoutTasks() passing the userId, taskIdList and the appropriate workflowImpl object.
The checkoutTasks() constructs the CheckoutTaskVO object and sets taskIdList and UserId into the CheckoutTaskVO.
Invokes the checkoutTasks() on the SAW Workflow Implementation object, which is on JCAPSWorkflow class.
Invokes the checkoutTasks() on the Sun Java Composite Application Platform Workflow Service that is running as an Enterprise Java Beans (EJB) and does the actual checking out of the task.
The task is then marked as "checked out" by CPina.
To modify the attributes of a task, call the saveTasks() on the appropriate SAW Workflow Implementation object. Add the following code to your class:
private com.sun.saw.vo.OutputVO saveTasks(String userId,java.util.List taskIdList, String output,java.util.Map customAttributesMap,com.sun.saw.Workflow workflowImpl) throws com.sun.saw.WorkflowException { com.sun.saw.vo.OutputVO outputVO = null; com.sun.saw.vo.SaveTaskVO saveTaskVO = new com.sun.saw.vo.SaveTaskVO (); saveTaskVO.setTaskIdList(taskIdList); saveTaskVO.setUserId(userId); saveTaskVO.setOutput(output); saveTaskVO.setCustomAttributesMap(customAttributesMap); // key is fn, value is the dynamicParamVO. outputVO = workflowImpl.saveTasks(saveTaskVO); return outputVO; } //Call the above method from your main(). For example: client.saveTasks("CPina", taskIdList,"output",null,workflowImpl); |
The output gets saved as a task attribute.
Once you check out a task and modify the attributes, you may want to mark the status of a task as completed. This marking is called completing a task.
To complete a task, add the following method to a class:
private com.sun.saw.vo.OutputVO completeTasks(String userId,java.util.List taskIdList, com.sun.saw.Workflow workflowImpl) throws com.sun.saw.WorkflowException { com.sun.saw.vo.OutputVO outputVO = null; com.sun.saw.vo.CompleteTaskVO completeTaskVO = new com.sun.saw.vo.CompleteTaskVO(); completeTaskVO.setTaskIdList(taskIdList); completeTaskVO.setUserId(userId); outputVO = workflowImpl.completeTasks(completeTaskVO); return outputVO; } //Call the above method from your main(). For example,. client.completeTasks("CPina", taskIdList,workflowImpl); |
The task is marked as completed.
To get tasks, add the following method to a class:
public com.sun.saw.vo.OutputVO getTasks(String startDate,String endDate,java.util.List taskIdList,java.util.List userIdList, java.util.List taskStatusList,java.util.List groupIdList,String userId,int startRecord, int recordsPerPage,com.sun.saw.Workflow workflowImpl) throws com.sun.saw.WorkflowException { com.sun.saw.vo.FilterTaskVO filterTaskVO = new com.sun.saw.vo.FilterTaskVO(); filterTaskVO.setStartDate(startDate); filterTaskVO.setEndDate(endDate); filterTaskVO.setTaskIdList(taskIdList); filterTaskVO.setUserIdList(userIdList); filterTaskVO.setTaskStatusList(taskStatusList); filterTaskVO.setGroupIdList(groupIdList); filterTaskVO.setUserId(userId); filterTaskVO.setStartRecord(startRecord); filterTaskVO.setRecordsPerPage(recordsPerPage); OutputVO outputVO = workflowImpl.getTasks(filterTaskVO); //System.out.println(outputVO.getTaskVOList().size()); return outputVO; } //Call the above method from your main(). For example,. client.getTasks(null, null, null, null, null, null,userId,1,10,workflowImpl); |
Tag libraries in SAW are available to:
Get tasks based on search criteria.
Get a task by task id.
Count the number of tasks that meet the search criteria.
Ensure that the saw.tld file is in classpath.
Add the declaration on the JSP.
<%@ taglib uri="http://java.sun.com/saw" prefix="saw"%> |
Use the following tag library to get tasks that meet the search criteria.
<c:catch var="getTasksException"> <saw:getTasks filterTaskVO="${sessionScope.filterTaskVO}" returnvalue="taskList"/> </c:catch> |
It takes the following two attributes
filterTaskVO - Instance of the FilterTaskVO object
returnvalue - Name under which the list of workflowTaskVOs are available in the JSP, for the user to iterate and print.
<c:forEach items = "${taskList}" var ="task"> </c:forEach> |
Use the following tag library to get the count of number of tasks that match the search criteria.
<saw:countTask filterTaskVO="${sessionScope.filterTaskVO}" returnvalue="taskCount" subordinateCount="true"/> |
Besides the filterTaskVO and returnvalue attributes, the count task include another attribute called the subordinateCount. The subordinateCount attribute decides whether the count should include the tasks assigned to the subordinates of the user.
Use the following tag library to get the details of a task.
<c:catch var="getTasksException"> <saw:getTaskById filterTaskVO="${sessionScope.filterTaskVO}" returnvalue="taskInfo"/> </c:catch> |
Use ${taskInfo.input} to access the task attributes available in the JSP.
All the above taglib calls, optionally take a properties attribute also. If you set this properties attribute value, then the WorkflowFactory does not look for the WorkflowConfig.properties classpath, instead uses this properties object. For example:
<c:catch var="getTasksException"> <saw:getTasks filterTaskVO="${sessionScope.filterTaskVO}" returnvalue="taskList" properties="${sessionScope.propObject}"/> </c:catch> |