Oracle SOA Suite Online Training

Interested in learning Oracle SOA Suite 12c?
Learn from the author of this blog!
A complete and comprehensive course on the #1 platform on SOA - Oracle SOA Suite

Click here to find the complete course details
Click here to check the first session on Oracle SOA Suite 12c

================================================================================================

Composite Instance Migration across different revisions

Often you find scenarios where you may want to migrate the running instances in one revision to another. A very common example for this is when you make some critical changes in your process, and you want all the older, already started but running instances, to continue in this new revision.

In such cases, the ant script ant-composite-instance-migration.xml will come handy

Location : <ORACLE_HOME>/bin/ant-composite-instance-migration.xml

Please note that this file has some errors in the jar locations, so cross-verify.

Create a build script for using this ant file. You need to provide the following information
1. Server details
2. Source Revision
3. Target Revision

Here's my build.xml file

--------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="migration-approvalProcess-straightMigration">
    <!--
        CREATE/MODIFY THE FOLLOWING
        ===========================
ENVIRONMENT VARIABLE ORACLE_HOME
REPORTS DIRECTORY VALUE
SERVER DETAILS IN <locatorConfig>
SOURCE COMPOSITE REVISION AND FILTER CONDITIONS IN <compositeInstanceFilterDef>
TARGET COMPOSITE REVISION IN <generateMigrationReport> AND <migrateCompositeInstances>
NOTE : MIGRATION PLAN IS NOT REQUIRED FOR MIGRATION FLAGGED AS AUTOMATIC
-->
    <property environment="envVar"/>
    <property name="srcBpmRevision" value="1.0"/>
    <property name="targetBpmRevision" value="2.0"/>
    <import file="${envVar.ORACLE_HOME}/bin/ant-composite-instance-migration.xml"/>
    <property name="reports.dir" value="${basedir}/MigrationReports"/>
    
    <!-- SERVER CONNECTION DETAILS -->
    <locatorConfig id="c1" host="asdf.abc.com" port="10030" user="userid" password="pwd"/>
    
    <target name="migrateCompositeInstances">
        <compositeInstanceFilterDef id="f1" domainname="default" compositedn="default/ApprovalProcess_InstanceMigration!${srcBpmRevision}" compositeinstanceid="2410732"/>
        <locatorSession configid="c1">
            <generateMigrationReport filterid="f1" revision="${targetBpmRevision}" outputfile="${reports.dir}/MigrationFeasibilityReport_AutomaticMigration_${srcBpmRevision}.xml"/>
            <!-- Migration Plan is not required for automatic migration -->
            <migrateCompositeInstances  filterId="f1" revision="${targetBpmRevision}" outputFile="${reports.dir}/MigrationResultReport_AutomaticMigration_${srcBpmRevision}.xml"/>
        </locatorSession>
    </target>

</project>

--------------------------------------------------------------------------------------------------------------------

Understanding the build file
compositeInstanceFilterDef : Filter for what instances to migrate. You can use various filter attributes like
id*, compositeDN*, flowId, pageStart, pageSize, tenantId, maxCreationDate, minCreationDate, maxModifyDate, minModifyDate, like, ecid, conversationId, compositeName, domainName, label, revision, title (* - Mandatory)
generateMigrationReport : This generates a report with the migration feasibility. It is a good practice to run only this first, analyse the report and then run the actual migration
migrateCompositeInstances : This runs the migration


Note that for those instances where the migration is marked as 'automatic' in the feasibility report do not require a migration plan, they can straight away be migrated.

Functions in Oracle Business Rule

This sample demonstrates creation of a custom function in Oracle Business Rules, using it in the RuleSet and calling it form a BPEL Process

High-level details

This example involves the following
a.      Implementation of a custom function in Oracle Business Rule
This is a simple function that adds the input date by 1 day and returns. This function will be further enhanced in later examples by extending the logic.
b.      Calling the custom function from the Business Rule If-Else Decision Service
c.      Calling the Business Rule from BPEL

Implementation


·        Create a schema for the input and output

·        Create a SOA Process with a BPEL Process using these input and output


·        Create a new Business Rule Component in the same component using the same input and output. In this example, since the usage of BPEL process is just to call the Business Rule, the schema elements are same but these could be any depending on your business requirement.


·        Business Rule Implementation
a.      Creating Globals - for constants




a
a.      Creating Function
First, define the signature of the function
Click on the '+' icon, give the name of the function, returnType, and description
In the Arguments section, define the input arguments of this function


You'll see a warning as the function is not implemented yet
Pseudo Code for the function
Initialize the variables
Convert the input  string into XMLGeorgianCalendar format (This has many date related functions, so used this type)
Add 1 day to this converted date
Convert the resulting value to String and return


