In order to bring you the best possible user experience, this site uses Javascript. If you are seeing this message, it is likely that the Javascript option in your browser is disabled. For optimal viewing of this site, please ensure that Javascript is enabled for your browser.
Login  |   Cloud ERP  |   Home  |   qad.com



  •     QAD Glossary

  • Parsing SOAP Responses
    QXtend Outbound already parses SOAP responses from QXtend Inbound. As such, there is a class available to check for SOAP errors and this can be extended to parse the remainder of a SOAP response.
    The structure that a class would take to parse a SOAP response would be as follows:
    In other words, the CustomResponseParser will inherit the SOAPParser class, and implement the ISubscriberResponseParser and ISAXParserResult interfaces. This results in five methods that must be implemented in the parser. The SOAP Parser uses SAX to parse the XML response.
    The ISAXParserResult interface is this:
    method public void startElement ().
    method public void endElement ().
    method public void setResult (input pcResultCode as character).
    method public void addException (input pcNumber as character,
    input pcDescription as character,
    input pcSeverity as character,
    input pcContext as character).
    The startElement method is called when a start node is encountered in the XML.
    The endElement method is called when an end node is encountered in the XML.
    The setResult method is called when the parser has determined the overall state of the response, where it will create a ttProcessingResult record.
    The addException method is called when the parser has found a detailed exception message, where it will create a ttProcessingException record.
    In addition to this, the SOAPParser class has a number of properties that can be used to assist in parsing the response.
     
    Property
    Type
    Description
    CurrentElementName
    character
    The current node in the XML
    CurrentElementData
    character
    The current data between the nodes
    CurrentNamespace
    character
    The namespace of the current node
    CurrentAttributes
    handle
    Handle to the attributes of the current node
    StopParser
    logical
    Flag to stop parsing at any time
    ParserResultHandler
    ISAXParserResult
    Object reference to the result handler
    Example: A successful SOAP response from an external web service looks like this:
    <?xml version="1.0" encoding="UTF-8" ?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
    <Response xmlns="urn:custom-service:custom">
    <resultCode>
    <codeNumber>200</codeNumber>
    <userMessage>OK</userMessage>
    <debugInfo />
    </resultCode>
    </Response>
    </soapenv:Body>
    </soapenv:Envelope>
    And an unsuccessful response looks like this:
    <?xml version="1.0" encoding="UTF-8" ?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
    <Response xmlns="urn:custom-service:custom">
    <resultCode>
    <codeNumber>411</codeNumber>
    <userMessage>Login Failed</userMessage>
    <debugInfo>Unauthorized access</debugInfo>
    </resultCode>
    </Response>
    </soapenv:Body>
    </soapenv:Envelope>
    From this we can determine that a codeNumber of 200 means the request was successful, but any other code means the request returned an error. The response is also a SOAP response, hence there may be SOAP errors such as invalid address information, bad envelopes or other errors. We can extend the SOAPParser to create a response parser for this type of response. The response parser we will create will examine the codeNumber value, the userMessage value, and stop parsing once it has reached the end of the resultCode block.
    using com.qad.xml.SOAPParser.
    using com.qad.xml.ISAXParserResult.
    using com.qad.qxtend.qxo.ISubscriberResponseParser.
    using com.qad.qxtend.qxo.QdocResponseHandler.
     
    class CustomResponseParser inherits SOAPParser
    implements ISAXParserResult,ISubscriberResponseParser:
     
    {com/qad/qxtend/qxo/dsResponseDetails.i}
     
    define variable gcReturnCode as character no-undo.
    define variable gcExceptionDesc as character no-undo.
    define variable giExceptionSequence as integer no-undo.
    constructor CustomResponseParser ():
    /*
    * The SOAPParser class makes calls to a class that implements the
    * ISAXParserResult interface whenever it starts and finishes
    * processing a node. Make this object that class
    */
    assign
    ParserResultHandler = this-object.
    end constructor.
    method public void parseResponse (input pcResponse as longchar,
    output dataset for dsQdocResponseDetails):
    /*-------------------------------------------------------------------------
    Purpose : Starts the parsing of the Response XML
    Parameters : [input]
    pcResponse - The full XML response
    [output]
    dsQdocResponseDetails - Result and Exceptions dataset
    Notes : Implementation of the ISubscriberResponseParser interface
    ------------------------------------------------------------------------*/
    dataset dsQdocResponseDetails:empty-dataset().
     
    /*
    * Call the method on the SOAPParser class to start parsing
    */
    startParser(input pcResponse).
    end.
    method public void startElement ():
    /*-------------------------------------------------------------------------
    Purpose : Executes when a start node is encountered
    Parameters : [none]
    Notes : Implementation of the ISAXParserResult interface. There is
    nothing we need to do when the parser encounters the
    start of an element.
    ------------------------------------------------------------------------*/
    end method.
    method public void endElement ():
    /*-------------------------------------------------------------------------
    Purpose : Executes when an end node is encountered
    Parameters : [none]
    Notes : Implementation of the ISAXParserResult interface.
    ------------------------------------------------------------------------*/
    if CurrentNamespace = "urn:custom-service:custom" then do:
    case CurrentElementName:
    when "codeNumber" then
    gcReturnCode = CurrentElementData.
    when "userMessage" then do:
    gcExceptionDesc = CurrentElementData.
    /*
    * The '200' response means there were no exceptions. Anything
    * else indicates there was a problem and we must log it. Set
    * the result to be an "APPERR"
    */
    if gcReturnCode <> "200" then do:
    setResult (input QdocResponseHandler:ApplicationErrorCode).
    addException (input gcReturnCode,
    input gcExceptionDesc,
    input "",
    input "").
    end.
    end.
    when "resultCode" then do:
    if gcReturnCode = "200" then do:
    /*
    * Set the result to be a success, or "DLV"
    */
    setResult (input QdocResponseHandler:SuccessStatusCode).
    /*
    * Stop parsing at this point, since we have reached the
    * end node containing all the information we need
    */
    StopParser = true.
    end.
    end.
    end case.
    end.
    end method.
    method public void setResult (input pcResultCode as character):
    /*-------------------------------------------------------------------------
    Purpose : Creates a processing result record
    Parameters : [input]
    pcResultCode - A string representing the result of the
    response
    Notes : Implementation of the ISAXParserResult interface. This
    method will allow the SOAPParser class to create
    SOAPERR results
    ------------------------------------------------------------------------*/
    find first ttProcessingResult no-error.
    if not available ttProcessingResult then
    create ttProcessingResult.
    assign
    ttProcessingResult.resultStatus = pcResultCode
    ttProcessingResult.resultSequence = 1.
    end method.
    method public void addException (input pcNumber as character,
    input pcDescription as character,
    input pcSeverity as character,
    input pcContext as character):
    /*-------------------------------------------------------------------------
    Purpose : Creates an exception record
    Parameters : [input]
    pcNumber - Exception number
    pcDescription - Exception description
    pcSeverity - Exception severity
    pcContext - Exception context
    Notes : Implementation of the ISAXParserResult interface. This
    will allow the SOAPParser class to log detailed
    error messages when it gets a SOAP Error
    ------------------------------------------------------------------------*/
    create ttProcessingException.
    assign
    ttProcessingException.resultSequence = 1
    ttProcessingException.exceptionSequence = giExceptionSequence
    ttProcessingException.exceptionNumber = pcNumber
    ttProcessingException.exceptionDescription = pcDescription
    ttProcessingException.exceptionContext = pcContext
    ttProcessingException.exceptionSeverity = pcSeverity.
     
    giExceptionSequence = giExceptionSequence + 1.
    end method.
    end class.
    To enable a subscriber in QXtend Outbound to use this response parser, just enter the full name of the parser class. In this case the parser class is just CustomResponseParser, however you can also put it in a package form; for example, com.xyz.parser.CustomerResponseParser.

    Subscriber Configuration Parameters
    The class must be compiled into the regular location for the QXtend Outbound services; that is, a directory in the PROPATH defined in the start-sess.sh script.