Oracle SOA Suite -
Tips, Tricks, Secrets

I've worked fairly extensively with Oracle SOA Suite since 2006 (back when it was 10g). I currently work with a recent version 12c. It is a very capable and mature integration platform, there's not a lot you can't do with it. However, there are plenty of "gotchas". Tricky little quirks to work through to get things to work how you'd expect. Here I document some hard-earned tips and tricks. I work with both OSB (Oracle Service Bus) and BPEL, but I definitely prefer BPEL due to its clearer way of illustrating process flows and tracking results. 

Interestingly these 2 main components of SOA Suite almost compete with each other, as you can use either for most integration processes. These are both part of SOA Suite as they are the result of acquisitions made by Oracle over time. Firstly Oracle acquired Collaxa Inc. (BPEL/BPMN engine) in 2004, then Oracle acquired BEA Systems Inc. in 2008 (WebLogic and AquaLogic Service Bus or ALSB which became OSB). The Oracle in-house ESB became Mediator. 

The overall result is a productive, reliable, high performance, superb middleware integration platform (and I'm not even getting paid for this!).

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

Diagnosing Database Adapter Issues

Using Diagnosability Reports you can quickly and easily identify issues with JCA Adapters. For example, we had a project whereby a polling dbAdapter was not reading the records we expected it to. We had a Db column STATUS, a certain value to trigger the adapter to read the records and do a "logical delete"  (i.e change STATUS value, so the same records don't get read again). Couldn't see the problem. This adapter was joining 3 related tables (1:n:n) to retrieve a relational dataset. The issue wasn't appearing in the logs. (soa_infra -> Logs -> View Log Messages -> Search for [Composite_Name]

To get the issues to appear in the logs...  Go to the Composites' Home Page, under Services and References, click on the errant dbAdapter, go to the tab Adapter Reports and click Enable Reports...

Give it a few moments to take effect and you'll see the page change and start to show reporting details. Leave this setting in place for a few cycles of the polling adapter. In our case the adapter polled every 10 seconds so a minute was enough to capture a few instances of the error condition.
Search the logs again (same as above, just using the composite name) and viola!

This shows us the error (in our case) is caused by an unexpected column name in one of the joined tables. This was due to a deployment issue, where an old script had been used to create the table.  ORA-00904: "XX"."REG_CONTENT_CODE": invalid identifier


Go back to the Composite/dbAdapter and Disable Reports. 

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

BPEL Flow Instances - Display a Custom Value

The BPEL Instances Audit is great. It lets you see all the instances that are running / have been run. You can even get it to display a custom value from within your process, to make it easier to see what you need to.

Assign this to a dummy variable: - oraext:setFlowInstanceTitle($Variable_of_Choice).  In the BPEL Flow Instance list you will see your custom value appear in the Name column.

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

BPEL: Sending Custom HTTP Headers

I'm not the first to document this, but I like to keep things simple and easy to find, so here's my take on this. You have a BPEL process which makes a call to some SOAP web service (i.e a "reference"). Say you need this call to send a custom HTTP header (not to be confused with a SOAP header). In the Invoke you need to set the header Name and Value like so... (the value can also come from a variable).

Other people around the 'net seem to tell you this part, and it is required, but on it's own it doesn't work, you also need the next part...
In the composite.xml you need to "declare" the required HTTP header (i.e the header name) like this...

Now it all works as you'd expect.

It should be noted that this doesn't apply to the ReST adapter. The Rest adapter already handles custom HTTP headers when you set a property in the Invoke component namely rest.binding.http.header-name. The Rest adapter essentially strips out the preceding 'rest.binding.http.' and sends out the header-name and value in the HTTP request.

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

FTP File List

Often within an integration process you need to get a simple listing of the files on a remote (s)FTP server. For this you can configure the FTP adapter to perform a List operation. I won't go into the details here as it's clearly documented both in the product manuals and all over the 'net already. However, I spent too much time getting this to actually work. It kept producing an empty file list. After trying many settings variations to no avail, I finally enabled trace-level logging on the FTP adapter in my test environment (EM->Server->Log configuration->oracle.soa.adapter->oracle.soa.adapter.ftp, set trace to Finest, [Apply]), ran my test process, examined the resulting log file (<servername>-diagnostic.log) and found an interesting little morsel of information...

...blah blah...inside directory: /<dirname>. 2*MaxRaiseSize used to limit number of files returned is: -2. Number of files in FileList is: 0

Reading the product doco, the MaxRaiseSize setting limits how many results the adapter will return. Neither the JDeveloper wizard nor I, had set a value for this, so I can only assume "-2" was a default or a global server/environment setting(?). Explicitly setting this to a sensible number in the JCA file got it producing the expected file listing (doh! mutter, mutter).

e.g add this line in the JCA file for this adapter will return a maximum of 1000 file list items...

<property name="MaxRaiseSize" value="1000"/>

Remember to set logging back to your previous settings, Trace-Finest is very verbose!

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

DbAdapter; Inserting into a table that has an auto-generated id/key

Some years back Oracle introduced auto-generated keys. This allows you to create a table that has a unique ID column whose value is GENERATED [ ALWAYS | BY DEFAULT [ ON NULL ] ] AS IDENTITY [ ( identity_options ) ] It's a great feature that makes things easier. However, if you use SOA Suite DbAdapter to insert into a table with this, you may get an error ORA-32795: cannot insert into a generated always identity column.  Some non-SOA database developers and DBA folks just use GENERATED ALWAYS AS IDENTITY, and make it the primary key, which SOA Suite (Toplink) will use when it generates the table artifacts. If you change this to ...GENERATED BY DEFAULT ON NULL AS IDENTITY..., then ensure to pass in either no value or null for the ID column... then all will be well.   

Alter table <my_table> modify <id_column> generated by default on null as identity ... [etc. e.g sequence syntax];

If, for any reason (e.g Merge/Upsert an empty column value), you need to force the output of a node to have a null value, use... <nodeName xsi:nil="true"/>

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

Preventing BPEL Flow Instance recording

There are times when you want to prevent the BPEL engine from recording instances. This might apply to processes that are frequently invoked, creating many instances over a short period of time. You may not need them all recorded and may need to conserve repository resources to maintain performance etc. You can set a BPEL process to record an instance only when a fault occurs instead of always. You can do this by setting the property bpel.config.completionPersistPolicy to a value of 'faulted' within the BPEL Component definition in the composite.xml file, like so...

Note: This property is used only when the inMemoryOptimization property is set to true, and that setting is only effective if the process does not have dehydration points. Activities such as wait, receive, onMessage, and onAlarm create dehydration points in the process.  Read more detail in the Oracle Documentation


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

Preventing ESS Schedules from executing queued up (in the past) jobs on startup


When you restart ESS for any reason, by default it seems to queue up all the jobs it was meant to run during the downtime. When it comes back up, they all start to execute, like it's "catching up"!

To prevent this behaviour you must set a specific System Property in each job definition. Set SYS_executePast = false. 

As always, check out the Oracle doco for full details...

https://docs.oracle.com/middleware/12211/ess/administer-scheduler/GUID-773B2FBE-D7D6-4698-9106-99361FE41EA8.htm#ESSAG4127


=================================================================================
Error: oracle.tip.tools.ide.fabric.addin.CompositeNode cannot be cast to oracle.sb.tooling.ide.sca.internal.sca.SbCompositeNode


If you open an OSB composite in JDeveloper that was saved using an older version (of 12c or 11g) you can sometimes get this error. 

The workaround is simple. Open the <your_project>.jpr file in a text editor (e.g Notepad++) and remove (or comment out) the line <string v=”SOA”/> as highlighted below.

Save, then restart JDeveloper. When you open the OSB composite all will be well.

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

BPEL x Instances or Singleton

There are times when you may want to limit the number of instances of a composite that can be running at once. I've seen people do this using flags in a database table to indicate if instances are running. The problem with this approach is because it's controlled by the actual process itself, things can and do go wrong. For example instance xxx gets an exception and aborts without resetting the flag, then when next instance starts (e.g from an ESS event), it falsely detects an instance already running, so the process effectively never runs again, until someone discovers this and resets the flag(!). 

A more reliable approach is to check the SOA repository database to see if any other instances of your process are already in the running state.

You will need a JCA database adapter that connects to SOA infra (e.g we have eis/DB/soainfra which uses the username orabpel), and run the query SELECT cikey FROM cube_instance WHERE component_name={process_name} AND state < 1.  Where {process_name} comes from assigning  ora:getComponentName()

This returns a set of the running instances. If count({the_output_var}) > 1 then there are other instances of this process running (i.e more than this instance). Terminate if there are others. You've achieved your goal.

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