a.      Defining Ruleset
               This is a simple ruleset to call the just defined function

The final Ruleset looks like this



Now that the Business Rule is implemented successfully, the only thing left is to use this in the BPEL Process

·        Using the Business Rule inside BPEL Process
Inside BPEL, drag and drop the Business Rule component from the SOA Components section in the Resource Pallette
Input & Output Association in BPEL



Your final BPEL Process should look like this



Thats it!
Deploy & Test the Process


If-Else in Assign Activity

There are scenarios often that need if-else conditions in your BPEL. For this, you will usually use a switch or if activities.

But if the condition is so simple, and you do not want to use a switch activity, then you might consider the 'translate' xpath function provided in the Assign activity.

This is how the translate function works

translate(arg1, arg2, arg3)

arg1 : Is your value that you want to operate on
arg2 : What characters are to be picked for replacement
arg3 : Character-by-Character replacement

translate funciton replaces the content character by character.
For example, if you want to replace 1 with A, 2 with B, 3 with C, and so on, your translate function would look like

translate(arg1, 'ABCDEFGH','12345678')
Example 1 :
If arg1 = BDGHFCDGA,
then the result would be 247863471

The above example is just for explanation on how it works, but a real world application would be as follows

lets say you get a requestId from input and you want to check if the request id is null or not, and if not null, result value is Y, otherwise N

Psuedo code :
Step 1
First, you will check if the input contains numbers, and replace all the numbers with 'Y' (you can use any letter for that matter in this step)
    So, if the input is 54695, then after translation, your output will be YYYYY
Step 2
Then, you will check if the result in step 1 contains 'Y' using the 'contains' xpath function
    In this step, your output will be either true or false
Step 3
Next, if the output of the previous step is true, replace the first letter 't' with 'Y' and ignore the rest

Actual Code
(These are mappings in assign activity)
Step 1
translate('../ns0:requestId','0123456789','YYYYYYYYYY') ------> $varReqId
Step 2 & 3
translate(contains($varReqId, 'Y'), 'truefals', 'Y') -----------> $varReqId

Explanation :
Lets say varReqId = 3246
Step 1 result will be YYYY (As 3 is replaced with Y, 2 is replaced with Y, 4 is replaced with Y, 6 is replaced with Y)
Next, Contains (YYYY,Y) results in true
Next, translate(true, truefals,Y) will replace t with Y and ignore the rest.
So, the first letter in true will be replaced with Y and the rest is ignored.

If you are not comfortable with this approach, or if its confusing, you always have the switch or if activity in BPEL, but your BPEL will become huge if the number of such conditions are more.

Hope this helps.

Unable to install OracleXE - Checking for Oracle XE instance : Failed

I got this error when I tried to install Oracle XE database.
What happened earlier is that I installed Oracle XE in another drive, but that drive got formatted. So, in the registry, XE is actually considered to be installed but in realty, the installation folder itself got deleted. So, when I tried to install it again, it checks the registry and finds the service to be available, atleast for the name sake.

To validate, you can go to Run --> services.msc
                    And you'll see OracleServiceXE here. You should remove this entry

Open command prompt and type
          sc delete OracleServiceXE

Now, try to install and it gets through. Hope this helps.

Oracle BPM : Share Data across instances in Oracle BPM

Suppose there is a scenario where you want to share the data across multiple instances of the same Human Task, here is the way to do it.

On the HumanTask definition, click on Settings --> In 'Payload Display for Parallel Participants', choose 'All task participants share the same payload'


I've used Oracle 12C, but the process remains the same for 11g.

Once deployed, one participant's payload(comments, attachments, etc) will be shown for the other assigned participant.

I've created a sample where I'm doing a multi-instance on a HumanTask to check if the payload is shared among the participants

Here's how my composite looked like




Input is an array of 2 which means the task is assigned to 2 participants. You may simulate this in your own way.

Login as the first participant and create attachments and comments. Also enter the actual inputs.


Now, login as the second participant to see if the comments and attachments are shared.
Please note that the actual payload is not shared, but the extra stuff alone.
And they are...


Now, when you add comments here, then those will be shared to the next participant.

Hope this helps.

Oracle BPM : Taskform not coming up in Workspace - Error : An established connection was aborted by the software in your host machine

In BPM Workspace, when you click on a task, sometimes the Taskform doesn't open up, giving the following error

 <Error> <oracle.adfinternal.controller.application.AdfcExceptionHandler> <ADFC-50018> <ADFc: No exception handler was found for an application exception.
javax.faces.FacesException: An established connection was aborted by the software in your host machine


The reason for this is because the ADF Taskform's host URL is set to an IP that is not allowed by your machine. You can check the IP to which it is set in EM --> Composite --> Human Task --> Administration

