Wednesday, March 31, 2010

BPEL Set Title

BPEL titles are extremely important for troubleshooting anything from BPELConsole. It is basically providing title-name to BPEL instance. I also wrote blog on how to do wildcard search on those BPEL titles (http://chintanblog.blogspot.com/2010/03/bpel-title-wildcard-search_01.html).

Now the part comes is how to set titles. I am still working on implementing non-intrusive way of setting titles without ever changing BPEL code, but for now let's talk about how it is done Out of the Box:

Recommended Approach is:



I didn't like the idea of Java embed, just as it conflicts with other best practices Oracle has and it creates an additional workItem overhead for BPEL RT. Correct way of doing this would be to write BPEL function to do this. I wrote BPEL function as below:

ora:setProcessTitle()

This function sets the title of BPEL process
The signature of this function is : ora:setProcessTitle ('title', 'auditTrail'?)
auditTrail: true/false, it is optional and default value is true.

With this, you can set the title as native assign operation:


It doesn't reduce the code footprint that much, but still provides neater BPEL code and centralized way of handling Audit.

AIA BPEL Dynamic Partnerlink Lookup

BPEL dynamic partnerlink lookup concept is quite old and been there since 10.1.2 and it works great. AIA took that concept little far and forced the design pattern. E.g. all endpoint URLs should be strictly in AIAConfigurationProperties.xml file.

Example would be:

Step 1: put the endpoint URL in AIAConfigurationProperties.xml file:



Step 2: Change the BPEL code to look up this URL at run time using Java Embed.



Step 3: Follow the same old rule for BPEL dynamic partner-link once we have the right endpoint URL.



So far so good, but the problem is 20 lines of "non reusable" java embed code in my BPEL. If you talk with any decent Oracle SOA guru, they will ask you to avoid Java Embed as much as possible. AIA design pattern didn't stop here, they have recommended not to put EndPoint (or Partner-link) name directly in your Java Embed. Reason seems to quite obvious, you just specify the partner-link name, and based on SystemID or CAVS parameter, we can route it to any place without doing any code change. At the end your Java Embed looks something like this:

AIAConfigurationProperties.xml:


Java Embed:





Functional point of view it looks great, but technically - holy crap! 93 lines of non reusable code copied for every partner-link and every BPEL process.


I took initiative to eliminate the code for and obviously the best option was to use Oracle BPEL XPath Function. Initial functionality didn't take long time to develope BPEL function and register them to BPEL RT engine, but making addAuditTrailEntry working in my custom function was an amazing experience. Rather than going too much into details, would just go with final product. I created two separate bpel functions:

1) ora:getSimpleDynamicURL (simpler version)

This function gets dynamic URL from AIAConfigurationProperties.xml.
The signature of this function is : ora:getSimpleDynamicURL ('serviceName', 'partnerlinkName', 'auditTrail'?)
auditTrail: true/false, it is optional and default value is true.


2) ora:getDynamicURL (richer version)

This function gets dynamic URL from AIAConfigurationProperties.xml.
The signature of this function is : ora:getDynamicURL ('serviceName', 'partnerlinkName', 'ebmMsgBpelVariableName', 'ebmMsgPartName', 'auditTrail'?)
auditTrail: true/false, it is optional and default value is true.


If I look at my BPEL process now, it looks like the way it supposed to. I can get TargetEndpointLocation from AIAConfigurationProperties.xml based on parameters, and hallelujah!



It just reminds me the most basic programming tip which my friend told me: "Don't do copy and paste, just do cut and paste.

Thursday, March 4, 2010

Namespace agnostic XPath/XQuery

Problem Description

I have two different type of XML files, both have multiple namespaces in it. First one contains prefixes along with namespaces, where second one doesn't. The question is how do I find title (Organization->Person->title) using XPath or XQuery?



Solution - 1 (Aware of Namespace)

The standard way (which I don't recommend) of doing this would be to create XPath resolver and register all the namespaces with it. I created external properties file with all the namespace like below (Note: Namespace prefix doesn't have to match between XPath and XML Input Payload (e.g. org to org1). Only namespaces has to match.):


Now, I started writing a method which does Xpath resolution.

For this method, I had to create a class for Namespace resolution. I wrote a class which resolves namespaces based on property file:


That's it, now if you provide /org1:Organization/person1:Person/person1:title as XPath to this program, it can evaluate it as "Engineer"! I was not too impressed with this approach because everytime payload comes up with change/addition in namespace, I have to maintain my property file. In small organization it might workout OK, but in rapidly changing world I can not imagine it would work at all.



Solution - 2 (Namespace Agnostic XPath/XQuery)

For this, I wrote method which doesn't require any Namespace Context. E.g.


