Spring WS: Servicios Web a través del correo electrónico
Introducción.
En el siguiente tutorial vamos a construir un Servicio Web que atienda las peticiones a través del correo electrónico. Es decir, el servicio web
monitorizará una cuenta de correo para ver si tiene peticiones (un email con un mensaje SOAP en el cuerpo del mensaje), las procesará y enviará un correo electrónico con la respuesta al cliente que solicitó sus servicios.
En este tutorial no vamos a ver todo el proceso de construcción de clientes y servicios Web desde cero, simplemente vamos a ver
los cambios que tenemos que realizar (muy pocos :-)) para que funcione todo usando el cliente y el servicio web que ya construimos en tutoriales anteriores:.
- Spring WS: Creación de Servicios Web con Spring
- Spring WS: Construcción de Clientes de Servicios Web con Spring
De todas formas os dejo el código fuente (proyectos Eclipse, Maven) para que realices tus pruebas.
¿Cambios a realizar en el servicio web?
Los cambios a realizar son a nivel de configuración de Spring y agregar alguna dependencia al archivo de configuración de Maven.
Cambios a realizar en el archivo de configuración de Spring 2 (/main/resources/applicationContext.xml)
:
Si comparas ambos archivos, verá que lo único que cambia es se añade el bean «messageReceiver» y se elimina el
bean «bibliotecaWS», el archivo está autocomentado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <!-- Realiza la lógica de negocio de consulta de libros en base a la petición --> <bean name="requestProcesor" class="com.autentia.tutoriales.spring.ws.DummyRequestProcessor"/> <!-- EndPoint del WS: Recibirá la petición del WS (WSDL operation) --> <bean id="bibliotecaWSEndpoint" class="com.autentia.tutoriales.spring.ws.BookInfoEndPoint"> <property name="procesor" ref="requestProcesor" /> </bean> <!-- Indicamos que hable SOAP 1.2 --> <bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"> <property name="soapVersion"> <util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/> </property> </bean> <!-- payloadMapping: Redirige mensajes XML entrantes hacia el EndPoint apropiado. Lo haremos en base al elemento raiz del XML, es decir, en función del PayLoad del SOAP:Body del mensaje. (Otra opción podría ser a través de la cabecera SOAPAction: org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping) --> <bean id="payloadMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping"> <property name="endpointMap"> <map> <!-- ¡¡ Ojo !! No dejar espacios entre el namespace y el elemento raiz --> <entry key="{http://www.adictosaltrabajo.com/spring/ws/schemas}BooksInfoRequest" value-ref="bibliotecaWSEndpoint"/> </map> </property> <!-- Validación de peticiones y/o respuestas --> <property name="interceptors"> <list> <ref bean="validatingInterceptor"/> </list> </property> </bean> <!-- Para validar las peticiones y/o respuestas --> <bean id="validatingInterceptor" class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor"> <property name="schema" value="classpath:bibliotecaWS.xsd"/> <property name="validateRequest" value="true"/> <property name="validateResponse" value="true"/> </bean> <!-- Este bean convertirá cualquier excepción Java en un fallos SOAP (SOAP Fault) --> <bean id="endpointExceptionResolver" class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver"> <property name="defaultFault" value="RECEIVER,Server error" /> <property name="exceptionMappings"> <props> <prop key="org.springframework.oxm.UnmarshallingException">SENDER,Invalid request</prop> <prop key="org.springframework.oxm.ValidationFailureException">SENDER,Invalid request</prop> </props> </property> </bean> <!-- Lee y envia mensajes SOAP a trávés del correo electrónico --> <bean id="messagingReceiver" class="org.springframework.ws.transport.mail.MailMessageReceiver"> <property name="messageFactory" ref="messageFactory"/> <!-- Por defecto comienza a monitorizar los mensajes al arrancar, mejor se lo indicamos nosotros desde código fuente --> <property name="autoStartup" value="false"/> <!-- Cuenta de correo para leer los mensajes SOAP --> <property name="storeUri" value="pop3://unUsuarioEmail:usuarioEmailPasswd@servidorPOP:110/INBOX"/> <!-- Ejemplo: pop3://contabilidad%40mobiletest.es:yxx83..4@mail.mobiletest.es:110/INBOX --> <!-- Cuenta de correo para enviar mensajes de respueta --> <property name="transportUri" value="smtp://unUsuarioEmail:usuarioEmailPasswd@servidorSMTP:25"/> <!-- Ejemplo: smtp://contabilidad%40mobiletest.es:yxx83..4@mail.mobiletest.es:25 --> <!-- Propiedad From del mensaje de respuesta --> <property name="from" value="UnaDireccionDeCorreo"/> <!-- Ejemplo: contabilidad%40mobiletest.es --> <!-- Analiza los mensajes entrantes e invoca la lógica de negocio en función del cuerpo del mensaje (payload) del mensaje --> <property name="messageReceiver"> <bean id="messageDispatcher" class="org.springframework.ws.soap.server.SoapMessageDispatcher"> <property name="endpointMappings" ref="payloadMapping"/> </bean> </property> <!-- Opciones de monitorización --> <property name="monitoringStrategy"> <bean class="org.springframework.ws.transport.mail.monitor.Pop3PollingMonitoringStrategy"> <!-- Mira si hay mensajes nuevos cada X milisegundos --> <property name="pollingInterval" value="5000"/> <!-- En caso de realizar un tratamiento correcto, los borra para no volver a tratarlos --> <property name="deleteMessages" value="true"/> </bean> </property> </bean> </beans> |
Cambios en el archivo de configuración de Maven pom.xml
:
Si compara ambos archivos, verá que tiene que agregar 3 dependencias nuevas (spring-ws-support, mail, activation):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.autentia.tutoriales</groupId> <artifactId>bibliotecaEmailWS</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>bibliotecaEmailWS</name> <url>http://www.adictosaltrabajo.com</url> <!-- Sintáxis Java 5 --> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <!-- Spring WS: Maven gestionará automáticamente todas sus dependencias, que no son pocas :-) --> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>1.5.6</version> </dependency> <!-- Requerido para Transporte sobre Mail, JMS.. --> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-support</artifactId> <version>1.5.6</version> </dependency> <!-- JavaMail --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1</version> </dependency> <!-- Para nuestros tests --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.3.1</version> <scope>test</scope> </dependency> </dependencies> </project> |
¿Cambios a realizar en el cliente?
Los cambios a realizar son a nivel de configuración de Spring y agregar alguna dependencia al archivo de configuración de Maven.
Cambios a realizar en el archivo de configuración de Spring 2 (/main/resources/applicationContext.xml)
:
Si compara ambos archivos, verá que lo único que cambia es el bean «messageSender», el archivo está autocomentado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"> <!-- Wrapper del cliente --> <bean id="biblioStub" class="com.autentia.tutoriales.spring.ws.biblioteca.cliente.BibliotecaCliente"> <property name="webServiceTemplate" ref="wsTemplate"/> </bean> <!-- Plantilla para comunicarnos con el WS --> <bean id="wsTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"> <!-- Creación de mensajes SOAP --> <property name="messageFactory"> <!-- Saaj usa DOM, si se quiere más rendimiento y consumir menos recursos puede usar: org.springframework.ws.soap.axiom.AxiomSoapMessageFactory que usa AXIOM. --> <bean name="innermf" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"> <property name="soapVersion"> <util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/> </property> </bean> </property> <property name="messageSender"> <bean class="org.springframework.ws.transport.mail.MailMessageSender"> <!-- Cuanto tiempo esperamos antes de intentar leer la respuesta --> <property name="receiveSleepTime" value="20000"/> <!-- Cabecera From del correo electrónico --> <property name="from" value="UnaDireccionDeCorreo"/> <!-- Ejemplo: callcenter%40mobiletest.es --> <!-- Cuenta de correo para leer los mensajes SOAP (respuestas del servicio) --> <property name="storeUri" value="pop3://unUsuarioEmail:usuarioEmailPasswd@servidorPOP:110/INBOX"/> <!-- Ejemplo: pop3://callcenter%40mobiletest.es:yxx83..4@mail.mobiletest.es:110/INBOX --> <!-- Cuenta de correo para enviar las peticiones SOAP --> <property name="transportUri" value="smtp://unUsuarioEmail:usuarioEmailPasswd@servidorSMTP:25"/> <!-- Ejemplo: smtp://callcenter%40mobiletest.es:yxx83..4@mail.mobiletest.es:25 --> </bean> </property> <!-- Por defecto, los mensajes serán enviados a esta dirección. --> <!-- Los métodos de WebServiceTemplate están sobrecargados para especificar o no una URI de destino. --> <property name="defaultUri" value="mailto:contabilidad%40mobiletest.es"/> </bean> </beans> |
Cambios en el archivo de configuración de Maven pom.xml
:
Si compara ambos archivos, verá que tiene que agregar 3 dependencias nuevas (spring-ws-support, mail, activation):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.autentia.tutoriales</groupId> <artifactId>bibliotecaEmailWSCliente</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>bibliotecaEmailWSCliente</name> <url>http://www.adictosaltrabajo.com</url> <build> <plugins> <!-- Sintáxis Java 5 --> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <!-- Spring WS: Maven gestionará automáticamente todas sus dependencias, que no son pocas :-) --> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>1.5.6</version> </dependency> <!-- Requerido para Transporte sobre Mail, JMS.. --> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-support</artifactId> <version>1.5.6</version> </dependency> <!-- JavaMail --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1</version> </dependency> <!-- Para volcar las trazas. (sólamente dejamos trazas SOAP) --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> <!-- Para nuestros tests --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.3.1</version> <scope>test</scope> </dependency> </dependencies> </project> |
Referencias
- http://static.springframework.org/spring-ws/sites/1.5/reference/html/index.html
- http://static.springframework.org/spring-ws/sites/1.5/reference/html/server.html
- http://static.springframework.org/spring-ws/sites/1.5/reference/html/client.html
- http://static.springsource.org/spring-ws/sites/1.5/apidocs/org/springframework/ws/transport/mail/MailMessageSender.html
Conclusiones
A la hora de diseñar una arquitectura, conocer todas las alternativas disponibles es un tema muy importante, en este tutorial hemos expuesto
un modo de comunicación síncrono en donde un servicio web atiende las solicitudes a través de cuenta de correo, pero podíamos haberlo asíncrono e incluso
haber tenido N servicios distribuidos leyendo la misma cuenta de correo, haber usado colas JMS…
Elegir uno u otro modelo depende de las necesidades, restricciones, etc.. en Autentia impartimos constantemente cursos a medida sobre estas y otras tecnologías, espero nos tengáis en cuenta en caso de que necesitéis formación.
Otra cosa, recuerda que esto no es más que un tutorial, hay más puntos al respecto sobre los que profundizar.
Carlos García Pérez. Creador de MobileTest, un complemento educativo para los profesores y sus alumnos.
cgpcosmad@gmail.com
Para acotar la búsqueda Necesita Servicio Transporte, se pueden usar las opciones:
Necesita Servicio Transporte, Transporte y Servicio Clientes.