2010-11-08 18 views
5

J'essaie d'écrire un service Web à l'aide de la bibliothèque de services Web Spring. Je suis capable de configurer mes terminaux avec succès et ça fonctionne bien, mais je suis confronté à quelques problèmes avec les mappages d'exception.Comment créer un message de panne de savon personnalisé à l'aide du service Web de printemps

Je suis en mesure de cartographier les exceptions en utilisant @SoapFault et SoapFaultAnnotationExceptionResolver mais la définition wsdl est la suivante

<xsd:schema elementFormDefault="qualified" targetNamespace="http://abc.com/soap/"> 
    <xsd:complexType name="ServiceException"> 
     <xsd:sequence> 
      <xsd:element name="message" nillable="true" type="xsd:string"/> 
     </xsd:sequence> 
    </xsd:complexType> 

    <xsd:complexType name="ValidationException"> 
     <xsd:complexContent> 
      <xsd:extension base="tns:ServiceException"> 
       <xsd:sequence/> 
      </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 

    <xsd:complexType name="InternalException"> 
     <xsd:complexContent> 
      <xsd:extension base="tns:ServiceException"> 
       <xsd:sequence/> 
      </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 

    <xsd:complexType name="AuthenticationException"> 
     <xsd:complexContent> 
      <xsd:extension base="tns:ServiceException"> 
       <xsd:sequence/> 
      </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 

    <xsd:complexType name="LoginInput"> 
     <xsd:sequence> 
      <xsd:element minOccurs="1" maxOccurs="1" name="UserName" nillable="false" type="xsd:string"/> 
      <xsd:element minOccurs="1" maxOccurs="1" name="PassWord" nillable="false" type="xsd:string"/> 
     </xsd:sequence> 
    </xsd:complexType> 

    <xsd:complexType name="LoginOutput"> 
     <xsd:sequence> 
      <xsd:element minOccurs="1" maxOccurs="1" name="ValidTo" nillable="false" type="xsd:dateTime"/> 
     </xsd:sequence> 
    </xsd:complexType> 

    <xsd:element name="login" type="tns:LoginInput"/> 
    <xsd:element name="loginResponse" type="tns:LoginOutput"/> 

    <xsd:element name="ValidationException" type="tns:ValidationException"/> 
    <xsd:element name="InternalException" type="tns:InternalException"/> 
    <xsd:element name="AuthenticationException" type="tns:AuthenticationException"/> 
</xsd:schema> 

<message name="LoginRequest"> 
    <part name="login" element="tns:login"/> 
</message> 

<message name="LoginResponse"> 
    <part name="loginResponse" element="tns:loginResponse"/> 
</message> 

<message name="ValidationException"> 
    <part name="ValidationException" element="tns:ValidationException"/> 
</message> 

<message name="InternalException"> 
    <part name="InternalException" element="tns:InternalException"/> 
</message> 

<message name="AuthenticationException"> 
    <part name="AuthenticationException" element="tns:AuthenticationException"/> 
</message> 

<portType name="ServicePortType"> 
    <operation name="Login"> 
     <input message="tns:LoginRequest"/> 
     <output message="tns:LoginResponse"/> 
     <fault name="ValidationException" message="tns:ValidationException"/> 
     <fault name="InternalException" message="tns:InternalException"/> 
     <fault name="AuthenticationException" message="tns:AuthenticationException"/> 
    </operation> 
</portType> 

<binding name="ServiceBinding" type="tns:ServicePortType"> 
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> 
    <operation name="Login"> 
     <soap:operation soapAction="urn://Service#Login"/> 
     <input> 
      <soap:body use="literal"/> 
     </input> 
     <output> 
      <soap:body use="literal"/> 
     </output> 
     <fault name="ValidationException"> 
      <soap:fault name="ValidationException" use="literal"/> 
     </fault> 
     <fault name="InternalException"> 
      <soap:fault name="InternalException" use="literal"/> 
     </fault> 
     <fault name="AuthenticationException"> 
      <soap:fault name="AuthenticationException" use="literal"/> 
     </fault> 
    </operation> 
</binding> 

Comment puis-je écrire une exception pour le traitement de cette définition de service?

Merci

Répondre

7

Après une recherche plus j'ai trouvé this from spring source forum.

SoapMessage response = (SoapMessage) messageContext.getResponse(); 
SoapBody soapBody = response.getSoapBody(); 

SoapFault soapFault = 
soapBody.addClientOrSenderFault(ex.getMessage(), Locale.ENGLISH); 

SoapFaultDetail faultDetail = soapFault.addFaultDetail(); 
Result result = faultDetail.getResult(); 

// My detail XML object 
InvalidArgumentFault fault = new InvalidArgumentFault(); 
fault.setErrorCode("Custom Error Code"); 
fault.setOpsMessage("This is the ops message"); 
fault.setSystemMessage("This is the system message"); 

// Marshal the detail. We have to use the ObjectFactory which isn't 
// marshaller agnostic because the detail element doesn't have an 
// XmlRootElement tag as required by JAXB. 
ObjectFactory of = new ObjectFactory(); 
mMarshaller.marshal(of.createInvalidArgumentFault(fault), result); 

