When you import a WSDL in Salesforce, Salesforce autogenerates two Apex classes for each namespace in the imported WSDL. One class is the service class for the synchronous service, and the other is a modified version for the asynchronous service. The autogenerated asynchronous class name starts with the Async prefix and has the format AsyncServiceName. ServiceName is the name of the original unmodified service class. The asynchronous class differs from the standard class in the following ways.
You can generate Apex classes from a WSDL in the Salesforce user interface. From Setup, enter Apex Classes in the Quick Find box, then select Apex Classes.
To make asynchronous Web service callouts, call the methods on the autogenerated asynchronous class by passing your Continuation instance to these methods. The following example is based on a hypothetical stock-quote service. This example assumes that the organization has a class, called AsyncSOAPStockQuoteService, that was autogenerated via a WSDL import. The example shows how to make an asynchronous callout to the service by using the autogenerated AsyncSOAPStockQuoteService class. First, this example creates a continuation with a 60-second timeout and sets the callback method. Next, the code example invokes the beginStockQuote method by passing it the Continuation instance. The beginStockQuote method call corresponds to an asynchronous callout execution.
public Continuation startRequest() { Integer TIMEOUT_INT_SECS = 60; Continuation cont = new Continuation(TIMEOUT_INT_SECS); cont.continuationMethod = 'processResponse'; AsyncSOAPStockQuoteService.AsyncStockQuoteServiceSoap stockQuoteService = new AsyncSOAPStockQuoteService.AsyncStockQuoteServiceSoap(); stockQuoteFuture = stockQuoteService.beginStockQuote(cont,'CRM'); return cont; }
When the external service returns the response of the asynchronous callout (the beginStockQuote method), this callback method is executed. It gets the response by calling the getValue method on the response object.
public Object processResponse() { result = stockQuoteFuture.getValue(); return null; }
The following is the entire controller with the action and callback methods.
public class ContinuationSOAPController { AsyncSOAPStockQuoteService.GetStockQuoteResponse_elementFuture stockQuoteFuture; public String result {get;set;} // Action method public Continuation startRequest() { Integer TIMEOUT_INT_SECS = 60; Continuation cont = new Continuation(TIMEOUT_INT_SECS); cont.continuationMethod = 'processResponse'; AsyncSOAPStockQuoteService.AsyncStockQuoteServiceSoap stockQuoteService = new AsyncSOAPStockQuoteService.AsyncStockQuoteServiceSoap(); stockQuoteFuture = stockQuoteService.beginGetStockQuote(cont,'CRM'); return cont; } // Callback method public Object processResponse() { result = stockQuoteFuture.getValue(); // Return null to re-render the original Visualforce page return null; } }
This example shows the corresponding Visualforce page that invokes the startRequest method and displays the result field.
<apex:page controller="ContinuationSOAPController" showChat="false" showHeader="false"> <apex:form > <!-- Invokes the action method when the user clicks this button. --> <apex:commandButton action="{!startRequest}" value="Start Request" reRender="result"/> </apex:form> <!-- This output text component displays the callout response body. --> <apex:outputText value="{!result}" /> </apex:page>
Testing asynchronous callouts that are based on Apex classes from a WSDL is similar to the process that’s used with callouts that are based on the HttpRequest class.
This example is the test class that corresponds to the ContinuationSOAPController controller. The test method in the class sets a fake response and invokes a mock continuation. The callout isn’t sent to the external service. To perform a mock callout, the test calls these methods of the Test class: setContinuationResponse(requestLabel, mockResponse) and invokeContinuationMethod(controller, request).
@isTest public class ContinuationTestingForWSDL { global static testmethod void testWebService() { ContinuationSOAPController demoWSDLClass = new ContinuationSOAPController(); // Invoke the continuation by calling the action method Continuation conti = demoWSDLClass.startRequest(); // Verify that the continuation has the proper requests Map<String, HttpRequest> requests = conti.getRequests(); system.assert(requests.size() == 1); // Perform mock callout // (i.e. skip the callout and call the callback method) HttpResponse response = new HttpResponse(); response.setBody('Mock response body'); // Set the fake response for the continuation String requestLabel = requests.keyset().iterator().next(); Test.setContinuationResponse(requestLabel, response); // Invoke callback method Object result = Test.invokeContinuationMethod(demoWSDLClass, conti); // result is the return value of the callback System.assertEquals(null, result); // Verify that the controller's result variable // is set to the mock response. System.assertEquals('Mock response body', demoWSDLClass.result); } }