2015-12-14 26 views
15

My Spring Web Client Service ha questa risoluzione personalizzato per catturare SoapFaults:SOAPFault personalizzato resolver innescando ma non trovando SoapFault in SOAPBody

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 [email protected] 
       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); 
    } 

che viene eseguito quando questo guasto torna dal servizio:

<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> 

e scrive questo al file di log:

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] - [email protected] 
MySoapFaultResolver-resolveFault] - sb_name:{http://schemas.xmlsoap.org/soap/envelope/}Body 
MySoapFaultResolver-resolveFault] - soap body does not have fault 
MySoapFaultResolver-resolveFault] - exiting 

sono sconcertato dal motivo per cui la c ode non sta trovando SoapFault all'interno di SoapBody. Qualcuno può far luce su questo? --appendiato-- Intrigante. Possiedo anche il webservice che sta gettando questo errore:

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"); 
    } 

e qui è quello che registra:

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--

Così qui vediamo che il codice di errore è impostato su 500 nell'errore prima che lasci il servizio ma non compaia nel browser. TIA,

Ancora-learning Stev

+0

Si accede "fc:" , ma nel tuo file di registro "om_fc:" è riportato; il sam con "frs:". Sei sicuro che questo codice e questo file di log combaciano? –

+0

Sì.om_fc e om_frs e fc e fsr sono tutti unici. fc e fsr non vengono mai registrati perché sb.hasFault() restituisce false come dimostrato da "soap body non ha difetti" come si vede nel file di log. – user1201168

+0

Ti suggerisco di ridigitare il codice e verificare cosa faccia esattamente "sb.hasFault()". Può avere almeno un'indicazione su cosa fare –

risposta

3

ho affrontato un problema simile prima d'ora. Alla fine il problema era il codice di stato HTTP.

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/

Non avendo il codice di stato HTTP corretto ha causato la mia libreria client (Metro/Glassfish) per ignorare la sezione colpa del tutto.

Nota che questo è per Soap 1.1, tuttavia credo che per Soap 1.2 questo sia di nuovo diverso, se questo è rilevante per te allora puoi leggere le specifiche ma sembra che tu stia usando 1.1.

+0

Intrigante. Non vedo un codice di errore nel xml restituito dal servizio web. Ma possiedo anche il webservice e sto cercando nei log il mio CXF FaultInterceptor in uscita. Vedo dove f.getStatusCode restituisce 500. Quindi penso che siamo sulla strada giusta - il problema potrebbe non trovarsi con il resolver del client ma con cosa l'intercettore del servizio sta cacciando via. Indagherò Grazie per il tuo aiuto. Film a 11. – user1201168

+0

@ user1201168 fortuna con questo? Sono curioso del caso. –

+0

in armeggiare con l'intercettore sul servizio che ho scoperto 1) disattivando gli intercettatori si ottiene una soapfault come mostrato, 2) accendendo gli interceptor e non lanciando nulla si ottiene una soapfault come mostrato, 3) attivando gli interceptor e generando un errore esplicito con qualcosa come throw new Fault (new MyCustomException) non ha fornito alcuna soapfault ma piuttosto una risposta 200-Ok errata. Usando SoapUI si velocizza notevolmente la verifica di ciò che ritorna dal servizio. Ho intenzione di mettere questo nel dimenticatoio fino a quando non posso far scattare i miei intercettatori clienti. Grazie per l'aiuto. – user1201168

3

L'errore di sapone che si sta restituendo manca lo spazio dei nomi di definizione che potrebbe essere il motivo per cui il codice non riesce a individuare l'errore.

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

Si consiglia di provare compreso questo come

<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"> 
0

Internamente, il metodo sb.hasFault() ottiene tutti gli elementi figli di SoapBody alla ricerca di uno di nome Fault e definito con l'URI http://schemas.xmlsoap.org/soap/envelope/. In qualche modo non lo trova.

Tuttavia, è possibile estrarre le informazioni dall'oggetto SoapBody con qualcosa di simile:

DOMSource source = (DOMSource)sb.getPayloadSource(); 
Node fault = source.getNode().getChildNodes().item(0); 

String faultcode = fault.getChildNodes().item(0) // "faultcode" 
         .getChildNodes().item(0) // text node inside "faultcode" 
          .getNodeValue(); 
String faultstring = fault.getChildNodes().item(1) // "faultstring" 
         .getChildNodes().item(0) // text node inside "faultstring" 
          .getNodeValue(); 

o cercando di gettare il bambino di SoapBody direttamente:

SoapFault sff = null; 
DOMSource source = (DOMSource)sb.getPayloadSource(); 
Node fault = source.getNode().getChildNodes().item(0); 
if(fault instanceof SoapFault) { 
    sff = (SoapFault)fault; 
}