Now the trick is in the XPath, I wrote XPath: /*[contains(name(),'Organization')]/*[contains(name(),'Person')]/*[contains(name(),'title')]. This XPath resolves to "Engineer" given XML payload and it doesn't require any namespace. Correct way of writing this XPath would be to [name()='Organization' or ends-with(name(),':Organization')], but unfortunately ends-with is not supported with Oracle XML parser, but I don't see any huge issue with current Xpath.


Test

Finally I just wrote test case to test this out, e.g.


Ran the test, and I could not be more happier after looking at the results:




FYI, just found two more approaches to write name space agnostic XPath:
a) /*[local-name()='Organization']/*[local-name()='Person']/*[local-name()='title']
b) //*[local-name()='title']

Wednesday, March 3, 2010

JAZN Security - Hacked

I guess pretty much everybody in Oracle community knows that Oracle supports indirect password (for data-sources.xml) via file based security system (Jazn). All the container passwords e.g. oc4jadmin, bpeladmin are also stored in Jazn. File name is $ORACLE_HOME/j2ee/<<container_name>>/config/system-jazn-data.xml

There are multiple ways to implement indirect password, and you can go through http://download.oracle.com/docs/cd/B31017_01/web.1013/b28957/deploysimple.htm#BABCCIFH if you really using it first time.
- You can use EM to use indirect password
- You can change data-sources.xml and put ! infront of password.
- You can put "->USERNAME" and create that USERNAME in Jazn with indirect password using EM

Anyways, back to the main problem, passwords are stored in encrypted form in system-jazn-data.xml, so people who has access to the file system would not know clear text password. The encryption algorithm used was way too weak to break. I would avoid putting the solution on my blog just to avoid hacking encouragement.

I would assume the person who wrote encryption algorithm for Jazn was either too lazy or didn't want to implement it correctly, because I believe an average Java programmer can decrypt system-jazn-data.xml in less than 30 minutes.

Tuesday, March 2, 2010

ESB Interceptor

I guess I am pretty late on this blog, I had this working 2 years ago, and implemented it for more than 2 clients over last two years and now probably does not value that much. I still thought to share it and it is a little bit documented in http://download.oracle.com/docs/cd/E12524_01/relnotes.1013/e12523/esb.htm as well.

Basically, implementing IEsbMessageInterceptor interface, which looks something like this (You probably have to tweak it little bit as IEsbMessageInterceptor has been changed from 10.1.3.4 to 10.1.3.5).

public class CustomESBInterceptor implements IEsbMessageInterceptor {
public CustomESBInterceptor() {
System.out.println("Initializing Custome Interceptor");
}

public void invoke(FlowId pFlowId, String pInstanceId, Element pPayload, Element pHeader, String pServiceName, String pSystemName, boolean isOutbound) {
System.out.println("----------------------------------------");
System.out.println("Custom Interceptor ");
System.out.println("FlowId: " + pFlowId + " subflowid: " + pFlowId.getSubFlowId() );
System.out.println("instanceid: " + pInstanceId);
System.out.println("Header: " + XMLHelper.toXML(pHeader));
System.out.println("payload: " + XMLHelper.toXML(pPayload));
System.out.println("Service: " + pServiceName);
System.out.println("System: " + pSystemName);
System.out.println("----------------------------------------");
}
}

Once we compile this class, we can put the class in bpel/system/classes directory and add following to $ORALCE_HOME/integration/esb/config/esb_config.ini file:

inboundMessageInterceptor = CustomESBInterceptor
outboundMessageInterceptor = CustomESBInterceptor

Just to clarify, just like any other interceptor this is extreamly dangerous point. We should keep following things in mind:
  • Call from ESB runtime to this interceptor is made in synchronous fashion, so if CustomESBInterceptor.invoke errors out, then entire ESB RT will have issues.
  • Another issue is if we are doing any heavy processing in CustomESBInterceptor.invoke, that will affect performance of entire ESB RT. The code in invoke should be absolutely error free and as quick as possible. We should use AQ or another JMS implementation to avoid real time processing if needed.
  • You can possibly change the payload and header values if you want to (it should be avoided for best practices)

BPELConsole Timeout Issue



In 10.1.3.5 Oracle SOA Suite we realized that BPELConsole to load the flow page, often timeouts. It gets worse if you are accessing the BPELConsole remotely or from different country. Error seems something like: failed to load resource: xmlGetAuditTrail.jsp?referenceId=bpel%3A//localhost/<<domain-name>>/<<process-name>>%7E1.15/431669&id3j0son2=1

After doing extensive digging in the JSP code a little bit, I found that one of the Java Script which was making server call had 20 second timeout!! After bumping up that to higher number, I was able to resolve that issue. Here is the fix:

$ORACLE_HOME\j2ee\oc4j_soa\applications\orabpel\console\ui\util2\1001.js
(search for rInfo.timeout)
increase timeout from 20 to 200

Monday, March 1, 2010

BPEL Title WildCard Search

I probably would be blogging on setting title for BPEL processes in non-intrusive way, but have to get through couple of hurdles before I get there. It is quite common practice to set Titles for BPEL process so that you can search from BPELConsole.

e.g. setTitle("Title = " + title); //in embedded Java (you can also look at http://blogs.oracle.com/pt/2009/02/searching_bpel_process_instanc_1.html if you are interested on how to use title in intrusive way)

The problem people complain is that BPEL title search doesn't support wild card search. It only supports exact search. While looking through BPELConsole JSP, I found this was quite easy change it from exact search to wild card search. The query was getting generated as part of $ORACLE_HOME/j2ee/oc4j_soa/applications/orabpel/console/ngInstanceList.jsp. To change exact title search to wild card search, here is the change required:

- In $ORACLE_HOME/j2ee/oc4j_soa/applications/orabpel/console/ngInstanceList.jsp, search for keyword called instanceTitle, you should see something like:

String instanceTitleQ = request.getParameter( "instanceTitle" );
if ( instanceTitleQ != null && instanceTitleQ.length( ) != 0 )
{
buf.setLength( 0 );
tmpWhere.setClause( buf.append( n++ > 0 ? " AND " : "" )
.append( SQLDefs.AL_ci_title )
.append( " = ? " )
.toString() );
tmpWhere.setString( 1, instanceTitleQ );
where.append( tmpWhere );
}

You can change it to:

String instanceTitleQ = request.getParameter( "instanceTitle" );
if ( instanceTitleQ != null && instanceTitleQ.length( ) != 0 )
{
buf.setLength( 0 );
tmpWhere.setClause( buf.append( n++ > 0 ? " AND " : "" )
.append( SQLDefs.AL_ci_title )
.append( " LIKE ? " )
.toString() );
tmpWhere.setString( 1, instanceTitleQ );
where.append( tmpWhere );
}


Once it is changed, you can search for Title in BPELConsole using % as wild card character.