Sunday 15 January 2012

Using Intermediate Events and Advanced TaskService Interactions in Oracle BPM Suite 11g

This blog post will demonstrate with the help of a basic use-case the use and importance of intermediate events in Oracle BPM based processes. A typical business process also has manual touch points that are implemented by process users through Human Task UI’s. It is evident that a very important aspect in any agile business process is the ability to interact with these in-flight human tasks based on intermediate events. This post shall also demonstrate how to modify in-flight task States in Oracle BPM Suite 11g. You can similarly do a host of other operations with the full use of the Worklist Management API’s.  Keep reading.
Intermediate Events occur in the middle of the process and are of either Catch or Throw type. The Catch Events wait or block for appropriate signals while the Throw events proceed after throwing the signal.
The Basic Use Case
XYZ Bank has a simple business process defined for a Credit Card approval flow. Below are some important activities that any card application request has to go through.
Manual Card Approval
All requests that require further investigation (i.e. applications that cannot be pre approved using the business rules) should be sent to analysts belonging to the Credit Card Approvers role. The approver can complete the review by either Approving or Rejecting the request.
Cancel Card Application Event
While a card application request is in process, a customer can indicate that they wish to cancel their request. The customer is asked to provide an optional reason for wanting to cancel the request. The result of the cancellation request can be:
  • The request was cancelled
  • The request could not be cancelled because it had already been completed.
In that case the outcome of the original request should be provided to the customer.
Note : This example doesn’t deals with the cancellation scenario. This is explained in details in my previous blog post.
Potential Fraud
There is an external process that is evaluating increase requests to look for patterns that might signal fraud. When the pattern is matched, the process generates an Handle Fraud Event for a specific application request with a score that indicates that fraud is:
Probable ( Score =< 8 )
Possible ( Score >8 )
The process needs to listen for these events and take the following actions when the Handle Fraud Event is for the specific request that is in flight.
For Possible Fraud
When a possible fraud is recorded the existing process should be terminated. Before terminating the process the Manual Approval In-Flight task (if any) should also be withdrawn.
For Probable Fraud
An Ad-Hoc Manual Task should be created for the role FraudInvestigator. While the investigation is ongoing, the normal path of process must be suspended. The outcomes of the investigation is either APPROVE or REJECT. If the outcome is REJECT the current card application request likely represents fraud, or NO, the current increase request does not represent fraud. If the investigation result is APPROVE, the normal approval processing should be resumed unless the process has been tagged as cancelled.
Refer the business process diagram below to understand the use case better.
image
Prerequisites
The following version of software have been used to for this example and demonstration.
  • JDeveloper 11g PS4 (With BPM-SOA FP Extension)
  • PS4 FP SOA and BPM Extensions for JDeveloper
  • Oracle BPM Suite 11g PS4 Feature Pack
