2

I'm currently working on a project, which requires flight status information from OAG's On-Demand Flight Status information service (WSDL).

I can test the service with SOAPui. Request:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.oag.com">
       <soapenv:Header/>
       <soapenv:Body>
          <ws:Authenticate>
             <ws:UserId>test</ws:UserId>
             <ws:Password>test</ws:Password>
          </ws:Authenticate>
       </soapenv:Body>
    </soapenv:Envelope>

Response (using proper username / password):

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <AuthenticateResponse xmlns="http://ws.oag.com">
         <AuthenticateResult>1</AuthenticateResult>
         <SecurityToken xsi:type="xsd:string"><![CDATA[<OAGToken><Username>********</Username><IssueDateTime>2015-11-05T07:12:17</IssueDateTime><ExpiryDateTime>2015-11-06T07:12:17</ExpiryDateTime><CustomerNo>********</CustomerNo><Signature>***************************</Signature></OAGToken>]]></SecurityToken>
      </AuthenticateResponse>
   </soap:Body>
</soap:Envelope>

I'm both interested in the AuthenticateResult value and embedded XML part within SecurityToken.

The WSDL lacks XML element types in two spots at element SecurityToken. To be able to generate apex from the WSDL, I made these elements type string (also tested token).

After calling the webservice with the generated apex, the value of SecurityToken does not contain the full CDATA contents, but a concatenation of all XML values within the CDATA embedded XML.

So I decided to manually call the service with HTTPRequest.

Code:

public class fc_OAGFS_OnDemand_Client {
    // TODO: Place in custom setting
    private static final String username = 'test';
    private static final String password = 'test';

    private static final String authenticateEndPoint = 'https://secure.oag.com/ws_oag_com/oagflightstatusinformation.asmx';

    public static void authenticate() {
        String payLoad = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://ws.oag.com"><soapenv:Header/><soapenv:Body><ws:Authenticate><ws:UserId>'+username+'</ws:UserId><ws:Password>'+password+'</ws:Password></ws:Authenticate></soapenv:Body></soapenv:Envelope>';

        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setMethod('POST');
        req.setHeader('Content-Type','text/xml;charset=UTF-8');
        req.setHeader('SOAPAction', ''); // Empty as in SOAPui
        req.setEndpoint(authenticateEndPoint);              
        req.setHeader('Content-Length',String.valueOf(payLoad.length()));
        req.setBody(payLoad);

        HttpResponse res = h.send(req);

        System.debug('>>> Answer String '+res.getBody());
        System.debug('>>> Answer XML Document '+res.getBodyDocument().toXmlString());
        System.debug('>>> Answer BLOB '+res.getBodyAsBlob().toString());
    }
}

Interesting part of debug log:

14:22:42.956 (3956667815)|USER_DEBUG|[47]|DEBUG|>>> Answer String 1<OAGToken><Username>********</Username><IssueDateTime>2015-11-05T07:22:42</IssueDateTime><ExpiryDateTime>2015-11-06T07:22:42</ExpiryDateTime><CustomerNo>********</CustomerNo><Signature>*********************************************</Signature></OAGToken>

14:22:42.957 (3957449646)|USER_DEBUG|[48]|DEBUG|>>> Answer XML Document 1<OAGToken><Username>********</Username><IssueDateTime>2015-11-05T07:22:42</IssueDateTime><ExpiryDateTime>2015-11-06T07:22:42</ExpiryDateTime><CustomerNo>********</CustomerNo><Signature>*********************************************</Signature></OAGToken>

14:22:42.957 (3957601751)|USER_DEBUG|[49]|DEBUG|>>> Answer BLOB 1<OAGToken><Username>********</Username><IssueDateTime>2015-11-05T07:22:42</IssueDateTime><ExpiryDateTime>2015-11-06T07:22:42</ExpiryDateTime><CustomerNo>********</CustomerNo><Signature>*********************************************</Signature></OAGToken>

As above log shows, only a mangled part of the response from OAG's service is returned. Salesforce performs some processing / interpretation.

How can I receive the complete response, including SOAP envelope?

2 Answers 2

1
+100

I tried replicating your issue, using both WebServiceCallout.invoke and HttpRequest. This was somewhat limited as I didn't have valid credentials to the web service. I've applied for a trial account, so I'll see what comes of that.

As you mentioned in the question, I needed to add a type attribute in the WSDL for the two elements named SecurityToken that were missing the value.

<s:element minOccurs="0" maxOccurs="1" name="SecurityToken" type="s:string" /> <!-- Added missing type -->

From there I could use Wsdl2Apex to generate the required Apex classes (OK, I actually used the FuseIT SFDC Explorer Wsdl2Apex implementation, but the result should be the same. Disclose, this is a free tool from my current employer).

Using the following anonymous Apex it appeared to process fine (aside from the invalid credentials).

wsOagCom.OAGFlightStatusInformationSoap oagService = new wsOagCom.OAGFlightStatusInformationSoap();
wsOagCom.AuthenticateResponse_element result = oagService.Authenticate('UserId','Password','SecurityToken');

