Proyecto Java EE
 

Integración componentes Java EE: EJB y JMS

GlassFish y Componentes EJB

Vamos a crear una nueva versión del proyecto de Biblioteca basada en una arquitectura EJB. Se debe desarrollar una nueva versión del proyecto, partiendo del último Sprint del proyecto de integración.

Utilizaremos la arquitectura definida en la sesión 4 de EJB, en la que a capa de lógica de datos se implementa con EJBs de sesión en los que se inyectan los DAOs que se encargan de la persistencia.

En la primera parte de la sesión tendréis que integrar la aplicación desarrollada hasta ahora en GlassFish y NetBeans, cambiando el proveedor de persistencia de Hibernate a EclipseLink. Tendréis también que refactorizar la aplicación a la nueva arquitectura en la que los servicios se implementan con componentes EJB.

Pasos

Vista general de los pasos a realizar:

  1. Crear el dominio de GlassFish
  2. Configurar la fuente de datos en el dominio
  3. Clonar de Bitubucket la estructura y proyectos POM de los módulos de la solución
  4. Completar los módulos:
    • Completar el módulo con el proyecto modelo con las entidades JPA
    • Completar el módulo con la capa de persistencia (clases DAO)
    • Crear la capa de lógica de negocio como EJBs que acceden a los DAO por inyección de dependencias, haciendo remotos los métodos relacionados con el bibliotecario
  5. Crear una aplicación cliente

Configuración del dominio GlassFish

Debes crear un dominio nuevo llamado jbib-domain. Créalo sin password con el comando:

./asadmin create-domain 9000 jbib-domain

Una vez creado añade un nuevo servidor a NetBeans utilizando este nuevo dominio. Llámalo por ejemplo Server jbib:

Nuevo servidor

Lánzalo y abre una consola de administración en http://localhost:4048:

Consola de administración

Creación de la fuente de datos XA

Configura la fuente de datos en GlassFish en el dominio jbib-domain como una fuente de datos XA y dale como nombre jdbc/jbib. Copia el driver JDBC de MySQL en el directorio lib del dominio. Ahora ya puedes lanzar GlassFish y conectarte a su consola de administración. Es recomendable lanzarlo desde NetBeans, para poder visualizar sus mensajes en el panel de Output.

Crea en GlassFish una fuente de datos de tipo XA conectada a la base de datos biblioteca. Primero crea el conjunto de conexiones BibliotecaPool:

Define los siguientes parámetros:

  • user: root
  • password: expertojava
  • URL: jdbc:mysql://localhost:3306/biblioteca

Termina creando la nueva fuente de datos JDBC con el nombre jdbc/jbib basada en el conjunto de conexiones que acabas de crear.

Proyecto enterprise

En el repositorio java_ua/proyint-ent-expertojava hay una versión inicial de la solución que contiene la estructura Maven de todos los módulos, con sus ficheros POM. También contiene un ejemplo con una entidad (BibliotecarioDomain), y el DAO y el EJB que implementa su capa de servicio.

Los proyectos que hay en la solución son:

  • jbib-ent: Proyecto Maven padre de todos. Contiene las dependencias utilizadas en todos los demás proyectos y sirve para construir todos los artefactos.
  • jbib-ent-ear: Aplicación EAR que se despliega en el servidor y que contiene los proyectos EJB y WEB.
  • jbib-ent-modelo: Librería JAR con las clases del modelo y las reglas de negocio. La hemos separado de la capa de persistencia para poder distribuirla más fácilmente a las aplicaciones clientes.
  • jbib-ent-ejb: Proyecto EJB que contiene la capa de persistencia, con el fichero de configuración persistence.xml, las clases DAO que se inyectan en los EJBs de sesión (clases Service) que definen la capa de lógica de negocio.
  • jbib-ent-web: Proyecto web que se conecta con las interfaces locales de los EJB de la capa de servicio.
  • jbib-ent-remotelibrary: Liberaría JAR con las interfaces remotas de los EJB.
  • jbib-ent-client: Aplicación remota que se trabaja con las interfaces remotas de los EJB.

1. Clona en tu cuenta de bitbucket el repositorio java_ua/proyint-ent-expertojava. Usa el mismo nombre y no olvides quitar la opción de heredar permisos de acceso.

2. Desde Netbeans, descarga en tu disco el repositorio con la opción Team > Mercurial > Clone Other.... Pon el nombre del repositorio que acabas de clonar: https://bitbucket.org/login/proyint-ent-expertojava. Deja ese mismo repositorio como repositorio push y pull por defecto. Pon como directorio padre el lugar donde quieres que se guarde el repositorio (por ejemplo /home/expertojava/NetBeansProjects/ y deja proyint-ent-expertojava como nombre del repositorio. Di que NetBeans abra los proyectos descargados desplegando el proyecto padre y seleccionando todos.

3. Comprueba que funcionan correctamente todos los módulos:

  • Construye todos los módulos pulsando el botón derecho sobre el proyecto padre jbib-ent y seleccionando Clean and Build. Se deben pasar todos los tests, entre ellos los de la capa de persistencia que utilizan DbUnit para añadir unos datos iniciales a la única tabla Bibliotecario que hemos incluido en la versión inicial.
  • Comprueba que la tabla Bibliotecario se ha creado y que contiene a javier.huertas.
  • Despliega la aplicación EAR en el servidor pulsando el botón derecho sobre el proyecto jbib-ent-ear y seleccionando Run. Selecciona el servidor cuando NetBeans te lo pida.
  • Comprueba en la URL http://localhost:8080/jbib-ent-web/PruebaServicios que el servlet se conecta correctamente con la interfaz local del EJB BibliotecarioService.
  • Por último lanza la aplicación cliente remota en el proyecto jbib-ent-client para comprobar que la conexión remota con el EJB funciona correctemente.

