Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

custom soapfault resolver triggering but not finding SoapFault in SoapBody

My Spring Web Service Client has this custom resolver to catch SoapFaults:

public class MySoapFaultResolver extends SoapFaultMessageResolver implements FaultMessageResolver 
{
    private static Logger logger = Logger.getLogger( MySoapFaultResolver.class);

    @Override
    public void resolveFault(WebServiceMessage wsm) throws IOException 
    {
        logger.debug("entering");

//      SOAPMessage soapMessage = (SOAPMessage) wsm;   cant cast to this
        SoapMessage soapMessage = (SoapMessage) wsm;

        if( soapMessage == null) {
            logger.debug("soapMessage is null");
        } else {
            logger.debug("soapMessage is not null");
            QName om_fc = soapMessage.getFaultCode();
            String om_frs = soapMessage.getFaultReason();
            logger.debug("om_fc:" + om_fc);
            logger.debug("om_frs:" + om_frs);
            if( soapMessage.getSoapBody() == null) {
                logger.debug("soap body is null");               
            } else {
                logger.debug("soap body is not null"); 
                SoapBody sb = soapMessage.getSoapBody();
                logger.debug( sb.toString() ); // prints org.springframework.ws.soap.saaj.SaajSoap11Body@1d23bf4
                QName sb_name = sb.getName();
                logger.debug("sb_name:" + sb_name);
                Iterator<QName> iter_attr_sb = sb.getAllAttributes();
                while( iter_attr_sb.hasNext()) {
                    QName qname = iter_attr_sb.next();
                    String qname_valu = sb.getAttributeValue(qname);
                    logger.debug("attribute: " + qname + ":" + qname_valu);
                }
                if( sb.hasFault()) {
                    logger.debug("soap body has fault");
                    SoapFault sff = sb.getFault();
                    QName fc = sff.getFaultCode();
                    String fsr = sff.getFaultStringOrReason();
                    logger.debug("fc:" + fc);
                    logger.debug("fsr:" + fsr);
                    Iterator<QName> iter_attr = sff.getAllAttributes();
                    while( iter_attr.hasNext()) {
                        QName qname = iter_attr.next();
                        String qname_valu = sff.getAttributeValue(qname);
                        logger.debug("attribute: " + qname + ":" + qname_valu);
                    }
                    if( sff.getFaultDetail() == null) {
                        logger.debug("fault has no details");
                    } else {
                        logger.debug("fault has details");
                        SoapFaultDetail faultDetail = sff.getFaultDetail();
                        Iterator<SoapFaultDetailElement> detailEntries = faultDetail.getDetailEntries();
                        while( detailEntries.hasNext()) {
                            SoapFaultDetailElement detailElement = detailEntries.next();
                            logger.debug("Found SoapFaultDetailElement name:" + detailElement.getName());
                        }
                    }
                } else {
                    logger.debug("soap body does not have fault");    
                }
            }
        }
        logger.debug("exiting");

        SoapFaultClientException sfce = new SoapFaultClientException( soapMessage);
        throw new IOException( "cursesfoiledagain", sfce);
    }

which gets executed when this fault comes back from the service:

<soap:Envelope>
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Server</faultcode>
      <faultstring>Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection</faultstring>
    </soap:Fault>
  </soap:Body>
</soap:Envelope>

and writes this to the logfile:

MySoapFaultResolver-resolveFault] - entering
MySoapFaultResolver-resolveFault] - soapMessage is not null
MySoapFaultResolver-resolveFault] - om_fc:null
MySoapFaultResolver-resolveFault] - om_frs:null
MySoapFaultResolver-resolveFault] - soap body is not null
MySoapFaultResolver-resolveFault] - org.springframework.ws.soap.saaj.SaajSoap11Body@1d23bf4
MySoapFaultResolver-resolveFault] - sb_name:{http://schemas.xmlsoap.org/soap/envelope/}Body
MySoapFaultResolver-resolveFault] - soap body does not have fault
MySoapFaultResolver-resolveFault] - exiting

I am baffled by why the code isn't finding the SoapFault within the SoapBody. Can anyone shed some light on this? --appended-- Intriguing. I also own the webservice that's throwing this error:

public class MyOutSoapFaultInterceptor extends AbstractSoapInterceptor
{
    private static Logger logger = Logger.getLogger( MyOutSoapFaultInterceptor.class);

