Advertisements

Posts Tagged 'BPEL'

Using BPM Java API – WorkflowContext

 

Once the human task instance is created, we can perform several actions like:

  • Withdraw
  • Delegate
  • Update Task outcome
  • Add Attachment
  • Add Comments
  • Query Task details
  • etc..

If we observe these actions, we can guess that all users of the system should not be able to perform these actions and should be controlled through roles/privileges/permissions. So all these actions requires a user context to determine these permissions. BPM APIs accept this user context in form of WorkflowContext. WorkflowContext is a session object maintained by SOA server tied to an user.

How to create workflowcontext for a specific user?

Task Query service has authenticate method that accepts user credentials and returns a WorkflowContext as shown below.


public IWorkflowServiceClient getWfServiceClient()
 {
 IWorkflowServiceClient wfSvcClient = null;

wfSvcClient = WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT);
return wfSvcClient;
 }

public IWorkflowContext getUserWorkflowContext()
 {
 IWorkflowContext wfCtx = null;
 try
 {
 wfCtx = getWfServiceClient().getTaskQueryService().authenticate("weblogic", "weblogic1".toCharArray(), null);
 }
 catch(WorkflowException wex)
 {
 wex.printStackTrace();
 }

 return wfCtx; 
 }

How to create workflowcontext for a logged in user?

Same Task Query service is used to get workflowcontext for the logged in user as shown below. Make sure that your java/web application is security enabled.

 public IWorkflowContext getLoggedinUserWorkflowContext()
 {
 IWorkflowContext wfCtx = null;
 try
 {
 wfCtx = getWfServiceClient().getTaskQueryService().getWorkflowContextForAuthenticatedUser();
 }
 catch(WorkflowException wex)
 {
 wex.printStackTrace();
 }

 return wfCtx; 
 }

How to create workflowcontext on behalf of a user?

In some of the cases, password may not be available to get the user context but the task actions should be performed by this user. In those cases, we can create admin workflow context and use authenticateOnBehalfOf method of Task Query Service as shown below. Here the user weblogic is admin i.e. having BPMWorkflowAdmin role.

 public IWorkflowContext getOnbehalfOfUserWorkflowContext()
 {
 IWorkflowContext wfCtx = null;
 try
 {
 wfCtx = getWfServiceClient().getTaskQueryService().authenticate("weblogic", "weblogic1".toCharArray(), null);
 wfCtx = getWfServiceClient().getTaskQueryService().authenticateOnBehalfOf(wfCtx, "svgonugu");
 }
 catch(WorkflowException wex)
 {
 wex.printStackTrace();
 }
 return wfCtx; 
 }

How to assign BPMWorkflowAdmin role to an User?

  • Login to EM console and navigate to Weblogic Domain -> <<domainName>> -> Security -> Application Roles.
  • Search for BPMWorkflowAdmin role by choosing soa-infra as application stripe.

search.jpg

  • Click Edit to assign this role to an user and click Add. Note that weblogic user will have admin role by default so the screenshots presented here are only demo purpose.

add.jpg

  • Search for the user weblogic and click ok.

add1

add3.jpg

  • You will observe the following error when try to use authenticateOnBehalfOf method using the workflowcontext created using non-admin user.

ORABPEL-30509

exception.code:30509
exception.type: ERROR
exception.severity: 2
exception.name: Insufficient privileges to authenticate on behalf of another user.
exception.description: User siva cannot authenticate on behalf of user svgonugu without admin privil
eges.
exception.fix: Only users with admin privileges can authenticate on behalf of another user.

Do we have any timeout settings for WorkflowContext?

As mentioned earlier, Workflowcontext is a session object maintained by SOA/BPM server in heap memory. So creating more and more workflowcontexts might cause out of memory errors on the server. So whenever we are done with workflowcontext we should always destroy the context. Also BPM runtime has a default timeout of 60 min after which the workflowcontext object is destroyed. This timeout setting can be modified by navigating to Weblogic Domain -> <<domain name>> -> System MBean Browser -> Application Defined MBeans -> oracle.as.soainfra.config -> Workflow Config -> WorkflowServiceSesionTimeoutInMinutes as shown below.

timeout

If we use workflowcontext after timeout, we will get WorkflowException.

How to destroy WorkflowContext?


getWfServiceClient().getTaskQueryService().destroyWorkflowContext(wfCtx);

Advertisements

Using BPM Java API – wf_client_config.xml

In previous posts (post1 & post2), we have seen how to use SOAP and Remote clients to work with BPM Java APIs. One immediate problem we can see is using server urls in the code which makes deployment across environments difficult. In this post, we will see how to take care of this.