System.debug(result);
System.debug('AuthenticateResult: ' + result.AuthenticateResult);
System.debug('SecurityToken : ' + result.SecurityToken)

enter image description here

I also tried generating the equivalent HttpRequest. Again, no immediate issue processing the response into an AuthenticateResponse_element.

I then tried making a test case and HttpCalloutMock implementation that returned the same response that you get from SoapUI.

Mock

@isTest
public class wsOagComMock implements HttpCalloutMock {

    protected Integer code = 200;
    protected String status = 'OK';

    protected String bodyAsString = 
    '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
        '<soap:Body>' +
            '<AuthenticateResponse xmlns="http://ws.oag.com">' +
                '<AuthenticateResult>1</AuthenticateResult>' +
                '<SecurityToken xsi:type="xsd:string">' + 
                    '<![CDATA[<OAGToken><Username>UN</Username><IssueDateTime>2015-11-05T07:12:17</IssueDateTime><ExpiryDateTime>2015-11-06T07:12:17</ExpiryDateTime><CustomerNo>CN</CustomerNo><Signature>Sig</Signature></OAGToken>]]>' + 
                '</SecurityToken>'+
            '</AuthenticateResponse>' +
        '</soap:Body>' +
    '</soap:Envelope>';

    protected Map<String, String> responseHeaders;


    public wsOagComMock() {
    }

    public HTTPResponse respond(HTTPRequest req) {
        HttpResponse resp = new HttpResponse();
        resp.setStatusCode(code);
        resp.setStatus(status);

        resp.setBody(bodyAsString);

        if (responseHeaders != null) {
            for (String key : responseHeaders.keySet()) {
                resp.setHeader(key, responseHeaders.get(key));
            }
        }
        return resp;
    }
}

Test

@isTest
public class wsOagComTest {
    public static testmethod void testAccountCallout() {
        wsOagComMock fakeResponse = new wsOagComMock();
        Test.setMock(HttpCalloutMock.class, fakeResponse);
        wsOagCom.OAGFlightStatusInformationSoap oagService = new wsOagCom.OAGFlightStatusInformationSoap();
        //wsOagCom.AuthenticateResponse_element result = oagService.Authenticate('UserId','Password','SecurityToken');

        wsOagCom.AuthenticateResponse_element result = oagService.Authenticate_Http('UserId','Password','SecurityToken');

        System.debug(result);

        System.debug('AuthenticateResult: ' + result.AuthenticateResult);
        System.debug('SecurityToken : ' + result.SecurityToken);

        System.assertEquals(1, result.AuthenticateResult);
    }
}

That test gives a positive response.

enter image description here

A couple of thoughts:

  1. Change your line
    req.setHeader('SOAPAction', ''); // Empty as in SOAPui to req.setHeader('SOAPAction', 'blank'); // Empty as in SOAPui
    See Missing SOAP action header
  2. What are you using to view the debug log? I checked both the Developer Console and out FuseIT Explorer. It is possible it is having encoding issues and is hiding some of the data.
1

I have manually parsed SOAP XML responses using Apex with no problem - it is not Salesforce mangling the XML.

The response you are getting is a "invalid login and password" error message generated from the service that appears to be written in Visual Basic:

525<OAGToken><ERROR><ErrInfo>An unexpected VB error occured in clsWSAuthenticate.WSLogin</ErrInfo><ErrNumber>525</ErrNumber><ErrDescription>A customer_identifier element has invalid login and password combination.
</ErrDescription></ERROR></OAGToken>

So the problem looks to me like the remote service doesn't emit well-formed XML (let alone a valid SOAP response) when this error occurs.

Add the ws:Authenticate elements to your request XML to avoid the error.

PS

Sorry didn't read your question carefully enough to see that you are sending the ws:Authenticate. If OAG's documentation explains the difference between the error code 524 and 525 that might provide a hint. My only other guess would be to be more explicit in the headers you send:

req.setHeader('Content-Type','application/soap+xml;charset=utf-8');
req.setHeader('Accept','application/soap+xml;charset=utf-8');
6
  • ws:Authenticate elements are added to the request XML in the code. Agreed, output message from OAG seems invalid at <SecurityToken xsi:type="xsd:string">. How can I get the full raw answer in getBody() using the manual callout with HTTPRequest? Commented Nov 5, 2015 at 10:07
  • I performed the validation of the output message with SOAPui. Other validators show the output message as valid. Commented Nov 5, 2015 at 10:21
  • @PeterdeJong My mistake - see PS.
    – Keith C
    Commented Nov 5, 2015 at 10:58
  • Corrected above examples with output using a valid subscription. Will try your suggestion. Commented Nov 5, 2015 at 13:25
  • Webservice borks using the header parameters you specified: soap:Client Server found request content type to be 'application/soap+xml;charset=utf-8', but expected 'text/xml'. When using text/xml;charset=utf-8 instead, there is no difference. Commented Nov 5, 2015 at 13:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .