Monday, April 21, 2008

Oracle SOA suite - Retrieving process information

The problem statement
To retrieve the information of a process from dehydration store even when I did not have the instance id using data present in the request of the process. (This is a part of a bigger problem I am trying to resolve)

I have an a unique field in the BPEL input. How can I find the BPEL instance and the related instances (This BPEL is executed which in turn executes several other BPEL processes ). I could not modify the existing BPEL so I was left with only one option that was to use the Oracle BPEL Process Manager Client API. This API has very less documentation, most of the help I got was from some blogs specially http://orasoa.blogspot.com/2007/06/calling-bpelesb-webservice-from.html and the API documentation http://download-uk.oracle.com/docs/cd/B31017_01/integrate.1013/b28986/toc.htm.

Driving to the beach
The Marc Kelderman blog solved one of the biggest problems I faced the 'jar hell'. I had tried several other posts but was not successful in setting up the project correctly, but the jar files as specified by him worked wonderfully.

Finally my classpath contained :-
connector15.jar, ejb.jar, oc4j-internal.jar, optic.jar, orabpel.jar, orabpel-ant.jar, orabpel-boot.jar, orabpel-common.jar, orabpel-exts.jar, orabpel-thirdparty.jar, oracle_http_client.jar, orawsdl.jar, xmlparserv2.jar. I am using SOA Suite version 10.1.3.3.

Now I setup a new java project in eclipse with these jars in my classpath. I then setup a server configuration file

Getting your feet wet

## server_config.properties
java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFactory
java.naming.provider.url=opmn:ormi://someserver.com:6004:oc4j_soadqa/orabpel
java.naming.security.principal=myname
dedicated.connection=true
java.naming.security.credentials=mypwd
Load the properties:-

 prop = new Properties();
InputStream resourceAsStream = BPELManagerControl.class
.getClassLoader().getResourceAsStream("server_config.properties");
prop.load(resourceAsStream);
The next piece of code I wrote was to retrieve all the instances of a specific BPEL process,



  Locator locator = new Locator("domainname", prop);
WhereCondition whereProcessId = new WhereCondition("process_id = ?");
whereProcessId.setString(1, "myprocessname");
IInstanceHandle[] instanceHandles = locator
.listInstances(whereProcessId);

Taking the dive

And using the instance handles I could display the states and instance id's of the processes. Now this was just the beginning of learning of how to use the API. I needed to modify it to suite my requirements. The previous piece of code returns all record in no particular order, this would make my task very difficult. By trial and error I realized that the API was using a view admin_list_ci to query and all its fields could be used in the query. Thus I added the following to order by creation_date (My instance would be one of the current instances in the server) desc. The next problem was if there was an error the list would continue processing infinitely. So I decided that my instance would be one of the last 50 instance executed on the server. This was a safe assumption since I would be searching immediately after submission. Thus my code became:-


   Locator locator = new Locator("domainname", prop);
WhereCondition whereProcessId = new WhereCondition("process_id = ?");
whereProcessId.setString(1, "myprocessname");
whereProcessId.append("ORDER BY CI_Creation_Date desc");
IInstanceHandle[] instanceHandles = locator
.listInstances(whereProcessId,0,50);
The next problem to resolve was ho do I find if the given IInstanceHandle handle was the instance I was searching for. I needed to search if my application specific id was present in the request of the instance.



  • The IInstanceHandle object had a getField method which seemed to suite my requirements (get the request variable and get the xml from it), but I realized it could only be used for a process that is not finished, thus had to drop the idea of using this method.
  • The only other way to get the data I could find was using the debug and audit xmls. In the BPELConsole along with the flow of the executed instance it also can display the Audit and Debug xmls. Corresponding methods were getAuditTrail and getDebugTrace that gave the dump of the whole BPEL instance data. I decided to use the getAuditTrail as the debug trace referred to the XML as an id (probably a refernce to some other table) which I could not find. Audit trail seemed to be working thus I decided to use it.
   String auditTrailXML = instanceHandle.getAuditTrail();
String XPATH = "//event[@label=\"receiveInput\"]/details/text()";
String receiveInput = Utils.xPathEvaluator(auditTrailXML, XPATH);
XPathFactory factory = XPathFactory.newInstance();
XPath xPath = factory.newXPath();

NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("ns1"))
uri = "http://www.sash.com/Schema/Declaration";
else
uri = null;
return uri;
}

public Iterator getPrefixes(String val) {
return null;
}

public String getPrefix(String uri) {
return null;
}
};

xPath.setNamespaceContext(ctx);
String XPATH2 = "//ns1:appid/text()";
XPathExpression xPathExpression = xPath.compile(XPATH2);
String appid = xPathExpression.evaluate(new InputSource(
new StringReader(receiveInput)));

And from the appid compare with the appid we had and keep on looping until the instance is found. Thus I was successful in retrieving the instance id.

To find all the related instances find the current instance and get it's handle. Then use the following where condition to retrieve related instances:-

    WhereCondition wpi = new WhereCondition("ROOT_ID=?");
wpi.setString(1, instanceHandle.getRootId());

Conclusion

  1. The whole code was mostly based on trial and error and basic API documentation.
  2. The API can be very helpful but very difficult to use
  3. The view admin_list_ci in the BPEL dehydration store can be used to construct the where clause in the query.
  4. Setting up the project is not very simple. The jars have to be correct.
  5. Do you want to use the API? Depends on your requirement. I turned to this API when I had no other option and yes I was satisfied as it resolved my problem.