    public MyOutSoapFaultInterceptor()
    {
        super(Phase.MARSHAL);
    }

    @Override
    public void handleMessage( SoapMessage message) throws Fault
    {
        logger.debug("entering");

        Exception e = message.getContent( Exception.class);
        if( e == null) {
            logger.debug("e is null");
        } else {
            logger.debug("e is not null");
            logger.debug("e.getCause:" + e.getCause());
            logger.debug("e.getMessage:" + e.getMessage());
            if( e instanceof Fault) {
                logger.debug("e is instanceOf Fault");
                Fault f = (Fault) message.getContent( Fault.class);
                SoapFault sf = SoapFault.createFault((Fault) e, message.getVersion());
                logger.debug("sf is not null");
                logger.debug("sf.getCause:" + sf.getCause());
                logger.debug("sf.getMessage:" + sf.getMessage());
                logger.debug("sf.getStatusCode:" + sf.getStatusCode());
                logger.debug("sf.getCode:" + sf.getCode());
                FormsEndpointFault newFault = new FormsEndpointFault();
                newFault.setCode( sf.getStatusCode());
                newFault.setMessage( sf.getMessage());
                if( sf.hasDetails()) {
                    logger.debug("sf has details");    
                    Element eee = sf.getDetail();
                    if( eee.hasAttributes()) {
                        NamedNodeMap nnm = eee.getAttributes();
                        logger.debug("sf.details has " + nnm.getLength() + " attributes");
                        for( int ii = 0 ; ii < nnm.getLength() ; ii++ ) {
                            Node nnode = nnm.item(ii); //WARNING Nodes are recursive structures
                            logger.debug(" attribute node value:" + nnode.getNodeValue());
                        }
                    }
                    if( eee.hasChildNodes()) {
                        NodeList nl = eee.getChildNodes();
                        logger.debug("sf.details has " + nl.getLength() + " child nodes");
                        for( int ii = 0 ; ii < nl.getLength() ; ii++ ) {
                            Node nnode = nl.item(ii);
                            logger.debug(" child node value:" + nnode.getNodeValue());
                        }
                    }
                } else {
                    logger.debug("sf has no details");                
                }
            }
        }
        logger.debug("exiting");
    }

and here's what it logs:

handleMessage] - entering
handleMessage] - e is not null
handleMessage] - e.getCause:org.springframework.orm.jpa.JpaSystemException: Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
handleMessage] - e.getMessage:Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
handleMessage] - e is instanceOf Fault
handleMessage] - sf is not null
handleMessage] - sf.getCause:org.springframework.orm.jpa.JpaSystemException: Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
handleMessage] - sf.getMessage:Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
handleMessage] - sf.getStatusCode:500
handleMessage] - sf.getCode:Could not open connection; nested exception is org.hibernate.exception.GenericJDBCException: Could not open connection
handleMessage] - sf has no details
handleMessage] - exiting

-/appended--

So here we see that the fault code is set to 500 in the fault before it leaves the service but doesn't appear in the browser. TIA,

Still-learning Stev

like image 648
user1201168 Avatar asked Dec 14 '15 06:12

user1201168


2 Answers

I've dealt with a similar issue before. In the end the problem was the HTTP status code.

In case of a SOAP error while processing the request, the SOAP HTTP server MUST issue an HTTP 500 "Internal Server Error" response and include a SOAP message in the response containing a SOAP Fault element (see section 4.4) indicating the SOAP processing error.

http://www.w3.org/TR/2000/NOTE-SOAP-20000508/

Not having the correct HTTP status code caused my client library (Metro/Glassfish) to ignore the fault section entirely.

Note that this is for Soap 1.1, however I believe that for Soap 1.2 this is different again, if this is relevant to you then you can read the specs but it looks like you're using 1.1.

like image 75
Sebastiaan van den Broek Avatar answered Oct 17 '22 13:10

Sebastiaan van den Broek


The soap fault you are returning is missing the definition namespace which could be the reason that your code is failing to find the fault.

if( sb.hasFault()) {
   logger.debug("soap body has fault");
   ...

You may want to try including this as

<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
like image 23
Mike Murphy Avatar answered Oct 17 '22 13:10

Mike Murphy