More information about downloading it can be found here
Implementing the Process
Oracle  SOA Suite leverages the Human Workflow Engine to implement Manual/User Tasks. The Human Workflow Engine exposes APIs (both Java and Web Service based) which can be used to interact with Tasks for specific business needs. There are Task Management Services which can be used to alter States of in-flight tasks, Task Query Service that can query for task details based on taskId, taskNumber or other task Predicates.
In this example I will show how we can use the TaskService to manipulate task states from within a business process.
Getting the Task Id for the “Approve Card Manually” user task.
The first thing to do is create a Process Data Object called manualTaskApprovalId to hold the value of the generated Task Id for the manual Task. The data object should be assigned the value of execData.systemAttributes.taskId from the Output tab in the Data Association for the task activity.
image
We will use this obtained taskId to invoke operations on the TaskService API.
Creating a Reference to the TaskService in the Composite Application
Next we will have to create a reference to the TaskService.wsdl in our composite. The TaskService.wsdl can be located in the soainfra metadata store partition.
image
The operations of the TaskService Web Service API’s now appear in the External Reference panel of the composite application.
Create a Mediator Component that acts as a Proxy to the TaskService Interface
Drop a Mediator Component into the composite and Define its interface from the TaskService.wsdl that is now copied into the project directory. In case you have chosen not to copy the wsdl and its dependent artifacts into the project you can refer it from the MDS. It is just the same. Also uncheck the Create Composite Service with SOAP bindings since we will only need to invoke it from within the composite.
Double click on the Mediator Component you just created. We will see that all operations in the TaskService interface appear in the Mediator. Go to the suspendTask operation in the Mediator and create a static routing rule  for it. The static routing rule should invoke a Service. From the wizard prompt use the suspendTask operation from the TaskService interface.
image
In a similar way create the static routing for other two operations i.e withdrawTask and resumeTask.
Fraud Check Event Subprocess
Coming to the Fraud check event sun-process the first thing we need to do is define correlation for the Handle Fraud start event. This is required as this is an intermediate event and this need to correlate with the desired in-flight process instance.
image
To know more about the use of correlation in Oracle BPM 11g read my previous post here.
When there is a Probable Fraud i.e fraud check score is less than 8 the process needs to be suspended in case it is awaiting for manual approval.
This can be achieved quite easily. All that we have to do is create a Service Task Activity and invoke the suspendTask operation of the TaskFlowMediator.
To keep this absolutely simple the only input required for suspendTask operation is the taskId for the Approve Card Manually Task that we had captured earlier in a process data object.
image
This will suspend the Manual Approval task and hence the process instance cannot  move ahead unless it is withdrawn or resumed and subsequently Approved or Rejected.
Depending upon the outcome of the Ad Hoc Approval by the FraudInvestigator role the process can either be Resumed and the original process flow continue (as the Handle Fault Event was defined as a non Interrupting Event) or it can be withdrawn the process Terminated.
This is pretty much it about the defining the main tasks and services in the process. You can find the Composite Application attached here to be more acquainted with the process flow.
Testing the Process and Verifying the Results
Post deployment of the composite application to a running server we cam test it. The composite exposes three operations (approveCard, cancelCardRequest and handleFraudEvent). Let us start to test the composite by invoking the approveCard operation that will start the card application approval process.
image
As you observed the instance has moved to the ManualCardApproval touch point and is awaiting for a response from a user with CreditCardApprover role.
image
Now let say a Fraud Event is reported now for this instance while the CreditCardApprover still hasn’t dealt with this task. In this case the Fraud Event Subprocess should kick off and the FraudInvestigator is involved for Ad Hoc Approval in case the fraud is probable.
We can emulate this scenario by unit testing the composite once again. But this time we will invoke the handleFraudEvent opetation of the composite. One important point to note here is that since we are using the customer contact number to correlate the fraudEvent with the in-flight instance, we need to have the same customer contact number in the request of this operation.
image
The effect of a fraud intermediate event is that the original task assigned to the CreditCardApprover role will be suspended and hence the process instance is stalled.
The FraudInvestigator has to provide an ad hoc response to confirm/reject this probable fault. So an Ad Hoc Approval Task awaits his response in his worklist.
image
If the FraudInvestigator approves the application then the original task is once again resumed and appears in the Assigned state in the CreditCardApprover’s worklist. Once it is approved once again (this time the approval is based on things like applicant’s eligibility, credit score, limit requested etc) the process is successfully completed.
image
The entire process flow diagram will give a picture of the path that the process took during its Happy-Path completion.
image
Testing the Unhappy Path – FraudInvestigator Confirms a Probable Fraud
To test this follow a couple of steps that we did earlier i.e. invoking an approveCard operation and then invoking the intermediate fraud check event operation for the same customer.
The flow will be similar to the above till here. The Fraud Investigator will have an Ad Hoc Approval Task and the original task will be suspended.
Now if the FraudInvestigator confirms a fraud in the application then the process instance is terminated and the original Manual Card Approval task is withdrawn.
image
A look at the process flow will now reveal that the process instance doesn’t moves back to the original instance (Since it is Terminated).
image
That’s is with the process.
Conclusion
This article deals with some advanced concepts around Oracle BPM Suite 11g. Hope it explains how we can effectively use intermediate events (of both Interrupting and Non-Interrupting Type). It also explains how we can interact with the Worklist API’s using the TaskService interface to interact with Human Workflow tasks from within a BPM process.
The composite used for the demonstration can be downloaded from this location or from here
Please send across your questions, commends and feedback and i will be eager to answer them.
.

September 9, 2011

Oracle BPM Human Task Management : Using Human Task Events to Invoke Microsoft Exchange Web Services

