jaxb2: schemas in PayloadValidatingInterceptor, ORDER MATTERS!!!!
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 20 Dec 2015 18:25:22 +0000 (19:25 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 20 Dec 2015 18:25:22 +0000 (19:25 +0100)
jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomExceptionResolver.java [deleted file]
jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java [new file with mode: 0644]
jaxb2/web-services-spring-jaxb2-server/src/main/resources/spring-configuration/ws/soap-ws.xml

diff --git a/jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomExceptionResolver.java b/jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomExceptionResolver.java
deleted file mode 100644 (file)
index f2a375f..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package de.spring.webservices.endpoints;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.xml.transform.Result;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.oxm.Marshaller;
-import org.springframework.util.CollectionUtils;
-import org.springframework.ws.soap.SoapFault;
-import org.springframework.ws.soap.SoapFaultDetail;
-import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
-import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
-import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
-
-import de.spring.webservices.auto.Element;
-import de.spring.webservices.auto.ExampleFault;
-import de.spring.webservices.exceptions.CustomBusinessException;
-
-public class MyCustomExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
-       private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomExceptionResolver.class);
-       
-       private Marshaller marshaller;
-
-       private Map<String, String> exceptionMappings = new LinkedHashMap<>();
-
-       /**
-        * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
-        * no wildcard support at present.
-        *
-        * <p>The values of the given properties object should use the format described in
-        * {@code SoapFaultDefinitionEditor}.
-        *
-        * <p>Follows the same matching algorithm as {@code SimpleMappingExceptionResolver}.
-        *
-        * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
-        *                                 values
-        * @see SoapFaultDefinitionEditor
-        */
-       public void setExceptionMappings(Properties mappings) {
-               for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
-                       if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
-                               exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
-                       }
-               }
-       }
-       
-       @Override
-       protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
-               if (!CollectionUtils.isEmpty(exceptionMappings)) {
-                       String definitionText = null;
-                       int deepest = Integer.MAX_VALUE;
-                       for (String exceptionMapping : exceptionMappings.keySet()) {
-                               int depth = getDepth(exceptionMapping, ex);
-                               if (depth >= 0 && depth < deepest) {
-                                       deepest = depth;
-                                       definitionText = exceptionMappings.get(exceptionMapping);
-                               }
-                       }
-                       if (definitionText != null) {
-                               SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
-                               editor.setAsText(definitionText);
-                               return (SoapFaultDefinition) editor.getValue();
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Return the depth to the superclass matching. {@code 0} means ex matches exactly. Returns {@code -1} if
-        * there's no match. Otherwise, returns depth. Lowest depth wins.
-        *
-        * <p>Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
-        */
-       protected int getDepth(String exceptionMapping, Exception ex) {
-               return getDepth(exceptionMapping, ex.getClass(), 0);
-       }
-
-       @SuppressWarnings("unchecked")
-       private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
-               if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
-                       return depth;
-               }
-               if (exceptionClass.equals(Throwable.class)) {
-                       return -1;
-               }
-               return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
-       }
-
-       protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
-               SoapFaultDetail detail = fault.addFaultDetail();
-               Result result = detail.getResult();
-               
-               Element element = new Element();
-               element.setMessage(ex.getMessage());
-               
-               if (ex instanceof CustomBusinessException) {
-                       List<String> arguments = element.getMessageArgs();
-                       arguments.add("ARGUMENT 1");
-                       arguments.add("ARGUMENT 2");
-               }
-               
-               ExampleFault customFault = new ExampleFault();
-               customFault.setTechnicalError(getStackTrace(ex));
-               List<Element> elements = customFault.getElements();
-               elements.add(element);
-               
-               try {
-                       marshaller.marshal(customFault, result);
-               } catch (Exception marshallEx) {
-                       LOGGER.error("", marshallEx);
-               }
-       }
-       
-       public void setMarshaller(Marshaller marshaller) {
-               this.marshaller = marshaller;
-       }
-       
-       private static String getStackTrace(final Throwable throwable) {
-            final StringWriter sw = new StringWriter();
-            final PrintWriter pw = new PrintWriter(sw, true);
-            throwable.printStackTrace(pw);
-            return sw.getBuffer().toString();
-       }
-}
diff --git a/jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java b/jaxb2/web-services-spring-jaxb2-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java
new file mode 100644 (file)
index 0000000..f2a375f
--- /dev/null
@@ -0,0 +1,131 @@
+package de.spring.webservices.endpoints;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.Result;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.oxm.Marshaller;
+import org.springframework.util.CollectionUtils;
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapFaultDetail;
+import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
+import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
+import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
+
+import de.spring.webservices.auto.Element;
+import de.spring.webservices.auto.ExampleFault;
+import de.spring.webservices.exceptions.CustomBusinessException;
+
+public class MyCustomExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
+       private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomExceptionResolver.class);
+       
+       private Marshaller marshaller;
+
+       private Map<String, String> exceptionMappings = new LinkedHashMap<>();
+
+       /**
+        * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
+        * no wildcard support at present.
+        *
+        * <p>The values of the given properties object should use the format described in
+        * {@code SoapFaultDefinitionEditor}.
+        *
+        * <p>Follows the same matching algorithm as {@code SimpleMappingExceptionResolver}.
+        *
+        * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
+        *                                 values
+        * @see SoapFaultDefinitionEditor
+        */
+       public void setExceptionMappings(Properties mappings) {
+               for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
+                       if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
+                               exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
+                       }
+               }
+       }
+       
+       @Override
+       protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
+               if (!CollectionUtils.isEmpty(exceptionMappings)) {
+                       String definitionText = null;
+                       int deepest = Integer.MAX_VALUE;
+                       for (String exceptionMapping : exceptionMappings.keySet()) {
+                               int depth = getDepth(exceptionMapping, ex);
+                               if (depth >= 0 && depth < deepest) {
+                                       deepest = depth;
+                                       definitionText = exceptionMappings.get(exceptionMapping);
+                               }
+                       }
+                       if (definitionText != null) {
+                               SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
+                               editor.setAsText(definitionText);
+                               return (SoapFaultDefinition) editor.getValue();
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Return the depth to the superclass matching. {@code 0} means ex matches exactly. Returns {@code -1} if
+        * there's no match. Otherwise, returns depth. Lowest depth wins.
+        *
+        * <p>Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
+        */
+       protected int getDepth(String exceptionMapping, Exception ex) {
+               return getDepth(exceptionMapping, ex.getClass(), 0);
+       }
+
+       @SuppressWarnings("unchecked")
+       private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
+               if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
+                       return depth;
+               }
+               if (exceptionClass.equals(Throwable.class)) {
+                       return -1;
+               }
+               return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
+       }
+
+       protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
+               SoapFaultDetail detail = fault.addFaultDetail();
+               Result result = detail.getResult();
+               
+               Element element = new Element();
+               element.setMessage(ex.getMessage());
+               
+               if (ex instanceof CustomBusinessException) {
+                       List<String> arguments = element.getMessageArgs();
+                       arguments.add("ARGUMENT 1");
+                       arguments.add("ARGUMENT 2");
+               }
+               
+               ExampleFault customFault = new ExampleFault();
+               customFault.setTechnicalError(getStackTrace(ex));
+               List<Element> elements = customFault.getElements();
+               elements.add(element);
+               
+               try {
+                       marshaller.marshal(customFault, result);
+               } catch (Exception marshallEx) {
+                       LOGGER.error("", marshallEx);
+               }
+       }
+       
+       public void setMarshaller(Marshaller marshaller) {
+               this.marshaller = marshaller;
+       }
+       
+       private static String getStackTrace(final Throwable throwable) {
+            final StringWriter sw = new StringWriter();
+            final PrintWriter pw = new PrintWriter(sw, true);
+            throwable.printStackTrace(pw);
+            return sw.getBuffer().toString();
+       }
+}
index 243e56d..dc7d6f5 100644 (file)
@@ -98,7 +98,7 @@
     <sws:dynamic-wsdl id="example" portTypeName="Examples"
         createSoap12Binding="true" createSoap11Binding="false"
         locationUri="/spring-ws/example"
