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"
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">
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"/>
21 Three ways of using a marshallers/unmarshallers.
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
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.
29 2. Especificando el context-path para ser escaneado por Spring usando anotaciones. Esto
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.
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.
42 <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
44 maven-jaxb2-plugin does NOT generate again the objects in web-services-spring-jaxb2-globalxsds
45 So we MAY scan everything and there is no trouble because there is not more than one class representing
48 <property name="packagesToScan" value="de.spring.webservices"/>
50 <!-- Searches for @PayloadRoot -->
51 <sws:annotation-driven marshaller="marshaller" unmarshaller="marshaller" />
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.
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.
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()
74 EN LUGAR DE USAR LA ANOTACIÓN PODRÍAMOS HABER DECLARADO EXPLÍCITAMENTE CADA BEAN TAL QUE ASÍ:
76 <bean id="soapFaultMappingExceptionResolver"
77 class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
78 <property name="order" value="0" />
81 <bean id="payloadRootAnnotationMethodEndpointMapping"
82 class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
83 <property name="order" value="0" />
86 CON LA ANOTACIÓN ME AHORRO DECLARAR bean POR bean PERO LO MALO ES QUE INSTANCIO MANEJADORES QUE LUEGO NO USO :(
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)
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
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:schemas/examples.xsd"/>
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)
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" />
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.
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).
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"/>
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 :/
141 <bean id="validatingInterceptor"
142 class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
143 <property name="schemas">
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)
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
155 <value>classpath:schemas/parent.xsd</value>
157 <value>classpath:schemas/examples.xsd</value>
160 <property name="validateRequest" value="true"/>
161 <property name="validateResponse" value="true"/>
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
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.
174 <bean id="soapFaultMappingExceptionResolver"
175 class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
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.
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")
184 <property name="defaultFault" value="SERVER"/>
186 <property name="exceptionMappings">
189 <prop key="de.spring.webservices.exceptions.BusinessException">SERVER,something went wrong in server side,en_US</prop>
191 Si hago esto en lugar de devolver al cliente el mensaje que va dentro de la excepcion devuelvo siempre:
193 <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
198 <env:Value>env:Receiver</env:Value> Receiver y Server significa lo mismo. Cuando pongo "SERVER" en primer token aquí aparece Receiver.
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.
207 El primer token es el Value. Si es SERVER o RECEIVER se muestra Receiver. Si es CLIENT o SENDER se muestra Sender.
209 El segundo token es el mensaje que SIEMPRE se mostrará.
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")
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.
221 Uso SERVER porque de.spring.webservices.exceptions.BusinessException es una excepción generada en el lado servidor.
223 <prop key="de.spring.webservices.exceptions.BusinessException">SERVER</prop>
226 <!-- Así mi manejador de excepciones entra antes que SimpleSoapExceptionResolver pero después que
227 SoapFaultAnnotationExceptionResolver
229 <property name="order" value="1" />
234 <bean id="myCustomMappingExceptionResolver" class="de.spring.webservices.endpoints.MyCustomMappingExceptionResolver">
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
243 <property name="defaultFault" value="SERVER"/>
244 <property name="exceptionMappings">
247 <prop key="de.spring.webservices.exceptions.CustomBusinessException">SERVER</prop>
250 <property name="marshaller" ref="marshaller"/>
251 <!-- Así mi manejador de excepciones entra antes que SimpleSoapExceptionResolver pero después que
252 SoapFaultAnnotationExceptionResolver y SoapFaultMappingExceptionResolver
254 <property name="order" value="2" />