cxf: multiple changes following jabx2 implementation
authorGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 20 Dec 2015 19:16:54 +0000 (20:16 +0100)
committerGustavo Martin Morcuende <gu.martinm@gmail.com>
Sun, 20 Dec 2015 19:16:54 +0000 (20:16 +0100)
cxf/web-services-spring-cxf-client/src/main/build-resources/wsdl/example.wsdl
cxf/web-services-spring-cxf-client/src/main/resources/spring-configuration/ws/client-spring-configuration.xml
cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/endpoints/MyCustomExceptionResolver.java [deleted file]
cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java [new file with mode: 0644]
cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/exceptions/CustomBusinessException.java
cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/services/impl/CustomBindingExampleServiceImpl.java
cxf/web-services-spring-cxf-server/src/main/resources/spring-configuration/ws/soap-ws.xml

index 5094a3a..f0ddf0f 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://gumartinm.name/spring-ws/example" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://gumartinm.name/resource/wsdl/schemas" targetNamespace="http://gumartinm.name/resource/wsdl/schemas">
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://gumartinm.name/spring-ws/example" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://gumartinm.name/spring-ws/exampleService" targetNamespace="http://gumartinm.name/spring-ws/exampleService">
   <wsdl:types>
     <xs:schema xmlns:annox="http://annox.dev.java.net" xmlns:example="http://gumartinm.name/spring-ws/example" xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:parent="http://gumartinm.name/spring-ws/parent" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" jaxb:extensionBindingPrefixes="inheritance annox" jaxb:version="2.1" targetNamespace="http://gumartinm.name/spring-ws/example">
     
     <wsdl:part element="sch:CustomBindingExampleFault" name="CustomBindingExampleFault">
     </wsdl:part>
   </wsdl:message>
-  <wsdl:message name="CustomBindingExampleRequest">
-    <wsdl:part element="sch:CustomBindingExampleRequest" name="CustomBindingExampleRequest">
-    </wsdl:part>
-  </wsdl:message>
   <wsdl:message name="ExampleRequest">
     <wsdl:part element="sch:ExampleRequest" name="ExampleRequest">
     </wsdl:part>
     <wsdl:part element="sch:CustomBindingExampleResponse" name="CustomBindingExampleResponse">
     </wsdl:part>
   </wsdl:message>
+  <wsdl:message name="CustomBindingExampleRequest">
+    <wsdl:part element="sch:CustomBindingExampleRequest" name="CustomBindingExampleRequest">
+    </wsdl:part>
+  </wsdl:message>
   <wsdl:portType name="Examples">
     <wsdl:operation name="Example">
       <wsdl:input message="tns:ExampleRequest" name="ExampleRequest">
   </wsdl:binding>
   <wsdl:service name="ExamplesService">
     <wsdl:port binding="tns:ExamplesSoap12" name="ExamplesSoap12">
-      <soap12:address location="http://localhost:8080/web-services-spring-jaxb2-server/spring-ws/example"/>
+      <soap12:address location="http://localhost:8080/web-services-spring-cxf-server/spring-ws/example"/>
     </wsdl:port>
   </wsdl:service>
 </wsdl:definitions>
\ No newline at end of file
index f231006..5025d2f 100644 (file)
@@ -63,7 +63,8 @@
                        at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:888)
                        
                ESTE ERROR SE PRODUCE PORQUE cxf-codegen-plugin GENERA Examples QUE ES UN inteface @WebService
-               maven-jaxb2-plugin NO GENERA ESTOS OBJETOS (otra razón más para usar maven-jaxb2-plugin)
+               maven-jaxb2-plugin NO GENERA ESTOS OBJETOS pero maven-jaxb2-plugin NO ES BUENO PARA GENERAR CLASES
+               DESDE WSDLs POR LAS RAZONES EXPLICADAS EN EL pom.xml DEL PROYECTO web-services-spring-jaxb2-client.
      -->
      <oxm:jaxb2-marshaller id="marshaller" context-path="de.spring.webservices.auto"/>
        
         class="org.springframework.ws.client.support.interceptor.PayloadValidatingInterceptor">
         <property name="schemas">
             <list>
-                <value>classpath:examples.xsd</value>
-                <value>classpath:parent.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:parent.xsd</value>
+                    
+                 <value>classpath:examples.xsd</value>
             </list>
         </property>
         <property name="validateRequest" value="true"/>
         <property name="validateResponse" value="true"/>
     </bean>
     
