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:
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.
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.
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.
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.
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.

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.
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.
As you observed the instance has moved to the ManualCardApproval touch point and is awaiting for a response from a user with CreditCardApprover role. 
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.
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.
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.
The entire process flow diagram will give a picture of the path that the process took during its 
Happy-Path completion.
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.
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).

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.
.
       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.
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.
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

You can obtain the Exchange Service URL by opening 
Outlook->File->Account Settings
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.
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.
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.
02 | import java.io.IOException;</pre> | 
03 | import org.apache.commons.httpclient.HttpClient; | 
04 | import org.apache.commons.httpclient.HttpException; | 
05 | import org.apache.commons.httpclient.HttpStatus; | 
06 | import org.apache.commons.httpclient.NTCredentials; | 
07 | import org.apache.commons.httpclient.auth.AuthScope; | 
08 | import org.apache.commons.httpclient.methods.PostMethod; | 
09 | import org.apache.commons.httpclient.methods.StringRequestEntity; | 
11 | public class ExchangeServices { | 
12 | private 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") | 
14 | public static String  invokeExService(String endPoint, String messageHeader, String  messageBody, String userName, String password, String operation) throws HttpException, IOException | 
16 | StringBuffer soapMessage = new StringBuffer(); | 
17 | soapMessage.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); | 
19 | soapMessage.append(messageHeader); | 
20 | soapMessage.append(messageBody); | 
21 | soapMessage.append("</soapenv:Envelope>\n"); | 
23 | HttpClient client = new HttpClient(); | 
25 | PostMethod postMethod = new PostMethod(endPoint.trim()); | 
26 | postMethod.setRequestHeader("SOAPAction", soapAction); | 
27 | postMethod.setRequestHeader("Content-Type", "text/xml; charset=UTF-8"); | 
28 | postMethod.setRequestHeader("SOAPAction", soapAction); | 
29 | postMethod.setRequestHeader("User-Agent", userAgent); | 
30 | postMethod.setRequestEntity(new StringRequestEntity(soapMessage.toString().trim(), "text/xml; charset=UTF-8", null)); | 
31 | String errorMessage =""; | 
32 | String responseBodyString =""; | 
33 | NTCredentials ntCredentials = new NTCredentials(userName, password, "hostName", "domainName"); | 
34 | client.getState().setCredentials(new AuthScope(null,-1,null), ntCredentials); | 
35 | int status = client.executeMethod(postMethod); | 
36 | if(status != HttpStatus.SC_OK) | 
38 | errorMessage = "Method Failed :" + postMethod.getStatusLine(); | 
41 | responseBodyString= postMethod.getResponseBodyAsString(); | 
43 | return responseBodyString; | 
The above class is needs a few Apache Jar’s as dependent jars in the build path.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.

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.

An outlook Task with a recurring reminder has now been created in the user inbox.
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.
.
        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.
03 | <xsd:element name="CreditInformation"> | 
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"/> | 