WorkflowServiceClientFactory class has different overloaded methods to get the client. When we don’t pass any properties like below, BPM run time will look for a file wf_client_config.xml in classpath of ear file.


private IWorkflowServiceClient getWfServiceClient()
{
IWorkflowServiceClient wfSvcClient = null;

wfSvcClient = WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT);
return wfSvcClient;
}

We can create wf_client_config.xml with the following contents having the server details and information pertaining to both SOAP and REMOTE clients. The file can be placed in a folder like conf under our project folder.


<?xml version="1.0" encoding="UTF-8"?>
<workflowServicesClientConfiguration xmlns="http://xmlns.oracle.com/bpel/services/client">
<server name="default" default="true">
<remoteClient>
<serverURL>t3://localhost:7005/soa-infra</serverURL>
<userName>weblogic</userName>
<password>weblogic1</password>
<initialContextFactory>weblogic.jndi.WLInitialContextFactory</initialContextFactory>
<participateInClientTransaction>false</participateInClientTransaction>
</remoteClient>
<soapClient>
<rootEndPointURL>http://localhost:7005</rootEndPointURL>
<identityPropagation mode="dynamic" type="saml">
<policy-references>
<policy-reference enabled="true" category="security"
uri="oracle/wss10_saml_token_client_policy"/>
</policy-references>
</identityPropagation>
</soapClient>
</server>
</workflowServicesClientConfiguration>

Include this file in the ear deployment profile using the below steps i.e. corresponding to ADF BC Service project. Create new file group APP-INF/classes as shown below.

app-inf

Add the contributor pointing to conf directory having wf_client_config.xml file.

app-inf1.jpg

Now filters section of APP-INF/classes group should be shown like below.

app-inf2.jpg

Deploy the ear file and re-test your webservice method.

During testing, if the following error is seen in the logs make sure that <?xml version = ‘1.0’ encoding = ‘UTF-8’?> is present as first line in wf_client_config.xml file.

[Exception [EclipseLink-25008] (Eclipse Persistence Services – 2.6.4.v20160829-44060b6): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element workflowServicesClientConfiguration was not found in the project]

Since the server details are externalized you can use tokens in wf_client_config.xml and replace them using actual server urls before deploying to specific environments.

 

Using BPM Java API – Creating Human Task (Contd..)

In the previous post, we used SOAP client to invoke BPM java APIs to create a human task. As i mentioned, we will not be able to test remote interface unless we create some java application and deploy to WLS. So in this post, i will create ADF BC Service project to demonstrate this and assume the readers have basic understanding on how to create ADF BC Services.

Following code snippet shows getting the remote client to invoke BPM java API. note the usage of URL.


//admin credentials
private static final String wlsUser = "weblogic";
private static final String wlsPassword = "weblogic1";

//soa-infra url
private static final String soaURL = "t3://localhost:7005/soa-infra";

private Map<CONNECTION_PROPERTY, String> getClientProp(String clientType)
{
Map<CONNECTION_PROPERTY, String> properties = new HashMap<CONNECTION_PROPERTY, String>();

if (WorkflowServiceClientFactory.REMOTE_CLIENT.equals(clientType))
{
properties.put(CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");

//soa-infra url
properties.put(CONNECTION_PROPERTY.EJB_PROVIDER_URL, soaURL);

//admin user
properties.put(CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL, wlsUser);

//admin pwd
properties.put(CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS, wlsPassword);
}
else if (WorkflowServiceClientFactory.SOAP_CLIENT.equals(clientType))
{
properties.put(CONNECTION_PROPERTY.SOAP_END_POINT_ROOT,
"http://localhost:7005");
properties.put(CONNECTION_PROPERTY.SOAP_IDENTITY_PROPAGATION, "non-saml");
}
return properties;
}

private IWorkflowServiceClient getWfServiceClient()
{
IWorkflowServiceClient wfSvcClient = null;

wfSvcClient =
WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.REMOTE_CLIENT,getClientProp(WorkflowServiceClientFactory.REMOTE_CLIENT),null);
return wfSvcClient;
}

The AM method code which is exposed as webservice method remains similar as shown below.


private Element getTaskPayload() throws Exception
{
String payloadStr =
" <payload xmlns=\"http://xmlns.oracle.com/bpel/workflow/task\">" +
"<EmployeeExpenseInput xmlns=\"http://xmlns.oracle.com/expenses/approval/schema\">" +
" <employeeId></employeeId> " + " <firstName></firstName> " + " <lastName></lastName>" +
" <expenseType></expenseType>" + " <expenseDescription></expenseDescription>" +
" <expenseLocation></expenseLocation>" + " <expenseDate></expenseDate>" +
" <amount></amount>" + "</EmployeeExpenseInput>" + " </payload>";
Document doc = null;

try
{
doc = XMLUtil.parseDocumentFromXMLString(payloadStr);
}
catch (Exception e)
{
throw new Exception("Exception in parsing string to xml");
}
return doc.getDocumentElement();
}