Replace the host with 'localhost'

and it works.

Set Composite Instance Name in Mediator or BPEL

You can set the Composite Instance Name that appears in the Name column in EM Instances screen.

This could be done either in the Mediator or in BPEL Component

In Mediator

In the Routing Rule 'Assign Values' section, you need to set the Composite Instance Title.



Set the value you want to display in the Name column of EM using the function setCompositeInstanceTitle('Name to be displayed') to the property 'tracking.compositeInstanceTitle'. This property is not available by default, just type it.

Namespace of the function will be 'http://schemas.oracle.com/mediator/xpath'

Here is the XML generated, you can check the namespace if the default generated one causes problems

<!-- START -->
<assign>
                  <copy target="$out.property.tracking.compositeInstanceTitle"
                        expression="med:setCompositeInstanceTitle(concat('CREATE GROUP ESN :: ',$in.parameters/xsd1:createRequest/xsd1:gpInfo/xsd1:masterESN))"
                        xmlns:xsd1="http://www.soatutor.com/MyServices"
                        xmlns:med="http://schemas.oracle.com/mediator/xpath"/>
               </assign>
<!-- FINISH -->

In BPEL
Use the function
ora:setCompositeInstanceTitle and set it to any temporary variable in the BPEL Process, and the process will set the Composite Instance Title.


Namespace : xmlns:ora="http://schemas.oracle.com/xpath/extension"

Here is the sample XML generated

<!-- START -->
<copy>
            <from expression="ora:setCompositeInstanceTitle(concat(&quot;Failed :: &quot;,bpws:getVariableData('errorOperation')))"/>
            <to variable="title"/>
          </copy>
<!-- FINISH -->

Assign the whole input to a variable

Sometimes, you need to log the whole request to a log table for error tracking. In such cases, you can use the function

oraext:get-content-as-string(bpws:getVariableData('inputVariable','redeemRequest','/ns2:redeemRequest'))

XSL for splitting CSV into seperate nodes

Input

<varForCSVComplexType>
 <IndActivityPayload xmlns="http://www.example.org">
  <PlannedFinishDate/>
  <AttachmentLoc>406,405,401</AttachmentLoc>
  <reviewerApproval/>
  <reviewerComments/>
 </IndActivityPayload>
</varForCSVComplexType>

Required Output

<ArrayOfUCMDocIds xmlns:ns0="http://www.example.org" xmlns="http://www.example.org">
<ns0:indDocId>406</ns0:indDocId>
<ns0:indDocId>405</ns0:indDocId>
<ns0:indDocId>401</ns0:indDocId>
</ArrayOfUCMDocIds

XSLT : Kind of recurrent call till there are no comma(',')

<xsl:stylesheet version="1.0"
                xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
                xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
                xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
                xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
                xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:ns0="http://www.example.org"
                xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
                xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:med="http://schemas.oracle.com/mediator/xpath"
                xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
                xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
                xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
                xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:bpmn="http://schemas.oracle.com/bpm/xpath"
                xmlns:ora="http://schemas.oracle.com/xpath/extension"
                xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator"
                xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap"
                exclude-result-prefixes="xsi xsl ns0 xsd bpws xp20 mhdr bpel oraext dvm hwf med ids bpm xdk xref bpmn ora socket ldap">

 <xsl:strip-space elements="*"/>
 <xsl:template match="/ns0:IndActivityPayload/ns0:AttachmentLoc">
  <ns0:IndActivityPayload>
    <xsl:apply-templates/>
  </ns0:IndActivityPayload>
 </xsl:template>

 <xsl:template match="text()" name="split">
  <xsl:param name="pText" select="."/>
  <xsl:param name="pItemElementName" select="'ns0:AttachmentLoc'"/>
 
    <xsl:if test="string-length($pText) > 0">
     <!-- Below declaration basically concatenates a ',' to the value just in case we have only one element and if there is no comma, then the value just returns nothing -->
     <xsl:variable name="vNextItem" select="substring-before(concat($pText, ','), ',')"/>
     <ns0:indDocId>
        <xsl:value-of select="$vNextItem"/>
      </ns0:indDocId>
      <xsl:call-template name="split">
        <xsl:with-param name="pText" select="substring-after($pText, ',')"/>
        <xsl:with-param name="pItemElementName" select="$pItemElementName"/>
      </xsl:call-template>
    </xsl:if>
 </xsl:template>
</xsl:stylesheet>

Caused by javax.resource.spi.InvalidPropertyException: Missing Property Exception. Missing Property: [ConnectionFactory> xADataSourceName or dataSourceName].

Exception Trace

