jaxb2 and cxf: CustomFaultMessageResolver
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Mon, 21 Dec 2015 00:33:13 +0000 (01:33 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Mon, 21 Dec 2015 00:33:13 +0000 (01:33 +0100)
19 files changed:
cxf/web-services-spring-cxf-client/src/main/build-resources/wsdl/example.wsdl
cxf/web-services-spring-cxf-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java [new file with mode: 0644]
cxf/web-services-spring-cxf-client/src/main/java/de/spring/webservices/client/ExampleClientService.java
cxf/web-services-spring-cxf-client/src/main/java/de/spring/webservices/client/MainTest.java
cxf/web-services-spring-cxf-client/src/main/resources/examples.xsd
cxf/web-services-spring-cxf-client/src/main/resources/log4j2.xml
cxf/web-services-spring-cxf-client/src/main/resources/spring-configuration/ws/client-spring-configuration.xml
cxf/web-services-spring-cxf-globalxsds/src/main/resources/parent.xsd
cxf/web-services-spring-cxf-server/src/main/resources/examples.xsd
cxf/web-services-spring-cxf-server/src/main/resources/log4j2.xml
jaxb2/web-services-spring-jaxb2-client/src/main/build-resources/wsdl/example.wsdl
jaxb2/web-services-spring-jaxb2-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java [new file with mode: 0644]
jaxb2/web-services-spring-jaxb2-client/src/main/java/de/spring/webservices/client/MainTest.java
jaxb2/web-services-spring-jaxb2-client/src/main/resources/log4j2.xml
jaxb2/web-services-spring-jaxb2-client/src/main/resources/schemas/examples.xsd
jaxb2/web-services-spring-jaxb2-client/src/main/resources/spring-configuration/ws/client-spring-configuration.xml
jaxb2/web-services-spring-jaxb2-globalxsds/src/main/resources/schemas/parent.xsd
jaxb2/web-services-spring-jaxb2-server/src/main/resources/log4j2.xml
jaxb2/web-services-spring-jaxb2-server/src/main/resources/schemas/examples.xsd

index 9b3fdaf..20ce10e 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault"/>
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault"/>
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">
diff --git a/cxf/web-services-spring-cxf-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java b/cxf/web-services-spring-cxf-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java
new file mode 100644 (file)
index 0000000..244be4e
--- /dev/null
@@ -0,0 +1,83 @@
+package de.spring.webservices.client;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.xml.transform.Source;
+
+// cxf-codegen-plugin DOES generate again the objects in web-services-spring-jaxb2-globalxsds :(
+// So I guess it is better to use the objects generated in this package
+// than the ones from globalxsds even if they should be the same.
+import name.gumartinm.spring_ws.parent.GeneralFault;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.oxm.Unmarshaller;
+import org.springframework.oxm.XmlMappingException;
+import org.springframework.ws.WebServiceMessage;
+import org.springframework.ws.client.core.FaultMessageResolver;
+import org.springframework.ws.soap.SoapBody;
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapFaultDetail;
+import org.springframework.ws.soap.SoapFaultDetailElement;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.client.core.SoapFaultMessageResolver;
+
+/**
+ * Enables us to log custom Fault remote messages. 
+ *
+ */
+public class CustomFaultMessageResolver implements FaultMessageResolver {
+
+private static final Logger LOGGER = LoggerFactory.getLogger(CustomFaultMessageResolver.class);
+       
+       private final FaultMessageResolver defaultMessageResolver = new SoapFaultMessageResolver();
+       
+       private Unmarshaller unmarshaller;
+       
+       @Override
+       public void resolveFault(WebServiceMessage message) throws IOException {
+               
+               // Same behavior as default message resolver (SoapFaultMessageResolver) but this implementation also
+               // logs error information.
+               if (LOGGER.isErrorEnabled()) {
+                       try {
+                               logErrorInformation(message);
+                       } catch (Exception ex) {
+                               LOGGER.error("CustomFaultMessageResolver exception:", ex);
+                       }
+               }
+               
+               defaultMessageResolver.resolveFault(message);
+       }
+       
+       private void logErrorInformation(WebServiceMessage message) throws XmlMappingException, IOException {
+               SoapMessage soapMessage = (SoapMessage) message;
+               SoapBody body = soapMessage.getSoapBody();
+               SoapFault soapFault = body != null ? body.getFault() : null;
+               SoapFaultDetail detail = soapFault != null ? soapFault.getFaultDetail() : null;
+               
+               if (detail != null) {
+                       Iterator<SoapFaultDetailElement> iterator = detail.getDetailEntries();
+                       while (iterator.hasNext()) {
+                               SoapFaultDetailElement bodyElement = iterator.next();
+                               Source detailSource = bodyElement.getSource();
+                               // TODO: How to check if I am receiving GeneralFault before trying to unmarshal?
+                               //       Right now there will be exception if unmarshal doesn't return a GeneralFault object.
+                               GeneralFault error = (GeneralFault)this.unmarshaller.unmarshal(detailSource);
+                               LOGGER.error("TECHNICALERROR:");
+                               LOGGER.error(error.getTechnicalError());
+                               LOGGER.error("ELEMENTS:");
+                               error.getElements().forEach(element -> {
+                                       LOGGER.error("MESSAGE: " + element.getMessage());
+                                       LOGGER.error("MESSAGEARGS:");
+                                       element.getMessageArgs().forEach(messageArg -> LOGGER.error(messageArg));
+                               });
+                       }
+               }
+       }
+       
+       public void setUnmarshaller(Unmarshaller unmarshaller) {
+               this.unmarshaller = unmarshaller;
+       }
+}
index c7d9758..32e1435 100644 (file)
@@ -6,10 +6,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.ws.client.core.WebServiceTemplate;
 
-import de.spring.webservices.client.auto.CustomBindingExampleFault;
+import de.spring.webservices.client.auto.CustomBindingExampleFault_Exception;
 import de.spring.webservices.client.auto.CustomBindingExampleRequest;
 import de.spring.webservices.client.auto.CustomBindingExampleResponse;
-import de.spring.webservices.client.auto.ExampleFault;
+import de.spring.webservices.client.auto.ExampleFault_Exception;
 import de.spring.webservices.client.auto.ExampleRequest;
 import de.spring.webservices.client.auto.ExampleResponse;
 import de.spring.webservices.client.auto.Examples;
@@ -29,7 +29,7 @@ public class ExampleClientService {
            this.webServiceTemplate = webServiceTemplate;
     }
 
-       public ExampleResponse sendAndReceiveJava() throws ExampleFault {
+       public ExampleResponse sendAndReceiveJava() throws ExampleFault_Exception {
         final ExampleRequest exampleRequest = new ExampleRequest();
         exampleRequest.setData("SCARLETT JAVA. IT IS CANON.");
 
@@ -49,7 +49,7 @@ public class ExampleClientService {
         return exampleResponse;
     }
        
-       public CustomBindingExampleResponse sendAndReceiveJavaCustom() throws CustomBindingExampleFault {
+       public CustomBindingExampleResponse sendAndReceiveJavaCustom() throws CustomBindingExampleFault_Exception {
         final CustomBindingExampleRequest customBindingxampleRequest =
                        new CustomBindingExampleRequest();
         customBindingxampleRequest.setData("CUSTOM BINDING JAVA. SCARLETT. IT IS CANON.");
index 8527ab5..54cc644 100644 (file)
@@ -16,7 +16,7 @@ import de.spring.webservices.client.auto.ExampleResponse;
  * 
  */
 public class MainTest {
-       private static final Logger logger = LoggerFactory.getLogger(MainTest.class);
+       private static final Logger LOGGER = LoggerFactory.getLogger(MainTest.class);
        
     public ApplicationContext context;
 
@@ -25,7 +25,7 @@ public class MainTest {
      * @throws ExampleFault_Exception 
      * @throws CustomBindingExampleFault_Exception 
      */
-    public static void main(final String[] args) throws ExampleFault, CustomBindingExampleFault {
+    public static void main(final String[] args) {
         final MainTest test = new MainTest();
 
         test.context = new ClassPathXmlApplicationContext(
@@ -34,23 +34,35 @@ public class MainTest {
         final ExampleClientService example =
                        (ExampleClientService) test.context.getBean("exampleClientService");
 
-        logger.info("ExampleResponse Java:");
-        ExampleResponse response = example.sendAndReceiveJava();
-        logger.info(response.getData());
+        LOGGER.info("ExampleResponse Java:");
+        ExampleResponse response;
+               try {
+                       response = example.sendAndReceiveJava();
+                       LOGGER.info(response.getData());
+               } catch (Exception e) {
+                       LOGGER.info("ExampleResponse Java error:", e);
+               }
         
         
-        logger.info("CustomBindingExampleResponse Java:");
-        CustomBindingExampleResponse customBindingResponse = example.sendAndReceiveJavaCustom();
-        logger.info(customBindingResponse.getData());
         
+        LOGGER.info("CustomBindingExampleResponse Java:");
+        CustomBindingExampleResponse customBindingResponse;
+               try {
+                       customBindingResponse = example.sendAndReceiveJavaCustom();
+                       LOGGER.info(customBindingResponse.getData());
+               } catch (Exception e) {
+                       LOGGER.info("CustomBindingExampleResponse Java error:", e);
+               }
         
-        logger.info("ExampleResponse Spring:");
+        
+        
+        LOGGER.info("ExampleResponse Spring:");
         response = example.sendAndReceiveSpring();
-        logger.info(response.getData());
+        LOGGER.info(response.getData());
         
         
-        logger.info("CustomBindingExampleResponse Spring:");
+        LOGGER.info("CustomBindingExampleResponse Spring:");
         customBindingResponse = example.sendAndReceiveSpringCustom();
-        logger.info(customBindingResponse.getData());
+        LOGGER.info(customBindingResponse.getData());
     }
 }
index 26cd175..e419711 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault" />
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault" />
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">
index 5aa51de..5d47d57 100644 (file)
         <Logger name="org.springframework.ws.client.support.interceptor.PayloadValidatingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
         </Logger>
+        
+        <!-- 
+               Con esta configuración podemos loguear mensajes de error (SOAP Fault) procedentes del sevidor customizados. En mi caso
+               usando GeneralFault. No se loguean los de validación (ni de envio de cliente ni de respuesta desde el servidor)
+               porque esto lo hace PayloadValidatingInterceptor.
+         -->
+        <Logger name="de.spring.webservices.client.CustomFaultMessageResolver" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
 
         <!-- Specific log level for SOAP XML messages.
                 
                 
                 This configuration enables us to log the SOAP XML Request (sent from this client), Response (sent by remote server) and Fault (sent by remote server).
        -->
-               <Logger name="org.springframework.ws.client.MessageTracing" level="TRACE" additivity="false">
+               <Logger name="org.springframework.ws.client.MessageTracing" level="INFO" additivity="false">
                        <AppenderRef ref="STDOUT" />
         </Logger>
-        <Logger name="org.springframework.ws.server.MessageTracing" level="TRACE" additivity="false">
+        <Logger name="org.springframework.ws.server.MessageTracing" level="INFO" additivity="false">
                <AppenderRef ref="STDOUT" />
                </Logger>
         
index b701475..a824d54 100644 (file)
      <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <!-- 
                contextPath because of Examples autogenerated class, which is an @Weberservice interface.
+               
+               cxf-codegen-plugin DOES generate again the objects in web-services-spring-jaxb2-globalxsds :(
+               So we MAY NOT scan everything because there is more than one class representing
+               the same XML element. :(
+               
+               We scan the objects generated in this package.
         -->
        <property name="contextPath" value="de.spring.webservices.client.auto:name.gumartinm.spring_ws.parent"/>
         </bean>
         <property name="validateResponse" value="true"/>
     </bean>
     
+       <!-- 
+               Los errores de validacion se devuelven así:
+               
+               <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
+                  <env:Header/>
+                  <env:Body>
+                     <env:Fault>
+                        <env:Code>
+                           <env:Value>env:Sender</env:Value>
+                        </env:Code>
+                        <env:Reason>
+                           <env:Text xml:lang="en">Validation error</env:Text>
+                        </env:Reason>
+                        <env:Detail>
+                           <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-maxLength-valid: El valor 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' con la longitud = '91' no es de faceta válida con respecto a maxLength '30' para el tipo 'limitedString'.</spring-ws:ValidationError>
+                           <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-type.3.1.3: El valor 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' del elemento 'exam:data' no es válido.</spring-ws:ValidationError>
+                        </env:Detail>
+                     </env:Fault>
+                  </env:Body>
+               </env:Envelope>
+               
+               El manejador de errores de validación es implementado por AbstractValidatingInterceptor (PayloadValidatingInterceptor)
+               luego si quisiéramos loguear los mensaje de error de validación de algún modo especial tendríamos que crear nuestro propio PayloadValidatingInterceptor :(
+        -->
+    
+    <!-- Enables us to log custom Fault remote messages. No loguea mensajes de error de validación :( -->
+    <bean id="customFaultMessageResolver" class="de.spring.webservices.client.CustomFaultMessageResolver">
+               <property name="unmarshaller" ref="marshaller"/>
+       </bean>
     
     <!-- 
     WebServiceTemplate using these strategies by default (see WebServiceTemplate.properties file)
                 <ref bean="payloadValidatingInterceptor" />
             </list>
         </property>
+        
+        <property name="faultMessageResolver" ref="customFaultMessageResolver" />
     </bean>
     
     <!--
index c5801a6..165c6fd 100644 (file)
         </xs:sequence>
     </xs:complexType>
     
-    <xs:complexType name="generalFault">
-        <xs:sequence>
-               <xs:element name="technicalError" type="xs:string" />
-               <xs:element name="elements" type="parent:element" minOccurs="0" maxOccurs="unbounded"/>
-        </xs:sequence>
-    </xs:complexType>
+    <xs:element name="GeneralFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element name="technicalError" type="xs:string" />
+                       <xs:element name="elements" type="parent:element" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 </xs:schema>
index 26cd175..e419711 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault" />
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault" />
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">
index 28a4ed7..ea6ded3 100644 (file)
@@ -32,6 +32,8 @@
                see soap-ws.xml Spring configuration file.
                
                This configuration enables us to log validation errors of data sent from remote client or data created by this server.
+               
+               Los errores de validación se loguean aquí (tanto de validación de datos de respuesta de servidor como de datos recibidos desde cliente)
          -->
         <Logger name="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
@@ -43,6 +45,8 @@
                 see soap-ws.xml Spring configuration file.
                 
                 This configuration enables us to log the SOAP XML Request (received from remote client), Response (sent by this server) and Fault (sent by this server).
+                
+                Aquí no se loguean errores de validación.
        -->
         <Logger name="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
index 374ed46..2018a37 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault"/>
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault"/>
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">
diff --git a/jaxb2/web-services-spring-jaxb2-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java b/jaxb2/web-services-spring-jaxb2-client/src/main/java/de/spring/webservices/client/CustomFaultMessageResolver.java
new file mode 100644 (file)
index 0000000..9fdea6b
--- /dev/null
@@ -0,0 +1,83 @@
+package de.spring.webservices.client;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.xml.transform.Source;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.oxm.Unmarshaller;
+import org.springframework.oxm.XmlMappingException;
+import org.springframework.ws.WebServiceMessage;
+import org.springframework.ws.client.core.FaultMessageResolver;
+import org.springframework.ws.soap.SoapBody;
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapFaultDetail;
+import org.springframework.ws.soap.SoapFaultDetailElement;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.client.core.SoapFaultMessageResolver;
+
+// maven-jaxb2-plugin for WSDL DOES generate again the objects in web-services-spring-jaxb2-globalxsds :(
+// So I guess it is better to use the objects generated in this package
+// than the ones from globalxsds even if they should be the same.
+import de.spring.webservices.client.auto.GeneralFault;
+
+/**
+ * Enables us to log custom Fault remote messages. 
+ *
+ */
+public class CustomFaultMessageResolver implements FaultMessageResolver {
+
+private static final Logger LOGGER = LoggerFactory.getLogger(CustomFaultMessageResolver.class);
+       
+       private final FaultMessageResolver defaultMessageResolver = new SoapFaultMessageResolver();
+       
+       private Unmarshaller unmarshaller;
+       
+       @Override
+       public void resolveFault(WebServiceMessage message) throws IOException {
+               
+               // Same behavior as default message resolver (SoapFaultMessageResolver) but this implementation also
+               // logs error information.
+               if (LOGGER.isErrorEnabled()) {
+                       try {
+                               logErrorInformation(message);
+                       } catch (Exception ex) {
+                               LOGGER.error("CustomFaultMessageResolver exception:", ex);
+                       }
+               }
+               
+               defaultMessageResolver.resolveFault(message);
+       }
+       
+       private void logErrorInformation(WebServiceMessage message) throws XmlMappingException, IOException {
+               SoapMessage soapMessage = (SoapMessage) message;
+               SoapBody body = soapMessage.getSoapBody();
+               SoapFault soapFault = body != null ? body.getFault() : null;
+               SoapFaultDetail detail = soapFault != null ? soapFault.getFaultDetail() : null;
+               
+               if (detail != null) {
+                       Iterator<SoapFaultDetailElement> iterator = detail.getDetailEntries();
+                       while (iterator.hasNext()) {
+                               SoapFaultDetailElement bodyElement = iterator.next();
+                               Source detailSource = bodyElement.getSource();
+                               // TODO: How to check if I am receiving GeneralFault before trying to unmarshal?
+                               //       Right now there will be exception if unmarshal doesn't return a GeneralFault object.
+                               GeneralFault error = (GeneralFault)this.unmarshaller.unmarshal(detailSource);
+                               LOGGER.error("TECHNICALERROR:");
+                               LOGGER.error(error.getTechnicalError());
+                               LOGGER.error("ELEMENTS:");
+                               error.getElements().forEach(element -> {
+                                       LOGGER.error("MESSAGE: " + element.getMessage());
+                                       LOGGER.error("MESSAGEARGS:");
+                                       element.getMessageArgs().forEach(messageArg -> LOGGER.error(messageArg));
+                               });
+                       }
+               }
+       }
+       
+       public void setUnmarshaller(Unmarshaller unmarshaller) {
+               this.unmarshaller = unmarshaller;
+       }
+}
index 8d79220..92b1638 100644 (file)
@@ -14,7 +14,7 @@ import de.spring.webservices.client.auto.ExampleResponse;
  * 
  */
 public class MainTest {
-       private static final Logger logger = LoggerFactory.getLogger(MainTest.class);
+       private static final Logger LOGGER = LoggerFactory.getLogger(MainTest.class);
        
     public ApplicationContext context;
 
@@ -41,13 +41,13 @@ public class MainTest {
 //        logger.info(customBindingResponse.getData());
         
         
-        logger.info("ExampleResponse Spring:");
+        LOGGER.info("ExampleResponse Spring:");
         ExampleResponse response = example.sendAndReceiveSpring();
-        logger.info(response.getData());
+        LOGGER.info(response.getData());
         
         
-        logger.info("CustomBindingExampleResponse Spring:");
+        LOGGER.info("CustomBindingExampleResponse Spring:");
         CustomBindingExampleResponse customBindingResponse = example.sendAndReceiveSpringCustom();
-        logger.info(customBindingResponse.getData());
+        LOGGER.info(customBindingResponse.getData());
     }
 }
index 5aa51de..5d47d57 100644 (file)
         <Logger name="org.springframework.ws.client.support.interceptor.PayloadValidatingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
         </Logger>
+        
+        <!-- 
+               Con esta configuración podemos loguear mensajes de error (SOAP Fault) procedentes del sevidor customizados. En mi caso
+               usando GeneralFault. No se loguean los de validación (ni de envio de cliente ni de respuesta desde el servidor)
+               porque esto lo hace PayloadValidatingInterceptor.
+         -->
+        <Logger name="de.spring.webservices.client.CustomFaultMessageResolver" level="INFO" additivity="false">
+            <AppenderRef ref="STDOUT" />
+        </Logger>
 
         <!-- Specific log level for SOAP XML messages.
                 
                 
                 This configuration enables us to log the SOAP XML Request (sent from this client), Response (sent by remote server) and Fault (sent by remote server).
        -->
-               <Logger name="org.springframework.ws.client.MessageTracing" level="TRACE" additivity="false">
+               <Logger name="org.springframework.ws.client.MessageTracing" level="INFO" additivity="false">
                        <AppenderRef ref="STDOUT" />
         </Logger>
-        <Logger name="org.springframework.ws.server.MessageTracing" level="TRACE" additivity="false">
+        <Logger name="org.springframework.ws.server.MessageTracing" level="INFO" additivity="false">
                <AppenderRef ref="STDOUT" />
                </Logger>
         
index 26cd175..e419711 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault" />
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault" />
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">
index cd67e3e..389f361 100644 (file)
@@ -53,6 +53,8 @@
                maven-jaxb2-plugin for WSDL DOES generate again the objects in web-services-spring-jaxb2-globalxsds :(
                So we MAY NOT scan everything because there is more than one class representing
                the same XML element. :(
+               
+               We scan the objects generated in this package.
        -->
        <property name="packagesToScan" value="de.spring.webservices.client.auto"/>
        </bean>
     </bean>
     
     <!-- 
+               Los errores de validacion se devuelven así:
+               
+               <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
+                  <env:Header/>
+                  <env:Body>
+                     <env:Fault>
+                        <env:Code>
+                           <env:Value>env:Sender</env:Value>
+                        </env:Code>
+                        <env:Reason>
+                           <env:Text xml:lang="en">Validation error</env:Text>
+                        </env:Reason>
+                        <env:Detail>
+                           <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-maxLength-valid: El valor 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' con la longitud = '91' no es de faceta válida con respecto a maxLength '30' para el tipo 'limitedString'.</spring-ws:ValidationError>
+                           <spring-ws:ValidationError xmlns:spring-ws="http://springframework.org/spring-ws">cvc-type.3.1.3: El valor 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' del elemento 'exam:data' no es válido.</spring-ws:ValidationError>
+                        </env:Detail>
+                     </env:Fault>
+                  </env:Body>
+               </env:Envelope>
+               
+               El manejador de errores de validación es implementado por AbstractValidatingInterceptor (PayloadValidatingInterceptor)
+               luego si quisiéramos loguear los mensaje de error de validación de algún modo especial tendríamos que crear nuestro propio PayloadValidatingInterceptor :(          
+        -->
+    
+    <!-- Enables us to log custom Fault remote messages. No loguea mensajes de error de validación :( -->
+    <bean id="customFaultMessageResolver" class="de.spring.webservices.client.CustomFaultMessageResolver">
+               <property name="unmarshaller" ref="marshaller"/>
+       </bean>
+       
+    <!-- 
     WebServiceTemplate using these strategies by default (see WebServiceTemplate.properties file)
     
     org.springframework.ws.client.core.FaultMessageResolver=org.springframework.ws.soap.client.core.SoapFaultMessageResolver
         <property name="unmarshaller" ref="marshaller" />
 
         <!-- For local deployments change to http://localhost:8080/web-services-spring-jaxb2-server/spring-ws/example -->
-        <property name="defaultUri" value="http://gumartinm.name/spring-ws/example"/>
+        <property name="defaultUri" value="http://localhost:8080/web-services-spring-cxf-server/spring-ws/example"/>
 
         <property name="interceptors">
             <list>
                 <ref bean="payloadValidatingInterceptor" />
             </list>
         </property>
+        
+        <property name="faultMessageResolver" ref="customFaultMessageResolver" />
     </bean>
     
     <!--
index c5801a6..165c6fd 100644 (file)
         </xs:sequence>
     </xs:complexType>
     
-    <xs:complexType name="generalFault">
-        <xs:sequence>
-               <xs:element name="technicalError" type="xs:string" />
-               <xs:element name="elements" type="parent:element" minOccurs="0" maxOccurs="unbounded"/>
-        </xs:sequence>
-    </xs:complexType>
+    <xs:element name="GeneralFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element name="technicalError" type="xs:string" />
+                       <xs:element name="elements" type="parent:element" minOccurs="0" maxOccurs="unbounded"/>
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 </xs:schema>
index 28a4ed7..ea6ded3 100644 (file)
@@ -32,6 +32,8 @@
                see soap-ws.xml Spring configuration file.
                
                This configuration enables us to log validation errors of data sent from remote client or data created by this server.
+               
+               Los errores de validación se loguean aquí (tanto de validación de datos de respuesta de servidor como de datos recibidos desde cliente)
          -->
         <Logger name="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
@@ -43,6 +45,8 @@
                 see soap-ws.xml Spring configuration file.
                 
                 This configuration enables us to log the SOAP XML Request (received from remote client), Response (sent by this server) and Fault (sent by this server).
+                
+                Aquí no se loguean errores de validación.
        -->
         <Logger name="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor" level="INFO" additivity="false">
             <AppenderRef ref="STDOUT" />
index 26cd175..e419711 100644 (file)
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="ExampleFault" type="parent:generalFault" />
+    <xs:element name="ExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
 
        <!-- Using custombinding.xjb instead of inheritance plugin.
             </xs:all>
         </xs:complexType>
     </xs:element>
-    <xs:element name="CustomBindingExampleFault" type="parent:generalFault" />
+    <xs:element name="CustomBindingExampleFault">
+       <xs:complexType>
+               <xs:sequence>
+                       <xs:element ref="parent:GeneralFault" />
+               </xs:sequence>
+       </xs:complexType>
+    </xs:element>
 
        <!-- Example of creating array list by means of XSD -->
     <xs:complexType name="car">