public String createHumanTask(String taskTitle)
{
String taskId = null;
IInitiateTaskResponse taskResponse = null;

try
{
ObjectFactory of = new ObjectFactory();
Task newTask = of.createTask();

//set required attribute before calling BPM task api
newTask.setTaskDefinitionId(taskNameSpace);
newTask.setPayloadAsElement(getTaskPayload());
newTask.setCreator(wlsUser);
if(taskTitle == null || taskTitle.isEmpty())
{
newTask.setTitle("BPM API TESTING USING CREATE HUMAN TASK");
}
else
{
newTask.setTitle(taskTitle);
}

newTask.setCategory("TESTING");
newTask.setIdentificationKey("587776676");

taskResponse = getWfServiceClient().getTaskService().initiateTask(newTask);

if (taskResponse != null)
{
newTask = taskResponse.getTask();
taskId = newTask.getSystemAttributes().getTaskId();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return taskId;
}

When the service method is invoked for the first time, we may observe the following error.


<?xml version="1.0" encoding="UTF-8"?><env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>JBO-29000: Unexpected exception caught: java.lang.NoClassDefFoundError, msg=oracle/bpel/services/workflow/task/model/ObjectFactory</faultstring>
<detail>
<tns:ServiceErrorMessage xmlns:tns="http://xmlns.oracle.com/adf/svc/errors/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tns:code>29000</tns:code>
<tns:message>JBO-29000: Unexpected exception caught: java.lang.NoClassDefFoundError, msg=oracle/bpel/services/workflow/task/model/ObjectFactory</tns:message>
<tns:severity>SEVERITY_ERROR</tns:severity>
<tns:detail xsi:type="tns:ServiceErrorMessage">
<tns:message>oracle/bpel/services/workflow/task/model/ObjectFactory</tns:message>
<tns:severity>SEVERITY_ERROR</tns:severity>
<tns:exceptionClassName>java.lang.NoClassDefFoundError</tns:exceptionClassName>
</tns:detail>
<tns:exceptionClassName>oracle.jbo.JboException</tns:exceptionClassName>
</tns:ServiceErrorMessage>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>

This error can be resolved by adding oracle.soa.workflow.wc as library reference in weblogic-application.xml. The file can be found in Application Resources -> Descriptors -> META-INF in JDeveloper.


	<library-ref>
	<library-name>oracle.soa.workflow.wc</library-name>
</library-ref>

Testing

Input

input

Output

output

output2

output3.jpg

The sample ADF BC service project can be found here.

Using BPM Java API – Creating Human Task

In the previous post, I described how different participant types work when we use Named User, Approval Group, Application Role etc in the assignment. Now we will see how to use BPM Java APIs in a series of post. I used 12.2.1.2.0 release for demonstration. This article assumes basic working knowledge of Human Workflows and does not get into finer details of the same.

SOA/BPM exposes number of human workflow services as listed below and all these services can be invoked either using SOAP or remote interface with an exception of Identity service which can be invoked only through SOAP interface. You can refer to url for more information on accessing the service and functionality exposed by each. In this post, we will see how to use Task Service to create a human task from java code.

  • Task service
  • Task query service
  • Identity service
  • Task metadata service
  • User metadata service
  • Task report service
  • Runtime config service
  • Evidence store service

Steps:

  • Create a Human Workflow in a SOA composite and deploy to SOA Server.
  • Create a java project in Jdeveloper with a java class having main method.
  • Add BPM Workflow library by navigating to Project properties -> Libraries and Classpath. This jar will have necessary classes to work with human workflow services mentioned above. Note that the libraries Oracle XML Parser V2 and JAX-WS client also need to be added.
  • To call any of the human workflow services, we need to get workflow service client as the first step which can either SOAP or REMOTE. Following snippet of code shows how to get a SOAP based workflow service client.
private IWorkflowServiceClient getWfServiceClient()
{
IWorkflowServiceClient wfSvcClient = null;
wfSvcClient =
WorkflowServiceClientFactory.getWorkflowServiceClient(WorkflowServiceClientFactory.SOAP_CLIENT,
getClientProp(WorkflowServiceClientFactory.SOAP_CLIENT),null);
return wfSvcClient;
}

private Map<CONNECTION_PROPERTY, String> getClientProp(String clientType)
{
Map<CONNECTION_PROPERTY, String> properties = new HashMap<CONNECTION_PROPERTY, String>();
if (WorkflowServiceClientFactory.REMOTE_CLIENT.equals(clientType))
{
properties.put(CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");

//soa-infra url
properties.put(CONNECTION_PROPERTY.EJB_PROVIDER_URL, soaInfraURL);

//admin use
properties.put(CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL, wlsUser);

//admin pwd
properties.put(CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS, wlsPassword);
}
else if (WorkflowServiceClientFactory.SOAP_CLIENT.equals(clientType))
{
properties.put(CONNECTION_PROPERTY.SOAP_END_POINT_ROOT, "http://host:soaPort");
properties.put(CONNECTION_PROPERTY.SOAP_IDENTITY_PROPAGATION, "non-saml");
}
return properties;
}
  • Use the following code to create a task using Task service. You can get task namespace from .task file and is the targetNamespace mentioned there. The Task payload preparation should be as per payload defined in Data section of the human task. Note the usage of workflow service client to get the task service.

private Element getTaskPayload()
throws Exception
{
String payloadStr =
" <payload xmlns=\"http://xmlns.oracle.com/bpel/workflow/task\">" +
"<EmployeeExpenseInput xmlns=\"http://xmlns.oracle.com/expenses/approval/schema\">" +
" <employeeId></employeeId> " + " <firstName></firstName> " + " <lastName></lastName>" +
" <expenseType></expenseType>" + " <expenseDescription></expenseDescription>" +
" <expenseLocation></expenseLocation>" + " <expenseDate></expenseDate>" +
" <amount></amount>" + "</EmployeeExpenseInput>" + " </payload>";
Document doc = null;

try
{
doc = XMLUtil.parseDocumentFromXMLString(payloadStr);
}
catch (Exception e)
{
throw new Exception("Exception in parsing string to xml");
}
return doc.getDocumentElement();
}

public String createHumanTask()
{
String taskId = null;
IInitiateTaskResponse taskResponse = null;

try
{
ObjectFactory of = new ObjectFactory();
Task newTask = of.createTask();

//set required attribute before calling BPM task api
newTask.setTaskDefinitionId(taskNameSpace);
newTask.setPayloadAsElement(getTaskPayload());
newTask.setCreator(wlsUser);
newTask.setTitle("BPM API TESTING USING CREATE HUMAN TASK");
newTask.setCategory("TESTING");
newTask.setIdentificationKey("587776676");

taskResponse = getWfServiceClient().getTaskService().initiateTask(newTask);

if (taskResponse != null)
{
newTask = taskResponse.getTask();
taskId = newTask.getSystemAttributes().getTaskId();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return taskId;
}

  • Similarly, other human workflow services can be accessed using workflow service client. Note that you may not be able to test the remote client from java main method. You need to deploy this to WLS to see it in action.
  • You can download the java project from here.

Human Workflow Participant Types Behavior

Recently I got a chance to work on one of the interesting assignments where I had explored BPM APIs, mainly Human workflow related. I want to share my learning in this blog through a series of articles. This article assumes the basic terminology associated with Human workflow, otherwise one can read the documentation here.

The main focus of this article is to present how notifications will be sent and how many approvals are required for different participant types Single, Parallel, Serial and FYI.I used business rules with Named User, Application Role, Approval Group and Hierarchies (Supervisor/Job/Position) and used 12.2.1.2 version for demonstration. Please note that you should have BPM (just not SOA Suite) installed to try with a few of the assignment types described here.

Assignment Type Participant Type Behavior
Named User

Note that, multiple assignment users can be given for value based setup too.

Single Notifications will be sent at same time to all the users derived in rule evaluation. Only one approval is enough for completion.  A user may have to claim before providing approval.
Parallel Notifications will be sent at same time to all the users derived in rule evaluation. The number of approvals for completion depends on the voting percentage.
Chain/Serial Notifications will be sent at same time to all the users derived in rule evaluation as there is no serial relationship defined among users. Approvals from all assignees are required for completion.
FYI Notifications will be sent at same time to all the users derived in rule evaluation and no approval is required.
Application Role Single Notifications will be sent at same time to all the users having the application role used in rules. Only one approval is enough for completion. A user may have to claim before providing approval.
Parallel
Chain/Serial
FYI Notifications will be sent at same time to all the users having the application role used in rules and no approval is required.
Approval Group Single Notifications will be sent at same time to all the users of approval group. Only one approval is enough for completion.  A user may have to claim before providing approval.
Parallel Notifications will be sent at same time to all the users of approval group. The number of approvals for completion depends on the voting percentage.
Chain/Serial Notification will be sent in sequential manner as setup in approval groups i.e. if approval group has user1 and user2 first notification will be sent to user1 and then to user 2. Approvals from all assignees are required for completion.
FYI Notifications will be sent at same time to all the users of approval group and no approval is required.
Supervisor Hierarchy

Position Hierarchy

Job Hierarchy

Single Notifications will be sent at same time to users part of hierarchy used in rules. Only one approval is enough for completion.  A user may have to claim before providing approval.
Parallel Notifications will be sent at same time to users part of hierarchy used in rules. The number of approvals for completion depends on the voting percentage.
Chain/Serial Notification will be sent in sequential manner as setup in hierarchy i.e. if hierarchy is user1 and user2 first notification will be sent to user1 and then to user 2. Approvals from all assignees are required for completion.
FYI Notifications will be sent at same time to users part of hierarchy and no approval is required.

Observations:

  • The behavior of single participant type is same irrespective of assignment type user, role etc… i.e. only one approval is required for completion. To verify this, do multiple user assignment for single participant type, run human workflow and query WFTASK table. Here we can observe that the ASSIGNEES column having all these users with ‘,’ as separator.
  • The behavior of using application role is same irrespective of participant type i.e. only one user can provide the approval having that application role.
  • To get Chain/Serial behavior we should always go for approval groups or hierarchies. In all other scenarios the serial participant behavior is same as parallel with 100% voting.

SOA 12c – Using Schedule Job activity in BPEL

In this post, we will learn how to use the Schedule Job activity to submit a ESS request from BPEL process during orchestration. And we will use the ESS job created from this post.

Create a Sync BPEL process and drag Schedule Job activity into BPEL from Components –> Oracle Extensions as shown below.

jobactivity

jobactinbpel

We need to create a MDS connection so that we can do the lookup for the ESS jobs. Create a new SOA-MDS Connection in Resources –> IDE Connections and select MDS partition essUserMetadata as shown below.

mdsconn

Double click on Schedule Job activity in BPEL to being up the below editor and select the required ESS job as shown in following screenshots. This way, we can also explore ESS jobs deployed to partition using different namespaces.

selectjob

selectjob2

selectedjob

Similarly, we can select Schedule if required as shown below.

selectsch

Navigate to Application Properties tab and give the value for Job Propetires using XPath expression as shown below.

jobargs1

jobargs2

jobargs3

We can also verify the ESS Job system properties in System Properties tab.

sysprop

Click OK to observe a sequence of activities are created in your BPEL flow as shown below. We can click each of these activities and observe what has been done automatically for us.

essexpand

essservice

On selecting the job, we will see following artifacts get created automatically in our project.

esswsdl

Since our composite using ESS abstract WSDL it will result into build errors. So modify your ESS partner link entry in composite.xml to add bindings and port as highlighted below.

<reference name="EssService"
           ui:wsdlLocation="WSDLs/ESSWebServiceAbstract.wsdl">
  <interface.wsdl interface="
http://xmlns.oracle.com/scheduler#wsdl.interface(ESSWebService)"
                  callbackInterface="http://xmlns.oracle.com/scheduler#wsdl.interface(ESSWebServiceCallback)"/>
  <binding.ws port="
http://xmlns.oracle.com/scheduler#wsdl.endpoint(ESSWebService/SchedulerServiceImplPort)"
        location="WSDLs/ESSWebServiceAbstract.wsdl"/>
  <callback>
    <binding.ws port="
http://xmlns.oracle.com/scheduler#wsdl.endpoint(ESSWebServiceCallback/ESSWebServiceCallback_pt)"/>
  </callback>
</reference>

Or generate configuration plan for composite and give port and binding along with ESS Webservice location as shown below.

<reference name="EssService">
      <binding type="ws">
        <attribute name="port">
          <replace>
http://xmlns.oracle.com/scheduler#wsdl.endpoint(ESSWebService/SchedulerServiceImplPort)</replace>
        </attribute>
        <attribute name="location">
          <replace>
http://localhost:7015/ess/esswebservice?wsdl</replace>
        </attribute>
      </binding>
      <callback>
        <binding type="ws">
          <attribute name="port">
            <replace>
http://xmlns.oracle.com/scheduler#wsdl.endpoint(ESSWebServiceCallback/ESSWebServiceCallback_pt)</replace>
          </attribute>
        </binding>
      </callback>
    </reference>

We can always verify ESS Webservice WSDLs by navigating to Webservices section in url >:>/ess">http://<<host>>:<<port>>/ess.

Deploy your SOA project using above configuration plan and Test.  Now we will observe the following error as ESS Webservices can’t be run with anonymous user credentials. To get away with that, modify the ESS webservice by attaching OWSM policy as detailed by Lucas in his blog.

svcerror

Since ESS Webservice is secured we need to attach the corresponding client policy to our Partner link and need to pass on the credentials of valid user. So as a first step, create a credential store key ESS_KEY_USER with weblogic credentials using the following steps in EM Console.

security

credkey

credkey1

Now attach the corresponding client policy to our partner link as shown below.

owsm4req

attchedowsm

Click pencil icon and modify OWSM policy to specify csf-key as shown below.

csfkey

This would populate wsm-assembly.xml file with the policy details as below.

owsmpolicy

Now again deploy the SOA composite and run. This time composite run will be successful and can observe the Request ID of ESS job as the response.

flowtrace

Navigate to ESSAPP –> Search Job Requests to see our job is submitted as expected and shows user as weblogic which is used in csf-key.

jobrequest

You can find sample project here.

Observation:

There is some run time error coming during BPEL process testing when we specified job description for Schedule Job activity as above. This is due to the missing quotes around so we have to manually open assign activity and surround your job description in quotes as shown below.

essissue

Business Events in Action

The purpose of this blog post is to explore subscription consistency levels. Subscriber can use any of the following consistency levels while subscribing to business events raised by publisher:

    • immediate
    • guaranteed
    • one and only one

Following is an extract from documentation explaining the functionality of each consistency level:

    • immediate – Events are delivered to the subscriber in the same global transaction and same thread as the publisher. The publish call does not return until all immediate subscribers have completed processing. If any subscribers throw an exception, no additional subscribers are invoked and an exception is thrown to publisher. The transaction is rolled back in case of any error during immediate processing
    • guaranteed – Events are delivered to the subscriber asynchronously without a global transaction. The subscriber can choose to create its own local transaction for processing, but it is committed independently of the rest of event processing. In addition, EDN does not attempt to resend an event (regardless of the backing store being AQ or JMS). If one or more subscribers fail to consume the event (while others succeed), those subscribers lose the message.
    • one and only one – Events are delivered to the subscriber in its own global (that is, JTA) transaction. Any changes made by the subscriber within that transaction are committed after the event processing is complete. If the subscriber fails, the transaction is rolled back. Failed events are retried a configured number of times.

This document shows you business events in action from the perspective of above highlighted points and might help you in choosing the right consistency level depending on the scenario.

Assumptions:

    • Using EDN-DB, though observations noted here will not vary when used EDN-JMS.
    • No clustered environment.

Use case:

A mediator raises 2 business events CreateOrder and UpdateOrder. For CreateOrder , we have the following subscribers:

    • Mediator routing the request to ASync BPEL (within same composite)
    • Mediator routing the request to Sync BPEL (within same composite)
    • Asynchronous BPEL process (within same composite)
    • Mediator throws exception while routing the request to Asynchronous BPEL (in different composite)

For UpdateOrder, we have the following subscribers:

    • Mediator routing the request to Asynchronous BPEL (in different composite)

We will observe the behavior in different scenarios by modifying event subscription consistency levels for above subscribers. The exception during the mediator routing is simulated by adding <onReply/> tag which is not needed in actual when routing to Async BPEL process. Example is shown below:

<switch>

<case executionType="direct"

name="Order2BPELProcess1.order2bpelprocess1_client.process">

<action>

<transform>

<part name="$out.payload"

function="xslt(xsl/CreateOrder_To_process.xsl, $in.payload)"/>

</transform>

<invoke reference="Order2BPELProcess1.order2bpelprocess1_client"

operation="process">

<onReply/>

</invoke>

</action>

</case>

</switch>

Configuration:

The retry configuration for one and only one subscribed events and the other EDN configuration can be set in EM console by navigating to soa-infra -> Administration -> System MBean Browser -> Application Defined MBeans -> oracle.as.soainfra.config -> EDN Config -> edn. This will bring up the following screen showing the default parameters.

event retry

Demonstration:

To start with, have a look at the list of events being used and it’s subscriptions below:

events

subsc

Consistency Level – immediate:

Modify all the event subscriptions to immediate consistency level.

immediate

Now raise the CreateOrder event and observe flow trace shown below. Since consistency level is immediate and the exception is thrown by one of the subscribers not all of the subscribers have received the event at all. And also no retry happened in case of faulted subscriber.

flowtrace1

Also we can’t find this event in event recovery console which is shown below:

immediaterecover

To confirm the above observed behavior, now modify the consistency level of few of the events to either guaranteed or one and only one.

imm1

Now again raise the CreateOrder event and observe flow trace shown below. We don’t see any change in behavior from previous iteration. So if an exception is thrown by any one of the immediate consistency level subscribers, then remaining subscribers will not get the event at all irrespective of their subscription consistency levels. And also we would see the exception thrown back while executing from EM console.

imme2

exceptionimmedaite

Consistency Level – guaranteed:

Modify all the event subscriptions to guaranteed consistency level.

gua1

Now raise the CreateOrder event and observe flow trace shown below. Since consistency level is guaranteed all the subscribers have received the event though one of the subscriber is faulted. And no fault is thrown back while testing from EM console as we saw in ‘immediate’ . Also no retry happened in case of faulted subscriber and the event is lost for that subscriber.

gua2

Also we can’t find this event in event recovery console which is shown below:

immediaterecover

Consistency Level – one and only one:

Modify all the event subscriptions to one and only one consistency level.

oaoo1

Now raise the CreateOrder event and observe flow trace shown below. Since consistency level is ‘one and only one’ all the subscribers have received the event though one of the subscriber is faulted. And no fault is thrown back while testing from EM console as we saw in ‘immediate’ . Also retry happened thrice in case of faulted subscriber as we configured the NumberOfRetrys property to 3 (see Configuration section).

oaoo2

If event delivery is failed even after the configured number of retries that event will be marked for Recovery and will be shown in Faults section of Business Events screen in EM console as shown below. Use ‘Retry’ button to recover the event delivery or use ‘Abort’ button to discard.

oaoo3

Other Observations:

Scenario 1: Mediator routes the request to Sync BPEL which throws fault and not caught, then event retry is happening irrespective of the value set for property bpel.config.transaction.

obs1

Scenario 2: Mediator routes the request to ASync BPEL which throws fault and not caught, then event retry is not happened as expected, as the fault in Async BPEL process will not propagated back unless we do it by explicit callback and bpel.config.transaction is irrelevant in this case and the value of property bpel.config.oneWayDeliveryPolicy is set to async.persist.

obs2

Scenario 3: Mediator routes the request to ASync BPEL which throws fault and not caught having the value of property bpel.config.oneWayDeliveryPolicy is set to sync. As expected, the event retry happened in this case.

obs3

The same behavior isobserved, when BPEL is subscribed to event (no mediator in between) and the value of property bpel.config.oneWayDeliveryPolicy is set to sync.

obs31

Scenario 4: Event is published and one of the subscribers is not active. In this case, non-active subscriber will loose event and no event delivery happens even after bringing up the subscriber. We will simulate this case using by doing shutdown of another composite. In the below screenshot, we could see that event is not delivered to 6th subscriber as the composite is down and the flow trace will not change even after bringing up the composite.

obs4

This is due to fact that list of subscriptions no longer has this entry as shown below, so one should think about this type of possibility in real time use cases and have contingency plan in place for such cases.

obs5

References:

http://docs.oracle.com/cd/E28280_01/dev.1111/e10224/obe_intro.htm#CHDIBHBE

Download:

Sample code used in this post can be downloaded from here.

Query to find BPEL execution time

I had a scenario where business event is captured by a mediator in one of the composites and routes it to several BPEL processes in a sequence to complete particular business flow. I had to know the time taken by each of these BPELs in my end-to-end flow. Instead of going through each of the BPEL instance in EM console, I came up with the following query to find out the time taken. I used the ECID to correlate all the BPEL instances generated during my process flow. Check if it’s of help to any.

SELECT INSTANCE_KEY, COMPOSITE_NAME, COMPONENT_NAME,
       CREATION_DATE, MODIFY_DATE, EVAL_TIME
FROM (SELECT INSTANCE_KEY, COMPOSITE_NAME, COMPONENT_NAME,
               CREATION_DATE, MODIFY_DATE, EVAL_TIME
       FROM BPEL_PROCESS_INSTANCES
        WHERE instance_key IN (SELECT cikey FROM CUBE_INSTANCE
                              WHERE ecid = <<ecid>>)
       UNION ALL
       SELECT 1 INSTANCE_KEY, ‘Comp’ COMPOSITE_NAME, COMPONENT_NAME,
             CREATED_TIME CREATION_DATE, UPDATED_TIME MODIFY_DATE,
             CASE
          WHEN UPDATED_TIME IS NOT NULL THEN
            (extract(DAY FROM (UPDATED_TIME – CREATED_TIME)) * 24 * 60 * 60 +
             extract(hour FROM (UPDATED_TIME – CREATED_TIME)) * 60 * 60 +
             extract(minute FROM (UPDATED_TIME – CREATED_TIME)) * 60 +
             extract(second FROM (UPDATED_TIME – CREATED_TIME))) * 1000
         ELSE NULL
             END AS eval_time
        FROM MEDIATOR_INSTANCE
    WHERE ecid = <<ecid>>
       )
ORDER BY INSTANCE_KEY;

In case of the multiple events, we can rewrite the query if the composites are using sensors. The following query has been used in our case to monitor and to get execution times, minimum and maximum time taken for each of the component in process flow.

/*SELECT ECID, INSTANCE_KEY, CID, COMPOSITE_NAME, COMPONENT_NAME, CREATION_DATE,  MODIFY_DATE, EVAL_TIME */
–SELECT COMPONENT_NAME,  min(EVAL_TIME), max(eval_time)
SELECT ECID, count(component_name) cnt
FROM (SELECT ECID, CIKEY INSTANCE_KEY, CIKEY CID, COMPOSITE_NAME, COMPONENT_NAME, CREATION_DATE, MODIFY_DATE,
        CASE
        WHEN MODIFY_DATE IS NOT NULL
        THEN (extract(DAY FROM (MODIFY_DATE – CREATION_DATE)) * 24 * 60 * 60 +
              extract(hour FROM (MODIFY_DATE – CREATION_DATE)) * 60 * 60 +
              extract(minute FROM (MODIFY_DATE – CREATION_DATE)) * 60 +
              extract(second FROM (MODIFY_DATE – CREATION_DATE))) * 1000
          ELSE NULL
              END AS EVAL_TIME
      FROM CUBE_INSTANCE
      WHERE ecid IN (SELECT b.ecid FROM COMPOSITE_SENSOR_VALUE a, MEDIATOR_INSTANCE b
                                               WHERE sensor_name = <<sensor name>>
                            AND  a.composite_instance_id = b.composite_instance_id
                                        AND string_value IN (<<values>>)
                        )                           
    UNION ALL
    SELECT a.ECID, 1 INSTANCE_KEY, a.composite_instance_id CID,
               ‘Comp’ COMPOSITE_NAME, a.COMPONENT_NAME,
              a.CREATED_TIME CREATION_DATE, a.UPDATED_TIME MODIFY_DATE,
              CASE
        WHEN UPDATED_TIME IS NOT NULL
        THEN (extract(DAY FROM (UPDATED_TIME – CREATED_TIME)) * 24 * 60 * 60 +
              extract(hour FROM (UPDATED_TIME – CREATED_TIME)) * 60 * 60 +
              extract(minute FROM (UPDATED_TIME – CREATED_TIME)) * 60 +
              extract(second FROM (UPDATED_TIME – CREATED_TIME))) * 1000
          ELSE NULL
              END AS eval_time
      FROM MEDIATOR_INSTANCE a, COMPOSITE_SENSOR_VALUE b
      WHERE a.composite_instance_id = b.composite_instance_id
        AND b.sensor_name = <<sensor name>>
        AND b.string_value IN (<<values>>)
  )
–GROUP BY COMPONENT_NAME
GROUP BY ECID order by cnt

–ORDER BY ecid, INSTANCE_KEY, CID;

Note: Based on the requirement, the above select and group by statements have to be commented/uncommented.

HTTP Binding In BPEL- Testing from SOAP UI

Recently, we came across a requirement of exposing the BPEL service to be accessible over HTTP without exposing it as SOAP service. We have used the HTTP binding for this purpose. This blog provides the useful information on coming up with actual HTTP url to be used for testing as we faced issues with testing the process from EM console.

Basically the url should be some thing like below for GET invocation:

<<url given in EM>>/?<your query string>&operationName=<get operation name>

Just wanted to add simple update on this topic, the URL is working even by giving different name for operation other than default operation name ‘Request-Response’. The same has been tested from SOAP UI (GET method invocation).

Error while using the HTTP Binding in BPEL

HTTP Binding can be used in BPEL to call the RESTful services. We might have come across one common error REPLACE_WITH_ACTUAL_URL while calling. Came across a metalink note that talks about this so thought of sharing the same.

Metalink Note ID: 1328955.1

Following are the few reasons that i found during my testing with the HTTP adapter to invoke REST based urls:

–  If the URL is not accessible from the server because of the firewall or HTTP proxy

– Using the XML complex types in the request structure.

Though, the metalink url says that XML complex types are not supported it’s working in 11.1.1.5 version ( i verified only in this version). The same working sample can be downloaded from here.

The example calls the Echo application which can be downloaded from  here (Antony Reynold’s blog).


Advertisements

Pages

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 337 other followers

Enter your email address to follow this blog and receive notifications of new posts by email.


%d bloggers like this: