Guidelines for Calling Web Services in Order Management Extensions

Apply these guidelines when your extension calls a web service.

Process Calls to Your Web Services

If you use the invokeSoapService method more than one time in your code, then make sure you finish processing the response from the first call before you make the second call.

Correct Code

Line Code
1 def serviceInvoker = context.getServiceInvoker();
2 def response1 = serviceInvoker.invokeSoapService("connector1",payload).getSoapBody();
3 String tagStorageLimitDays = response1.getElementsByTagNameNS("*", "tagStorageLimitDays").item(0)?.getTextContent()?: 0;
4 def response2 = serviceInvoker.invokeSoapService("webservice2", payload).getSoapBody();
5 String status = response2.getElementsByTagNameNS("*", "status").item(0)?.getTextContent()?: "failure";

This code processes the response from webservice1 before it calls webservice2. This is how you should write your code.

  • Line 2 calls web service webservice1 and line 3 processes the response from webservice1.
  • Line 4 calls web service webservice2 and line 5 processes the response from web service webservice2.

Incorrect Code

Line Code
1 def serviceInvoker = context.getServiceInvoker();
2 def response1 = serviceInvoker.invokeSoapService("webservice1", payload).getSoapBody();
3 def response2 = serviceInvoker.invokeSoapService("webservice2", payload).getSoapBody();
4 String tagStorageLimitDays = response1.getElementsByTagNameNS("*", "tagStorageLimitDays").item(0)?.getTextContent()?: 0;
5 String status = response2.getElementsByTagNameNS("*", "status").item(0)?.getTextContent()?: "failure";

This code will fail because line 3 calls webservice2 before line 4 has a chance to process the response from webservice1. This happens because the response from webservice1 is no longer available.

To avoid this problem, process the response from the first call before you make the second call.

As an alternative, you can add the extractContentAsDocument method to make sure the extension finishes extracting the response from the first call. For example:

Line Code
1 def serviceInvoker = context.getServiceInvoker();
2 def response1 = serviceInvoker.invokeSoapService("webservice1", payload).getSoapBody().extractContentAsDocument();
3 def response2 = serviceInvoker.invokeSoapService("webservice2", payload).getSoapBody();
4 String tagStorageLimitDays = response1.getElementsByTagNameNS("*", "tagStorageLimitDays").item(0)?.getTextContent()?: 0;
5 String status = response2.getElementsByTagNameNS("*", "status").item(0)?.getTextContent()?: "failure";

Line 2 calls the extractContentAsDocument method in the SOAPBody object to make sure the extension finishes extracting the response from webservice1 before it calls webservice2.

Use Method and Create Connector

extension that calls a web service

Note

  1. Use the invokeSoapService method in your extension to call the web service.

    You can call an Oracle Application web service or some other service that resides outside of Oracle Applications. You can call only a SOAP service. You can't call REST API. For details and examples, go to REST API for Oracle Supply Chain Management Cloud, expand Order Management, then click Sales Orders for Order Hub.

  2. Set up the connector.

    Note: You must use the Manage Connector Details page to set up a connector for the web service that you reference in your extension.

    Set these values.

    Attribute

    Value

    Connector Name

    Use the exact same name that you use in the extension. For example:

    invokeSoapService("FundsCapturePaymentMethod") 

    For this example, set Connector Name to FundsCapturePaymentMethod.

    Connector URL

    Enter the URL that locates the web service address that you deploy on the system that resides outside of Order Management.

    User Name

    Enter the user name you use to sign into the web service.

    Password

    Enter the password you use to sign into the web service.

    Invocation Mode

    You must use Synchronous Service.

    For details, see Manage Connector Details Between Order Management and Your Fulfillment System.

Create the Payload

payload that calls a web service

Note

  1. Create the payload. This example uses String payLoad to hard code the payload as a string. You can also use other techniques to meet your requirements, such as defining variables in the payload.

  2. Reference your payload definition in a parameter of the invokeSoapService method. This example references string payLoad.

  3. Use the getSoapBody method to handle the response that the web service sends in reply to your request. Your extension can receive the response, parse it, then extract the details it requires from the response.

  4. Create your payload so it includes only the main content. Don't include envelope or body details. invokeSoapService expects only the main content. It will add envelope and body details.

Extract Details from Web Service Response

The getSoapBody() call on the response object in a web service response is an instance of Java class for a SOAP body (Simple Object Access Protocol). For details, see Interface SOAPBody. Use the methods that are available on these interfaces to extract details from a web service response.

This example order management extension uses methods from these interfaces to extract data from the response.

import oracle.apps.scm.doo.common.extensions.ValidationException;
import oracle.apps.scm.doo.common.extensions.Message;

def poNumber = header.getAttribute("CustomerPONumber");

if( poNumber != "CreditCheck" ) return; 

// get attribute to populate in the payload
String customer = header.getAttribute("BillToCustomerName");
Long accountId = header.getAttribute("BillToCustomerIdentifier");
BigDecimal amount = new BigDecimal(1000);

// prepare the payload
String payLoad = "<ns1:creditChecking xmlns:ns1=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/types/\">" +
 "<ns1:request xmlns:ns2=\"http://xmlns.oracle.com/apps/financials/receivables/creditManagement/creditChecking/creditCheckingService/\">" +
  "<ns2:CustomerName>" + customer + "</ns2:CustomerName>" +
  "<ns2:CustomerAccountNumber>" + accountId + "</ns2:CustomerAccountNumber>" + 
  "<ns2:RequestType>Authorization</ns2:RequestType>" + 
  "<ns2:PriceType>ONE_TIME</ns2:PriceType>" +
  "<ns2:RecurrencePeriod></ns2:RecurrencePeriod>" +
  "<ns2:RequestAuthorizationAmount currencyCode=\"USD\">" + amount + "</ns2:RequestAuthorizationAmount>" +
  "<ns2:RequestAuthorizationCurrency>USD</ns2:RequestAuthorizationCurrency>" +
  "<ns2:ExistingAuthorizationNumber></ns2:ExistingAuthorizationNumber>" +
  "<ns2:Requestor>ar_super_user</ns2:Requestor>" +
  "</ns1:request>" +
  "</ns1:creditChecking>";

// Use the CreditCheckService web service connector to the Check Check service. You use the Manage External Interface Web Service Details task to set up the connector. Since this is a service that is secured
// using message protection policy, we have registered the the https URL of the service
def response = context.invokeSoapService("CreditCheckService", payLoad); 

// print a debug message. This appends the entire response to the shipping instuctions attribute. 
// To avoid performance problems, you must comment out all debug statements in your production environment.
debug(response.getSoapBody().getTextContent());

// The response XML sent by the Credit Check service contains an element named 'Response'. A YES value indicates that credit check passed. Let us extract the contents of Response tag. The following XML API will return all nodes (tags)
// with name 'Response' in a NodeList element. We are expecting only one such element in our XML response
def nodeList = response.getSoapBody().getElementsByTagNameNS("*", "Response");

// print out the lenght of the node list
debug(nodeList.getLength());

// Get the first element with name 'Response' (we are expecting only one), and gets its text content
String ccResponse = nodeList.item(0).getTextContent();

debug(ccResponse);

// Check if credit check passed
if( ccResponse != 'YES' ) {
 // Credit check failed. Raise a warning validation exception here
 throw new ValidationException( new Message(Message.MessageType.WARNING, "Credit check failed.") );
}
else {
 // Credit check passed
 // Write the credit check response in an EFF attribute.
 def psiContext = header.getOrCreateContextRow("ComplianceDetails");
 psiContext.setAttribute("_ComplianceInfo", ccResponse);   
}

/**
* Appends passed in msg to the Shipping Instructions attribute. This method has been implemented only for debugging purposes.
*/
void debug(def msg) {
 String si = header.getAttribute("ShippingInstructions");
 header.setAttribute("ShippingInstructions", si + ", " + msg.toString());
}

Inspect Payloads When You Use Web Services or Public View Objects

It might be difficult to examine the response from a web service or from the view criteria of a public view object. Use the setAttribute method during development to get values for the attributes that your code references, display them in the Order Management work area, then examine these values to verify your code returns the values you expect.

using the setAttribute method during development

For example, assume your extension references shipping instructions. You can use this code to write the contents of ShippingInstructions into the response from the web service.

header.setAttribute("ShippingInstructions", response.getSoapBody().getTextContext());

You can write the same data into the response from a public view object.

Make sure you convert your test code to log files or comment it ( // ) before you deploy to production.

You can also write a message to achieve a similar result. However, a message stops or pauses processing. Use a payload so processing can continue without interruption, and so you can view attribute values in the context of how they display in the Order Management work area, such as the Shipping Instructions attribute on the order line.