-        targetNamespace="http://gumartinm.name/resource/wsdl/schemas">
+        targetNamespace="http://gumartinm.name/spring-ws/exampleService">
         <sws:xsd location="classpath:schemas/examples.xsd"/>
     </sws:dynamic-wsdl>
 
             class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
             <property name="schemas">
                 <list>
-                    <value>classpath:schemas/examples.xsd</value>
+                       <!--
+                                ALWAYS FIRST THE XSD FILES TO BE IMPORTED!!!!!  O.o
+                                OTHERWISE THE import IN examples.xsd WILL BE SOLVED BY MEANS OF DOWNLOADING THE
+                                EXTERNAL parent.xsd (USING THE URL LINKED BY THE IMPORT STATEMENT IN examples.xsd)
+                                
+                                        IF YOU DON'T DO THIS, PayloadValidatingInterceptor WILL TRY TO CONNECT TO THE
+                                        EXTERNAL SERVER WHERE parent.xsd IS LOCATED AND IT WILL FAIL IF BECAUSE SOME
+                                        REASON YOU DON'T HAVE IN THAT VERY MOMENT NETWORK CONNECTION. SO, DON'T MESS WITH THIS
+                                        CONFIGURATION.
+                        -->
                     <value>classpath:schemas/parent.xsd</value>
+                    
+                    <value>classpath:schemas/examples.xsd</value>
                 </list>
             </property>
             <property name="validateRequest" value="true"/>
         class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
         <!--
                No quiero usar un valor por defecto porque si no, si mi manejador no machea ninguna excepción
-               devolvera este valor por defecto.
+               devolvera este valor por defecto. Y no se probará con otros manejadores de excepción que tengan un order con menor precedencia.
                
                Cuando se escribe value="SERVER" Spring está seteando SoapFaultDefinition.SERVER en defaultValue
                de org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver Esto parece
     
     
     
-    <bean id="myCustomExceptionResolver" class="de.spring.webservices.endpoints.MyCustomExceptionResolver">
+    <bean id="myCustomMappingExceptionResolver" class="de.spring.webservices.endpoints.MyCustomMappingExceptionResolver">
+        <!--
+               Voy a usar un valor por defecto porque este va a ser el último manejador que haya antes de
+               SimpleSoapExceptionResolver. SimpleSoapExceptionResolver será siempre por el order que he puesto
+               el último manejador de excepciones.
+                       Así todas las excepciones que no hayan sido macheadas por los otros manejadores serán siempre
+                       cogidas por este y se les asignará un SoapFaultDefinition.SERVER. En este caso SimpleSoapExceptionResolver
+                       nunca será usado.
+        -->
+        <property name="defaultFault" value="SERVER"/>
         <property name="exceptionMappings">
             <props>