Recently while working on a specific use case for an enterprise where I had to develop a mechanism of notifying organizational users in case a human workflow task is assigned to them. The enterprise in consideration here had a need to create an Microsoft Exchange Task for the user once he is assigned with a BPM Human Task and need to act on it.
In this blog post I would be covering as how we can achieve this. This may also be useful in case you are required to use Exchange Web Services in Oracle SOA Suite. Before i begin I would like to cover a little bit of rationale behind this approach.
The Rationale to this Approach
Oracle Human Workflow Tasks allow us to configure Notification settings through which we can can Email/SMS notifications through the Notification service. For a human task we can choose to set reminders at preset intervals, send actionable links in notification emails, attach task attachments, add custom headers etc.
image
However our need was quite simple. What we needed was to simply create a Outlook Task for the assigned user that will take care of Reminders. Imagine a task in which we have some bulky attachments. Retrying from the Notification Service by leveraging the Oracle Taskflow Messaging mechanism is quite expensive as this leads to multiple emails being sent.
Creating a Recurring Task saves us from repetitive emails. We can use recurring Outlook Task for reminders.
image
Readying the Backbone
A bit about Exchange Web Service APIs
Microsoft provides a very rich and exhaustive set of API as well as Developer SDK’s for Exchange web services.
You can see the whole list of operations provided by the API in the link below
http://msdn.microsoft.com/en-us/library/bb409286%28v=EXCHG.140%29.aspx
In this post however i will be demonstrating how to invoke the “CreateItem” operation to create a user Task in outlook.
The WSDL for the exchange web services can be obtained at by typing the following in your browser.
https://exchangeServerURL/EWS/Services.wsdl
image
You can obtain the Exchange Service URL by opening Outlook->File->Account Settings
image
I was able to get this web service running from a web service client like SOAPUI to see it in action.
The Exchange Web Services are on HTTPS and require HTTP Basic Authentication credential to invoke the caller. They are no different from your NT Credentials.
image
However Off course we would need to invoke this service from within our SOA Suite domain. But this gives us a heads up about the working of Exchange web services.
Oracle Service Bus Plumbing to Invoke The Exchange Web Services
This part is somehow tricky. We would need to invoke the Exchange service from the Human Task Service. Since Oracle Service Bus is the place where we organize our enterprise wide reusable services i choose to implement the service call to the Exchange endpoint from within the bus.
That shouldn’t be difficult.
Create a  Proxy Service in OSB based on the Exchange service WSDL. Also copy the dependent XSD’s in the service bus project.
image
This is the place I had hit my first roadblock. The Exchange Web Services need a NTLM Authentication mechanism where as OSB doesn’t support NTLM out of the box. The workaround for this is that we have to create a custom Java class for doing this which can be invoked from OSB by a Java Callout action.
Create a simple Java Project in Eclipse and use the Java Class below. It works like a treat to get this thing done.
01package blog.soatech;
02import java.io.IOException;</pre>
03import org.apache.commons.httpclient.HttpClient;
04import org.apache.commons.httpclient.HttpException;
05import org.apache.commons.httpclient.HttpStatus;
06import org.apache.commons.httpclient.NTCredentials;
07import org.apache.commons.httpclient.auth.AuthScope;
08import org.apache.commons.httpclient.methods.PostMethod;
09import org.apache.commons.httpclient.methods.StringRequestEntity;
10 
11public class ExchangeServices {
12private static final String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13";
13@SuppressWarnings("unused")
14public static String invokeExService(String endPoint, String messageHeader, String messageBody, String userName, String password, String operation) throws HttpException, IOException
15{
16StringBuffer soapMessage = new StringBuffer();
17soapMessage.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
19soapMessage.append(messageHeader);
20soapMessage.append(messageBody);
21soapMessage.append("</soapenv:Envelope>\n");
22//System.out.print("Request : " + soapMessage.toString());
23HttpClient client = new HttpClient();
25PostMethod postMethod = new PostMethod(endPoint.trim());
26postMethod.setRequestHeader("SOAPAction", soapAction);
27postMethod.setRequestHeader("Content-Type", "text/xml; charset=UTF-8");
28postMethod.setRequestHeader("SOAPAction", soapAction);
29postMethod.setRequestHeader("User-Agent", userAgent);
30postMethod.setRequestEntity(new StringRequestEntity(soapMessage.toString().trim(), "text/xml; charset=UTF-8", null));
31String errorMessage ="";
32String responseBodyString ="";
33NTCredentials ntCredentials = new NTCredentials(userName, password, "hostName", "domainName");
34client.getState().setCredentials(new AuthScope(null,-1,null), ntCredentials);
35int status = client.executeMethod(postMethod);
36if(status != HttpStatus.SC_OK)
37{
38errorMessage = "Method Failed :" + postMethod.getStatusLine();
39// System.out.println(errorMessage);
40}
41responseBodyString= postMethod.getResponseBodyAsString();
42//System.out.println("Response Message ;" +responseBodyString);
43return responseBodyString;
44}
45}
The above class is needs a few Apache Jar’s as dependent jars in the build path.
image
Package this as a JAR file by exporting it as a JAR from eclipse. Next we will have to import this JAR in our OSB project so that the ExchangeService.class inside it can be used for Java Callout.
image
Add a line the setDomainEnv.cmd file in the OSB Domain so that it can locate these classpath entries at runtime.
set POST_CLASSPATH=%DOMAIN_HOME%\lib\commons-codec-1.5.jar;%DOMAIN_HOME%\lib\commons-httpclient-3.1.jar;%DOMAIN_HOME%\lib\commons-logging-1.1.1.jar;%POST_CLASSPATH%
The second thing that we need to do is add the Exchange service certificate to the Keystore of the OSB domain. Remember the Exchange services are https services.
Obtain the X.509 certificate from the exchange server and save it as a .pem file. Locate the location of the DemoKeyStore from the weblogic server console.
image
The X.509 certificate from the exchange server can be imported in the keystore by running the Keytool command below
keytool -import -trustcacerts -file <FileLoc>\cert.pem -keystore <KeyStoreLoc>\DemoTrust.jks
The default keystore password is DemoTrustKeyStorePassPhrase
Reboot the OSB Domain after applying these changes for them to take affect.
Lastly export the OSB Proxy Service as a WSDL so that it can be used in our BPM composite.
image
We can now move on to create the BPM process with a Human task that will invoke this OSB service.
Creating the BPM Composite with a Human Task
For the purpose of demonstration here I will be creating the most basic BPM process that has one message start event, one user task event (implemented as an Oracle Human Task) and an end event.
image
The process can be exposed as a web service since it has a Message Start event. This is a simple Card Approval Process in which a Credit Card Approver is presented with a Credit Card request that he has to either approve or reject.
The Task Activity is implemented as a Human Workflow Task. Open the .task for this task in JDeveloper.
We can enter additional task details from here like Task Title, Task Deadlines, Assignees, Notification Setting etc.
Add a Fixed Duration Deadline to this Task in the Deadlines tab.
image
This will set the expirationDate element in the task payload.
This is also where lies the crux of this article.
Since we want to create an Exchange Task for the assignee as soon as the Human Task is assigned to him we have to create and implement an onAssigned Event for this task.
image
You are allowed to create different events based on the task status from here. For now we are only interested in the first event i.e onAssigned event.
When a workflow event is triggered the in build EDN (Event Delivery Network) framework throws an event that contains the assigned Task Message payload containing the complete task information.
Learn more about EDN in Oracle SOA Suite here.
http://beatechnologies.wordpress.com/2011/06/14/lightweight-introduction-to-oracle-soa-suite-11g/
http://blogs.oracle.com/soabpm/entry/event_delivery_network_chapter
Creating a Mediator to Subscribe to Workflow Events
We have raised an event from the Human Task. We now have to implement a listener for this event that can listen to it and do something (calling the Exchange Service operations in this case).
Doing this couldn’t have been much simpler. What you need to do is create a composite application that has a Mediator component listening to this event.
image
The Event Definition File (EDL) for subscribing to Human Workflow events can be found in the MDS Repository under soa/shared/workflow/HumanTaskEvent.edl.
The mediator can subscribe to any one or all of the events and will fan out the process depending upon the event it receives.
image
Next create a Web service reference in the composite that is based on the Exchange Service OSB Proxy and wire the Mediator to Create Item of this service.
image
Open the Mediator Routing Definition to see that the a Static Routing Rule has been created for OnTaskAssigned event.
We can use the an XSL based Transformation to transform a task request to the CreateItemRequest message for the Exchange webservice.
image
Deploy the BPM Application for Card Approval Process and also the composite application containing the Event Subscribing Mediator component to a running soa server so see everything in action together.
Seeing Everything in Action
Go to the Enterprise Manager console where the Card Approval BPM composite is deployed.
Test the composite with a card approval request message from the composite. You will see that a running instance of the composite is created.
image
Looking at the Audit Trail of this instance will reveal an interesting thing. You will see that as soon as the the process flow reaches the ApproveCard user activity an OnTaskAssigned event is fired.
A WorkflowEventSubcriber Mediator Component that is listening to this type of event processes the event and calls the external web service. Opening the trace will further reveal that the service has returned a success response.
image
An outlook Task with a recurring reminder has now been created in the user inbox.
image
The Ending Conclusion
Another thing we did was to delete this Outlook task once a Human Workflow participant has acted on the it.
This is quite simple and achievable by raising an OnTaskCompleted event from the Human Task, extending the composite to subscribe to this type of event as well and call the DeleteItem operation on the Exchange web service.
Please feel free to post your questions and suggestions here.
.

