The Mediator component in SOA Suite 11g has a the option to specify a Java Callout, one for every WSDL operation. The Java Callout refers to a Java Class, either on the SOA Suite’s classpath or deployed as part of the SOA Composite application. This class should implement interface oracle.tip.mediator.common.api.IJavaCallout and a convenient way of doing so is by extending AbstractJavaCalloutImpl in package oracle.tip.mediator.common.api.
The Java Callout is invoked by the Mediator on a number of times, prior to and after performing the Routing Rule and each of the cases in it. The Java Callout class can implement a number of methods, one for each specific event or stage in the Mediator process. These methods get access to the input message as well as the transformation result. That means that the callout class can inspect, validate, log, audit and even manipulate these messages, their payloads, headers and properties. Interestingly enough, the methods are not static what I thought might be the case. The first one to be called is an initialize() that has you initialize the callout class instance to prepare the object for further callout processing. This means that all stages in a single Mediation action are processed by the same callout object. This allows you to compare for example the pre and post transformation values.
The methods that the callout interface specifies are: initialize, preRouting (before any routing rule cases are processed), preRoutingRule (before one specific routing rule is processed), preCallbackRouting (This method is called before Mediator finishes executing callback handling. You can customize this method to perform callback auditing and custom fault tracking.) , postCallbackRouting, postRoutingRule, postRouting.
This article shows a simple example of creating a SOA Composite Application – the simplest one you can create I believe using the new 11g feature of Echo – with use of the Java Callout class.
The steps to go through are fairly straightforward:
1. Create a new Application in JDeveloper of template SOA; select the option Composite with Mediator. I have called the Application and the Project MediatorCallout.
2. In the Create Mediator dialog, select the option Synchronous interface.
This creates a Mediator with a WSDL and XSD that specifies an input message consisting of a single string and and response message with that same content.
3. Create a new static routing rule – of type Echo
This is a new 11g feature that creates a simple short cut: the request is received, validated if so desired, transformed and returned to the invoker. No reference needs to be involved. This is what makes this the simples SOA Composite application – even simpler than the previous champion, the synchronous hello world BPEL process.
4. Create the transformation between request and response – by clicking on the transformation or mapping icon.
Have a new mapper file created. Press the OK button to go to the mapper editor and define the mapping.
5. Complete the mapping
Connect the input element in the source/input/.request (left side) to the input element under the singleString element on the right side (target/response).
At this point, the simplest SOA Composite application in the world is done. You can deploy it and invoke it. You send a string to it and receive the exact same string in return. By all means, try it out. But of course we are only just getting to the beef of this article.
6. Create a new Java Class in your project, under SCA-INF/src. Mine is called MediatorCalloutProcessor. This class should extend the class AbstractJavaCalloutImpl, that provides default (no-op) implementations for all methods defined in the interface oracle.tip.mediator.common.api.IJavaCallout.
package nl.amis.soasuite11g; import oracle.tip.mediator.common.api.AbstractJavaCalloutImpl; public class MediatorCalloutProcessor extends AbstractJavaCalloutImpl{ }
Now it is time to flesh out this class and have it actually do something – like intercepting the response message the Mediator has prepared for returning and inspecting & logging it.
Override the postRouting method. This method is invoked when the response message has been prepared.
@Override public boolean postRouting(CalloutMediatorMessage calloutMediatorMessage, CalloutMediatorMessage calloutMediatorMessage2, Throwable throwable) throws MediatorCalloutException { System.out.println("Mediator has invoked Java Callout; executing postRouting"); boolean returnValue = super.postRouting(calloutMediatorMessage, calloutMediatorMessage2, throwable); String sPayload = "null"; for (Iterator msgIt = calloutMediatorMessage2.getPayload().entrySet().iterator();msgIt.hasNext(); ) { Map.Entry msgEntry = (Map.Entry)msgIt.next(); Object msgKey = msgEntry.getKey(); if (msgKey.equals("reply")) { Object msgValue = msgEntry.getValue(); sPayload = XmlUtils.convertDomNodeToString((Node)msgValue); System.out.println("Mediator sends reply: " + sPayload); } } //for return returnValue; }
Here we print two messages to the output (the command window in which the soa_server1 is running). The first message is just an indication that the Java Callout is invoked. The second one is more interesting: it shows the content of the Response Message that is about to be returned to the invoker.
The code loops over the documents in the payload of the CalloutMediatorMessage. When it finds the only that is associated with the key reply we have found the response message, that we can then write to the output.
7. Configure the Mediator to invoke the Java Callout
8. Deploy the SOA Composite application to the SOA Suite
9. Invoke the application from the FMW Control in Enterprise Manager; provide some input and verify that the input is echoed in the response message.
Then inspect the output in the soa_server1 command window – to see whether the call out has taken place:
Manipulating the response in the Java Callout class
A Java Callout class is potentially even more useful if it not just reads the messages, but manipulates them as well. As a very simple example, we will replace the response message with some XML document of our own design. One by the way that does not comply with the XSD definition for the request message – not something you should do in real life of course.
The code in the Java Callout class is slightly extended:
@Override public boolean postRouting(CalloutMediatorMessage calloutMediatorMessage, CalloutMediatorMessage calloutMediatorMessage2, Throwable throwable) throws MediatorCalloutException { System.out.println("postRouting"); boolean returnValue = super.postRouting(calloutMediatorMessage, calloutMediatorMessage2, throwable); String sPayload = "null"; for (Iterator msgIt = calloutMediatorMessage2.getPayload().entrySet().iterator();msgIt.hasNext(); ) { Map.Entry msgEntry = (Map.Entry)msgIt.next(); Object msgKey = msgEntry.getKey(); if (msgKey.equals("reply")) { Object msgValue = msgEntry.getValue(); sPayload = XmlUtils.convertDomNodeToString((Node)msgValue); try { XMLDocument changedoc; changedoc = XmlUtils.getXmlDocument(sPayload); XMLNode input = (XMLNode)changedoc.selectSingleNode("//inp1:input", new LocalNamespaceResolver()); System.out.println("the value of the input element = " + input.getTextContent()); XMLDocument doc = prepareReturnMessage(input.getTextContent()); String mykey = "reply"; calloutMediatorMessage2.addPayload(mykey, doc.getDocumentElement()); } catch (Exception f) { System.out.println(f); } } } //for return returnValue; }
And uses a helper method and private class to construct the response document:
private XMLDocument prepareReturnMessage(String input) throws ParserConfigurationException { JXDocumentBuilderFactory factory = (JXDocumentBuilderFactory)JXDocumentBuilderFactory.newInstance(); JXDocumentBuilder documentBuilder = (JXDocumentBuilder)factory.newDocumentBuilder(); XMLDocument doc = (XMLDocument)documentBuilder.newDocument(); doc.setVersion("1.0"); doc.setEncoding("UTF-8"); XMLElement hospitalElement = (XMLElement)(doc.createElement("hospital")); doc.appendChild(hospitalElement); XMLElement surgeonElement = (XMLElement)(doc.createElementNS("http://specialDoctorNamespace", "doc:surgeon")); hospitalElement.appendChild(surgeonElement); XMLText title = (XMLText)doc.createTextNode("Input After Manipulation " + input.toLowerCase().replace('e','x').replace('a','x')); surgeonElement.appendChild(title); return doc; } class LocalNamespaceResolver implements NSResolver { public String resolveNamespacePrefix(String prefix) { if ("inp1".equalsIgnoreCase(prefix)) { return "http://xmlns.oracle.com/singleString"; } return null; } }
Note: you need to add the library Oracle XML Parser v2 to the project, in order to use the XMLDocument, XMLNode, XMLElement and XMLText classes.
When we deploy and run the SOA Application, regardless of our input, the response message looks something like:
The output in the console window displays:
Resources
Download JDeveloper 11g Application: MediatorCallout.zip.
During development if we just add the external jar to SCA-INF/lib , will Jdeveloper or Ant script be able to find the jar ?
Â
We are getting error at compile time that external jar classes are not found? Where else do we need to add at compile time apart from SCA-INF/lib directoryu
Hi Abhay,
It would seem to be that my reply to Sumit probably is your solution as well.
Lucas
Hi Sumit,
I am not sure I understand your question. Could you not simply create two Mediator Components and have the first one call the second? You can create a routing rule for the Reply from the first service call to be forwarded to the second – including the original request as well. The filter can then be specified in this second Mediator.
The complement to Chapter 7 in the Oracle SOA Suite 11g Handbook contains a detailed example of this type of enrichment. See: https://4547611390595480921-a-1802744773732722657-s-sites.googlegroups.com/site/soasuite11ghandbooksupmat/supporting-materials/SOA_CH07_ChapterComplement_PartOne_18April2010.pdf?attachauth=ANoY7cpeaxluCxuH9l-xg0rY7sEYMrNjH_sojYq1Lk8FHwnqHtRNYqc2d4JPqvtJzIqOeSPlcLCqOlGI1kjOi2pC3W3DEMwSF8vOMOSUxP5Kg0sA_IYXZhB9z7tdwlnRh31GGotrHj1hPquAVb30zjg_h0-179JfvQOAZg_SKknPw6d9P-PYU2hjE1leaQUKM3gRJtGyIENtDpZ6js79nz2qdmbbkkqLHAcRK3VNvVJ1C3PqwvdwvbFsl98fi732AZC_hK_5EQVptsEx3IueoiGCMLdtLiWuxTt4P_v9x_HRtRK3P0s3Hsw%3D&attredirects=1
My colleague Edwin also describes a solution using Spring Component and more custom Java programming. See: http://biemond.blogspot.com/2010/06/enriching-and-forwarding-your-data-with.html
Lucas
Hi C Soneson,
Yes, I believe the SOAP Header can be manipulated as well.
Lucas
Hi Lucas,
My req is thatthe mediator should first call a webservice and get some data. This original request to the mediator has to be enriched with this data and then conditionally call the second process. The condition to call the second process depends on the output of the first call, basically i need to add a filter for the second call and that filter should be based upon the output of the first call. Also if the filter expression evaluates to true, the input of the second process should be the enriched input.
i am calling two processes from My mediator. Is it possible to pass the output of first process as input to the second process. I have a filter condition to be applied only for the second process. This filter condition depends on the output of the first process.
Awesome . I was stuck with one transformation. this post definitely helped . esp the prepareReturnMessage function
Well done! Do you know if the SOAP header elements can be manipulated as well?
Excellent post, Lucas! Kudos!
I am fairly new to SOA Suite and I am looking for a way to perform fairly complex message validation/manipulation…. Java seems to me the most obvious choice, relegating OBR, Schematron and XSL to simpler, standard cases.
YET Java support for XML manipulation is quite bad, you must write convoluted code to get things done…. I wish Oracle introduces “Groovy Callout”, Groovy handles XML in a much more elegant way…
For an example of Groovy Callout in OSB (not in SOA Suite, but I think the same can be done) here is a post: http://blog.aujava.com/?p=64
Excellent post, Lucas! Kudos!
I am fairly new to SOA Suite and I am looking for a way to perform fairly complex message validation/manipulation…. Java seems to me the most obvious choice, relegating OBR, Schematron and XSL to simpler, standard cases.
YET Java support for XML manipulation is quite bad, you must write convoluted code to get things done…. I wish Oracle introduces “Groovy Callout”, Groovy handles XML in a much more elegant way…
For an example of Groovy Callout in OSB (not in SOA Suite, but I think the same can be done) here is a post: http://blog.aujava.com/?p=64
Â
Â
Â