dba53c43fdd14e75858eee0731caf88c0303a95f
[SpringWebServicesForFun/.git] / cxf / web-services-spring-cxf-server / src / main / resources / spring-configuration / ws / soap-ws.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   xmlns:context="http://www.springframework.org/schema/context"
5   xmlns:sws="http://www.springframework.org/schema/web-services"
6   xmlns:util="http://www.springframework.org/schema/util"
7
8   xsi:schemaLocation="http://www.springframework.org/schema/beans 
9                       http://www.springframework.org/schema/beans/spring-beans.xsd
10                       http://www.springframework.org/schema/web-services 
11                       http://www.springframework.org/schema/web-services/web-services.xsd
12                       http://www.springframework.org/schema/context 
13                       http://www.springframework.org/schema/context/spring-context.xsd
14                       http://www.springframework.org/schema/util 
15                       http://www.springframework.org/schema/util/spring-util.xsd">
16
17         <!-- Searches for beans in packages (instead of XML configuration we can use in this way annotations like @Service, @Endpoint, etc, etc)  -->
18     <context:component-scan base-package="de.spring.webservices"/>
19
20     <!--
21         Three ways of using a marshallers/unmarshallers.
22         
23         1. No declarar nada en el XML y dejar que Spring lo haga internamente todo por nosotros.
24         Esto equivale a esta configuracion en XML
25         
26         <oxm:jaxb2-marshaller id="marshaller" context-path="de.spring.webservices"/>
27         El context-path Spring supongo que lo rellena automáticamente en base al component-scan declarado arriba.
28         
29         2. Especificando el context-path para ser escaneado por Spring usando anotaciones. Esto
30         se hace de este modo:
31         
32         <oxm:jaxb2-marshaller id="marshaller" context-path="de.spring.webservices.server.auto"/>
33         Esto es lo mismo que haría Spring si no declaramos nada en el XML pero así tenemos opción de
34         de especificar un context-path en concreto.
35         
36         3. Especificando la implementación concreta del marshaller.
37         Con esta opción además puedo usar packagesToScan, contest-path si no recuerdo mal tenía problemas
38         cuando había dos ObjectFactory con el mismo package. Uno está en globalxsds y otro en este proyecto.
39         De todos modos, probablemente habría que usar un package distinto para lo que hay
40         en globalxsds (quizás incluso basado en el namespace del xsd) y así podría evitar esta configuración.
41      -->
42     <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
43         <!--
44                 cxf-xjc-plugin generates again the objects in web-services-spring-cxf-globalxsds :(
45                 So we MAY NOT scan everything because there is more than one class representing
46                 the same XML element. :(
47         -->
48         <property name="packagesToScan" value="de.spring.webservices.server.auto"/>
49         </bean>
50         <!-- Searches for @PayloadRoot -->
51     <sws:annotation-driven marshaller="marshaller" unmarshaller="marshaller" />
52     
53     
54     <!-- 
55         CONSECUENCIAS DE USAR sws:annotation-driven VER: org.springframework.ws.config.AnnotationDrivenBeanDefinitionParser
56         Cuanto más bajo es el valor de order mayor es la prioridad.
57         
58         1. Manejadores de excepción, orden por defecto inicializado en AnnotationDrivenBeanDefinitionParser:
59         a) SoapFaultAnnotationExceptionResolver será el primer manejador de excepciones que se intente usar por defecto. order = 0
60         b) SimpleSoapExceptionResolver será el último manejador de excepciones que se intente usar por defecto. order = Ordered.LOWEST_PRECEDENCE
61                    Se usará si la excepción generada no pudo ser manejada por SoapFaultAnnotationExceptionResolver (porque la excepción no fue anotada con
62                    @SoapFault. Este manejador se traga cualquier excepción.
63         
64         2. Endpoints a buscar, orden por defecto inicializado en AnnotationDrivenBeanDefinitionParser:
65         a) PayloadRootAnnotationMethodEndpointMapping será el primer tipo de endpoints que se buscará y que se intentará usar. order = 0
66                    Si el XML SOAP que llega no machea ningún metodo anotado con este EndPoint pasamos a b).
67         b) SoapActionAnnotationMethodEndpointMapping será el segundo tipo de endpoints que se intentará usar. order = 1
68                    Si el XML SOAP que llega no machea ningún metodo anotado con este EndPoint pasamos a c).
69         c) AnnotationActionEndpointMapping será el último tipo de endpoints que se buscará. order = 2
70                    Si el XML SOAP que llega no machea tampoco métodos anotado con este EndPoint se
71                    lanza NoEndpointFoundException desde org.springframework.ws.server.MessageDispatcher.dispatch()
72         
73         
74         EN LUGAR DE USAR LA ANOTACIÓN PODRÍAMOS HABER DECLARADO EXPLÍCITAMENTE CADA BEAN TAL QUE ASÍ:
75         
76         <bean id="soapFaultMappingExceptionResolver"
77                 class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
78                 <property name="order" value="0" />
79         </bean>
80         
81         <bean id="payloadRootAnnotationMethodEndpointMapping"
82                 class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
83                 <property name="order" value="0" />
84         </bean>
85         
86         CON LA ANOTACIÓN ME AHORRO DECLARAR bean POR bean PERO LO MALO ES QUE INSTANCIO MANEJADORES QUE LUEGO NO USO :(
87         
88         
89         ATENCION:
90         Solo se usa una instancia de org.springframework.oxm.jaxb.Jaxb2Marshaller que será usada por todas las llamadas (todos los hilos).
91         Es hilo seguro, por debajo usa javax.xml.bind.JAXBContext que es hilo seguro.
92         JAXBContext debe ser siempre un singleton porque la primera vez tarda mucho en inicializarse. Cada vez que se haga marshalling y unmarshalling
93         se deben crear objetos ligeros y no seguros mediante los métodos JAXBContext.createMarshaller() y JAXBContext.createUnmarshaller()
94         (esto es lo que hace Jaxb2Marshaller por nosotros) Los objetos ligeros creados son javax.xml.bind.Marshaller y javax.xml.bind.Unmarshaller
95         que no son hilo seguro y por tanto serán creados por cada petición (todo esto lo está haciendo Spring ya, así que genial)
96      -->
97
98     <!--
99         Spring makes the WSDL file for us from the XSD file.
100         Launch the Jetty server and download WSDL file from this URL:
101         http://localhost:8080/web-services-spring-jaxb2-server/spring-ws/example/example.wsdl
102     -->
103     <sws:dynamic-wsdl id="example" portTypeName="Examples"
104         createSoap12Binding="true" createSoap11Binding="false"
105         locationUri="/spring-ws/example"
106         targetNamespace="http://gumartinm.name/spring-ws/exampleService">
107         <sws:xsd location="classpath:examples.xsd"/>
108     </sws:dynamic-wsdl>
109
110
111     <!-- Required in order to use SOAP 1.2
112          id="messageFactory" is not a random choice, if you use another name it will not work
113          (Spring will end up loading SOAP 1.1)
114     -->
115     <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
116         <property name="soapVersion">
117             <util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12" />
118         </property>
119     </bean>
120     
121     <!-- The interceptors in this set are automatically configured on each registered EndpointMapping
122          What means, every class annotated with @Endpoint will be using these interceptors.
123          
124          This configuration enables us to log the SOAP XML Request (received from client), Response (sent by this server) and Fault (sent by this server).
125      -->
126     <sws:interceptors>
127         <bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor">
128             <property name="logRequest" value="true"/>
129             <property name="logResponse" value="true"/>
130             <property name="logFault" value="true"/>
131         </bean>
132
133         <!-- 
134             ¿Este validador funciona teniendo inheritance en el xsd? (inheritances es una cosa especial 
135             del JAXB2 que estoy usando para generar las clases desde el xsd)
136             Parece que el unmarshal (que supongo que se hace con el JAXB2 que está en el classpath
137             debido al tipo de Endpoint que estoy usando, que por cierto no sé cual JAXB2 está cogiendo realmente) 
138             funciona, así que supongo el validador tambien :/
139             Lo que realmente tampoco sé es si hay alguna relación entre los validadores y JAXB2 :/
140         -->
141         <bean id="validatingInterceptor" 
142             class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
143             <property name="schemas">
144                 <list>
145                         <!--
146                                  ALWAYS FIRST THE XSD FILES TO BE IMPORTED!!!!!  O.o
147                                  OTHERWISE THE import IN examples.xsd WILL BE SOLVED BY MEANS OF DOWNLOADING THE
148                                  EXTERNAL parent.xsd (USING THE URL LINKED BY THE IMPORT STATEMENT IN examples.xsd)
149                                  
150                                          IF YOU DON'T DO THIS, PayloadValidatingInterceptor WILL TRY TO CONNECT TO THE
151                                          EXTERNAL SERVER WHERE parent.xsd IS LOCATED AND IT WILL FAIL IF BECAUSE SOME
152                                          REASON YOU DON'T HAVE IN THAT VERY MOMENT NETWORK CONNECTION. SO, DON'T MESS WITH THIS
153                                          CONFIGURATION.
154                          -->
155                     <value>classpath:parent.xsd</value>
156                     
157                     <value>classpath:examples.xsd</value>
158                 </list>
159             </property>
160             <property name="validateRequest" value="true"/>
161             <property name="validateResponse" value="true"/>
162         </bean>
163     </sws:interceptors>
164     
165     
166     <!-- 
167             PARA METER MAS COSAS A LA RESPUESTA CON ERROR, por ejemplo si quisiéramos enviar en Reason Text la pila de excepción tengo que
168             implementar mi propio manejador de excepción que extienda de AbstractSoapFaultDefinitionExceptionResolver y añada todo aquello
169             que yo necesite.
170             
171             A mí me parecen muy pobres las implementaciones que trae Spring así que implementaré el mío propio que devuelva la pila
172             de excepción si la hay.
173      -->
174     <bean id="soapFaultMappingExceptionResolver"
175         class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
176         <!--
177                 No quiero usar un valor por defecto porque si no, si mi manejador no machea ninguna excepción
178                 devolvera este valor por defecto. Y no se probará con otros manejadores de excepción que tengan un order con menor precedencia.
179                 
180                 Cuando se escribe value="SERVER" Spring está seteando SoapFaultDefinition.SERVER en defaultValue
181                 de org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver Esto parece
182                 magia pero Spring lo logra usando org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor.setAsText("SERVER")
183                 
184         <property name="defaultFault" value="SERVER"/>
185         -->
186         <property name="exceptionMappings">
187             <props>
188                 <!--
189                         <prop key="de.spring.webservices.exceptions.BusinessException">SERVER,something went wrong in server side,en_US</prop>
190                         
191                         Si hago esto en lugar de devolver al cliente el mensaje que va dentro de la excepcion devuelvo siempre:
192                         
193                                         <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
194                                            <env:Header/>
195                                            <env:Body>
196                                               <env:Fault>
197                                                  <env:Code>
198                                                     <env:Value>env:Receiver</env:Value>    Receiver y Server significa lo mismo. Cuando pongo "SERVER" en primer token aquí aparece Receiver.
199                                                  </env:Code>
200                                                  <env:Reason>
201                                                     <env:Text xml:lang="en-US">something went wrong in server side</env:Text>   en-US porque puse como Locale en_US en el tercer token.
202                                                  </env:Reason>
203                                               </env:Fault>
204                                            </env:Body>
205                                         </env:Envelope>
206                         
207                         El primer token es el Value. Si es SERVER o RECEIVER se muestra Receiver. Si es CLIENT o SENDER se muestra Sender.
208                         
209                         El segundo token es el mensaje que SIEMPRE se mostrará.
210                         
211                         El tercer token mapea a un Locale en SoapFaultDefinition (por defecto Locale.ENGLISH). El mapeo se hace con
212                         org.springframework.util.StringUtils.parseLocaleString("en_US")
213                         
214                         
215                         
216                         
217                         
218                         Yo prefiero que se devuelva el mensaje que va dentro de la excepción. Para eso SOLO puede haber un token y
219                         el Locale siempre será entonces Locale.ENGLISH.
220                         
221                         Uso SERVER porque de.spring.webservices.exceptions.BusinessException es una excepción generada en el lado servidor.
222                  -->
223                         <prop key="de.spring.webservices.exceptions.BusinessException">SERVER</prop>
224                 </props>
225         </property>
226         <!-- Así mi manejador de excepciones entra antes que  SimpleSoapExceptionResolver pero después que
227                  SoapFaultAnnotationExceptionResolver
228         -->
229         <property name="order" value="1" />
230     </bean>
231     
232     
233     
234     <bean id="myCustomMappingExceptionResolver" class="de.spring.webservices.endpoints.MyCustomMappingExceptionResolver">
235         <!--
236                 Voy a usar un valor por defecto porque este va a ser el último manejador que haya antes de
237                 SimpleSoapExceptionResolver. SimpleSoapExceptionResolver será siempre por el order que he puesto
238                 el último manejador de excepciones.
239                         Así todas las excepciones que no hayan sido macheadas por los otros manejadores serán siempre
240                         cogidas por este y se les asignará un SoapFaultDefinition.SERVER. En este caso SimpleSoapExceptionResolver
241                         nunca será usado.
242         -->
243         <property name="defaultFault" value="SERVER"/>
244         <property name="exceptionMappings">
245             <props>
246                         <prop key="de.spring.webservices.exceptions.CustomBusinessException">SERVER</prop>
247                 </props>
248         </property>
249         <property name="marshaller" ref="marshaller"/>
250         <!-- Así mi manejador de excepciones entra antes que SimpleSoapExceptionResolver pero después que
251                  SoapFaultAnnotationExceptionResolver y SoapFaultMappingExceptionResolver
252         -->
253         <property name="order" value="2" />
254     </bean>
255     
256 </beans>