August 29, 2011

Using Parametric Roles in Oracle BPM 11g

Folks having first hand experience in creating Business processes with our good old ALBPM would have certainly used parametric or dynamic role assignments in their processes.
Recently one of my colleague had asked me as how to do the same in Oracle BPM Suite 11g. I instantly remembered someone else also asking the same question in Oracle forums. Here are two such posts that discusses about the same
This article will demonstrate a very simple composite application with a BPM process that leverages the use of dynamic/parametric roles.
Creating the Process Skeleton
Create a SOA composite application in JDeveloper. Add BPM extension to it. Name the application as DynamicApprovalManagement. Drag a BPMN Process in the Components pane of the composite. Base it on a Manual Process Pattern.
Change the Start event from simple to a Message Start Event. Create a interface for the message start event based on the below schema.
02targetNamespace="http://www.soatechnologies.blog/card" elementFormDefault="qualified"></pre>
03<xsd:element name="CreditInformation">
04<xsd:complexType>
05<xsd:sequence>
06<xsd:element name="cardNumber" type="xsd:string"/>
07<xsd:element name="holderSsn" type="xsd:string"/>
08<xsd:element name="holderFirstName" type="xsd:string"/>
09<xsd:element name="holderLastName" type="xsd:string"/>
10<xsd:element name="brand" type="xsd:string"/>
11<xsd:element name="creditLimitRequested" type="xsd:double"/>
12<xsd:element name="creditLimitGranted" type="xsd:double"/>
13<xsd:element name="latePaymentCount" type="xsd:int"/>
14<xsd:element name="creditScoringResult" type="xsd:string"/>
15</xsd:sequence>
16</xsd:complexType>
17</xsd:element>
18</xsd:schema>
image
Create two Process Data Objects as creditInputRequest(based on the above XSD) and approvalOutcome of string type.
image
Next rename the UserTask with an appropriate name. Also double click on the user task and click on the Implementation tab. Implement the user task activity with a Human Task.
image
Implementing Dynamic/Rule based Participants in Human Task
Open the Business Process Navigator and browse the ApproveApplication.task that we just created inside DynamicApprovalManagement->Business Catalog->Human Tasks. Double click on the task to open the task editing wizard.
Click on the Assignment tab on the left. This will open the approval flow showing the task participants associated with it. Double click on the participant to choose a participant to execute this task.
Under Participant List choose Rule-based from the “Build a list of participant using :” option box.
Give any appropriate name in the List Ruleset field and click OK.
image
It would be interesting to see that this creates a Decision Service component based on Oracle Rules Engine with the name of the Ruleset that we just provided. There are some others as well but we can ignore them for the time being.
Click on the GetApprovers Ruleset (the name of the Ruleset that i choose. Depending upon what name you choose it can vary) and create an if then else type rule. Here as part of this demonstration I create a simple two rule Ruleset that evaluates credit limit requested for credit card application. If the credit limit is below 10k let a card approval clerk handle the approval/rejection. If it is more than 10k the approval is to be handled by a manager.
image
The dynamic participant or approval group is selected by calling the CreateResourceList function. The arguments used in this function are explained below
  • users – The name of any authenticated user in the server security realm.
  • groups – Instead of users we can also select a group in the server realm. The task will be assigned to all the users part of this group.
  • approles – This in important because while designing business process flows we dont care about users or groups but with application roles instead. They are equivalent to swimlane roles.
  • responseType – If the response type is REQUIRED, the assignee has to act on the task; otherwise, the assignment would be converted to an FYI assignment.
  • ruleName – Rule name is used to create an assignment reason. Rule set name + “_” + rule name is used as a key to look up the resource bundle for a translatable reason for assignment. This resource is looked up first in the project resource bundle, then in the custom resource bundle, and last in the system resource bundle
  • lists – This is an object that is a holder for all the lists that are built. Clicking this option shows a pre-asserted fact ‘Lists’ object to be used as the parameter.