+    
+    <!-- 
+    Strategies used by default (see WebServiceTemplate.properties file)
+    
+    org.springframework.ws.client.core.FaultMessageResolver=org.springframework.ws.soap.client.core.SoapFaultMessageResolver
+       org.springframework.ws.WebServiceMessageFactory=org.springframework.ws.soap.saaj.SaajSoapMessageFactory
+       org.springframework.ws.transport.WebServiceMessageSender=org.springframework.ws.transport.http.HttpUrlConnectionMessageSender
+    
+     -->
 
     <bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
         <constructor-arg ref="messageFactory"/>
diff --git a/cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/endpoints/MyCustomExceptionResolver.java b/cxf/web-services-spring-cxf-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/cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java b/cxf/web-services-spring-cxf-server/src/main/java/de/spring/webservices/endpoints/MyCustomMappingExceptionResolver.java
new file mode 100644 (file)
index 0000000..f07d42e
--- /dev/null
@@ -0,0 +1,140 @@
+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 MyCustomMappingExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
+       private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomMappingExceptionResolver.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) {
+               ExampleFault customFault = new ExampleFault();
+               customFault.setTechnicalError(getStackTrace(ex));
+               
+               Element element = buildElement(ex);
+               List<Element> elements = customFault.getElements();
+               elements.add(element);
+               
+               SoapFaultDetail detail = fault.addFaultDetail();
+               Result result = detail.getResult();
+               try {
+                       marshaller.marshal(customFault, result);
+               } catch (Exception marshallEx) {
+                       LOGGER.error("MyCustomMappingExceptionResolver: marshaller error", marshallEx);
+               }
+       }
+       
+       public void setMarshaller(Marshaller marshaller) {
+               this.marshaller = marshaller;
+       }
+               
+       private Element buildElement(Exception ex) {
+               Element element = new Element();
+               element.setMessage(ex.getMessage());
+               
+               if (ex instanceof CustomBusinessException) {
+                       CustomBusinessException customEx = (CustomBusinessException) ex;
+                       List<String> messageArgs = element.getMessageArgs();
+                       List<String> argumentsEx = customEx.getArguments();
+                       
+                       for (String argumentEx: argumentsEx) {
+                               messageArgs.add(argumentEx);
+                       }
+               }
+               
+               return element;
+       }
+       
+       private String getStackTrace(Throwable throwable) {
+            final StringWriter sw = new StringWriter();
+            final PrintWriter pw = new PrintWriter(sw, true);
+            throwable.printStackTrace(pw);
+            return sw.getBuffer().toString();
+       }
+}
index 952e765..549c0b9 100644 (file)
@@ -3,7 +3,7 @@ package de.spring.webservices.exceptions;
 import java.util.List;
 
 /**
- * This exception will be caught by de.spring.webservices.endpoints.MyCustomExceptionResolver
+ * This exception will be caught by de.spring.webservices.endpoints.MyCustomMappingExceptionResolver
  *
  */
 public class CustomBusinessException extends RuntimeException {
index c5ce222..9863bae 100644 (file)
@@ -28,7 +28,7 @@ public class CustomBindingExampleServiceImpl implements
                // see soap-ws.xml Spring configuration file.
 //             throw new BusinessException("This feature has not been implemented yet.");
                
-               // Example about how works de.spring.webservices.endpoints.MyCustomExceptionResolver
+               // Example about how works de.spring.webservices.endpoints.MyCustomMappingExceptionResolver
                // see soap-ws.xml Spring configuration file.
 //             List<String> arguments = new ArrayList<>();
 //             arguments.add("ARGUMENT 1");
index 27ccc48..6dd10fc 100644 (file)
     <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:examples.xsd"/>
     </sws:dynamic-wsdl>
 
 
-    <bean id="parent" class="org.springframework.xml.xsd.SimpleXsdSchema">
-        <property name="xsd" value="classpath:parent.xsd"/>
-    </bean>
-
-
     <!-- Required in order to use SOAP 1.2
         id="messageFactory" is not a random choice, if you use another name it will not work
         (Spring will end up loading SOAP 1.1)
             class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
             <property name="schemas">
                 <list>
-                    <value>classpath: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:parent.xsd</value>
+                    
+                    <value>classpath: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>
-
                        <prop key="de.spring.webservices.exceptions.CustomBusinessException">SERVER</prop>
                </props>
         </property>