MISE À JOUR

Cette une mise en oeuvre de l'échantillon complet que je utilise,

import java.lang.reflect.Method; 
import java.util.Collection; 
import java.util.HashMap; 
import java.util.Locale; 
import java.util.Map; 

import javax.xml.transform.Result; 

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.springframework.beans.BeansException; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.ApplicationContextAware; 
import org.springframework.oxm.Marshaller; 
import org.springframework.ws.context.MessageContext; 
import org.springframework.ws.server.endpoint.AbstractEndpointExceptionResolver; 
import org.springframework.ws.soap.SoapBody; 
import org.springframework.ws.soap.SoapFault; 
import org.springframework.ws.soap.SoapFaultDetail; 
import org.springframework.ws.soap.SoapMessage; 

import org.apache.commons.lang.StringUtils; 

public class CustomSoapFaultDetailAnnotationExceptionResolver extends 
     AbstractEndpointExceptionResolver implements ApplicationContextAware { 
    private static Log log = LogFactory 
      .getLog(CustomSoapFaultDetailAnnotationExceptionResolver.class); 

    private Collection<Marshaller> marshallers; 

    private Map<Class<? extends Object>, Marshaller> marshallerMap = new HashMap<Class<? extends Object>, Marshaller>(); 

    public CustomSoapFaultDetailAnnotationExceptionResolver() { 
     setWarnLogCategory(getClass().getCanonicalName()); 
    } 

    @Override 
    protected boolean resolveExceptionInternal(MessageContext messageContext, 
      Object endpoint, Exception ex) { 
     boolean resolved = false; 

     try { 
      CustomSoapFaultDetails annotation = ex.getClass().getAnnotation(
        CustomSoapFaultDetails.class); 
      if (annotation != null) { 

       Method m = ex.getClass().getMethod("getFaultInfo", 
         new Class[] {}); 
       Object fault = m.invoke(ex, new Object[] {}); 

       SoapMessage response = (SoapMessage) messageContext 
         .getResponse(); 
       SoapBody soapBody = response.getSoapBody(); 

       SoapFault soapFault = soapBody 
         .addClientOrSenderFault(
           StringUtils.isBlank(ex.getMessage()) ? "server exception" 
             : ex.getMessage(), Locale.ENGLISH); 

       SoapFaultDetail faultDetail = soapFault.addFaultDetail(); 
       Result result = faultDetail.getResult(); 

       if (marshallerMap.containsKey(fault.getClass())) { 
        marshallerMap.get(fault.getClass()).marshal(fault, result); 
        resolved = true; 
       } else { 
        for (Marshaller marshaller : marshallers) { 
         try { 
          marshaller.marshal(fault, result); 
          marshallerMap.put(fault.getClass(), marshaller); 
          resolved = true; 
          break; 
         } catch (Exception e) { 
          // Ignore error 
         } 
        } 
       } 
      } 
     } catch (Exception e) { 
      log.error(e.toString(), e); 
     } 
     return resolved; 
    } 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) 
      throws BeansException { 
     this.marshallers = applicationContext.getBeansOfType(Marshaller.class) 
       .values(); 
    } 
} 
+0

D'où tirez-vous le 'mMarshaller'? –

+0

@Mark, j'ai mis à jour la réponse. S'il vous plaît laissez-moi savoir si vous avez des suggestions. –

+0

J'espérais que vous réussissiez à le sortir du 'MessageEndpoint' quelque part, mais en fin de compte je l'injecte comme vous le faites. –

2

Je l'ai utilisé avec succès Spring-WS DÉCLIC pour créer un service Web. Maintenant, je faisais la mise en œuvre de défaut dans ce service SOAP et j'ai pu le faire avec une classe que j'ai créé comme suit,

public class ServiceSoapFaultMappingExceptionResolver extends SoapFaultMappingExceptionResolver 

et à l'intérieur de la fonction surchargée suivante,

@Override 


protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) { 

//code for adding fault details 

    SoapFaultDefinition soapFaultDefinition = new SoapFaultDefinition(); 
    String ENVELOPE_NAMESPACE_URI = "http://schemas.xmlsoap.org/soap/envelope/"; 

    //  soapFaultDefinition.setFaultStringOrReason("--" + ex); 

    //  soapFaultDefinition.setLocale(Locale.ENGLISH); 

    QName CLIENT_FAULT_NAME = new QName(ENVELOPE_NAMESPACE_URI,"5003", "e"); 
    soapFaultDefinition.setFaultCode(CLIENT_FAULT_NAME); 
    setDefaultFault(soapFaultDefinition); 
    Result result = fault.addFaultDetail().getResult(); 

     // marshal 
     try { 
      JAXBContext.newInstance(ExceptionListType.class).createMarshaller().marshal(exceptionList, result); 

} 

S'il vous plaît this answer pour la solution originale.

+0

Bien que cela puisse théoriquement répondre à la question, [il serait préférable] (http://meta.stackoverflow.com/q/8259) d'inclure les parties essentielles de la réponse ici, et de fournir le lien pour référence. – chappjc

+0

ok.i fera le nécessaire. –

+1

@Himanshu s'il vous plaît voir la réponse mise à jour est ok. –