For making this demonstration simpler i have chosen to select dynamic participants based on user names. Hence the reason why groups and approles are set to null values.
Go and create these two users in the Weblogic domain security realm.
image
Auto Generate a UI for the Human Task and compile the application.
If you now make or compile the application you will see that the build fails with the below exception
Error: BPM-71504: Unexpected error parsing ‘oramds:///soa/shared/workflow/TaskEvidenceService.xsd’.  Cause: oracle.mds.exception.MDSException: MDS-00054: The file to be loaded oramds:/soa/shared/workflow/TaskEvidenceService.xsd does not exist..  Action: Verify that file is valid and accessible
image
This is a known issue and took me sometime to find a workaround. Below is a note that i got in some Oracle document highlight the issue and its workaround. The below document explains this
You Must Manually Remove Additional Slashes from the XSD file When Defining Human Tasks Assignments Based on Business Rules In BPM Suite if you define a human task assignments based on Business Rules, then
you must edit the XSD of the decision service to remove the additional slashes from the import statements.
For example, you must replace the following statement:
schemaLocation=”oramds:///soa/shared/workflow/TaskEvidenceService.xsd” with the following import statement: schemaLocation=”oramds:/soa/shared/workflow/TaskEvidenceService.xsd“.
For the example used in this article i had to open the xsd/DSApproveApplicationWorkflowTask.xsd and manually change the location.
image
Now build and deploy both the composite application and the UI project to a running SOA server.
Finally to see the composite project in action open the EM console and open the Test page for the application. Since we have created a BPM process with a Message Start Event it can be invoked as a webservice as well.
Test 1 : CreditLimtRequested < 10000
In this case ClerkApproval rule will fire and the task will land up in the inbox of clerk.
image
image
Test 2 : CreditLimtRequested > 10000
Similarly in this case ManagerApproval rule will fire and the task will land up in the inbox of manager.
image
image
Well needless to mention that this scenario is extremely useful in cases where the assignees have to be determined based on some business rules or even in cases where the information about workflow management is to be determined from the input payload itself.
The composite application and the UI Project can be downloaded from here. After downloading rename it to .zip and extract the JDeveloper application.

