Creación de servicios web RESTful con el soporte de RESTeasy de Jboss Seam.
0. Índice de contenidos.
- 1. Introducción.
- 2. Entorno.
- 3. Configuración.
- 4. Ejemplo práctico.
- 5. Referencias.
- 6. Conclusiones.
1. Introducción
Jboss Seam incluye entre sus módulos el proyecto RESTeasy, una implementación de la especificación
JAX-RS (JSR 311), cuya implementación de referencia es
Jersey. RESTeasy es también un proyecto de Jboss y al incluirse dentro de Seam vamos a tener el soporte para la generación de servicios web
«ligeros», sin necesidad de incluir en los mensajes de comunicación la envoltura SOAP.
Al integrarse dentro de Jboss Seam nos va a permitir convertir un componente de Seam (un POJO o un EJB) en un web service, con lo que se beneficia de las características propias de un componente Seam: manejado por el contenedor, inyección de dependencias,
eventos sobre el ciclo de vida, gestión declarativa de transacciones,..
Este tutorial muestra cómo configurar un proyecto Seam para dar soporte de RESTeasy y un ejemplo de publicación de un servicio web.
2. Entorno.
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 17′ (2.93 GHz Intel Core 2 Duo, 4GB DDR3 SDRAM).
- Sistema Operativo: Mac OS X Snow Leopard 10.6.1
- Jboss Seam 2.2.0.GA
- Maven 2.2.1.
- Eclipse 3.5: Galileo, con IAM (plugin para Maven).
- GlassFish v.2.1 con la jdk 1.6.
3. Configuración.
RESTeasy es un módulo de Seam que no se distribuye con las librerías del core, con lo que lo primero que debemos hacer es incluir la dependencia en el módulo web que lo necesite:
org.jboss.seam jboss-seam-resteasy ${seam.version} org.jboss.seam jboss-seam
En nuestro caso ${seam.version} es una propiedad que tenemos definida a nivel de pom.xml para su reutilización y llevamos a cabo una exclusión de la librería del core puesto que la dependencia la arrastramos del módulo padre y al empaquetarse como un ear, va a
ese nivel y no a nivel de war.
Lo siguiente es revisar la configuración del servlet de recursos de Jboss Seam a nivel del descriptor de despliegue del proyecto web (web.xml), es quien va a dar soporte a las peticiones a través de http a los servicios:
<servlet> <servlet-name>Seam Resource Servlet</servlet-name> <servlet-class>org.jboss.seam.servlet.ResourceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Seam Resource Servlet</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping>
Por último debemos añadir lo siguiente al fichero de configuración de Seam (components.xml):
<resteasy:application resource-path-prefix="/ws" />
Se trata del path relativo al path de recursos que va a dar servicio a los servicios web.
De este modo, la invocación a los servicios se realizará a través de la siguiente url: http://localhost:8080/app/resources/ws/servicio, donde localhost es la máquina, app es el contexto de la aplicación y servicio el nombre del servicio.
Podemos, además, configurar un nivel de seguridad de modo que la petición de un servicio solicite la autenticación del usuario a través de login y contraseña incluyendo lo siguiente en el mismo fichero components.xml:
<web:authentication-filter url-pattern="/resources/ws/*" auth-type="basic" realm="PLV Web Service layer" />
Por defecto enlazará con la configuración de seguridad definida en el mismo fichero vía <security:identity authenticate-method=
4. Ejemplo práctico.
A continuación mostramos un ejemplo de un componente anotado para su publicación con un web service con el soporte de REST. La idea es la de disponer de un servicio en la red que permita marcar ordenes de compra (PurchaseOrder) como cerradas
y su invocación la pueda realizar cualquier cliente sin necesidad de hablar en SOAP..
package com.autentia.web.ws; import java.io.Serializable; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.security.Restrict; import org.jboss.seam.log.Log; import com.autentia.core.services.PurchaseOrderManager; /** * Prueba de concepto de la publicación de un WS vía RESTful. * * @author Autentia Real Business Solutions S.L. * @see http://www.autentia.com */ @Name("purchaseOrderResource") @Path("/purchaseOrder") @Transactional public class PurchaseOrderResource implements Serializable { private static final long serialVersionUID = 8655977096519941447L; @Logger private Log log; @In private PurchaseOrderManager purchaseOrderManager; @GET @Path("/{reference}") @Produces("text/plain") @Restrict("#{s:hasRole('ADMIN')}") public String closePurchaseOrder(@PathParam("reference") String reference) { log.debug("request received [reference:'" + reference + "']"); purchaseOrderManager.closePurchaseOrder(reference); return "ok"; } }
Para invocarlo debemos realizar una petición a la siguiente url: http://localhost:8080/app/resources/ws/purchaseOrder/80002311, donde 80002311 es el número de referencia de la orden de compra a cerrar.
Vamos a repasar las anotaciones:
- 24: @Name(«purchaseOrderResource») publica la clase como un componente de Seam con el nombre purchaseOrderResource.
- 25: @Path(«/purchaseOrder») publica el componente como un servicio web accesible a través del path relativo purchaseOrder. Seam escanea las clases en busca de esta anotación de modo que no se requiere más configuración que esta.
- 26: @Transactional marca el ámbito de las llamadas a los puntos finales del servicio como transaccionales, si en vez de ser un POJO se tratase de un EJB no sería necesario puesto que es su comportamiento por defecto.
- 31: @Logger asigna una instancia del objeto de trazas manejado por el contenedor, de modo que no es necesario invocar a un método estático de una factoría para obtenerlo, nos viene inyectado (es una facilidad propia de Seam).
- 34: @In inyectamos la dependencia de un servicio (otro componente de Seam) que contiene la lógica de negocio necesaria para marcar como cerrada una orden de compra en función de su identificador.
- 37: @GET marcamos el método como accesible a través del método GET, una petición GET vía http.
- 38: @Path(«/{reference}») publicamos el método como punto final del servicio web accesible a través de un path relativo al servicio que declara un único parámetro y lo marca con el nombre de variable «reference».
- 39: @Produces(«text/plain») indica el tipo de respuesta del servicio, para esta prueba sencilla devolvemos una cadena.
- 40: @Restrict(«#{s:hasRole(‘ADMIN’)}») es una anotación propia de Seam que permite restringir la invocación al método únicamente a usuarios autenticados y con un nivel de autorización predeterminado.
- 41: @PathParam(«reference») asigna el valor de la variable marcada con el nombre reference en la anotación de la línea 38 al parámetro de entrada del método.
Con todo ello, en la línea 43 hacemos uso del servicio que nos viene inyectado invocando a un método del mismo que recibe el número de referencia que obtenermos directamente de la url que solicita el servicio.
5. Referencias.
6. Conclusiones.
Jboss Seam nos da soporte a múltiples tecnologías de integración, en este tutorial hemos visto un ejemplo de una de ellas, que nos permite exponer lógica de negocio de una manera sencilla hacía el exterior.
Si estáis interesados en el contenido de nuestros tutoriales y tenéis una necesidad formativa al respecto no dudeis en poneros en contacto con nosotros. En Autentia
nos dedicamos, además de a la consultoría, desarrollo y soporte a desarrollo, a impartir cursos de formación de las tecnologías con las que trabajamos.
Un saludo.
Jose