4. Completa todos los módulos refactorizando el proyecto de integración realizado hasta ahora:

  • En el proyecto jbib-ent-modelo añade las entidades con las clases de modelo. Hemos cambiado a EclipseLink como proveedor de persistencia para trabajar mejor con GlassFish, por lo que quizás tengas que cambiar alguna característica dependiente de Hibernate.
  • En el proyecto jbib-ent-ejb completa el persistence.xml y el persistence-test.xml para incluir todas las clases de entidad, añade los DAO, más datos de prueba a DBUnit y los tests de los DAO. Crea por último todos los EJB refactorizando las clases de servicio, construyendo sus interfaces locales y remotas. Incluye en las interfaces remotas las mismas operaciones que en las locales.
  • Actualiza el servlet de prueba del proyecto web para probar algún método local de cada servicio que vas añadiendo.

Aplicaciones clientes

Crea varias aplicaciones clientes por línea de comando que permitan:

  • Gestión de libros: listados, búsquedas y actualización de libros
  • Operaciones: probar alguna operación de la biblioteca

JMS y MDBs

El objetivo de esta parte de la sesión es integrar las tecnologías JMS/MDB dentro de nuestro proyecto de integración. Para ello, vamos a permitir que la aplicación envíe mensajes a un cola a través de un EJB, y que consuma mensajes mediante un MDB.

Ambos ejercicios los crearemos dentro del proyecto EJB que ya tenemos.

Multas Externas

Crearemos un MDB (es.ua.jtech.jbib.service.MultasExternasMDB dentro del proyecto jbib-ent-ejb) que escuche peticiones de multa de usuarios de sistemas externos. Así pues, la aplicación escuchará de una cola (JBibMultasUsuariosQueue) los envíos de sistemas externos respecto a los usuarios que tienen multas, mediante un mensaje de texto que contiene el login y el número de días de multa, ambos separados mediante el carácter '#'.

Una vez recibido el mensaje, el MDB debe guardar la multa en la base de datos, y cambiar el estado del usuario de ACTIVO a MULTADO. En el caso de que el usuario ya fuese moroso/multado, crearemos una nueva multa activa.

Gestión de multas
Para simplificar la gestión de multas, no vamos a comprobar si tenía otra multa activa previamente. Es decir, si el usuario ya tenía una multa previa y nos llega un mensaje con otra multa, tendrá dos multas.

Todas las operaciones deben formar parte de una transacción distribuida, de modo que si salta alguna excepción en alguna operación, se deshagan todas los operaciones.

Deshaciendo las Reservas

En este ejercicio, vamos a crear un Timer para deshaga las reservas que han caducado. Vamos a considerar que las reservas que tienen más de 30 días son reservas que se deberían cancelar automáticamente. Así pues, una vez se invoque al método marcado con @TimeOut, a parte de borrar las reservas caducadas, vamos a enviar un mensaje a la cola (JBibReservasCaducadasQueue) con el login y el isbn de la reserva que acaba de caducar.

Si al mismo tiempo caduca más de una reserva, se enviarán tantos mensajes como reservas caducadas.

Para invocar el timer, tenemos que crear un Servlet de inicio de aplicación (pista:load-on-startup), el cual llame al método del EJB que lanza el timer.

Aquí teneis un esqueleto de ejemplo de código de EJB, el cual podeis colocar dentro de uno de los EJBs que ya teneis creado o en un nuevo:

public void initTimer() {
	context.getTimerService().createTimer(1000, 1000*10, "TimerCaducaReserva");
}

@Timeout
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void caducaReservas(Timer timer) {
	String nombre = (String) timer.getInfo();

	if ("TimerCaducaReserva".equals(nombre)) {
		// 1º comprobamos si hay reservas caducadas
		// 2º por cada reserva caducada,
		//    cancelamos la reserva y enviamos mensaje a la cola
	}
}

Recordad que deberéis crear y cerrar la conexión JMS mediante los callbacks EJB, tal como vimos en la cuarta sesión de teoría.

Consulta de Reservas Caducadas
Para obtener las reservas que tenéis caducadas, podeis reutilizar la consulta de obtener las reservas activas y recorrer las que han caducado, o aún mejor, crear una consulta que únicamente devuelva las reservas caducadas.

Probando...

Para comprobar ambos ejercicios, vamos a crear dos aplicaciones cliente:

  • jbib-multas-client: cliente JMS que envía un mensaje de texto a JBibMultasUsuariosQueue con el login y el número de días de la multa separados por '#'.
  • jbib-reservas-client: cliente JMS que escucha en modo asíncrono un mensaje de texto de JBibReservasCaducadasQueue con el login y el isbn del libro cuya reserva ha caducado, ambos separados por '#'.

Para que ambos ejercicios funcionen, tenéis que crear los recursos JMS necesarios:

  • Una factoria de conexiones denominada JBibConnectionFactory.
  • 2 colas, una para las multas (JBibMultasUsuariosQueue) y otra para las reservas caducadas (JBibReservasCaducadasQueue).