August 24, 2011

Using Java APIs for Oracle Human Workflows

In continuation of my previous blogpost where I had discussed how we can use the web service APIs for Human Workflow components in Oracle SOA Suite 11g this blog will discuss how we can use the JAVA API’s to query and interact with worklist task items.
The earlier blog post can be viewed here
As previously discussed Oracle SOA Suite 11g has workflow API’s implemented both in JAVA as well as standard soap based web services. In some obvious cases there might be need to write some client side java code to interact with the workflow components.
Similar to the web service API’s I will talk about the two Java classes that is to be used for the purpose.
ITaskQueryService
This class provides a programmatic means for retrieving tasks, task details etc. To use this class to get access to task information and details we typically have to do the following
  • Write a remote client to connect to the remote SOA Suite server from the java class and get a client object.
  • Use an authentication method to authenticate a user and obtain an authenicated workflow context from the remote client object.
  • Use the obtained workflow context and a task list method to retrieve tasks that match some filter criterion viz taskNumber as displayed on the worklist page or taskStatus.
  • Use the context and a task details method to drill down on a task in the list (retrieve task details and actions that can be performed on the task)
ITaskService
The ITaskService class can be used to perform operations client operations on the task like adding/removing documents and comments, withdrawing/reassigning tasks, deleting/purging tasks etc.
The ITaskService uses the task query service to look up to a specific task and then do task operations on to them.
Writing the Java Client
I had followed the below steps to create a java client from the workflow classes.
Created a Java Project in JDeveloper and called it HumanTaskAPI. The libraries that have to be added to this project is shown below
image
Next create a class called TaskAuthenticationClient that would create a client object for the remote workflow service by looking up the server JNDI and also create a remote context for both the ITaskQueryService and ITaskService.
Here is the code snippet containing the explanatory comments along with it
01package blog.oracletechnologies.sales;
02 
03import java.util.HashMap;
04import java.util.Map;
05 
06import oracle.bpel.services.workflow.WorkflowException;
07import oracle.bpel.services.workflow.client.IWorkflowServiceClient;
08import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;
09import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;
10import oracle.bpel.services.workflow.query.ITaskQueryService;
11import oracle.bpel.services.workflow.task.ITaskService;
12 
13public class TaskAuthenticationClient {
14public TaskAuthenticationClient() {
15super();
16}
17 
18public IWorkflowServiceClient getWorkflowServiceContext () throws WorkflowException {
19 
20//Create WorflowServiceClient by looking up to the service JNDI
21String domainUrl ="t3://localhost:4003"; // host:port of the soa server
22Map<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String> connProperties = new HashMap<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String>();
23connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,WorkflowServiceClientFactory.REMOTE_CLIENT);
24connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,domainUrl);
25connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
26IWorkflowServiceClient workflowServiceClient = WorkflowServiceClientFactory.getWorkflowServiceClient(connProperties, null, null);
27return workflowServiceClient;
28}
29 
30//Get the task query service handle
31public ITaskQueryService getTaskQueryServiceRemoteContext () throws WorkflowException {
32ITaskQueryService taskQueryService = getWorkflowServiceContext().getTaskQueryService();
33return taskQueryService;
34}
35 
36public ITaskService getTaskServiceRemoteContext () throws WorkflowException {
37//Get the task service handle
38ITaskService taskService = getWorkflowServiceContext().getTaskService();
39return taskService;
40}
41}
Next create a class TaskQueryServiceClient that has two methods viz queryWorklistTasks() and getTaskDetailsByNumber()  that fetches task details from the soa workflow component.
The queryWorklistTask() operation accepts tow inputs objects. One is a Predicate object that determines what tasks need to be queried, the ordering and paging of result etc. The other input is a list of queryColumns that determines which columns in the task detail will be part of the output Task object.
The complete Class with a main() is copied below
001package blog.oracletechnologies.sales;
002 
003import java.io.StringWriter;
004 
005import java.util.ArrayList;
006import java.util.List;
007 
008import javax.xml.transform.OutputKeys;
009import javax.xml.transform.Transformer;
010import javax.xml.transform.TransformerConfigurationException;
011import javax.xml.transform.TransformerException;
012import javax.xml.transform.TransformerFactory;
013import javax.xml.transform.dom.DOMSource;
014import javax.xml.transform.stream.StreamResult;
015 
016import oracle.bpel.services.workflow.IWorkflowConstants;
017import oracle.bpel.services.workflow.WorkflowException;
018import oracle.bpel.services.workflow.query.ITaskQueryService;
019import oracle.bpel.services.workflow.repos.Predicate;
020import oracle.bpel.services.workflow.repos.TableConstants;
021import oracle.bpel.services.workflow.task.model.Task;
022import oracle.bpel.services.workflow.verification.IWorkflowContext;
023 
024import org.w3c.dom.Element;
025 
026public class TaskQueryServiceClient {
027public TaskQueryServiceClient() {
028super();
029}
030 
031public static IWorkflowContext getWorkflowContext () throws WorkflowException {
032return getTaskQueryService().authenticate("weblogic", "welcome123".toCharArray(), null);
033}
034public static ITaskQueryService getTaskQueryService () throws WorkflowException {
035TaskAuthenticationClient authenticationClient = new TaskAuthenticationClient();
036ITaskQueryService taskQueryService =authenticationClient.getTaskQueryServiceRemoteContext();
037return taskQueryService;
038}
039public static Predicate getTaskPredicate () throws WorkflowException {
040Predicate statePredicate=  new Predicate(TableConstants.WFTASK_STATE_COLUMN,Predicate.OP_EQ,IWorkflowConstants.TASK_STATE_ASSIGNED);
041return statePredicate;
042}
043public static List<String> getTaskQueryColumns () throws WorkflowException {
044// Set up list of columns to query. Also remember that only these columns will be fetched in taskQuery.
045List<String> queryColumns = new ArrayList<String>();
046queryColumns.add("TASKNUMBER");
047queryColumns.add("TASKID");
048queryColumns.add("TASKNUMBER");
049queryColumns.add("TITLE");
050queryColumns.add("OUTCOME");
051queryColumns.add("STATE");
052queryColumns.add("PRIORITY");
053return queryColumns;
054}
055 
056public void queryWorklistTasks(Predicate statePredicate, List<String> queryColumns) throws WorkflowException
057{
058//Query a list of tasks - list of Task objects
059List taskList = getTaskQueryService().queryTasks(getWorkflowContext(),
060queryColumns, //Custom Defined QueryColumns list
061null, // Do not query additional info
062ITaskQueryService.AssignmentFilter.MY_AND_GROUP,
063null, //No keywords
064statePredicate, //Custom Defined Predicate
065null, // No Task Ordering ordering
0660,0);  // Do not page the query result
067// Print exisiting Assigned tasks
068if (taskList != null)
069{
070System.out.println("Result of queryTask Opeartion");
071System.out.println("Total number of tasks: " + taskList.size());
072System.out.println("Tasks List: ");
073Task task = null;
074for (int i = 0; i < taskList.size(); i++)
075{
076task = (Task) taskList.get(i);
077System.out.println("Task Number: " + task.getSystemAttributes().getTaskNumber());
078System.out.println("Task Id: " + task.getSystemAttributes().getTaskId());
079System.out.println("Title: " + task.getTitle());
080System.out.println("Priority: " + task.getPriority());
081System.out.println("State: " + task.getSystemAttributes().getState());
082}
083}
084}
085public void getTaskDetailsByNumber(String taskNumber) throws WorkflowException,TransformerConfigurationException,TransformerException {
086// Query a list of tasks - list of Task objects
087Task task = getTaskQueryService().getTaskDetailsByNumber(getWorkflowContext(),Integer.valueOf(taskNumber));
088// Print exisiting Assigned tasks
089System.out.println("Result of getTaskDetailsByNumber Opeartion");
090System.out.println("Task Number: " + task.getSystemAttributes().getTaskNumber());
091System.out.println("Task Id: " + task.getSystemAttributes().getTaskId());
092System.out.println("Title: " + task.getTitle());
093System.out.println("Priority: " + task.getPriority());
094System.out.println("State: " + task.getSystemAttributes().getState());
095// This allows we to get the task payload (task data specific to our application). This is in XML format
096List list = task.getPayload().getContent();
097System.out.println("Task Payload : ");
098for (int i = 0; i < list.size(); i++)
099{
100Element taskDetails = (Element) list.get(i);
101printElement(taskDetails);
102}
103}
104 public static void  printElement (Element element) throws TransformerConfigurationException,TransformerException
105 {
106TransformerFactory transFactory = TransformerFactory.newInstance();
107Transformer transformer = transFactory.newTransformer();
108StringWriter buffer = new StringWriter();
109transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
110transformer.transform(new DOMSource(element),new StreamResult(buffer));
111String str = buffer.toString();
112System.out.println(str);
113}
114public static void main (String args[]) throws WorkflowException,TransformerConfigurationException,TransformerException
115{
116TaskQueryServiceClient taskQueryClient = new TaskQueryServiceClient();
117taskQueryClient.queryWorklistTasks(getTaskPredicate(),getTaskQueryColumns());
118taskQueryClient.getTaskDetailsByNumber("200783");
119}
120}
Running the java class will print the result of the task in the output console.
image
Finally the last thing that this article will show is a simple demonstration of how we can update an existing task with some extra comment. For this we would first need to fetch/query the specific task and use the ITaskService  class object to add an additional comment in the task.
Below is the TaskUpdateServiceClient class that has an addCommentToTask() method that takes a taskNumber as input and adds a user comment to it. This is very similar that we did with the Web service API.
The class also contains a main() method so that it can be run as a standalone class. Run the class and verify whether the comment has been added to the task comment section in the task.
01package blog.oracletechnologies.sales;
02 
03import javax.xml.transform.TransformerConfigurationException;
04import javax.xml.transform.TransformerException;
05 
06import oracle.bpel.services.workflow.StaleObjectException;
07import oracle.bpel.services.workflow.WorkflowException;
08import oracle.bpel.services.workflow.task.ITaskService;
09import oracle.bpel.services.workflow.task.model.Task;
10 
11public class TaskUpdateServiceClient {
12public TaskUpdateServiceClient() {
13super();
14}
15 
16public static ITaskService getTaskService() throws WorkflowException
17{
18TaskAuthenticationClient authenticationClient =new TaskAuthenticationClient();
19ITaskService taskService =authenticationClient.getTaskServiceRemoteContext();
20return taskService;
21}
22 
23public void addCommentToTask(String taskNumber) throws TransformerConfigurationException,TransformerException,WorkflowException,StaleObjectException
24{
25TaskQueryServiceClient taskQueryScvClient = new TaskQueryServiceClient();
26Task task = taskQueryScvClient.getTaskQueryService().getTaskDetailsByNumber
27(taskQueryScvClient.getWorkflowContext(),Integer.valueOf(taskNumber));
28 
29if (task != null)
30{
31TaskAuthenticationClient authenticationClient =new TaskAuthenticationClient();
32authenticationClient.getTaskServiceRemoteContext().addComment(taskQueryScvClient.getWorkflowContext(), task, "Comment Added From Java Client");
33}
34 
35}
36public static void main (String args[]) throws WorkflowException,TransformerConfigurationException,TransformerException,StaleObjectException {
37TaskUpdateServiceClient taskUpdateServiceClient = new TaskUpdateServiceClient();
38taskUpdateServiceClient.addCommentToTask("200783");
39}
40}
image
As you can see in the screenshot above that the comment that we added from the Java client reflects in the task detail page of the worklist user interface.
The ITaskQueryService and ITaskService offers an large set of methods that can be used further to exhaustively query and interact with worklist tasks in the Human Workflow component.
The JDeveloper Java project used in this article can be downloaded from here.
Another important note is that if you plan to use the code in the examples above make sure to handle and throw errors judiciously by having a suitable try-catch mechanism.
.