Create two 
Process Data Objects as 
creditInputRequest(based on the above XSD) and 
approvalOutcome of string type.

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.
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.
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.
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.
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  |  
 
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.
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.
Test 2 : CreditLimtRequested > 10000
Similarly in this case ManagerApproval rule will fire and the task will land up in the inbox of manager.
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.
        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
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
01 | package blog.oracletechnologies.sales; | 
03 | import java.util.HashMap; | 
06 | import oracle.bpel.services.workflow.WorkflowException; | 
07 | import oracle.bpel.services.workflow.client.IWorkflowServiceClient; | 
08 | import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants; | 
09 | import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory; | 
10 | import oracle.bpel.services.workflow.query.ITaskQueryService; | 
11 | import oracle.bpel.services.workflow.task.ITaskService; | 
13 | public class TaskAuthenticationClient { | 
14 | public TaskAuthenticationClient() { | 
18 | public IWorkflowServiceClient getWorkflowServiceContext () throws WorkflowException { | 
22 | Map<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String> connProperties = new HashMap<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String>(); | 
23 | connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,WorkflowServiceClientFactory.REMOTE_CLIENT); | 
24 | connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,domainUrl); | 
25 | connProperties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); | 
26 | IWorkflowServiceClient workflowServiceClient = WorkflowServiceClientFactory.getWorkflowServiceClient(connProperties, null, null); | 
27 | return workflowServiceClient; | 
31 | public ITaskQueryService getTaskQueryServiceRemoteContext () throws WorkflowException { | 
32 | ITaskQueryService taskQueryService = getWorkflowServiceContext().getTaskQueryService(); | 
33 | return taskQueryService; | 
36 | public ITaskService getTaskServiceRemoteContext () throws WorkflowException { | 
38 | ITaskService taskService = getWorkflowServiceContext().getTaskService(); | 
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
001 | package blog.oracletechnologies.sales; | 
003 | import java.io.StringWriter; | 
005 | import java.util.ArrayList; | 
006 | import java.util.List; | 
008 | import javax.xml.transform.OutputKeys; | 
009 | import javax.xml.transform.Transformer; | 
010 | import javax.xml.transform.TransformerConfigurationException; | 
011 | import javax.xml.transform.TransformerException; | 
012 | import javax.xml.transform.TransformerFactory; | 
013 | import javax.xml.transform.dom.DOMSource; | 
014 | import javax.xml.transform.stream.StreamResult; | 
016 | import oracle.bpel.services.workflow.IWorkflowConstants; | 
017 | import oracle.bpel.services.workflow.WorkflowException; | 
018 | import oracle.bpel.services.workflow.query.ITaskQueryService; | 
019 | import oracle.bpel.services.workflow.repos.Predicate; | 
020 | import oracle.bpel.services.workflow.repos.TableConstants; | 
021 | import oracle.bpel.services.workflow.task.model.Task; | 
022 | import oracle.bpel.services.workflow.verification.IWorkflowContext; | 
024 | import org.w3c.dom.Element; | 
026 | public class TaskQueryServiceClient { | 
027 | public TaskQueryServiceClient() { | 
031 | public static IWorkflowContext getWorkflowContext () throws WorkflowException { | 
032 | return getTaskQueryService().authenticate("weblogic", "welcome123".toCharArray(), null); | 
034 | public static ITaskQueryService getTaskQueryService () throws WorkflowException { | 
035 | TaskAuthenticationClient authenticationClient = new TaskAuthenticationClient(); | 
036 | ITaskQueryService taskQueryService =authenticationClient.getTaskQueryServiceRemoteContext(); | 
037 | return taskQueryService; | 
039 | public static Predicate getTaskPredicate () throws WorkflowException { | 
040 | Predicate statePredicate=  new Predicate(TableConstants.WFTASK_STATE_COLUMN,Predicate.OP_EQ,IWorkflowConstants.TASK_STATE_ASSIGNED); | 
041 | return statePredicate; | 
043 | public static List<String> getTaskQueryColumns () throws WorkflowException { | 
045 | List<String> queryColumns = new ArrayList<String>(); | 
046 | queryColumns.add("TASKNUMBER"); | 
047 | queryColumns.add("TASKID"); | 
048 | queryColumns.add("TASKNUMBER"); | 
049 | queryColumns.add("TITLE"); | 
050 | queryColumns.add("OUTCOME"); | 
051 | queryColumns.add("STATE"); | 
052 | queryColumns.add("PRIORITY"); | 
056 | public void queryWorklistTasks(Predicate statePredicate, List<String> queryColumns) throws WorkflowException | 
059 | List taskList = getTaskQueryService().queryTasks(getWorkflowContext(), | 
062 | ITaskQueryService.AssignmentFilter.MY_AND_GROUP, | 
070 | System.out.println("Result of queryTask Opeartion"); | 
071 | System.out.println("Total number of tasks: " + taskList.size()); | 
072 | System.out.println("Tasks List: "); | 
074 | for (int i = 0; i < taskList.size(); i++) | 
076 | task = (Task) taskList.get(i); | 
077 | System.out.println("Task Number: " + task.getSystemAttributes().getTaskNumber()); | 
078 | System.out.println("Task Id: " + task.getSystemAttributes().getTaskId()); | 
079 | System.out.println("Title: " + task.getTitle()); | 
080 | System.out.println("Priority: " + task.getPriority()); | 
081 | System.out.println("State: " + task.getSystemAttributes().getState()); | 
085 | public void getTaskDetailsByNumber(String taskNumber) throws WorkflowException,TransformerConfigurationException,TransformerException { | 
087 | Task task = getTaskQueryService().getTaskDetailsByNumber(getWorkflowContext(),Integer.valueOf(taskNumber)); | 
089 | System.out.println("Result of getTaskDetailsByNumber Opeartion"); | 
090 | System.out.println("Task Number: " + task.getSystemAttributes().getTaskNumber()); | 
091 | System.out.println("Task Id: " + task.getSystemAttributes().getTaskId()); | 
092 | System.out.println("Title: " + task.getTitle()); | 
093 | System.out.println("Priority: " + task.getPriority()); | 
094 | System.out.println("State: " + task.getSystemAttributes().getState()); | 
096 | List list = task.getPayload().getContent(); | 
097 | System.out.println("Task Payload : "); | 
098 | for (int i = 0; i < list.size(); i++) | 
100 | Element taskDetails = (Element) list.get(i); | 
101 | printElement(taskDetails); | 
104 |  public static void  printElement (Element element) throws TransformerConfigurationException,TransformerException | 
106 | TransformerFactory transFactory = TransformerFactory.newInstance(); | 
107 | Transformer transformer = transFactory.newTransformer(); | 
108 | StringWriter buffer = new StringWriter(); | 
109 | transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); | 
110 | transformer.transform(new DOMSource(element),new StreamResult(buffer)); | 
111 | String str = buffer.toString(); | 
112 | System.out.println(str); | 
114 | public static void main (String args[]) throws WorkflowException,TransformerConfigurationException,TransformerException | 
116 | TaskQueryServiceClient taskQueryClient = new TaskQueryServiceClient(); | 
117 | taskQueryClient.queryWorklistTasks(getTaskPredicate(),getTaskQueryColumns()); | 
118 | taskQueryClient.getTaskDetailsByNumber("200783"); | 
Running the java class will print the result of the task in the output console.

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.
01 | package blog.oracletechnologies.sales; | 
03 | import javax.xml.transform.TransformerConfigurationException; | 
04 | import javax.xml.transform.TransformerException; | 
06 | import oracle.bpel.services.workflow.StaleObjectException; | 
07 | import oracle.bpel.services.workflow.WorkflowException; | 
08 | import oracle.bpel.services.workflow.task.ITaskService; | 
09 | import oracle.bpel.services.workflow.task.model.Task; | 
11 | public class TaskUpdateServiceClient { | 
12 | public TaskUpdateServiceClient() { | 
16 | public static ITaskService getTaskService() throws WorkflowException | 
18 | TaskAuthenticationClient authenticationClient =new TaskAuthenticationClient(); | 
19 | ITaskService taskService =authenticationClient.getTaskServiceRemoteContext(); | 
23 | public void addCommentToTask(String taskNumber) throws TransformerConfigurationException,TransformerException,WorkflowException,StaleObjectException | 
25 | TaskQueryServiceClient taskQueryScvClient = new TaskQueryServiceClient(); | 
26 | Task task = taskQueryScvClient.getTaskQueryService().getTaskDetailsByNumber | 
27 | (taskQueryScvClient.getWorkflowContext(),Integer.valueOf(taskNumber)); | 
31 | TaskAuthenticationClient authenticationClient =new TaskAuthenticationClient(); | 
32 | authenticationClient.getTaskServiceRemoteContext().addComment(taskQueryScvClient.getWorkflowContext(), task, "Comment Added From Java Client"); | 
36 | public static void main (String args[]) throws WorkflowException,TransformerConfigurationException,TransformerException,StaleObjectException { | 
37 | TaskUpdateServiceClient taskUpdateServiceClient = new TaskUpdateServiceClient(); | 
38 | taskUpdateServiceClient.addCommentToTask("200783"); | 
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.
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.
.
  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 TaskQueryService service can be accessed at your SOA suite installation at the below endpoint.
This webservice api has many useful methods to query  tasks like getting task details, task history, query assignees of a task  etc.
Now use any soap client to invoke the query service operation to see how it works
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.
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.
Here is a small demonstration explaining how we can add a comment to a task from the 
operation of the service.
 user interface to validate that the comment is added and appearing.
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