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