August 22, 2011

Oracle Human Workflow Web Service APIs

Oracle SOA Suite offers an exhaustive set of both java and web service APIs for Human Workflows. In this blogpost i will show how we can use the two most important workflow webservices to query and update Human Tasks in Oracle SOA Suite 11g.
The two Taskflow webservices API’s that I would talk here about are
TaskQueryService
The TaskQueryService service can be accessed at your SOA suite installation at the below endpoint.
And the API is here
This webservice api has many useful methods to query tasks like getting task details, task history, query assignees of a task etc.
Tow important method in the API are getTaskDetailsByNumber and getTaskDetailsById that can be used to query task details from the task number that we see in the worklist user interface.
image
Now use any soap client to invoke the query service operation to see how it works
image
As you see that the entire task details has been retrieved. If we take a closer look at the response we would find thas the taskId is also retrieved. This taskId is required in many other operations of this webservice and it can be retrieved using the taskNumber.
image
There is one more operation queryTasks that can be used to query tasks based on various where clauses like the task state, the assignee, column name etc.
TaskService
Another useful webservice is the TaskService that has practically all operations to modify any aspect of a task like adding/removing task comments, attachments, delegating, withdrawing and reassigning tasks, deleting or purging them etc.
We can go ahead and build our own custom user interface with underlying actions that are implemented by these operations. Or also call from service clients like OSB in case we need to do any custom task operations.
The service can be accessed at your SOA suite installation at the below endpoint.
http://host:port/integration/services/TaskService/TaskServicePort
And the full API can be viewed at
http://host:port/integration/services/TaskService/TaskServicePort?TaskServicePortstub.html
Here is a small demonstration explaining how we can add a comment to a task from the addComment operation of the service.
See how I have used the taskId that was retrieved from the getTaskDetailsByNumber operation is used to add comment to an existing task
image
Verify it in the workslist user interface to validate that the comment is added and appearing.
image
The above blog demonstrates some simple webservice operations using the Task service APIs. However they provide a very rich and exhaustive mechanism to do a great lot of important stuff with human tasks in Oracle SOA Suite 11g.

No comments:

Post a Comment

xslt padding with characters call template for left pad and right pad

  Could a call-template be written that took two parameters ?   a string, and a   number) return the string with empty spaces appended t...