Oracle E-Business Suite Integrated SOA Gateway allows developers to extend the invoker subscription seeded rule function oracle.apps.fnd.wf.bes.WebServiceInvokerSubscription using Java coding standards for more specialized processing.
Developers can extend the seeded rule function to override following methods:
preInvokeService
postInvokeService
addWSSecurityHeader
setInputParts
addCustomSOAPHeaders
For detailed information about these methods, see Oracle Workflow API Reference.
Use the following steps to extend the seeded rule function:
Extend the methods using oracle.apps.fnd.wf.bes.WebServiceInvokerSubscription.
Upload the compiled custom class file at $JAVA_TOP/oracle/apps/fnd/wf/bes/.
Bounce the oacore and oafm servers.
Use the custom rule function oracle.apps.fnd.wf.bes.xxxx while creating the subscription.
Please note that xxxx is the name of extended custom class. For example, oracle.apps.fnd.wf.bes.CustomWebServiceInvoker.
This method is used for pre processing before Web service invocations.
protected String preInvokeService(Subscription eo, BusinessEvent event, WorkflowContext context) throws BusinessEventException;
The Web service input message or request message is available by calling event.getData(). This is the business event payload passed when raising the invoker event or generated by business event Generate function.
This method can perform additional processing on the request data if required. The default implementation through the seeded Java rule function performs XSL transformation using the XSL file specified in WFBES_IN_XSL_FILENAME if input payload message is available.
protected void postInvokeService(Subscription eo, BusinessEvent event, WorkflowContext context, String requestData, String responseData) throws BusinessEventException;
If the operation is synchronous request - response, the response is available in parameter responseData.
This method performs additional processing on the response and update application state if required. The default implementation through seeded Java rule function performs the following tasks:
XSL transformation on a response or Web service output message based on WFBES_OUT_XSL_FILENAME
Call back to Workflow Business Event System based on WFBES_CALLBACK_EVENT and WFBES_CALLBACK_AGENT parameter values
protected void addWSSecurityHeader(ArrayList headersList) throws Exception;
This method adds WS-Security compliant header to the SOAP request. The default implementation through Java seeded rule function adds UsernameToken element to the security header based on event parameters WFBES_SOAP_USERNAME, WFBES_SOAP_PASSWORD_MOD, and WFBES_SOAP_PASSWORD_KEY, and sets the expiration time for the header in the Timestamp element based on the WFBES_SOAP_EXPIRY_DURATION parameter.
This method can be overridden to add any WS-Security header or have custom logic to retrieve username and password to build UsernameToken element. The well-formed XML Element should be added to the ArrayList.
The following code snippet shows WS-Security added to a SOAP header:
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder bldr = factory.newDocumentBuilder();
Document doc = bldr.newDocument();
Element sec = doc.createElement("wsse:Security");
Attr attr = doc.createAttribute("xmlns:wsse");
attr.setValue("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsswssecurity-secext-1.0.xsd");
sec.setAttributeNode(attr);
doc.appendChild(sec);
Element unt = doc.createElement("wsse:UsernameToken");
sec.appendChild(unt);
.... build XML message ....
}
catch (Exception e) {
}
headersList.add(doc.getDocumentElement());
protected void setInputParts(String[] partNames, Hashtable<String,Element> partValues) throws Exception;
Note: The method, setInputParts(WSIFMessage, Input, String) throws Exception;, used in earlier releases is not supported in this release. Any subclass of WebServiceInvokerSubscription that implements this method should be modified to use the new method as explained here. Developers are required only to create org.w3c.dom.Element objects for input part values and set it to the Collections object.
This setInputParts method can be optionally implemented in a subclass of WebServiceInvokerSubscription to set values for all input parts for the operation. The subclass then is used as Java Rule Function for the "Invoke Web Service" event subscription.
This method gives the list of input part names for the operation that is invoked by that specific invocation instance as an array of java.lang.String in parameter partNames. Implementation of this method could set self-contained XML elements of type org.w3c.dom.Element to partValues java.util.Hashtable parameter for each part name as key.
You can use a mix of event parameters, event payload and extension of setInputParts method to pass input part values for a service invocation. For example, one or more of the following combination is possible:
All input part values can be set from implementation of setInputParts method and event payload could be null.
All input part values can be passed to the service invocation framework as business event parameters or payload. Typically event payload will carry the largest part value like the <soap:Body>.
Combination of both above approaches.
If some part values are passed as event parameters or payload and also set from setInputParts method, the value from setInputParts method prevails.
Input part values of type org.w3c.dom.Element for the Web service operation can be set in one of the following two ways:
Pass the XML Element value as event parameters of name WFBES_INPUT_<partname> for each part.
Method setInputParts(String[ ], Hashtable (<String, Element>) throws Exception; can be extended to generate and set XML elements corresponding to each Input part of the Web service operation that is invoked.
The following code snippet shows how this method is used to set values for Input parts 'header' and 'body' by creating Element objects out of hand-coded XML element string:
final protected void setInputParts(String[] partNames, Hashtable<String,Element>
partValues) throws Exception {
String METHOD_NAME = CLASS_PREFIX+"setInputParts(String[],
Hashtable<String,Element>";
writeLog(METHOD_NAME, "BEGIN", Log.PROCEDURE);
String value = "<SOAHeader xmlns:ns1=\"http://xmlns.oracle.com/apps/fnd/soaprovider/plsql/fnd_user_pkg/\>
<Responsibility>SYSTEM_ADMINISTRATOR<Responsibility>
<RespApplication>SYSADMINn<RespApplication>
<SecurityGroup><SecurityGroup>
<NLSLanguage><NLSLanguage>
<Org_Id><Org_Id>
<SOAHeader>";
partValues.put("header", getDocumentElement(value));
value = "<InputParameters
xmlns=\"http://xmlns.oracle.com/apps/fnd/soaprovider/plsql/fnd_user_pkg/testusername/\"><X_USER_NAME>SYSADMIN</X_USER_NAME></InputParameters>";
partValues.put("body", getDocumentElement(value));
value = "<GetTheatersAndMovies
xmlns=\"http://www.ignyte.com/whatsshowing\"><zipCode>32822</zipCode><radius>10</radius></GetTheatersAndMovies>";
partValues.put("parameters", getDocumentElement(value));
writeLog(METHOD_NAME, "END", Log.PROCEDURE);
}
/**
* This function is called to convert String to XML Element
* @param data
* @return
* @throws Exception
*/
public Element getDocumentElement(String data)
throws Exception {
String METHOD_NAME = "getDocumentElement(String)";
Element ret = null;
writeLog(CLASS_PREFIX + METHOD_NAME, "BEGIN", Log.PROCEDURE);
DOMParser parser = new DOMParser();
parser.parse(new StringReader(data));
Document doc = parser.getDocument();
if(doc != null) {
ret = doc.getDocumentElement();
}
writeLog(CLASS_PREFIX + METHOD_NAME, "END", Log.PROCEDURE);
return ret;
}
protected void addCustomSOAPHeaders(ArrayList<Element> customHeaders) throws Exception;
Note: The method addSOAPHeaders used in earlier releases is not supported in this release. Any subclass of WebServiceInvokerSubscription that implements this method should be modified to use the addCustomSOAPHeaders method as explained here. Developers are required only to create org.w3c.dom.Element objects for your custom SOAP header and set it to the Collections object.
This addCustomSOAPHeaders method can be optionally implemented in a subclass of WebServiceInvokerSubscription to set custom SOAP headers for the SOAP request. The subclass then is used as Java Rule Function for the "Invoke Web Service" event subscription.
Implementation of this method could set any number of self-contained XML elements of type org.w3c.dom.Element to customHeadersjava.util.ArrayList parameter. All the XML elements will be added to the SOAP header.
This method helps to add a custom SOAP header to the SOAP request that is not defined in the input message for the WSDL operation that is invoked. For setting values to specific input parts as defined in WSDL operation's input message, use setInputParts method.
The following code snippet shows how this method is used to set custom SOAP headers for a SOAP request:
final protected void addCustomSOAPHeaders(ArrayList customHeaders)
throws Exception {
String custHdr = mEvent.getStringProperty("XXX_CUSTOM_HEADER");
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder bldr = factory.newDocumentBuilder();
Document doc = bldr.newDocument();
doc = bldr.parse(new ByteArrayInputStream(custHdr.getBytes()));
customHeaders.add((Element)doc.getFirstChild());
}
catch (Exception e) {
throw e;
}
}
The following code shows how to extend the addCustomSOAPHeaders method to add any additional Header elements to a SOAP header that are not defined in WSDL:
final protected void addCustomSOAPHeaders(ArrayList customHeaders)
throws Exception {
String METHOD_NAME = CLASS_PREFIX+"addCustomSOAPHeaders(ArrayList)";
writeLog(CLASS_PREFIX + METHOD_NAME, "BEGIN", Log.PROCEDURE);
// Add my own Custom header
writeLog(METHOD_NAME, "Adding Custom header", Log.STATEMENT);
addMyCustomHeader(customHeaders);
// Add more headers if required to the ArrayList
System.out.println("Adding Custom Headers in the sub-class");
writeLog(METHOD_NAME, "END", Log.PROCEDURE);
}
private void addMyCustomHeader(ArrayList headersList)
throws Exception {
String METHOD_NAME = CLASS_PREFIX+"addMyCustomHeader(ArrayList)";
writeLog(METHOD_NAME, "BEGIN", Log.PROCEDURE);
// Adding special SOAP Header to the request. This is required only
// if the WSDL's SOAP binding does not mandate the header but it is
// still required by the service. The XML element should be self-sufficient
// with all namespace declarations local to this element
// In this case, the custom header is passed as an Event Parameter and
// set to the request to avoid hard-coding the header element in code.
// Any element can be passed at the time of raising the invoker business event
String custHdr = mEvent.getStringProperty("XXX_CUSTOM_HEADER");
if (custHdr != null && !"".equals(custHdr)) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder bldr = factory.newDocumentBuilder();
Document doc = bldr.newDocument();
doc = bldr.parse(new ByteArrayInputStream(custHdr.getBytes()));
// Add the element to the Headers list
headersList.add((Element)doc.getFirstChild());
writeLog(CLASS_PREFIX + METHOD_NAME, "Successfully added custom header 1", Log.STATEMENT);
}
catch (Exception e) {
throw new BusinessEventException("Exception when creating header element - "+e.getMessage());
}
}
String custHdr2 = mEvent.getStringProperty("XXX_CUSTOM_HEADER2");
if (custHdr2 != null && !"".equals(custHdr2)) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder bldr = factory.newDocumentBuilder();
Document doc = bldr.newDocument();
doc = bldr.parse(new ByteArrayInputStream(custHdr2.getBytes()));
// Add the element to the Headers list
headersList.add((Element)doc.getFirstChild());
writeLog(CLASS_PREFIX + METHOD_NAME, "Successfully added custom header 2", Log.STATEMENT);
}
catch (Exception e) {
throw new BusinessEventException("Exception when creating header element - "+e.getMessage());
}
}
writeLog(METHOD_NAME, "END", Log.PROCEDURE);
}