com.oracle.bpel.client.BPELFault: faultName: {{http://schemas.oracle.com/bpel/extension}bindingFault}
messageType: {{http://schemas.oracle.com/bpel/extension}RuntimeFaultMessage}
parts: {{
summary=<summary>Exception occured when binding was invoked.
Exception occured during invocation of JCA binding: "JCA Binding execute of Reference operation 'GetAccountInfoDS' failed due to: Could not create/access the TopLink Session.
This session is used to connect to the datastore.
Caused by javax.resource.spi.InvalidPropertyException: Missing Property Exception.
Missing Property: [ConnectionFactory> xADataSourceName or dataSourceName].
You may have set a property (in _db.jca) which requires another property to be set also.
 Make sure the property is set in the interaction (activation) spec by editing its definition in _db.jca.
.
You may need to configure the connection settings in the deployment descriptor (i.e. DbAdapter.rar#META-INF/weblogic-ra.xml) and restart the server.  This exception is considered not retriable, likely due to a modelling mistake.
". 
The invoked JCA adapter raised a resource exception.
Please examine the above error message carefully to determine a resolution.
</summary>
,detail=<detail>Missing Property Exception.
Missing Property: [ConnectionFactory> xADataSourceName or dataSourceName].
You may have set a property (in _db.jca) which requires another property to be set also.
 Make sure the property is set in the interaction (activation) spec by editing its definition in _db.jca.
</detail>
,code=<code>null</code>

When you get this while trying to connect to the database from a DatabaseAdapter, solution as follows

Solution :
Assuming you had already created the datasource & Outbound Connection Pool for the DatabaseAdapter,
Goto deployments --> dbAdapter --> check it & click on 'Update' --> Redeploy.
This should fix the issue. If not, restart and it should fix now.

XSLT : Duration between 2 Dates

XSLT 2.0 lets you calculate the date difference very easily.

My Input is as below

<?xml version="1.0" encoding="UTF-8" ?>
<input xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.example.org">
   <benefitsDeliveryServiceEndDate>2015-02-11-05:00</benefitsDeliveryServiceEndDate>
   <cboNextChargeDate><![CDATA[2015-12-11]]></cboNextChargeDate>
</input>

One thing to make sure is that the formats has to be the same. If the date formats are different, then make them into the same either using xp20:format-dateTime or using substrings.

Here is the xslt that calculates the duration b/w the two dates. I'm trimming the result to get only the number of days, you can do as per your requirement.

<xsl:stylesheet version="2.0"
                xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
                xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
                xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
                xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:ns0="http://www.example.org"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
  <xsl:template match="/">
    <ns0:dateDiff>
      <ns0:daysToBump>
        <xsl:variable name="bfDlvServEndDate" select="/ns0:input/ns0:benefitsDeliveryServiceEndDate"/>
        <xsl:variable name="cboServiceDate" select="/ns0:input/ns0:cboNextChargeDate"/>
            <!--<xsl:variable name="currentDate" select="xp20:current-date()"/>-->

            <!-- DateDifference Calculation -->
            <xsl:variable name="daysToBump" select="(xsd:date($bfDlvServEndDate) - xsd:date($cboServiceDate))"/>
            <!-- Convert date to string so that you can trim to get the Date -->
            <xsl:variable name="daysToBump" select="xsd:string($daysToBump)"/>
            <xsl:choose>
                <xsl:when test="contains($daysToBump,'D')">
                    <xsl:value-of select="substring-before(substring-after(xsd:string($daysToBump),'P'),'D')"/>
                </xsl:when>
                <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
      </ns0:daysToBump>
    </ns0:dateDiff>
  </xsl:template>
</xsl:stylesheet>

Will give the following result

<?xml version = '1.0' encoding = 'UTF-8'?>
<ns0:dateDiff xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns0="http://www.example.org" xsi:schemaLocation="http://www.example.org file:/C:/JDeveloper/mywork/SampleSOAApps/Project1/xsl/untitled1.xsd">
   <ns0:daysToBump>302</ns0:daysToBump>
</ns0:dateDiff>

java.lang.NullPointerException in BPEL Invoke

You might get the following error while invoking a service from BPEL

<bpelFault>
   <faultType>0</faultType>
   <remoteFault>
      <part name="summary">
         <summary>java.lang.NullPointerException</summary>
      </part>
      <part name="detail">
         <detail>null</detail>
      </part>
   </remoteFault>
</bpelFault>

This means that the service is not available, or atleast the bpel is not able to find the service operation.

But you might observe the service works fine directly.
This happens when the WSDL in the MDS is not updated with the right one (In my case, the service that I'm invoking is an OSB Service in some other machine)

Sometimes, the MDS doesn't get properly updated during the deployment. To confirm, create an MDS connection in JDev and check if the wsdl/xsd's are updated.

If not, then refresh the MDS / clear cache, and redeploy. It works now.