Está en la página 1de 184

Módulo 6

Desarrollo
componentes de
negocio con tecnología
empresarial JavaBeans

Profesional en
Plataforma

JAVA
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Contenido
Introducción y Objetivos ........................................................................................................ 1
Unidad 1. Análisis de Aplicaciones EJB...................................................................................... 2
Java y arquitectura de capas ............................................................................................... 2
Modulo WAR ...................................................................................................................... 3
Comunicación Capa Web+Capa Negocio ................................................................................ 4
Tecnología Enterprise Java Beans ......................................................................................... 5
Tipos de beans ................................................................................................................... 6
Especificaciones ................................................................................................................. 8
¿Qué servicios proveen los EJBs? ......................................................................................... 8
Evolución de la especificación EJB......................................................................................... 9
EJB 3.0 ........................................................................................................................... 10
Compatibilidad con EJB 2.x ................................................................................................ 11
Prestaciones y servicios de EJB 3........................................................................................ 12
Roles EJB en el equipo de desarrollo: .................................................................................. 13
Ventajas de la tecnología EJB ............................................................................................. 14
Unidad 2. Introducción a la Aplicación de Subasta ................................................................... 16
Introducción a los beans de sesión o “sessión beans” ............................................................ 16
Tipos de acceso: local, remoto o servicio web ...................................................................... 16
Patrones, Java y EJB ......................................................................................................... 18
Tipos de bean de sesión .................................................................................................... 20
¿Cuándo usar stateless, statefull o singleton? ...................................................................... 21
Invocación remota de un bean de sesión ............................................................................. 22
Invocación local de un bean de sesión ................................................................................. 23
Unidad 3. Implementación de los Beans de Sesión de EJB 3.0 ................................................... 25
Sesión con estado o stateful Session Bean ........................................................................... 25
La Clase Bean .................................................................................................................. 26
Ciclo de vida del bean con estado ....................................................................................... 28
Los bean sin estado o Stateless Session Bean ...................................................................... 29
Ciclo de vida bean sin estado ............................................................................................. 31
Acceso Local y remoto de un bean de sesión sin estado ........................................................ 31
Unidad 4. Implementación de Clases de Entidad. Conceptos Básicos .......................................... 33
Introducción a los beans de entidad .................................................................................... 33
Características generales de la API de Persistencia en Java .................................................... 35
Diferencias con los beans de sesión .................................................................................... 40
Requisitos para clases de entidad ....................................................................................... 41
Campos y Propiedades persistentes en clases de entidad ...................................................... 41

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Sobre la identidad de los objetos ........................................................................................ 43
Unidades de persistencia ................................................................................................... 44
Contextos de persistencia .................................................................................................. 45
Ciclo de vida de los Entity Beans ........................................................................................ 45
Entity Manager................................................................................................................. 45
Obteniendo un Entity Manager ........................................................................................... 46
Obteniendo un Entity Manager en aplicaciones JSE. .............................................................. 47
Persistiendo objetos.......................................................................................................... 47
Transacciones usando JPA en aplicaciones JSE. .................................................................... 47
Operaciones básicas ......................................................................................................... 48
Persist ............................................................................................................................ 48
Remove .......................................................................................................................... 48
Refresh ........................................................................................................................... 48
Merge ............................................................................................................................. 49
Búsquedas simples ........................................................................................................... 49
Laboratorio: EJB de estado ................................................................................................ 49
Unidad 5. Implementación de Clases de Entidad: Modelado de Relaciones de Asociación de Datos . 57
Las claves principales de las entidades ................................................................................ 57
Variedad de relaciones entre entidades ............................................................................... 58
Dirección de Relaciones de Entidad ..................................................................................... 59
Múltiples claves primarias en una entidad ............................................................................ 60
Relaciones entre entities ................................................................................................... 62
Operaciones en cascada .................................................................................................... 69
Estrategias de recuperación de relaciones ........................................................................... 70
Consecuencias del uso de relaciones LAZY ........................................................................... 70
Laboratorio: EJB de entidad ............................................................................................... 71
Unidad 6. Implementación de Clases de Entidad: Modelado de Relaciones de Herencia ................ 78
Jerarquías de clases.......................................................................................................... 78
Superclases no persistentes ............................................................................................... 78
Estrategias de persistencia para jerarquías de clases ............................................................ 79
Unidad 7. Uso del Lenguaje de Consulta (Ql) de Java Persistence .............................................. 86
Interfaz Query y los objetos derivados de ella ...................................................................... 87
getSingleResult() ............................................................................................................. 90
executeUpdate() .............................................................................................................. 91
setMaxResults() y setFirstResult() ...................................................................................... 91
setHint() ......................................................................................................................... 91
setParameter(...) ............................................................................................................. 91

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
setFlushModel() ............................................................................................................... 92
Composición del lenguaje QL ............................................................................................. 93
Sentencia Where .............................................................................................................. 95
Literales:......................................................................................................................... 95
Parámetros de entrada: .................................................................................................... 95
Sentencia ORDER BY ........................................................................................................ 97
Restricciones ................................................................................................................... 97
Laboratorio: Persistencia POJO ........................................................................................... 97
Unidad 8. Desarrollo de Aplicaciones Java EE Mediante el Uso de Mensajes ................................ 111
Dominios de Mensajes ..................................................................................................... 112
Dominio punto a punto(PTP) ............................................................................................. 112
Qué son las colas de mensajes .......................................................................................... 113
La cola de mensajes ........................................................................................................ 113
El API de JMS. Tipos de destinos ....................................................................................... 113
Objetos administrativos ................................................................................................... 114
Clientes JMS ................................................................................................................... 117
Unidad 9. Desarrollo de Beans Controlados por Mensajes ........................................................ 118
Beans dirigidos por mensajes o Message Driven Bean (MDB) ................................................ 118
Diseño de una clase para un MDB: .................................................................................... 119
Ciclo de Vida de MDB ....................................................................................................... 121
Diferencias con los beans de sesión y de entidad ................................................................. 121
Un ejemplo completo ....................................................................................................... 122
Laboratorio: Crear Servicio Mensajería ............................................................................... 124
Unidad 10. Interceptores ..................................................................................................... 135
Introducción. Interceptores y Entity Listener ....................................................................... 135
Interceptor ..................................................................................................................... 137
Deployment Descriptor..................................................................................................... 139
Entity Listener ................................................................................................................ 141
Unidad 11. Transacciones .................................................................................................... 144
Container Managed Transaction ........................................................................................ 146
@TransactionAttribute ..................................................................................................... 146
Bean Managed Transaction ............................................................................................... 150
Unidad 12. Excepciones....................................................................................................... 152
Manejo de excepciones en el contenedor ............................................................................ 154
Excepciones manejadas por el bean ................................................................................... 155
Manejo de excepciones por el cliente ................................................................................. 156
Excepciones en transacción .............................................................................................. 157

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 13. Temporizador .................................................................................................... 159
TimedObject y @Timeout ................................................................................................. 159
Interfaz TimerService ...................................................................................................... 161
Interfaz Timer ................................................................................................................. 162
Creación de un objeto timer.............................................................................................. 163
Recomendaciones finales .................................................................................................. 164
Unidad 14. Seguridad ......................................................................................................... 166
Autorización declarativa ................................................................................................... 168
Autorización programática ................................................................................................ 171
Responsabilidades del administrador .................................................................................. 174
Unidad 15. Uso de las Mejores Prácticas de la Tecnología EJB .................................................. 176
Con o sin estado ............................................................................................................. 176
Sin estado, pero ¿qué ocurre con los atributos?................................................................... 178
Con estado, pero ¿qué ocurre con el rendimiento? ............................................................... 178
Elegir ............................................................................................................................. 178

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Introducción y Objetivos

Introducción
La tecnología Enterprise JavaBeans incorpora una serie de mejoras como los beans de sesión únicos,
la vista interfaz, Java Naming and Directory Interface (JNDI), los beans de sesión asíncronos y el
servicio de temporizador, las cuales vienen a simplificar el proceso de crear componentes
empresariales.

Objetivo
Este módulo proporcionará los conocimientos para consturir aplicaciones robustas con la tecnología
Enterprise JavaBeans.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 1. Análisis de Aplicaciones EJB

Objetivo
Conocer los conceptos básicos que definen la programación de Enterprise JavaBeans y su
arquitectura.

Java y arquitectura de capas


Como hemos visto anteriormente J2EE utiliza una lógica de programación desarrollada en niveles o
capas.
Lo que nos permitirá encapsular o separar elementos de nuestras aplicaciones en partes claramente
definidas. Que quiere decir básicamente esto: que podremos dejar procesos en un lugar, datos en
otros, mostrar interfaces en otro.
En la programación por capas básicamente la idea es buscar la forma de separar lo que ve el usuario
con los procesos creados por el desarrollador. Así tenemos diferentes lenguajes que nos permiten
desarrollar aplicaciones por capa por ejemplo JSP, ASP, PHP. Por lo tanto debemos primero, ver de
forma global donde se encuentra el usuario y donde se encuentra el desarrollador:

Como observamos entonces ya tenemos una capa claramente definida que es la del Cliente en el
cual se realizaran todas las peticiones a las capas superiores y estas a su vez enviaran las
respuestas a esas solicitudes.
Pero definiendo aun más tenemos que:
 El servidor web es el encargado de realizar todos los procesos lógicos como crear consultas
crear formularios, ejecutar procesos, etc, un servidor web comúnmente utilizado es Apache.
 El Servidor de Bases de Datos es en el que, como su nombre lo dice, tenemos todas las
tablas, vistas y consultas que necesitamos para nuestro sistema, un servidor común es
PostgreSQL.
 Y la seguridad junto con las transacciones que contienen toda la lógica de negocio entre la
aplicación y la base de datos.
Ahora que sucede en la arquitectura de tres capas, tenemos las transacciones con el servidor web
realizándose en un mismo lugar, o en este caso una misma capa, y los datos se mantienen a su vez
también en una capa aun más superior y alejada del cliente, para dar un nivel más de seguridad.
Observemos el siguiente dibujo, en el cual ya se definen las 3 capas básicas del desarrollo de
aplicaciones web:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En esta arquitectura lo principal es que, separamos la segunda capa en dos: Capa Web que queda
solamente con el Servidor WEB y las Transacciones se realizan en la capa de Negocio:

Esto nos permitirá un mejor control de todos los elementos que entran en juego a la hora de
desarrollar aplicaciones Web.
Las aplicaciones J2EE se basan completamente en el modelo de aplicaciones de 4 niveles.
Todas las aplicaciones constan de 3 partes básicas, que son:
 Módulos EJB: encargado de tener la lógica del negocio y transacciones. En otras palabras
podemos decir que es el encargado de ejecutar programas, consultas a la base de dato
principalmente. (capa Negocio)
 Modulo WAR: que es la encargada de tener todos los elementos de interfaz como páginas
web, servlets, applets. (capa WEB).
 Aplicación EAR: contiene en su interior toda la configuración de la aplicación J2EE, eso
incluye el modulo WAR y EJB.

Modulo WAR
Este modulo como dijimos anteriormente es el encargado de la comunicación Cliente-Servidor WEB,
en el realizan las peticiones a las capas superiores, en el tenemos tres elementos básicos que son
los:
JSP: Java Server Pages (pagina web java)
Servlets: Componente web desarrollada con el objetivo de procesar requerimientos de un cliente o
requests y genera respuestas con contenido web dinámico. Para ser ejecutados es necesaria la
utilización de un servidor que soporte Servlets y su container.
Aplicaciones Java: códigos Java en su forma pura, que tienen métodos y atributos y que pueden ser
utilizados en aplicaciones JSP y Servlets.
Muchas veces se tiende a utilizar los JSP de la misma forma que paginas PHP, lo cual no es
recomendable debido a la gran cantidad de código que se genera y lo cual produce mucho desorden
por esto se hará gran énfasis a respetar la arquitectura J2EE, en donde debemos tener cada parte
donde corresponde, vale decir, Interfaces en la capa web, peticiones y respuestas en la capa de
negocio y las conexiones de la base de datos en la capa de datos.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Comunicación Capa Web+Capa Negocio
Cuando se comienza el desarrollo de estas aplicaciones, cuesta un poco saber donde realizar la
comunicación de cada una de las capas, como dijimos anteriormente uno tiene a escribir todo ese
código en las aplicaciones JSP, lo que no era recomendable, por lo que debemos hacerlo de la
siguiente forma:

Se deben utilizar los Servlets como ente comunicador de ambas capas, para poder mantener la
arquitectura de la aplicación y el orden.
Más adelante veremos que esta comunicación se realiza de una forma muy sencilla en la que la
herramienta de desarrollo, en este caso NetBeans, la realiza en 2 sencillos pasos.
Cabe señalar que es preciso tener conocimientos previos de HTML y de transferencia de información
entre páginas web, para poder llevar a cabo el desarrollo de la aplicación en la capa web.
Entonces a modo de resumen, Como conocimiento básico, se conoce el modelo de 3 capas, en el
cual tenemos, el cliente o navegador, servidor web y la capa de datos:

Tenemos, un navegador, que es el lugar donde se encuentra el cliente. Un servidor web, que es
donde se ejecutan las operaciones de negocio y comunicaciones con la BD, y se genera el HTML
dinámico que posteriormente será mostrado en los navegadores.
Servidor de Bases de Datos, donde se encuentra toda la información y de donde se retornan las
consultas.
Para el modelo de 4 capas tenemos que las operaciones de negocio y generación de HTML dinámico
que se envían al navegador se encuentran separadas.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Y en donde entran en juego elementos como los Servlets y EJB.

Tecnología Enterprise Java Beans


Hemos visto que con la programación orientada a objetos se pueden reutilizar clases. Sin embargo,
con los componentes podemos ir más lejos ya que es posible reutilizar un mayor nivel de
funcionalidades. Incluso podríamos cambiar dichas funcionalidades y ajustarlas a cada dominio del
problema en particular, sin necesidad de tocar el código del componente desarrollado.
Podemos interpretar un componente como un objeto más de programación, aunque portador de un
conjunto de servicios adicionales soportados en tiempo de ejecución por el contenedor de
componentes. Este contenedor recibe el nombre de contenedor EJB.

Dicho contenedor de componentes viene a ser una suerte de sistema operativo donde residen los
diferentes componentes. Hemos visto que en Java existe un modelo de programación de objetos
remotos denominado RMI. Pues bien, con RMI es posible enviar peticiones a objetos que están
ejecutándose en otra máquina virtual Java. De este modo un componente EJB sería un objeto
remoto RMI que reside en un contenedor EJB, el cual le proporciona un conjunto de servicios
adicionales.
Dada esta arquitectura de desarrollo tan particular, cuando desarrollemos componentes deberemos
dedicarle bastante atención al despliegue (deployment) del componente tanto como a su desarrollo.
El despliegue puede definirse como la incorporación del componente a nuestro contenedor EJB y a
nuestro entorno de trabajo (bases de datos, arquitectura del software, etc.). El despliegue se define
de forma declarativa, mediante un fichero XML (descriptor del despliegue, deployment descriptor) en
el que se definen todas las características del bean.
Una de las virtudes de esta forma de operar mediante componentes es que la industria ha generada
diversas expectativas comerciales. Así, han surgido diferentes empresas dedicadas a implementar y
vender componentes específicos a terceros. Aun así es difícil crear componentes genéricos que
pueden emplearse en multitud de ocasiones. Lo habitual es que cada dominio de un problema o
aplicación exija sus propios y específicos componentes, adaptados a sus necesidades y dificultades
concretas. La estandarización aunque deseable, resulta ciertamente complicada. No obstante hay un
cierto campo de negocio para este tipo de desarrollos como puede verse en esta web:
http://www.componentsource.com
Dentro de Java existe la especificación de Enterprise JavaBeans (EJBs), la cual está destinada a
ofrecer una arquitectura para el desarrollo y estructuración de aplicaciones de procesamiento de
transacciones, basados en objetos distribuidos y componentes de software del lado del servidor.
Pues bien, dichos componentes son llamados enterprise beans. Es decir, los objetos distribuidos que
se encuentran en Enterprise JavaBeans Containers y proveen servicios remotos a clientes
distribuidos a través de la red.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como puede verse en la ilustración anterior, un Enterprise javabeans no es lo mismo que un java
beans:
- Javabeans es un componente utilizado en Java que permite agrupar funcionalidades que
forman parte de una aplicación.
- Puede agrupar información personal, datos sobre una petición, requerimientos de órdenes,
etc.
- Requiere ser integrado con otros componentes para ser funcional.
En general, un bean es una clase que obedece ciertas reglas:
- Debe tener un constructor por defecto y sin argumentos.
- Debe tener persistencia, es decir, implementar el interface Serializable.
- Debe tener introspección. Los IDE reconocen ciertas pautas de diseño, nombres de las
funciones miembros o métodos y definiciones de las clases, que permiten a la herramienta de
programación mirar dentro del bean y conocer sus propiedades y su conducta.

Por su parte un Enterprise JavaBeans:


- Agrupa funcionalidades para una aplicación.
- Es un componente de despliegue, es decir, que existe dentro de un ambiente de ejecución
(Enterprise Java Bean Container).
- No requiere ser integrado, ya que puede ser activado mediante el Contenedor de los EJB.
- Es un conjunto de código que contiene campos y métodos para la implementación de
módulos en una lógica de negocio.
Podemos concebir un EJB como un bloque de construcción que se emplea de manera independiente
o en colaboración con otros EJBs para la ejecución de una lógica de negocio en un servidor J2EE.
Esta parte de la aplicación constituye el denominado módulo EJB

Tipos de beans
Cada EJB contiene muchas aplicaciones, entonces a cada uno de esos pequeños paquetes o beans
del EJB que contienen toda una lógica de programación para realizar alguna actividad en particular.
Existen tres tipos de Beans que son:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Entonces más detalladamente tenemos:
Beans de Sesión: representan sesiones interactivas con uno o más clientes, pueden mantener un
estado, pero solo durante el tiempo que el cliente interactúa con el bean. Esto significa que los
beans de sesión no almacenan sus datos en una BD después que el cliente termine el proceso. Se
dividen en dos
- Beans de sesión Con Estado: almacenan datos específicos obtenidos durante la conexión
con el cliente, cada bean de sesión con estado por lo tanto almacena el estado conversacional
de un cliente con el que interactúa. Este estado conversacional se modifica conforme el
cliente va realizando llamadas a los métodos de negocio del bean. El estado conversacional
no se guarda cuando el cliente termina la sesión. Ósea este beans usado va cambiando
conforme el cliente lo necesite, algunos métodos que contienen estos son los set y los get, un
ejemplo claro es el carrito de compras que a medida que vamos avanzando se le van
agregando más cosas, o en un inicio de sesión cuando necesitamos tener en alguna parte los
datos de la persona que ha hecho login.
- Beans de sesión Sin Estado: no se modifican con las llamadas de los clientes solo reciben
datos y devuelven resultados pero no modifican internamente el estado del bean. Estos
beans por lo general son usados para encapsular procesos de negocio, más que datos de
negocio (tarea de los beans de entidad), también puede usarse como puente de acceso a una
BD o a un bean de entidad. Cuando trabajamos con cliente-servidor estos beans podrían
proporcionar al interface de usuario los datos necesarios, estos beans de sesión sin estado
son de uso muy frecuente.
Beans de Mensajes: pueden escuchar mensajes de un servicio de mensajes JMS, estos nunca se
comunican directamente con el cliente y no necesitan objetos EJBObject. Un ejemplo podría ser
ListenerNuevoCliente que se activa cada vez que se envía un mensaje que se ha ingresado un nuevo
cliente.
Beans de Entidad: modelan conceptos o datos de negocio, que pueden expresarse como nombres.
Representan “cosas”, objetos del mundo real como Hoteles, habitaciones, expedientes, estudiantes y
otros. Un bean de entidad puede representar incluso cosas abstractas como una reserva, describen
tanto el estado como la conducta de objetos del mundo real y permite a los desarrolladores
encapsular reglas de datos y negocio asociadas con un concepto específico. Por ejemplo un bean de
entidad Estudiante encapsula los datos y reglas de negocio asociadas a un estudiante. Esto hace
posible manejar de forma consistente y segura los datos asociados a un concepto. Los beans pueden
contener información por ejemplo de un estudiante sin necesariamente estar conectados con una
BD. El contenedor se encarga de sincronizar las variables de instancia del bean con la BD. Debido a
que los beans de entidad se guardan en un mecanismo de almacenamiento se dice que es
persistente, Persistente significa que el estado del bean existe más tiempo que la duración de la
aplicación. Estos beans se dividen en dos:
- Persistencia gestionada por el Bean (BMP): contienen el código que accede a la BD.
- Persistencia Gestionada por el Contenedor (CMP): la relación entre las columnas de la
BD y el bean se describe en el fichero de propiedades del bean, y el contenedor EJB se ocupa
de la implementación.
Cada uno de ellos será objeto de minucioso análisis en las próximas unidades. Ahora, de momento,
veamos en la siguiente ilustración la posición que ocupan los diferentes tipos EJBs dentro de la capa
de negocio o Business Tier de una aplicación. Al mismo tiempo, observamos dónde deberían
colocarse opcionalmente los componentes JavaBeans en la misma arquitectura de la aplicación:
JavaBeans Components.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Especificaciones
La especificación exige un modelo de programación constituido por convenciones o protocolos y un
conjunto de clases e interfaces sobre las cuales de apoya el EJB API. El modelo de programación de
EJB provee a los desarrolladores y proveedores de beans, un conjunto de contratos que definen un
estándar común para el desarrollo. El principal logro de estos contratos es asegurar la portabilidad
entre distintos proveedores y así soportar un gran conjunto de funcionalidades.
Más concretamente, podríamos decir que Enterprise Java Beans (EJB) es una plataforma para
construir aplicaciones de negocio portables, reusables y escalables usando el lenguaje de
programación Java. Desde el punto de vista del desarrollador, un EJB es una porción de código que
se ejecuta en un contenedor EJB, que no es más que un ambiente especializado (runtime) que
provee determinados componentes de servicio.
Los EJBs presentan una doble naturaleza:
 Son componentes: desde el punto de vista que encapsulan comportamiento y permite
reutilizar porciones de código.
 Son una suerte de framework: desplegados dentro de un contenedor, proveen servicios para
el desarrollo de aplicaciones enterprise, servicios que son invisibles para el programador y no
ensucian la lógica de negocio con funcionalidades trasversales al modelo de dominio (a
menudo requerimientos no funcionales o aspectos).

¿Qué servicios proveen los EJBs?


En el apartado anterior hemos comentado que la diferencia fundamental entre los componentes y
los objetos clásicos reside en que los componentes habitan dentro de un contenedor EJB que los
envuelve proporcionando una capa de servicios añadidos. ¿Cuáles son estos servicios? Los más
importantes son los siguientes:
 Manejo de transacciones: apertura y cierre de transacciones asociadas a las llamadas a los
métodos del bean.
 Seguridad: comprobación de permisos de acceso a los métodos del bean.
 Concurrencia: llamada simultánea a un mismo bean desde múltiples clientes.
 Servicios de red: comunicación entre el cliente y el bean en máquinas distintas.
 Gestión de recursos: gestión automática de múltiples recursos, como colas de mensajes,
bases de datos o fuentes de datos en aplicaciones heredadas que no han sido traducidas a
nuevos lenguajes/entornos y siguen usándose en la empresa.
 Persistencia: sincronización entre los datos del bean y tablas de una base de datos.
 Gestión de mensajes: manejo de Java Message Service (JMS).
 Escalabilidad: posibilidad de constituir clusters de servidores de aplicaciones con múltiples
hosts para poder dar respuesta a aumentos repentinos de carga de la aplicación con sólo
añadir hosts adicionales.
 Adaptación en tiempo de despliegue: posibilidad de modificación de todas estas
características en el momento del despliegue del bean.

La ventaja de estos componentes radica en que no tenemos que desarrollarlos nosotros, sino que
podemos reutilizarlos para que incorporen todas estas características. Evidentemente, si en la

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
aplicación que estemos desarrollando no resultan necesarios estos servicios porque sólo vamos a
emplear una interfaz web, bastará utilizar simplemente páginas JSP y JDBC.

Evolución de la especificación EJB


En Marzo de 1998 Sun Microsystems propone la especificación 1.0 de la arquitectura Enterprise
JavaBeans. Esta especificación comienza con la siguiente definición:
 La arquitectura Enterprise JavaBeans es una arquitectura de componentes para el desarrollo
y despliegue de aplicaciones de empresa distribuidas y orientadas a objetos. Las aplicaciones
escritas usando la arquitectura Enterprise JavaBeans son escalables, transaccionales y
seguras para multi usuarios. Estas aplicaciones pueden escribirse una vez, y luego
desplegarse en cualquier servidor que soporte la especificación Enterprise JavaBeans.
Aunque se han introducido nuevas versiones de la especificación, que incorporan muchas mejoras a
la propuesta inicial, la definición de la arquitectura sigue siendo la misma. La siguiente tabla
muestra las distintas revisiones que ha sufrido la especificación de la arquitectura EJB.
Especificación Fecha Principales novedades
EJB
EJB 1.0 Marzo 1998 Propuesta inicial de la arquitectura EJB. Se introducen
los beans de sesión y los de entidad (de
implementación opcional). Persistencia manejada por el
contendedor en los beans de entidad. Manejo de
transacciones. Manejo de seguridad.
EJB 1.1 Diciembre 1999 Implementación obligatoria de los beans de entidad.
Acceso al entorno de los beans mediante JNDI.
EJB 2.0 Agosto 2001 Manejo de mensajes con los beans dirigidos por
mensajes. Relaciones entre beans manejadas por el
contenedor. Uso de interfaces locales entre beans que
se encuentran en el mismo servidor. Consultas de
beans declarativas, usando el EJB QL.
EJB 2.1 Agosto 2002 Soporte para servicios web. Temporizador manejado
por el contenedor de beans. Mejora en el EJB QL.
Como hemos visto, los Enterprise JavaBeans son una de las API que forman parte del estándar de
construcción de aplicaciones empresariales J2EE.
El modelo de programación propuesto por la versión 2.1 de EJB conllevaba una serie de
inconvenientes que limitaron mucho el uso de esta especificación y conllevó la aparición de
soluciones open source que suplían las carencias que presentaba EJB 2.1.
Por tal razón, se planteó la creación de una nueva especificación para EJB, la versión 3.0, dadas las
limitaciones presentadas por las versiones anteriores. Entre otras limitaciones encontramos:
- Crear múltiples descriptores de despliegue XML para un solo EJB. Se prefieren alternativas
como XDoclet.
- Se crean múltiples métodos callbacks usualmente inutilizados.
- Se deben crear las interfaces: remote y local, las interfaces home: remote y local, y
finalmente la clase Bean.
- Deficiente manejo de excepciones. Se tienen que lanzar (throw) y atrapar (catch)
gestionando varios tipos de excepciones en ocasiones innecesarias.
- Imposibilidad de probar (testear) EJB fuera del contexto del contenedor de EJB, desde
componentes como entity beans (container-managed) que son clases abstractas.
- EJB-QL tiene limitaciones en funcionalidad y dificultades de uso (principalmente en funciones
de sumarización para agrupamientos, causa que propicio la aparición de extensiones
propietarias del lenguaje EJB-QL). Búsqueda de otras alternativas como Toplink e Hibernate.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
EJB 3.0
El objetivo de Enterprise JavaBeans (EJB) 3.0 es simplificar el desarrollo de aplicaciones Java y
estandarizar el API de persistencia para la plataforma Java. EJB 3.0 está cambiando drásticamente
el modelo de programación de EJBs.
En este sentido, EJB 3.0 es una tecnología basada en J2EE que proporciona una arquitectura
escalable, transaccional y multiusuario. No obstante, su complejidad es un obstáculo para su
adopción por lo que herramientas como Hibernate y Toplink que han sido adoptadas como
soluciones en la capa del modelo para la persistencia, antes de EJB 3.0.
No obstante, con la introducción de EJB 3.0 se consigue:
- La estandarización de una estructura de persistencia (EJB es una especificación no un
Framework ni una herramienta).
- Hace más fácil el desarrollo de EJB.
El objetivo de Enterprise JavaBeans (EJB) 3.0 es simplificar el desarrollo de aplicaciones Java y
estandarizar el API de persistencia para la plataforma Java.
- Elimina la necesidad de construir interfaces EJB y descriptores de despliegue innecesarios, y
en lugar de esto, permite que los desarrolladores los generen especificando anotaciones
(similar a XDoclet). Esta aproximación libera a los desarrolladores de crear descriptores de
despliegue y de crear interfaces para los componentes
- Simplifica los EJBs para asemejarse a los POJOs o Java Beans.
- Elimina la necesidad de tener interfaces de componentes para los EJBs.
- Los beans de entidad no requieren ninguna interfaz de componente.
- Los beans de entidad utilizarán ahora una interfaz POJO.
- Elimina la necesidad de implementar métodos callback de ciclo de vida innecesarios.
En la especificación 3.0, los EJB no son más que POJOs (clases planas comunes y corrientes de
Java) con algunos poderes especiales implícitos, que se activan en runtime cuando son ejecutados
en un contenedor de EJBs.
Los servicios que debe proveer el contenedor de EJBs deben ser especificados por el programador a
través de metadata de configuración que puede escribirse como:
 Anotaciones de Java5 intercaladas en el código de las clases.
 Descriptores XML (archivos XML separados).
A partir de EJB 3 se puede usar cualquiera de estas dos técnicas. Las técnicas no son exclusivas,
pueden coexistir anotaciones con descriptores XML y, en el caso de superponerse la metadata, los
XML tendrán prioridad y podrán sobrescribir las anotaciones.
Una anotación transforma un simple POJO en un EJB.

Algunos ejemplos de los contenedores más populares que hay actualmente en el mercado son:
Glassfish, de Sun Microsystem, JBoss Application Server, de Red Hat, BEA Weblogic Server y Oracle
Application Server, ambos de Oracle y WebSphere de IBM.
Como hemos dicho, hasta cierto punto la nueva especificación EJB 3.0 supone el fin para los
descriptores XML. Se incorpora el uso de metadatos, denominados anotaciones agregadas en JDK
5.0 como parte de la especificación JSR 175 JCP.
Dichas anotaciones son un tipo de programación orientado a atributos. Una idea similar a XDoclet
pero ahora sometida la especificación. Al igual que existen los modificadores public/private de Java,
las anotaciones pueden ser usadas en clases, campos y métodos.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ejemplo:
import javax.ejb.*;
@Stateless
public class MyAccountBean implements MyAccount
{
@Tx(TxType.REQUIRED)
@MethodPermission({"customer"})
public void deposit(double money) {...}
}
@Stateless nos indica que el bean es stateless.
@Tx es un atributo que indica la demarcación transaccional para el método deposit.
@MethodPermission especifica a los usuarios quienes están permitidos para usar el método deposit.
Cambios generales:
- EJB 3.0 elimina la necesidad de las interfaces home y de componente, y el requisito de que
las clases bean implementen la interfaz javax.ejb.EnterpriseBean. Los EJBs pasan a ser ahora
POJOs.
- Simplificación de la configuración a través de valores por defecto y del uso de anotaciones de
metadatos en lugar de descriptores de despliegue.
- Se soporta la inyección de dependencias para utilizar EJBs, recursos y variables de entorno.
- Soporte métodos de ciclo de vida mejorados, y de clases listener para callbacks.
- Soporte de métodos de intercepción.
- Búsqueda e invocación de métodos simplificada.

API de persistencia / Beans de entidad:


1. Los beans de entidad CMP son ahora POJOs y pueden ser probados o usados fuera del
contenedor.
2. Se introduce el API EntityManager para la ejecución de operaciones CRUD sobre entidades.
3. Se estandariza un mecanismo de mapeo objeto-relacional a través de anotaciones de
metadatos. Versiones futuras de la especificación soportarán XML para este mapeo objeto-
relacional.
4. Mejora enormemente EJB-QL y añade soporte para la ejecución de SQL nativo.

EJB 3.0 hace más fácil el desarrollo de aplicaciones porque:


- Elimina la necesidad de construir interfaces EJB y descriptores de despliegue innecesarios, y
en lugar de esto, permite que los desarrolladores los generen especificando anotaciones
(similar a XDoclet). Esta aproximación libera a los desarrolladores de crear descriptores de
despliegue y de crear interfaces para los Componentes
- Simplifica los EJBs para asemejarse a los POJOs o Java Beans.
- Elimina la necesidad de tener interfaces de componentes para los EJBs.
- Los beans de entidad no requieren ninguna interfaz de componente.
- Los beans de entidad utilizarán ahora una interfaz POJO.
- Elimina la necesidad de implementar métodos callback de ciclo de vida innecesarios.

Compatibilidad con EJB 2.x


EJB 3.0 requiere compatibilidad e interoperabilidad con EJB 2.x; las aplicaciones EJB 2.x funcionan
en contenedores compatibles con EJB 3.0. El modelo de programación para los EJB ha cambiado
drásticamente entre EJB 2.x y EJB 3.0, por lo que migrar una aplicación a la nueva especificación no
resulta trivial.
Los vendedores de herramientas y de servidores de aplicaciones proporcionarán herramientas y
utilidades para hacer la migración más fácil.
Por ejemplo, la implementación previa de Oracle de EJB 3.0 soporta el concepto de migración
incremental.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Prestaciones y servicios de EJB 3
EJB es el único estándar Java que se ocupa de la lógica de negocio del lado del servidor, y esto es
fundamental para J2EE. El comité de especificación de EJB reconoce que EJB se quedó corto en
alcanzar algunas de sus ambiciosas metas, y necesitó de una modernización. Esta modernización
está muy enfocada en la facilidad de uso, principalmente mediante la simplificación de los
requerimientos para los desarrolladores.
Sin embargo, el comité de especificación también ha identificado un número de mejoras funcionales
críticas que facilitan el uso y la eliminación de ciertos anti-patrones J2EE.
Afortunadamente, la comunidad Java conoce ahora mucho más los problemas relacionados a la
construcción de aplicaciones web y empresariales que hace cinco años.
El comité de especificación pensó mucho como simplificar ciertos casos de usos generales
extremadamente comunes, como por ejemplo:
Actualizando datos
1. recuperar un dato
2. mostrarlo en pantalla
3. aceptar la entrada del usuario
4. actualizar el dato
5. comunicar el éxito al usuario

Ingresando nuevos datos


1. recuperar un dato
2. mostrarlo en pantalla
3. aceptar la entrada del usuario
4. crear un nuevo dato, con una asociación al primer dato
5. comunicar el éxito al usuario
Cada uno de estos casos involucra dos ciclos request/response (envío y respuesta) de aplicación
completos.
Ambos demuestran que el bloqueo optimista es esencial en una aplicación que requiere alta
concurrencia (ambos casos necesitarían ser implementados como una sola comunicación
atravesando dos transacciones ACID de base de datos distintas).
Pues bien, EJB 3 provee una serie de servicios que satisfacen con mucho el problema antes descrito
y otras muchas situaciones. Sucintamente se pueden enumerar dichos servicios del siguiente modo:
 Integración: Proveen una forma de acoplar en tiempo de ejecución diferentes componentes,
mediante configuración simple de anotaciones o de XML. El acoplamiento se puede hacer
mediante Inyección de Dependencia (DI) o usando JNDI, como se hacía en EJB 2. La
integración es un servicio que proveen los beans de sesión y los MDBs.
 Pooling: El contenedor de EJBs crea para los componentes EJB un pool de instancias que es
compartido por los diferentes clientes. Sin embargo, cada cliente cada instancia como
diferente dentro de los EJB y eso resulta así gracias a que el contenedor está constantemente
reusando los objetos para optimizar memoria. El pooling es un servicio que se aplica a los
Stateless Session Beans y los MDBs.
 Thread-safely: El programador puede escribir componentes del lado del servidor como si
estuviera trabajando en una aplicación sencilla con un solo thread (hilo). El contenedor se
encarga de que los EJBs tengan el soporte adecuado para una aplicación multi-usuario. Estas
son las aplicaciones Enterprise más habituales y el acceso se realiza de forma transparente,
segura y consistente. Dicha características se aplica a los beans de sesión y a los MDBs.
 Administración de Estados: El contenedor de EJBs almacena y maneja el estado de un
Stateful Session Bean de forma transparente, lo que significa que el programador puede
mantener el estado de los miembros de una clase como si estuviera desarrollando una
aplicación de escritorio ordinaria. De este modo, será el contenedor quien maneje los detalles
de las sesiones.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
 Mensajería: Mediante los MDBs es posible desacoplar por completo dos componentes para
que se comuniquen de forma asincrónica, sin reparar demasiado en los mecanismos de la
JMS API que los MDBs encapsulan.
 Transacciones: EJB soporta el manejo de transacciones declarativas que permiten agregar
comportamiento transaccional a un componente simplemente usando anotaciones o XMLs de
configuración. Esto significa que cuando un método de un EJB (Session Bean o MDB) se
completa normalmente, el contenedor se encargará de confirmar la transacción y efectuar los
cambios que se realizaron en los datos de forma permanente. Si algo fallara durante la
ejecución del método por causa de una excepción o de cualquier otro problema, la
transacción haría un rollback, de modo que es la aplicación actuaría como si el método jamás
se hubiera invocado.
 Seguridad: EJB soporta integración con la Java Authentication and Authorization Service
(JAAS) API, haciendo casi transparente el manejo transversal de la seguridad. Esta
característica es aplicable a todos los Session Beans.
 Interceptors: EJB introduce un framework liviano y simple para AOP (programación
orientada a aspectos). No es tan robusto y completo como otros, pero es lo suficientemente
útil para que sea utilizado por los demás servicios del contenedor para brindarnos de forma
invisible los crosscutting concerns de seguridad, transacciones, thread-safely. Además,
nosotros, como programadores, podemos agregar nuevos aspectos como logging o auditoria
y demás de forma configurable.
 Acceso Remoto: Es posible acceder de forma remota a distintos EJBs de forma sencilla,
simplemente mediante la Inyección de Dependencia. El procedimiento para inyectar un
componente local o uno remoto es exactamente el mismo, abstrayéndonos de las
complicaciones específicas de RMI o similares. Este servicio aplica únicamente a los Session
Beans.
 Web Services: Un Stateless Session Bean puede publicar sus métodos como web services
mediante una sencilla anotación.
 Persistencia: EJB 3 provee la especificación JPA para el mapeo de objetos (Entities) a
tablas.
 Catching and Performance: JPA provee de forma transparente un importante número de
servicios que permiten usar un caché de entidades en memoria y una lectura y escritura
sobre la base de datos altamente performante.

Roles EJB en el equipo de desarrollo:


La arquitectura EJB define seis papeles principales. Brevemente, son:
 Desarrollador de beans: desarrolla los componentes enterprise beans.
 Ensamblador de aplicaciones: compone los enterprise beans y las aplicaciones cliente
para conformar una aplicación completa
 Desplegador: despliega la aplicación en un entorno operacional particular (servidor de
aplicaciones)

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
 Administrador del sistema: configura y administra la infraestructura de computación y de
red del negocio
 Proporcionador del Contenedor EJB y Proporcionador del Servidor EJB: un fabricante
(o fabricantes) especializado en manejo de transacciones y de aplicaciones y otros servicios
de bajo nivel. Desarrollan el servidor de aplicaciones.

Ventajas de la tecnología EJB


La arquitectura EJB proporciona beneficios a todos los papeles que hemos mencionado previamente
(desarrolladores, ensambladores de aplicaciones, administradores, desplegadores, fabricantes de
servidores). Vamos en enumerar las ventajas que obtendrán los desarrolladores de aplicaciones y
los clientes finales.
Las ventajas que ofrece la arquitectura Enterprise JavaBeans a un desarrollador de aplicaciones se
listan a continuación.
 Simplicidad. Debido a que el contenedor de aplicaciones libera al programador de realizar
las tareas del nivel del sistema, la escritura de un enterprise bean es casi tan sencilla como la
escritura de una clase Java. El desarrollador no tiene que preocuparse de temas de nivel de
sistema como la seguridad, transacciones, multi-threading o la programación distribuida.
Como resultado, el desarrollador de aplicaciones se concentra en la lógica de negocio y en el
dominio específico de la aplicación.
 Portabilidad de la aplicación. Una aplicación EJB puede ser desplegada en cualquier
servidor de aplicaciones que soporte J2EE.
 Reusabilidad de componentes. Una aplicación EJB está formada por componentes
enterprise beans. Cada enterprise bean es un bloque de construcción reusable. Hay dos
formas esenciales de reusar un enterprise bean a nivel de desarrollo y a nivel de aplicación
cliente. Un bean desarrollado puede desplegarse en distintas aplicaciones, adaptando sus
características a las necesidades de las mismas. También un bean desplegado puede ser
usado por múltiples aplicaciones cliente.
 Posibilidad de construcción de aplicaciones complejas. La arquitectura EJB simplifica la
construcción de aplicaciones complejas. Al estar basada en componentes y en un conjunto
claro y bien establecido de interfaces, se facilita el desarrollo en equipo de la aplicación.
 Separación de la lógica de presentación de la lógica de negocio. Un enterprise bean
encapsula típicamente un proceso o una entidad de negocio. (un objeto que representa datos
del negocio), haciéndolo independiente de la lógica de presentación. El programador de
gestión no necesita de preocuparse de cómo formatear la salida; será el programador que
desarrolle la página Web el que se ocupe de ello usando los datos de salida que
proporcionará el bean. Esta separación hace posible desarrollar distintas lógicas de
presentación para la misma lógica de negocio o cambiar la lógica de presentación sin
modificar el código que implementa el proceso de negocio.
 Despliegue en muchos entornos operativos. Entendemos por entornos operativos el
conjunto de aplicaciones y sistemas (bases de datos, sistemas operativos, aplicaciones ya en
marcha, etc.) que están instaladas en una empresa. Al detallarse claramente todas las
posibilidades de despliegue de las aplicaciones, se facilita el desarrollo de herramientas que
asistan y automaticen este proceso. La arquitectura permite que los beans de entidad se
conecten a distintos tipos de sistemas de bases de datos.
 Despliegue distribuido. La arquitectura EJB hace posible que las aplicaciones se
desplieguen de forma distribuida entre distintos servidores de una red. El desarrollador de
beans no necesita considerar la topología del despliegue. Escribe el mismo código
independientemente de si el bean se va a desplegar en una máquina o en otra (cuidado: con
la especificación 2.0 esto se modifica ligeramente, al introducirse la posibilidad de los
interfaces locales).
 Interoperabilidad entre aplicaciones. La arquitectura EJB hace más fácil la integración de
múltiples aplicaciones de diferentes vendedores. El interfaz del enterprise bean con el cliente
sirve como un punto bien definido de integración entre aplicaciones.
 Integración con sistemas no-Java. Las APIs relacionadas, como las especificaciones
Connector y Java Message Service (JMS), así como los beans manejados por mensajes,

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
hacen posible la integración de los enterprise beans con sistemas no Java, como sistemas
ERP o aplicaciones mainframes.
 Recursos educativos y herramientas de desarrollo. El hecho de que la especificación
EJB sea un estándar hace que exista una creciente oferta de herramientas y formación que
facilita el trabajo del desarrollador de aplicaciones EJB.
Entre las ventajas que aporta esta arquitectura al cliente final, destacamos la posibilidad de elección
del servidor, la mejora en la gestión de las aplicaciones, la integración con las aplicaciones y datos
ya existentes y la seguridad.
 Elección del servidor. Debido a que las aplicaciones EJB pueden ser ejecutadas en
cualquier servidor J2EE, el cliente no queda ligado a un vendedor de servidores. Antes de que
existiera la arquitectura EJB era muy difícil que una aplicación desarrollada para una
determinada capa intermedia (Tuxedo, por ejemplo) pudiera portarse a otro servidor. Con la
arquitectura EJB, sin embargo, el cliente deja de estar atado a un vendedor y puede cambiar
de servidor cuando sus necesidades de escalabilidad, integración, precio, seguridad, etc. lo
requieran.
 Existen en el mercado algunos servidores de aplicaciones gratuitos (JBOSS, el servidor de
aplicaciones de Sun, etc.) con los que sería posible hacer unas primeras pruebas del sistema,
para después pasar a un servidor de aplicaciones con más funcionalidades.
 Gestión de las aplicaciones. Las aplicaciones son mucho más sencillas de manejar
(arrancar, parar, configurar, etc.) debido a que existen herramientas de control más
elaboradas.
 Integración con aplicaciones y datos ya existentes. La arquitectura EJB y otras APIs de
J2EE simplifican y estandarizan la integración de aplicaciones EJB con aplicaciones no Java y
sistemas en el entorno operativo del cliente. Por ejemplo, un cliente no tiene que cambiar un
esquema de base de datos para encajar en una aplicación. En lugar de ello, se puede
construir una aplicación EJB que encaje en el esquema cuando sea desplegada.
 Seguridad. La arquitectura EJB traslada la mayor parte de la responsabilidad de la seguridad
de una aplicación del desarrollador de aplicaciones al vendedor del servidor, el Administrador
de Sistemas y al Desplegador (papeles de la especificación EJB) La gente que ejecuta esos
papeles están más cualificados que el desarrollador de aplicaciones para hacer segura la
aplicación. Esto lleva a una mejor seguridad en las aplicaciones operacionales.

Ver Video: Examinando Aplicaciones EJB, en la Unidad 1,


en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 2. Introducción a la Aplicación de
Subasta

Objetivo
Conocer los conceptos básicos que definen la programación de Enterprise JavaBeans en su faceta de
sesión.

Introducción a los beans de sesión o “sessión beans”


Un bean de sesión es un componente de la tecnología EJB que representa un proceso o una acción
encapsulada de negocio. Normalmente, cualquier llamada a un servicio del servidor debería
comenzar con una llamada a un bean de sesión. Mientras que un bean de entidad representa una
cosa que se puede representar con un nombre, al pensar en un bean de sesión deberíamos pensar
en un verbo. Ejemplos de beans de sesión podrían ser un carrito de la compra de una aplicación de
negocio electrónico o un sistema verificador de tarjetas de crédito. De este modo, los Session Beans
son invocados por el cliente con el propósito de ejecutar operaciones de negocio específicas, como
por ejemplo podría ser chequear la historia crediticia del cliente de un banco. El nombre sesión
implica que la instancia del bean estará disponible durante una unidad de trabajo y no sobrevivirá
a una caída del servidor. En otras palabras, Un bean de sesión sirve para modelar cualquier
funcionalidad lógica de una aplicación y representa una conversación temporal con una
aplicación cliente. Cuando dicha aplicación cliente finaliza su ejecución, el bean de sesión y sus datos
desaparecen.
En definitiva, los beans de sesión representan sesiones interactivas con uno o más clientes. Los
bean de sesión pueden mantener un estado, pero sólo durante el tiempo que el cliente interactúa
con el bean. Esto significa que los beans de sesión no almacenan sus datos en una base de datos
después de que el cliente termine el proceso. Por ello se suele decir que los beans de sesión no son
persistentes.
A diferencia de los bean de entidad, los beans de sesión no se comparten entre más de un cliente,
sino que existe una correspondencia uno-uno entre beans de sesión y clientes. Por esto, el
contenedor EJB no necesita implementar mecanismos de manejo de concurrencia en el acceso a
estos beans.
Tomando en consideración lo antes dicho podemos establecer el ciclo de vida del bean de sesión del
siguiente modo:
 En primer lugar se produciría una instancia creada / enlazada cuando un cliente llamara al
bean.
 Dicha instancia permanecería asociada a un cliente como recurso privado mientras durara un
proceso cliente.
 En cuanto el proceso finalizara la instancia quedaría eliminada / liberada.
Este bean de sesión desde el punto de vista del cliente es también llamado una “interfaz de
negocio” de tipo POJI (Plain Old Java Interface). Una interfaz de negocio es una interfaz Java plana
(POJI).
Al igual que en el caso de stateless session beans, aunque se requiere este tipo de interfaz, no se
liga al programador a crearlas, debido a que se pueden generar automáticamente. Resulta posible
declarar métodos que puedan ser llamados por beans cliente.

Tipos de acceso: local, remoto o servicio web


El acceso permitido por el Enterprise vean puede ser de 3 tipos: local, remoto o un servicio web.
Elegir entre local y remoto depende de los siguientes factores:
- Si los beans están fuerte o débilmente relacionados entre sí.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- Tipo de cliente: si los beans son accedidos por aplicaciones clientes, debería permitir acceso
remoto (ya que general mente están fuera del servidor que corre a los beans). Si los beans
son accedidos por componentes web u otros Enterprise beans, el tipo de acceso depende de
cómo se desee distribuir los componentes.
- Distribución de los componentes: depende de la escala del sistema (uno o muchos
computadores diferentes al de computador donde el Enterprise vean fue desplegado). En un
escenario distribuido debería ser remoto.
- Rendimiento: siempre se debe buscar el mejor rendimiento de la aplicación. Hay que
considerar retardo por red en sistemas distribuidos
Puede ser declarado el acceso como local con la anotación @Local y después puede ser accedida
por otros beans en el mismo contenedor EJB. Mientras que para declarar un acceso remoto
usaremos la anotación @Remote y después puede ser accedida por las aplicaciones fuera del
contenedor de EJBs. No necesita declarar excepciones remotas de RMI, porque puede ser generada
desde una clase de bean por el contenedor.
Si todos los métodos de la clase del bean van a estar disponibles para los clientes, cuando un bean
invoca un método en la interfaz de negocio, la interacción actúa como un sustituto, no con la clase
del vean.
El sustituto, entonces, encamina la invocación y responde a través del contenedor y este inyecta
servicios del middleware basados en metadatos del bean. Esos metadatos vienen especificados
como anotaciones o en el descriptor de despliegue XML.
En resumen, las características básicas de un bean de sesión serían las siguientes:
 Un ciclo de vida corto porque si el servidor falla la sesión se pierde.
 No manejan persistencia.
 No es compartido entre clientes
 Pueden actualizar y crear entidades, estas últimas son persistentes.
 Un cliente (WEB como JSP o servlet y un cliente aplicación standalone) interactúa con un
session bean a través de la invocación de sus métodos (esta invocación se llama sesión)
 Un componente session bean es un POJO anotado.

 Un session bean está compuesto por una o más interfaces y una clase de implementación.
 Un cliente puede acceder a un session bean solamente a través de métodos definidos en la
interfaz del bean.
 La interfaz de define la vista al cliente de un bean.
 Un Session Bean puede ser invocado a través de RMI a través de una interfaz:
o Remota
o Local

Todas estas características podemos verlas resumidas en la siguiente ilustración:

En un nivel de descripción más profundo, podríamos decir que los EJBs de Sesión representan
procesos de negocio, es decir, funcionalidades de la aplicación que implementan un interfaz de

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
negocio (bussines interface). A través de ella, gestionan la interacción con los clientes y encapsulan
el flujo y manipulación de la información en el servidor.

Patrones, Java y EJB


Para ello los EJBs emplean un determinado patrón de diseño. Recordemos en qué consistían
sucintamente los patrones de diseño. Como analistas y programadores vamos desarrollando a diario
nuestras habilidades para resolver problemas usuales que se presentan en el desarrollo del
software. Por cada problema que se nos presenta pensamos distintas formas de resolverlo,
incluyendo soluciones exitosas que ya hemos usado anteriormente en problemas similares. Es así
que a mayor experiencia que tengamos, nuestro abanico de posibilidades para resolver un problema
crece, pero al final siempre habrá una sola solución que mejor se adapte a nuestra aplicación. Si
documentamos esta solución, podemos reutilizarla y compartir esa información que hemos
aprendido para resolver de la mejor manera un problema específico. Es aquí donde surgen los
patrones de diseño que son una abstracción de una solución en un nivel alto. Como ya se vio en
otras partes del curso hay patrones que abarcan las distintas etapas del desarrollo; desde el análisis
hasta el diseño y desde la arquitectura hasta la implementación. Muchos diseñadores y arquitectos
de software han definido el término de patrón de diseño de varias formas que corresponden al
ámbito a la cual se aplican los patrones. Luego, se dividió los patrones en diferentes categorías de
acuerdo a su uso. Los diseñadores de software extendieron la idea de patrones de diseño al proceso
de desarrollo de software. Debido a las características que proporcionaron los lenguajes orientados a
objetos (como herencia, abstracción y encapsulamiento) les permitieron relacionar entidades de los
lenguajes de programación a entidades del mundo real fácilmente, los diseñadores empezaron a
aplicar esas características para crear soluciones comunes y reutilizables para problemas frecuentes
que exhibían patrones similares. En un primer momento se recopilaron y documentaron 23 patrones
de diseño aplicados usualmente por expertos diseñadores de software orientado a objetos. Como
hemos dicho en otras ocasiones, los patrones del diseño tratan los problemas que se repiten y que
se presentan en situaciones particulares, con el fin de proponer soluciones a ellas. Por lo tanto, son
soluciones exitosas a problemas comunes. Existen muchas formas de implementarlos.
En atención a sus propósitos, los patrones de diseño pueden dividirse en 3 grandes categorías
Creacionales: Patrones creacionales tratan con las formas de crear instancias de objetos. El
objetivo de estos patrones es de abstraer el proceso de instanciación y ocultar los detalles de cómo
los objetos son creados o inicializados.
Estructurales: Los patrones estructurales describen como las clases y objetos pueden ser
combinados para formar grandes estructuras y proporcionar nuevas funcionalidades. Estos objetos
adicionados pueden ser incluso objetos simples u objetos compuestos.
Comportamiento: Los patrones de comportamiento nos ayudan a definir la comunicación e
iteración entre los objetos de un sistema. El propósito de este patrón es reducir el acoplamiento
entre los objetos.
Con la aparición del J2EE, todo un nuevo catálogo de patrones de diseño apareció. Desde que J2EE
es una arquitectura por si misma que involucra otras arquitecturas, incluyendo servlets, JavaServer
Pages, Enterprise JavaBeans, y más, merece su propio conjunto de patrones específicos para
diferentes aplicaciones empresariales.
Suelen recomendarse cinco capas en la arquitectura J2EE:
- Cliente
- Presentación
- Negocios
- Integración
- Recurso
Pues bien, los EJB harían uso de del patrón de diseño denominado Session Façade o beans de
fachada, el cual nos permitirá mantener la arquitectura y tener un mejor flujo de información y
orden entre las distintas capas.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
El uso de un bean de sesión como una
fachada (facade) para encapsular la
complejidad de las interacciones entre
Session Façade/ Session Entity Façade/ los objetos de negocio y participantes
Distributed Façade: en un flujo de trabajo. El Session
Façade maneja los objetos de negocio y
proporciona un servicio de acceso
uniforme a los clientes.

El beans de fachada tiene como cometido principal controlar las diferentes llamadas a
procedimientos que se producen en la capa de negocio, esto nos permitirá un mejor flujo de
información y ejecución de procedimientos.
Imaginemos un sistema de ventas que está diseñado más o menos de la siguiente manera,
tendremos mas de un JSP que realizaran las llamadas y peticiones a varios Servlets los que a su vez
llamaran a más de un beans de encargado de generar consultas, ingresos, etc. y a su vez estos
realizaran consultas a los distintos EJB ya sean de compra, ventas o de personas.
Gráficamente este modelado quedaría así:

En la imagen anterior identificamos a un cliente, varios archivos JSP y varios servlets que se
comunican con la capa de negocio, produciendo muchas llamadas entre las diferentes capas. Esto
situación contribuye a ralentizar el sistema o a generar mucho mas desorden, lo que conlleva a un
nivel de complejidad mayor en el desarrollo, porque complica la búsqueda y modificación del código,
localización de errores, etc.
El objetivo será, por tanto, pasar a este otro planteamiento:

Un solo beans encargado de la comunicación entre la capa web y negocio. Para ello crearemos un
beans que genere las respuestas a las solicitudes de cada servlet, y es aquí donde entra en juego el
beans de fachada, que nos permitirá disponer en una sola llamada todas las peticiones, y poder

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
representar a todos los demás beans necesarios. Además mediante HTML Dinámico, generamos
HTML que siempre cambiará en función de la llamada recibida y así poder tener una sola página JSP
en vez de varias.
En definitiva, este patrón denominado façade, literalmente, sirve a los clientes como una "fachada"
de los servicios proporcionados por otros componentes disponibles en el servidor.
En dicho contexto, los bean de sesión ofrecen operaciones síncronas (petición-respuesta) y procesos
de negocio ejecutados en respuesta a la solicitud del cliente. En ese momento, el contenedor de
EJBs crea e inicializa sus instancias, inyectándoles las referencias necesarias y las asigna a los
clientes a medida que estos los van requiriendo. Esta última operación es el pool de EJBs.
En un instante de tiempo dado, sólo un cliente tiene acceso a los métodos de la instancia del EJB,
por lo que hay un control de la concurrencia de llamadas. Y, además, también el contenedor de EJBs
garantiza que cada método del bean se ejecute dentro de una transacción atómica.

Tipos de bean de sesión


Existen dos tipos de beans de sesión: con estado y sin él.
Session Beans Stateful: conserva el estado a lo largo de toda una sesión. Los beans de sesión con
estado suponen un proceso de cliente que involucra y permite múltiples invocaciones o llamadas. En
este caso, los bean mantienen el estado a través de dichas múltiples invocaciones y dicho estado
dependiente del cliente es llamado conversational state. Aquí, el estado no es persistente porque se
pierde cuando un cliente libera el bean y, además, cada instancia corresponde a una entidad
distinta, por lo que no pueden compartir datos entre sí. No obstante, en este tipo de bean sus
variables almacenan datos de la interacción con el cliente. Este estado se va modificando en función
del uso que hace el cliente de los métodos del bean, no existiendo ningún almacén externo donde
guardar el estado del bean. Se deben usar beans de sesión con estado si se cumple alguna de las
siguientes directrices:
• El estado del bean representa la interacción entre el bean y el cliente.
• El bean necesita guardar información del cliente durante la interacción.
• El bean funciona como una vista simplificada del cliente para el resto de componentes de la
aplicación.
Como ejemplos prácticos podemos nombrar, un carrito de la compra donde el cliente almacena sus
artículos o un bean que reserva vuelo y alquila un coche en la web de una agencia de viajes.
Session Beans Stateless: no conserva el estado de ninguno de sus atributos de la invocación de
un método a otro. Los beans de sesión sin estado suponen que un proceso cliente implica una
operación simple. Los beans no se modifican con las llamadas de los clientes. Los métodos de que se
componen estos beans tienen como función coger y poner datos a disposición de los clientes. Esto
permitiría al contenedor de EJB´s crear una especie de almacén de EJB´s pudiendo asignar
cualquiera de ellos a cualquier cliente. Cuando un cliente solicita una instancia del bean, el
contenedor cogerá una cualquiera del almacén y se lo asigna al cliente. En este caso no se
almacenan los datos específicos de cliente entre invocaciones al bean. Pero resulta posible usar los
datos pasados como parámetros u obtenidos de la base de datos a todas las entidades existentes en
ese momento porque comparten la misma instancia. Los Session Beans Stateless son los únicos que
pueden exponerse como web services. El uso de este tipo de beans suele ligarse a tareas que no
están asignadas a un cliente en concreto, o como puente entre el cliente y el bean a modo de
interfaz o incluso como puente con un bean de entidad. Tenemos como ejemplos concretos: un bean
que recoge la cotización de un valor concreto en bolsa, o uno que compruebe la disponibilidad de
una habitación en una reserva hotelera.
En una aplicación enterprise típica, dividida en cuatro grandes capas o layers (presentación, lógica
de negocio (business logic), persistencia y base de datos (DBMS o EIS Tier)), los Session Beans
viven en la lógica de negocio o business tier.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Un nivel de detalle más descriptivo del empleo de EJB’s de sesión en una arquitectura típica de Java
lo tenemos en la siguiente imagen:

¿Cuándo usar stateless, statefull o singleton?


Se recomienda el uso de statefull cuando se cumpla una de las siguientes situaciones:
- El estado del bean representa la interacción entre el bean y un cliente específico.
- El bean necesita mantener información acerca del cliente a lo largo de varias invocaciones de
métodos.
- El bean es mediador entre el cliente y los otros componentes de la aplicación, presentando
una vista simplificada para el cliente.
- Tras bambalinas, el bean maneja el control de flujo de muchos otros enterprise beans.

Para incrementar el rendimiento, se podrían utilizar stateless session bean en alguna de las
siguientes situaciones:
- El estado del bean no tiene datos para un cliente en específico.
- En un único método de invocación, el bean realiza una tarea genérica para todos los clientes.
Por ejemplo, se podría utilizar un stateless session bean para mandar un email que confirme
una compra online.
- El bean implementa un servicio web.

Los singleton session bean son apropiados en las siguientes circunstancias:


- El estado necesita ser compartido a través de la aplicación.
- Un único enterprise bean necesita ser accedido por múltiples hebras concurrentemente.

Finalmente, otras características compartidas o no por los beans con y sin estado las vemos
indicadas en el siguiente cuadro. Si bien su correspondiente explicación será expuesta en las
próximas unidades.
Características Sin estado (stateless) Con estado (statefull)
Estado conversacional No Sí
Gestión de problemas Improbable Posible
Eventos de ciclo de vida PostConstruct PostCosntruct,
PreDestroy PreDestroy, Prepassive,
PostActive
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Temporizador Sí No
SessionSynchronization No Sí
para Transacciones
Servicios Web Sí No
PersistenceContext No Sí
Extendida

Invocación remota de un bean de sesión


El cliente remoto puede ejecutarse en un ordenador diferente y en una maquina virtual de Java
(JVM) diferente al Enterprise Javabean al que accede.
Dicho cliente remoto, a su vez, puede ser un componente web, una aplicación cliente u otro
enterprise bean. En todo caso, para el cliente remoto la ubicación del enterprise bean es
transparente, porque la interfaz remota define el ciclo de vida de los métodos que son especificados
en el enterprise bean.

Si queremos implementar un session bean con interfaz remota deberemos:


- En primer lugar, definir la interfaz anotada con @Remote.

- En segundo lugar, definir la clase que implementa la interfaz correspondiente

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Invocación local de un bean de sesión
Un cliente local puede invocar un session bean a través de una interfaz local. En este caso el cliente
reside en la misma instancia del bean de sesión.

El cliente local debe correr en la misma JVM que los enterprise bean que accede. Dicho cliente local
puede ser un componente web u otro enterprise bean.
Conviene subrayar que la interfaz local define el ciclo de vida de los métodos del vean y dicha
interfaz por defecto es local

A la hora de implementar un session bean con interfaz local deberemos:


En primer lugar, definir la interfaz anotada con @Local

En segundo lugar, definir la clase que implementa la interfaz correspondiente al bean.

Ver Video: Subasta de Aplicaciones , en la Unidad 2,


en el Módulo 6, en la plataforma elearning

Actividades

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 3. Implementación de los Beans de
Sesión de EJB 3.0
Objetivo
Conocer la programación de Enterprise JavaBeans en sus diferentes tipos de sesión.

Sesión con estado o stateful Session Bean


Almacena datos en variables de instancia, y esos datos van a tener un significado concreto durante
toda la conversación mantenida entre el cliente y el bean.
En un bean de sesión con estado, las variables de instancia del bean almacenan datos específicos
obtenidos durante la conexión con el cliente. Cada bean de sesión con estado, por tanto, almacena
el estado conversacional de un cliente que interactúa con el bean. Este estado conversacional se
modifica conforme el cliente va realizando llamadas a los métodos de negocio del bean. El estado se
mantiene durante la sesión del cliente con el bean. La instancia es reservada para el cliente y cada
una almacena la información del cliente. Todos estos datos hay que almacenarlos en unas variables,
que son las que conforman el estado del bean.
Ahora bien, dicho estado conversacional no se guarda o persiste cuando el cliente termina la sesión.

La interacción del cliente con el bean se divide en un conjunto de pasos. En cada paso se añade
nueva información al estado del bean. Cada paso de interacción suele denominarse con nombres
como setNombre o setDireccion, siendo nombre y direccion dos variables de instancia del bean.
Algunos ejemplos de beans de sesión con estado podrían ser:
 Un ejemplo típico es un carrito de la compra, en donde el cliente va guardando uno a uno los
ítems que va comprando.

 Un enterprise bean que reserva un vuelo y alquila un coche en un sitio Web de una agencia
de viajes.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
El estado del bean persiste mientras que existe el bean. A diferencia de los beans de entidad, no
existe ningún recurso exterior al contenedor EJB en el que se almacene este estado.
Debido a que el bean guarda el estado conversacional con un cliente determinado, no le es posible al
contenedor crear un almacén de beans y compartirlos entre muchos clientes. Por ello, el manejo de
beans de sesión con estado es más pesado que el de beans de sesión sin estado.
En general, se debería usar un bean de sesión con estado si se cumplen las siguientes
circunstancias:
 El estado del bean representa la interacción entre el bean y un cliente específico.
 El bean necesita mantener información del cliente a lo largo de un conjunto de invocaciones
de métodos.
 El bean hace de intermediario entre el cliente y otros componentes de la aplicación,
presentando una vista simplificada al cliente.
La sesión finaliza si el cliente remueve el bean o finaliza su sesión.

La Clase Bean
Una stateful session bean se define mediante la anotación @Stateful
Cada stateful session bean necesita implementar la interfaz serializable, para que de esta manera el
contenedor pueda serializar las instancias del bean y almacenarlas para preservar el estado cuando
las instancias no son usadas.
Ejemplo:
@Stateful
public class BeanComercial implements Comercial, Serializable {
public String simbolo = "";
public int cantidad = 0;

public void Comprar (String simbolo, int cantidad){


System.out.println("Comprando "+cantidad+ " de "+ simbolo);
}

public void Vender (String simbolo, int cantidad);{


System.out.println("Vendiendo "+cantidad+ " de "+ simbolo);
}

public String obtenerSimbolo(){ return simbolo; }


public int obtenerCantidad(){ return cantidad; }
...}
Por su parte el cliente Session Bean habría un uso del bean del siguiente modo:
Comercial tr = null;
if (tr == null) {
try {
InitialContext ctx = new InitialContext();
tr = (Comercial) ctx.lookup( Comercial.class.obtenerNombre());
} catch (Exception e) {
e.printStackTrace ();
}
}
La principal característica es que un Stateful Session Bean estará siempre firmemente vinculado a
la ejecución del cliente. Es decir, este tipo de beans tiene atributos que pueden ser accedidos,
modificados, etc en las distintas llamadas al bean.
@Stateful
public class CestaBean implements CestaRemote {

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
protected Vector<Producto> cesta= new Vector<Producto>();
public void insertarProducto(Producto producto) throws CestaException {
if (producto== null)
throw new CestaException("Cesta ist null");
producto setUnidadesPedidas(best.getUnidades());
cesta.add(producto);
}

public Vector<Producto> getProductos() {


return cesta;
}
}
Al igual que en Stateless las interfaces pueden ser locales o remotas y son definidas a través de las
anotaciones @Local y @Remote respectivamente.
Por ejemplo:
@local
Public interface CartServiceLocal{
Public void addproduct(Product product);
Public void remoteProduct(Product product);
Public collection getProduct();
}
Veamos una definición completa un session bean con estado:

A continuación remarcamos los aspectos característicos de esta configuración EJB:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ciclo de vida del bean con estado
El ciclo de vida responde a una serie de fases sucesivas. A su vez, Durante ese período de vida el
bean soporta callback o retrollamadas de los siguientes eventos de ciclo de vida: construcción,
destrucción, activación y pasivación.
- Creación del bean de sesión: Se produce cuando un cliente busca obtener una referencia a un
vean. El contenedor decide instanciar el vean, por lo que se llama a Class.newInstance().
Entonces el contenedor inyecta cualquier dependencia de contexto requerida. A su vez, el
contenedor llama a métodos de retrollamada opcionales etiquetados con @PostConstruct
- Uso de un bean de sesión: El contenedor puede llamar a métodos de negocio en nombre del
cliente. Conviene recordar que el cliente llama a un representante, mientras que el
contenedor llama a la instancia del bean. Hay dos estados asociados a este momento del
ciclo de vida: Activación y “pasivación”.
o “pasivación”, surge después de llamar a cualquier método opcional @PrePassivate o
bien cuando se alcanza un límite en el número de beans instanciados.
o Activación, después de llamar a cualquier método opcional @PostActivate o bien cuando
un cliente invoca un método de negocio
- Destrucción del bean de sesión: Se produce cuando un cliente llama a un método anotado
con @remove o cuando vence el temporizador. El contenedor decide eliminar el bean,
entonces llama a todos los métodos de retrollamada etiquetados con @PreDestroy. Hay que
señalar también no se llama cuando se cae el servidor es necesario que la aplicación guarde
proactivamente sus datos. En ese punto, la instancia del bean quedará lista para la
recolección de basura.
EJB 3.0 define varias anotaciones que permite describir cada método cuando ocurre uno de los
eventos ya mencionados: PostContruct, PreDestroy, PrePassivate, ProActive, Init.
 @PrePassivate: El contenedor podría cambiar el estado de la sesión a pasivo y almacenar su
estado a un caché. Se llama a este método antes de que ocurra este suceso.
 @PostActivate: se utiliza para restaurar el estado de un Session Bean en estado pasivo. El
método asociado a esta anotación es llamado cuando la sesión esté nuevamente activada.
 @Init: designa métodos de inicialización para un Session Bean.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Los bean sin estado o Stateless Session Bean
Se trata de un bean que por lo general contará con una seria de métodos que realizaran un trabajo
determinado e independiente y que el resultado de las operaciones realizadas dentro de cada uno de
los métodos no dependerá de ningún estado relativo a la conversación que mantiene el cliente con el
bean. Todo Bean sin estado debe tener una interfaz. Si el desarrollador no la crea el contenedor se
encargara de crearla.
Los beans de sesión sin estado no se modifican con las llamadas de los clientes. Los métodos que
ponen a disposición de las aplicaciones clientes son llamadas que reciben datos y devuelven
resultados, pero que no modifican internamente el estado del bean. Esta propiedad permite que el
contenedor EJB pueda crear una reserva (pool) de instancias, todas ellas del mismo bean de sesión
sin estado y asignar cualquier instancia a cualquier cliente. Incluso un único bean puede estar
asignado a múltiples clientes, ya que la asignación sólo dura el tiempo de invocación del método
solicitado por el cliente.
Una de las ventajas del uso de beans de sesión, frente al uso de clases Java u objetos RMI es que
no es necesario escribir los métodos de los beans de sesión de una forma segura para threads
(thread-safe), ya que el contenedor EJB se va a encargar de que nunca haya más de un thread
accediendo al objeto. Para ello usa múltiples instancias del bean para responder a peticiones de los
clientes.
Cuando un cliente invoca un método de un bean de sesión sin estado, el contenedor EJB obtiene una
instancia de la reserva. Cualquier instancia servirá, ya que el bean no puede guardar ninguna
información referida al cliente. Tan pronto como el método termina su ejecución, la instancia del
bean está disponible para otros clientes. Esta propiedad hace que los beans de sesión sin estado
sean muy escalables para un gran número de clientes. El contenedor EJB no tiene que mover
sesiones de la memoria a un almacenamiento secundario para liberar recursos, simplemente puede
obtener recursos y memoria destruyendo las instancias.
Los beans de sesión sin estado se usan en general para encapsular procesos de negocio, más que
datos de negocio (tarea de los entity beans). Estos beans suelen recibir nombres como
ServicioBroker o GestorContratos para dejar claro que proporcionan un conjunto de procesos
relacionados con un dominio específico del negocio.
Es apropiado usar beans de sesión sin estado cuando una tarea no está ligada a un cliente
específico. Por ejemplo, se podría usar un bean sin estado para enviar un e-mail que confirme un
pedido on-line o calcular unas cuotas de un préstamo.
También puede usarse un bean de sesión sin estado como un puente de acceso a una base de datos
o a un bean de entidad. En una arquitectura cliente-servidor, el bean de sesión podría proporcionar
al interfaz de usuario del cliente los datos necesarios, así como modificar objetos de negocio (base
de datos o bean de entidad) a petición de la interfaz. Este uso de los beans de sesión sin estado es
muy frecuente y constituye el denominado patrón de diseño session facade que ya vimos
anteriormente.
Algunos ejemplos de bean de sesión sin estado podrían ser:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
 Un componente que comprueba si un símbolo de compañía está disponible en el mercado de
valores y devuelve la última cotización registrada.
 Un componente que calcula la cuota del seguro de un cliente, basándose en los datos que se
le pasa del cliente.
Dado que no mantiene un estado conversacional con el cliente, cuando un cliente invoca los
métodos de un stateless bean, las variables de instancia del bean pueden contener un estado
específico del cliente, pero sólo por la duración de la invocación. Cuando el método finaliza, el
estado del cliente específico no debería mantenerse.
Ahora bien, las instancias pueden estar compartidas por los clientes. El contenedor tiene un pool de
instancias, cuando el cliente invoca un método se asigna una instancia, cuando la libere es
retornada al pool.

Ofrecen mejor escalabilidad para aplicaciones con gran cantidad de clientes e, incluso puede
implementar un web service, pero no otros tipos de Enterprise beans.
Un stateless session bean se define solo añadiendo la anotación @Stateless.

Veamos un ejemplo completo:


@Stateless
public class TraderBean implements Trader{

public void buy (String symbol, int quantity){


System.out.println("Buying "+quantity+ " of "+ symbol);
}

public void sell (String symbol, int quantity);{


System.out.println("Selling "+quantity+ " of "+ symbol);
}
}
En cuanto al cliente de este tipo de Session Bean:
private Trader tr = null;
public void initialize () {
try {
InitialContext ctx = new InitialContext();
tr = (Trader) ctx.lookup(Trader.class.getName());
}catch (Exception e) {

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
e.printStackTrace ();
}}// ... ...
public void service (Request req, Response rep) {
// ... ... double res = tr.buy("SNPS",1000);
}
Dentro de este tipo de beans y a partir de la versión EJB 3.1 está el singleton session bean, una
variante de un stateless session bean. Su nombre proviene del hecho de que es instanciado una vez
por aplicación y existe durante todo el ciclo de vida de la aplicación. Como característica principal
destaca que un vean de este tipo está diseñado para circunstancias en las cuales una sola instancia
de enterprise bean necesita ser compartida y es concurrentemente accedida por los clientes. Los
beans de sesión singleton mantienen su estado entre las invocaciones de los clientes, pero no es
requerido mantener su estado durante las caídas del servidor.

Ciclo de vida bean sin estado


Dos son los callback de ciclo de vida soportados por este tipo de sesión: PostConstruct y PreDestroy.
 @PostConstruct: ocurre después de cualquier inyección de dependencia por parte del
contenedor y antes de la invocación del primer método de negocio en el bean.
 @PreDestroy: ocurre al momento en que la instancia de bean es destruido.
El cliente inicia el ciclo de vida obteniendo una referencia al bean de sesión –stateful.

Acceso Local y remoto de un bean de sesión sin estado


Las anotaciones que describen los dos tipos de interfaz son: @Local y @Remote. La primera para
una invocación local, la segunda para una invocación de acceso remoto.
Ejemplo:
@Stateless
@Local ({Trader.class})
@Remote ({RemoteTrader.class})
public class TraderBean implements Trader, RemoteTrader
{
public void buy (String symbol, int quantity){
System.out.println("Buying "+quantity+ " of "+ symbol); }
public void sell (String symbol, int quantity);{
System.out.println("Selling "+quantity+ " of "+ symbol); }
}

Ver Video: Implementando EJB 3.0, en la Unidad 3,


en el Módulo 6, en la plataforma elearning

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 4. Implementación de Clases de
Entidad. Conceptos Básicos
Objetivo
Conocer el papel desempeñado por las clases de entidad en la tecnología EJB.

Introducción a los beans de entidad


Los beans de entidad representan un objeto concreto que tiene existencia en alguna base de datos
de la empresa. Así, una instancia de un bean de entidad suele corresponder a una fila en una tabla
de la base de datos. Por ejemplo, podríamos considerar el bean Cliente, con una instancia del bean
siendo Juan García (Cod_Cliente# 005) y otra instancia María Sánchez (Cod_Cliente#875).
Los beans de entidad modelan conceptos o datos de negocio que puede expresarse como nombres.
Esto es una regla sencilla más que un requisito formal, pero ayuda a determinar cuándo un concepto
de negocio puede ser implementado como un bean de entidad.
Los beans de entidad representan “cosas”: objetos del mundo real como hoteles, habitaciones,
expedientes, estudiantes, y demás. Un bean de entidad puede representar incluso cosas abstractas
como una reserva. Los beans de entidad describen tanto el estado como la conducta de objetos del
mundo real y permiten a los desarrolladores encapsular las reglas de datos y de negocio asociadas
con un concepto específico. Por ejemplo un bean de entidad Estudiante encapsula los datos y reglas
de negocio asociadas a un estudiante. Esto hace posible manejar de forma consistente y segura los
datos asociados a un concepto.
Los beans de entidad se corresponden con datos en un almacenamiento persistente (base de datos,
sistema de ficheros, etc.). Las variables de instancia del bean representan los datos en las columnas
de la base de datos. El contenedor debe sincronizar las variables de instancia del bean con la base
de datos. Los beans de entidad se diferencian de los beans de sesión en que las variables de
instancia se almacenan de forma persistente.
Aunque entraremos en detalle más adelante, es interesante adelantar que el uso de los beans de
entidad desde un cliente conlleva los siguientes pasos:
 Primero el cliente debe obtener una referencia a la instancia concreta del bean de entidad
que se está buscando (el estudiante "Francisco López") mediante un método finder. Estos
métodos finder se encuentran definidos en la interfaz home e implementados en la clase
bean. Los métodos finder pueden devolver uno o varios beans de entidad.
 El cliente interactúa con la instancia del bean usando sus métodos get y set. El estado del
bean se carga de la base de datos antes de procesar las llamadas a los métodos. Esto se
encarga de hacerlo el contenedor de forma automática o el propio bean en la función
ejbLoad().
 Por último, cuando el cliente termina la interacción con la instancia del bean sus contenidos
se vuelcan en el almacén persistente. O bien lo hace de forma automática el contenedor o
bien éste llama al método ejbStore().
Si pasamos de un nivel de abstracción a otro más cercano al código podríamos decir que un Entity
Bean es una clase ( POJO ) que representa una tabla de una base de datos, y cada instancia de esta
clase representa un registro de la tabla, es decir, con los entity beans lo que conseguimos es crear
un mapeo entre las propiedades de una clase y los campos de una tabla.
Además de este mapeo también vamos a poder especificar las relaciones que tienen las clases entre
sí (uno a uno, uno a muchos, muchos a uno y muchos a muchos).
Todo Entity Bean debe de tener una clave primaria que identifica a ese registro de forma única
dentro de la tabla.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Todas estas configuraciones las vamos a realizar a través de anotaciones, y el API que se encarga
de gestionar todos los aspectos relativos a la persistencia es JPA ( Java Persistent API ). El siguiente
dibujo ilustra el lugar de las entidades y JPA dentro de EJB 3 frente a los otros tipos de beans
existentes en la especificación.

Vamos a ver un ejemplo genérico antes de entrar en más detalles. Crearemos una entidad llamada
Team, para lo cual veremos que lo único que vamos a tener en cuenta es establecer una anotación
@Entity al principio de la clase, una anotación @Id para indicar cuál es la propiedad que representa
la clave primaria, y por último una anotación @OneToMany para indicar que un equipo puede estar
compuesto por muchos jugadores y que éstos sólo pueden pertenecer a un equipo:
@Entity
public class Team {

private int id;


private String name;
private Date foundationDate;
private Collection players;

@Id
public int getId() {
return id;
}

public void setId( int value ) {


id = value;
}

public String getName() {


return name;
}

public void setName( String value ) {


name = value;
}

public Date getFoundationDate() {


return foundationDate;
}

public void setFoundationDate( Date value ) {


foundationDate = value;
}

@OneToMany
public Collection getPlayers() {
return players;
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
public void setPlayers( Collection value ) {
players = value;
}

A continuación vamos a crear la Entidad Player, que al igual que la entidad anterior va a tener una
anotación @Entity, otra anotación @Id, y por último una anotación @ManyToOne para establecer
una relación bidireccional entre las dos entidades:
public class Player {

private int id;


private String name;
private Team team;

@Id
public int getId() {
return id;
}

public void setId( int value ) {


id = value;
}

public String getName() {


return name;
}

public void setName( String value ) {


name = value;
}

@ManyToOne
public Team getTeam() {
return team;
}

public void setTeam( Team value ) {


team = value;
}

Características generales de la API de Persistencia en


Java
Las características generales de la API podemos verlas sintéticamente expresadas en la siguiente
imagen:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Los componentes del Java Persistence API se encuentran en el paquete de javax.persistence
JPA Está basado en anotaciones los cuales cuentan con la siguiente estructura:

@NombreAnotacion (parametro=”valor”, parametro2=Tipo.CONSTANTE)


@Entity
@Table (“venta_mayoreo”)
El acceso a bases de datos con el Java Persistence API, utiliza fuertemente los siguientes elementos:
persistence.xml: Contiene la configuración de la capa de Persistencia, la cual incluye:
 La Unidad de persistencia: Indica el nombre de la unidad de persistencia, la cual nos permite
acceder a todos los recursos asignados a la conexión, tablas y entidades de la base de datos.
 La conexión a la base de datos: Indica el URL de acceso a datos, el Driver específico de la
base de datos.
 Transacciones: Indica el tipo de transacciones para la base de datos RESOURCE_LOCAL para
Swing y JTA para aplicaciones Web y Empresariales.
Entidades o Entities: Las entidades que están mapeadas entre Java y la base de datos.
 EntityManagerFactory (EMF): Es el responsable de obtener la unidad de persistencia, la cual
permitirá ligar Java con el acceso a datos. La unidad de persistencia se puede obtener de la
siguiente manera:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(NombreUnidadPU");
EntityManager (EM): Es el responsable de actualizar y leer la base de datos utilizando las entidades
descritas en Java. Un EntityManager se obtiene del EMF de la siguiente manera:
EntityManager em = emf.createEntityManager();
Las entidades se declaran utilizando annotations a través de los Plain Old Java Objects (POJO), los
cuales no son más que clases sencillas de Java, con propiedades y métodos set y get. Es muy
importante señalar que al utilizar anotaciones en Java, no se termina la instrucción con punto y
coma.
Se toman en cuenta algunas de las siguientes reglas:
 Cada clase que se desea utilizar en la capa de persistencia, debe tener la anotación de
@Entity
 En caso de que el nombre de la tabla, no coincida con el nombre de la clase se utiliza la
anotación @Table("nombreTabla")
 Cada una de las propiedades de la clase está mapeada a un campo de una tabla en la base
de datos (a menos de que sea transitiva, @Transient).

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
 Si no se describe la información de la columna utilizando la anotación @Column se mapeará
utilizando el tipo equivalente en la base de datos y buscará un campo con el mismo nombre
en la base de datos. Por ejemplo como ocurre en la siguiente ilustración:

 Si el campo de la clave primaria es un campo generado es necesario utilizar la anotación de


@GeneratedValue() acompañado de una estrategia.
 Las relaciones de uno a muchos, muchos a uno, muchos a muchos, se implementan
utilizando Collections.
Base de Datos Java
integer int o Integer
numeric float o double
date java.util.Date, java.sql.Date,
time java.util.Date, java.sql.Date, java.sql.Timestamp
varchar, String
varchar2, char
currency BigDecimal

La diferencia entre usar int e Integer en una propiedad de una clase radica en que los int no
soportan nulos, mientras que los objetos Integer, si.
Veamos un ejemplo sencillo donde se aplican muchas de las características que acaban de
enumerarse:
@Entity
@Table(name = "articulo")
@NamedQueries(
{
@NamedQuery(name = "Articulo.buscarTodos",
query = "SELECT a FROM Articulo a "),
@NamedQuery(name = "Articulo.buscarPorPK",
query = "SELECT a FROM Articulo a " +
"WHERE a.idArticulo = :idArticulo")
})
public class Articulo implements Serializable {
@Id
@Column(name = "id_articulo", nullable = false)
// NO OLVIDAR EL GENERADOR
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer idArticulo;

@Column(name = "clave", nullable = false, unique=true )


private String clave;

@Column(name = "nombre", nullable = false, leght=16)


private String nombre;

@Column(name = "cantidad", nullable = false)


private int cantidad;

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@Column(name = "precio")
private BigDecimal precio;
//Constructores
//Métodos Sets y Gets (Son necesarios)
}

Otro fragmento de código capturado de una aplicación:

Para que un Java Bean pueda ser guardado en una base de datos debe ser anotado como @Entity.
Una entidad debe cumplir una serie de restricciones como, por ejemplo, tener un constructor vacío,
ya sea público o protegido, poseer un campo que sea clave primaria, @Id. Veamos un ejemplo:
@Entity
@Table(name="USUARIOS")
public class Usuario {
@Id
private String nick;
...
public Usuario() { }
// Getters y Setters
}
La mayoría de motores de persistencia para JPA permiten omitir la declaración del constructor vacío.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
La anotación @Table nos permite especificar el nombre de la tabla donde se persistirá la entidad,
permite seguir la especificación de clases en singular y tablas en plural, si no está incluida la entidad
se persistirá en una tabla que coincida con el nombre de la clase. La anotación @Id marca el
identificador de la clase, es decir, su clave primaria.
Además, JPA define que los tipos primitivos, clases "envoltorio" de tipos primitivos,
java.lang.String, byte[], Byte[], char[], Character[], java.math.BigDecimal,
java.math.BigInteger, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Timestamp
son mapeados de forma automática en columnas, es decir, no es necesario marcarlos. Además
todos aquellos objetos que sean de tipo Serializable y estén marcados con la anotación @Basic.
Si lo que queremos es que una variable, de las que son mapeadas de forma automática, no sea
tomada como un campo deberemos usar la anotación @Transient.

JPA incluye formas de mapear cada campo indicando nombres de columna y otros valores.
@Entity
@Table(name="USUARIOS")
public class Usuario {
@Id
private String nick;

@Column(name="PASSWORD", nullable=false)
private String pass;

@Column(name="E-MAIL", nullable=false)
private String mail;

@Lob
@Basic(fetch=FetchType.LAZY)
private byte[] imagen;
...
public Usuario() { }
// Getters y Setters
}
La anotación @Column permite definir varias propiedades. La propiedad name especifica el nombre
de la columna donde va a ser persistido el campo, si esta propiedad no está presente el framework
de persistencia usará el nombre de la variable como nombre de la columna. La propiedad nullable
indica si la columna acepta valores null o no, si no se incluye el valor por defecto es true. Además
esta anotación soporta otras muchas propiedades como pueden ser columnDefinition, length,
precision, scale, insertable, updatable y table.
La anotación @Basic permite, además de lo dicho anteriormente, definir las propiedades optional y
fetch. La propiedad optional funciona igual que la propiedad nullable de la anotación @Column. La
propiedad fetch permite definir cuando se debe cargar el campo en cuestión, el valor
FetchType.Lazy indica que el campo se va a cargar de forma "perezosa". El valor FetchType.EAGER
indica que el valor será cargado cuando se cargue el resto del objeto. El valor por defecto de la
propiedad fetch es FetchType.EAGER.
La anotación @Lob indica que el contenido de un campo básico será guardado como LOB (Large
OBject). Si por ejemplo utilizamos esta anotación para marcar un campo que contenta un String o
caracteres el framework lo mapeará a una columna CLOB (Character Large OBject). Si es de otro
tipo será mapeado a una columna de tipo BLOB (Binary Large OBject).
Son muchas las ventajas de usar beans de entidad en lugar de acceder a la base de datos
directamente. El uso de beans de entidad nos da una perspectiva orientada a objetos de los datos y
proporciona a los programadores un mecanismo más simple para acceder y modificar los datos. Es
mucho más fácil, por ejemplo, cambiar el nombre de un estudiante llamando a student.setName()
que ejecutando un comando SQL contra la base de datos. Además, el uso de objetos favorece la

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
reutilización del software. Una vez que un bean de entidad se ha definido, su definición puede
usarse a lo largo de todo el sistema de forma consistente. Un bean Estudiante proporciona un forma
completa de acceder a la información del estudiante y eso asegura que el acceso a la información es
consistente y simple.
La representación de los datos como beans de entidad puede hacer que el desarrollo sea más
sencillo y menos costoso.

Diferencias con los beans de sesión


Los beans de entidad se diferencian de los beans de sesión, principalmente, en que son persistentes,
permiten el acceso compartido, tienen clave primaria y pueden participar en relaciones con otros
beans de entidad:

Persistencia. Debido a que un bean de entidad se guarda en un mecanismo de almacenamiento se


dice que es persistente. Persistente significa que el estado del bean de entidad existe más tiempo
que la duración de la aplicación o del proceso del servidor J2EE. Un ejemplo de datos persistentes
son los datos que se almacenan en una base de datos.
Los beans de entidad tienen dos tipos de persistencia:
- Persistencia Gestionada por el Bean (BMP, Bean-Managed Persistence) En este primer
caso (BMP) el bean de entidad contiene el código que accede a la base de datos.
- y Persistencia Gestionada por el Contenedor (CMP, Container-Managed Persistence). En
este segundo caso (CMP) la relación entre las columnas de la base de datos y el bean se
describe en el fichero de propiedades del bean, y el contenedor EJB se ocupa de la
implementación.
Acceso compartido. Los clientes pueden compartir beans de entidad, con lo que el contenedor EJB
debe gestionar el acceso concurrente a los mismos y por ello debe usar transacciones. La forma de
hacerlo dependerá de la política que se especifique en los descriptores del bean.
Clave primaria. Cada bean de entidad tiene un identificador único. Un bean de entidad alumno, por
ejemplo, puede identificarse por su número de expediente. Este identificador único, o clave primaria,
permite al cliente localizar a un bean de entidad particular.
Relaciones. De la misma forma que una tabla en una base de datos relacional, un bean de entidad
puede estar relacionado con otros EJB. Por ejemplo, en una aplicación de gestión administrativa de
una universidad, el bean alumnoEjb y el bean actaEjb estarían relacionados porque un alumno
aparece en un acta con una calificación determinada.
Las relaciones se implementan de forma distinta según se esté usando la persistencia manejada por
el bean o por el contenedor. En el primer caso, al igual que la persistencia, el desarrollador debe
programar y gestionar las relaciones. En el segundo caso es el contenedor el que se hace cargo de la
gestión de las relaciones. Por ello, estas últimas se denominan a veces relaciones gestionadas por el
contenedor.
En suma, las entities son los objetos Java que se persisten en la base de datos. Así, mientras que
los Session Beans son los verbos del sistema, las entidades son los sustantivos.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Requisitos para clases de entidad
Una clase de entidad debe seguir los siguientes requisitos:
 La clase debe ser anotada con javax.persistence.Entity.
 La clase debe tener una visibilidad pública o protegida y ningún argumento en su constructor.
 La clase no debe ser declarada como final. Tampoco ninguno de sus métodos o variables
persistentes instancia debe ser declarada como final.
 Si una instancia de la entidad ha de ser pasada por valor como un objeto individual, a través
de la interfaz de negocio de un bean de sesión, entonces la clase debe implementar la
interfaz Serializable.
 Las entidades pueden extender tanto en otras clase de entidad como de no-entidad y a su
vez, las clases que no sean entidad extenderse a clases de entidad.
 La variables de instancia persistente admiten ser declaradas como privadas, protegidas o
privadas dentro del paquete, y sólo se puede acceder a ellas directamente mediante los
métodos de la clase de entidad. Los clientes deben acceder al estado de la entidad a través
de métodos de acceso o de negocios.
Anotaciones:
@NotNull: Campo no puede ser nulo. En caso de serlo, se lanzará un error de validación.
@Pattern: Si es que el valor no cumple con la expresión regular, se lanzará un error de validación.
@Past: Asegura que el valor sea una fecha del pasado. Se lanzará un error de validación en caso
contrario.

Campos y Propiedades persistentes en clases de entidad


Al estado persistente de una entidad se puede acceder a través de variables de instancia de la
entidad o a través de propiedades de estilo del JavaBeans de estilo. En el lenguaje de tipos de Java,
los campos o propiedades disponibles son los siguientes:
 Tipos primitivos de Java

Otros tipos serializables como:


o Wrappers of Java primitive types
o java.math.BigInteger
o java.math.BigDecimal
o java.util.Date
o java.util.Calendar
o java.sql.Date
o java.sql.Time

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
o java.sql.TimeStamp
o Tipos serializables definidos por el usuario
o byte[]
o Byte[]
o char[]
o Character[]
 Tipos enumerados
 Otras entidades y/o colecciones de entidades.
 Clases anidadas.
Las entidades pueden hacer persistentes tanto los campos como las propiedades persistentes. Por
ejemplo, si las anotaciones de mapeo son aplicadas a las variables de instancia de la entidad, la
entidad hace los campos persistentes. Ahora bien, si la asignación de anotaciones se aplica a los
métodos getter de la entidad para las propiedades del Bean, entonces la entidad hace las
propiedades persistentes. No se puede aplicar anotaciones de mapeo a los campos y las propiedades
en una sola entidad.
a) Campos persistentes: Si la clase de entidad utiliza campos persistentes, la ejecución de
dicha persistencia accede directamente a la instancia de la variable perteneciente a una clase
de tipo entidad. Todos aquellos campos no anotados con javax.persistence.Transient o no
marcados como transitorios se considerarán persistentes dentro del almacén de datos. Así
pues, la anotación del mapeo relacional y el objeto deberá aplicarse a las variables de
instancia.
b) Propiedades persistentes: Si la entidad utiliza las propiedades persistentes, entonces
dicha entidad debe seguir las convenciones del método típicas de los componentes de
JavaBeans. Es decir, se utilizarán los habituales métodos getter y setter. Así, para todas las
propiedades persistentes property del tipo Type de la entidad, hay un método getter
getProperty y un método setter setProperty. Si la propiedad es un valor lógico, entonces
puede utilizar isProperty en lugar de getProperty. Por ejemplo, si una entidad cliente utiliza
las propiedades persistentes y tiene una variable de instancia privada llamada Nombre
llamada, la clase define un método getNombre y setNombre para recuperar y asignar el
estado de la variable de instancia Nombre.

La firma del método para un solo valor las propiedades persistentes son los siguientes:
Type getProperty()
void setProperty(Type type)

Colección con valores de campos persistentes y las propiedades deben utilizar la lista de interfaces
reconocidas en Java con independencia de que la entidad utilice campos persistentes o propiedades.
Las interfaces de colección que disponibles para su uso son:
 java.util.Collection
 java.util.Set
 java.util.List
 java.util.Map

Si la clase de entidad utiliza campos persistentes, el tipo en las firmas método anterior debe ser uno
de estos tipos de colección. No obstante, algunas variantes genéricas de estos tipos de colección
también se pueden utilizar. Por ejemplo, si la entidad Cliente tiene una propiedad persistente que
contiene un conjunto de números de teléfono, sería posible definir los siguientes métodos:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Set <PhoneNumber> getPhoneNumbers () {}
void setPhoneNumbers (Set <PhoneNumber>) {}

El objeto o su mapeo relacionar será aplicado a los métodos getter. Ahora bien dichas anotación de
mapeo no se pueden aplicar a los campos o propiedades que a su vez lleven la notación @Transient
o estén marcadas como transient.

Sobre la identidad de los objetos


Cada entidad tiene una identidad. Es una identidad que llamamos semántica (o de negocio), ya que
se refiere a determinar si dos objetos se refieren a la misma entidad de negocio. Esto es distinto a
determinar si dos variables referencian al mismo objeto.
Para ejemplificar esto, creamos una clase prototipo A:
public class A {
int valor;

public A(int valor) {


this.valor = valor;
}
}
Luego, utilizamos esta clase en un programa simple:
A a1 = new A(1);
A a2 = new A(1);
System.out.println(a1 == a2); // Muestra false.
System.out.println(a1.equals(a2)); // ¡Tambien muestra false!
Ambas comparaciones dan como resultado false. ¿Porqué? La comparación que utiliza el operador
== es una comparación referencial; es decir, determina si las variables a1 y a2 hacen referencia al
mismo objeto. Dado que las hemos inicializado creados dos objetos distintos, es correcto que el
resultado de la evaluación sea false. La segunda comparación, en cambio, pretende determinar si los
objetos son equivalentes. Para la clase A, esto debería ser cierto si ambos objetos tienen su atributo
valor con el mismo valor. Esta semántica está establecida en el método equals(Object) definido en la
clase java.lang.Object, y debemos sobrecargarlo para obtener el comportamiento deseado:
public class A {
int valor;

public A(int valor) {


this.valor = valor;
}

public boolean equals(Object obj) {


if (this == obj)
return true; // un objeto es igual a si mismo.
if (obj == null)
return false; // un objeto no es igual a null.
if (getClass() != obj.getClass())
return false; // si son de distinta clase, no pueden ser iguales.
final A other = (A) obj;
if (valor != other.valor)
return false; // si el atributo 'valor' tiene distinto valor, son distintos.
return true; // llegado este punto, nos aseguramos de que los objetos son_
del mismo tipo, y coincide el valor de su atributo 'valor'.
}
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Si volvemos a ejecutar nuestro programa de prueba:
A a1 = new A(1);
A a2 = new A(1);
System.out.println(a1 == a2); // Muestra false.
System.out.println(a1.equals(a2)); // Ahora muestra true.

Dentro de JPA, sin embargo, las comparaciones de identidad no se realizan utilizando el método
equals de cada clase, sino el método equals de la clave primaria. Es decir, cuando JPA debe
determinar si dos objetos representan la misma entidad, no compara los objetos sino sus
identificadores. Sin embargo, siguiendo los conceptos de diseño orientado a objetos, es conveniente
que implementemos el método equals para nuestras entidades.
También es conveniente sobrecargar el método hashCode. El valor devuelto por este método es
utilizado por algunas estructuras (por ejemplo, las colecciones java.util.HashSet y
java.util.HashMap).
Un escenario común en el cual es necesario implementar ambos métodos, es al utilizar una entidad
persistente con las clases de la API de colecciones. Estas clases hacen uso de los métodos equals y
hashCode para organizar los objetos en sus estructuras internas. Si los métodos no están
implementados correctamente, se podría obtener un comportamiento inesperado de estas clases.

Unidades de persistencia
Una unidad de persistencia define el conjunto de entities y su configuración de mapeo que se asocia
a un mismo origen de datos. En cada aplicación puede configurarse más de una unidad de
persistencia.
Las unidades de persistencia se definen en un archivo con cumbre persistence.xml. Se debe definir
al menos una unidad de persistencia. En aplicaciones JEE, se coloca en el directorio META-INF de un
archivo .jar, ejb-jar, .ear o .war; en aplicaciones JSE debe estar disponible en el classpath, dentro
del directorio META-INF. En este xml se declara para, cada unidad de persistencia, su nombre (el
cual utilizaremos dentro de la aplicación), una descripción, el proveedor de persistencia asociado, las
propiedades de configuración del mismo, el tipo de transacción (JTA o Local), y cualquier otra
información requerida por el proveedor de persistencia.
A continuación vemos un ejemplo de este archivo:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns=http://java.sun.com/xml/ns/persistence
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="ar.com.fit.planner">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.username" value="fit-planner" />
<property name="hibernate.connection.password" value="fit-planner" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/fit-
planner" ></property>
<!-- Descomentar la siguiente linea para que Hibernate genere el esquema de base de
datos -->
<!-- <property name="hibernate.hbm2ddl.auto" value="create-drop" /> -->
</properties>
</persistence-unit>
</persistence>

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Contextos de persistencia
Para cada unidad de persistencia, el motor de JPA establece un contexto de persistencia, que define
el contexto en el cual "viven" y se administran las instancias de las clases persistentes definidas en
la unidad de persistencia. La definición en la especificación de JPA dice: “es un conjunto de
instancias de entidades en donde para cada identidad persistente existe una única instancia de
entity asociada”.
Todo el ciclo de vida de los entities se produce dentro de un contexto de persistencia dado.

Ciclo de vida de los Entity Beans


JPA define un conjunto de estados que puede tener un objeto determinado en relación a un contexto
de persistencia en particular. El ciclo de vida de un Entity Bean es la definición de las transiciones de
un Entity Been entre los diferentes estados. A continuación vemos el diagrama de transición de
estados de este ciclo de vida:

 New: el entity existe en memoria pero no tiene asociada una identidad persistente en la BD
o un contexto de persistencia.
 Managed: el entity tiene asociado una identidad y un contexto de persistencia y el
EntityManager mantiene sincronizado su estado al momento de commit de la transacción o
bien al llamar al método flush().
 Detached: el entity no es administrado por el EntityManager, no está asociado a ningún
contexto de persistencia. Una entidad administrada (managed) se desvincula al finalizar la
vida del contexto de persistencia (scope, sesión) o cuando se serializa (por ej. al ser enviado
entre capas)
 Removed: el entity puede estar asociado al contexto de persistencia pero está marcado para
eliminación al momento de finalizar la transacción.
 Persisted: el entity bean existe en la base de datos, pero no ha sido cargado en memoria.

Entity Manager
El Entity Manager es la fachada de servicios de JPA. Cada Entity Manager permite acceder a un
contexto de persistencia, y cada contexto de persistencia se refiere a una unidad de persistencia.
Los servicios del Entity Manager operan sobre entidades. Todo cliente que quiera interactuar con
entidades persistentes debe primero obtener una instancia del Entity Manager. Provee operaciones
de búsqueda, actualización, borrado y persistencia de nuevas entidades.

Se incorpora dentro del ciclo de vida de la entidad tal y como se refleja en la siguiente ilustración:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
New: Aquí el objeto Java no persiste
Managed (persist()): Se asocia con un contexto de persistencia. La clave primaria hace que se
cree una fila en la tabla asociada en la base de datos
Detached: El objeto conserva sus datos pero no se sincroniza más con la base de datos. Un objeto
detached puede volverse a gestionar en el contexto de persistencia con merge()
Removed (remove() or by cascading): El objeto conserva sus datos pero se instruye a la base
datos que borre la fila asociada. Con flush() se fuerza a escribir datos en base de datos.

Veamos algunos fragmento de código de ejemplo para entender cómo se implementan los diferentes
estados desde el Entity Manager:
En este primer fragmento hacemos persistente el objeto:
public Order createNewOrder(Customer customer) {
Order order = new Order(customer);
entityManager.persist(order);
return order;
}
En este segundo fragmento de código realizamos una búsqueda para localizar el objeto y una vez
hallado lo borramos:
public void removeOrder(Long orderId) {
Order order = entityManager.find(Order.class, orderId);
entityManager.remove(order);
}

En el tercer fragmento realizamos una búsqueda mediante una sentencia de SQL a través del Entity
Manager:
public List findWithName(String name) {
return em.createQuery( "SELECT c
FROM Customer c
WHERE c.name LIKE :custName") .setParameter("custName", name)
.setMaxResults(10) .getResultList();
}

Obteniendo un Entity Manager


El Entity Manager es un objeto que implementa la interfaz javax.persistence.EntityManager. Existen
diferentes formas de obtener dicha instancia, dependiendo del tipo de aplicación. En entornos JEE el
Entity Manager es administrado por el contenedor y se obtiene de 2 formas posibles: inyección o
lookup JNDI. En entornos JSE el Entity Manager se obtiene a través de la interfaz
javax.persistence.EntityManagerFactory.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Obteniendo un Entity Manager en aplicaciones JSE.
Intentaremos realizar algunas operaciones con las clases persistentes que hemos definido hasta el
momento. Dado que aún no hemos armado la aplicación JEE completa, haremos una pequeña clase
de prueba, en la que accederemos al Entity Manager utilizando la interfaz
javax.persistence.EntityManagerFactory.
En primer lugar, debemos obtener una instancia de la interfaz EntityManagerFactory, para lo cual se
utiliza la clase bootstrap javax.persistence.Persistence. Esta clase se encarga de examinar el archivo
persistence.xml, y entregar una instancia de EntityManagerFactory asociada a una unidad de
persistencia determinada. Veamos un ejemplo:
EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory("ar.com.fit.p
lanner");
El método javax.persistence.Persistence.createEntityManagerFactory(String) recibe como parámetro
el nombre de una unidad de persistencia definida en el archivo persistence.xml. Una vez que
tenemos la instancia de EntityManagerFactory, podemos pedirle el EntityManager:
EntityManager em = emf.createEntityManager();
Hay dos tipos de Entity Manager:
a) Container-Managed Entity Managers: el ciclo de vida del Entity Manager es manejado por
el contenedor y el contexto es propagado automáticamente a todos los componentes de la
aplicación que usan la instancia en una transacción. Ejemplo:
@PersistentContext
EntityManager em;
b) Application-Managed Entity Managers: el ciclo de vida del Entity Manager es manejado
por la aplicación y el contexto no es propagado a los otros componentes. Ejemplo:
@PersistentUnit
EntityManagerFactory emf;
EntityManager em = emf.createEntityManager();
Ya podemos comenzar a operar con nuestros Entity Beans.

Persistiendo objetos
En este ejemplo vemos cómo crear un objeto utilizando una clase persistente, y cómo persistirlo con
el EntityManager:
em.getTransaction().begin();
Cliente cliente1 = new ClienteUnipersonal("Mario", "López");
em.persist(cliente1);
em.getTransaction().commit();

Transacciones usando JPA en aplicaciones JSE.


Si analizamos el código del ejemplo, vemos que la operación em.persist(fit) está encerrada entre
otras dos: em.getTransaction().begin() y em.getTransaction().commit().
Dado que no estamos en un ambiente JEE, debemos administrar las transacciones manualmente.
Esto implica especificarle al Entity Manager cuándo debe comenzar una transacción, y cuándo
terminarla. El EntityManager realizará ningún cambio en la base de datos hasta que no hayamos
realizado un commit de la transacción. En aplicaciones JEE, por supuesto, las transacciones son
administradas por el contenedor, por lo que esta tarea no es necesaria.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Operaciones básicas
Sobre los objetos resulta posible realizar algunas operaciones básicas. Pasamos a enumerar y
explicar las principales.

Persist
La operación EntityManager.persist(Object) recibe como parámetro un objeto de una clase anotada
con @Entity y lo persiste en la base de datos.
Ejemplo:
Person p = new Person(“Pepe”, “Perez”);
em.persist(p);
O bien:
LineItem li = new LineItem(...);
order.getLineItems().add(li);
em.persist(li);
return li;

Persiste, también, todos los objetos relacionados, cuya relación haya sido anotada con
CascadeType.PERSIST o CascadeType.ALL. Por lo tanto, con una única operación JPA puede persistir
todo un árbol de objetos, según las definiciones de las relaciones. En ese caso, el método persist es
propagado a todas las entidades relacionadas a la llamada de la entidad que tienen el elemento
cascade en ALL o PERSIST en la anotación de la relación:
Order.java
@OneToMany(cascade=ALL, mappedBy=“order")
public Collection<LineItem> getLineItems(){return
lineItems;}
Las operaciones de persistencia se traducen, en algún momento, en sentencias INSERT en la base
de datos. El proveedor de persistencia elige cuándo ejecutar estas sentencias. Hibernate, por
ejemplo, las ejecuta al realizar el commit de la transacción. En una aplicación JSE, esto ocurre
cuando se llama explícitamente al método entityManager.getTransaction().commit().
Después de realizar esta operación sobre un Entity Bean, el objeto queda en estado Managed.

Remove
La operación EntityManager.remove(Object) recibe un objeto de una clase anotada con @Entity, y lo
borra de la base de datos. Después de realizar esta operación, el objeto queda en estado Removed.
Al terminar la transacción, se ejecuta una sentencia DELETE.
Ejemplo:
em.remove(p.getAddress());
o bien combinando una búsqueda con la eliminación posterior del objeto encontrado:
Order order = em.find(...);
em.remove(order);

Refresh
La operación EntityManager.refresh(Object) recibe un objeto de una clase anotada con @Entity y
sincroniza su estado con el de la base de datos. Es decir, actualiza el objeto obteniendo los valores
de sus atributos y relaciones de la base de datos. Se ejecuta una sentencia SELECT. Después de
ejecutar esta operación, el objeto queda en estado Managed.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Merge
La operación EntityManager.merge(Object) sincroniza el estado de un objeto en la base de datos. Al
terminar la transacción, se ejecuta una sentencia UPDATE. El objeto no debe estar en estado
Removed. Después de ejecutar esta operación, el objeto queda en estado Managed.

Búsquedas simples
La forma más sencilla de buscar un Entity Bean es utilizar el método find(Class, Object) de la
interfaz EntityManager. Este método permite buscar un Entity por su clave primaria.

Para buscar una cliente por ejemplo, podríamos usar el siguiente código:
Cliente cliente = entityManager.find(Cliente.class, new Long(1));
El primer parámetro del método find es la clase del Entity que deseamos buscar. El segundo
parámetro, la clave primaria del Entity. La clase que pasemos como parámetro debe ser una
anotada con @Entity; no podemos usar, por ejemplo, una clase anotada con @MappedSuperclass.
En el ejemplo vemos que estamos accediendo a un cliente de manera polifórmica; es decir, no
conocemos a priori si el cliente es corporativo o unipersonal. Dado que la clase Cliente extiende a
Persona, también podríamos haber hecho:
Persona = entityManager.find(Persona.class, new Long(1));
Esta búsqueda debería devolver el mismo Entity, dado que toda la jerarquía de clases que extiende
a Persona comparte la misma clave primaria. Pero dado que estamos haciendo una búsqueda
polimórfica, no podemos saber, a priori, si la consulta devolverá un Cliente o un Empleado.

Ver Video: Implementación de Clases de Entidad y sus


Conceptos Básicos, en la Unidad 4, en el Módulo 6,
en la plataforma elearning

Laboratorio: EJB de estado


Objetivos
 Conocer el de la tecnología EJB.
 Acceso a datos en Beans de estado.

Enunciado
Vamos a realizar una aplicación que buscará un empleado y devolverá sus datos utilizando para la
lógica un Bean de session.
Para ello, utilizaremos la tecnología EJB y un proyecto empresarial.
Lo primero que vamos a realizar será crearnos un nuevo proyecto Enterprise Application.
Debemos hacer que el bean sea remoto debido a que estará ubicado en otro “proyecto”, que es el
proyecto EJB de la aplicación.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Lo llamaremos ProyectoEJBEmpleados

Crearemos el proyecto marcando la opción para generar los proyectos de tipo WAR y EJB y
utilizaremos el servidor GlassFish Server versión 3.

Lo primero que vamos a realizar será traernos las librerías para trabajar con datos. Para ello, sobre
el proyecto EJB, agregaremos la librería de Oracle.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
A continuación, sobre el proyecto EJB, crearemos un nuevo Session Bean.

Lo llamaremos BeanBuscadorEmpleados y lo incluiremos en un paquete cualquiera, por ejemplo


paquetebean.
Marcaremos la opción de tipo Session Stateful e indicaremos que será de tipo remoto y
seleccionaremos el nombre del proyecto EJB.

Una vez creado el Bean, vamos a implementar un método de acción que llamaremos
posteriormente.
Para ello, debemos ir al proyecto EJB, sobre la carpeta Enterprise Bean, seleccionamos la opción Add
 Bussines Method para crearnos un método de negocio que llamaremos posteriormente.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Escribimos el nombre del método, en nuestro caso buscarEmpleado, e indicamos que el tipo que
devolverá es de la clase String.
También le indicaremos que el método recibirá un dato de tipo int al que llamaremos idempleado.

Nos generará un código con el método de negocio buscarEmpleado y lo implementaremos para


buscar un empleado en nuestra tabla EMP:
package paquetebean;
import javax.ejb.Stateless;
import java.sql.*;
@Stateless
public class BeanBuscadorEmpleados implements BeanBuscadorEmpleadosRemote {

@Override
public String buscarEmpleado(int idempleado) {
try
{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection cn = DriverManager.getConnection("jdbc:oracle:_
thin:@localhost:1521:XE", "SYSTEM", "12345");
Statement sentencia = cn.createStatement();
ResultSet rs = sentencia.executeQuery("SELECT ENAME, JOB, SAL FROM EMP");
String dato = "";
if (rs.next())
{
dato = "<table border='1'>";
dato += "<tr>";
dato += "<td>"+rs.getString(1)+"</td>";
dato += "<td>"+rs.getString(2)+"</td>";
dato += "<td>"+rs.getString(3)+"</td>";
dato += "</tr>";
dato += "</table>";
}else
{
dato = "<h1>No existe el empleado buscado</h1>";
}
return dato;
}catch (Exception ex)
{
return ex.toString();
}
}
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ahora vamos a agregar un Servlet que implementará la funcionalidad del componente EJB que nos
hemos creado.

Sobre el proyecto WAR, seleccionaremos la opción New  Servlet.

Lo llamaremos ServletEmpleado y lo incluiremos en un paquete cualquiera, en nuestro ejemplo lo


hemos llamada paqueteservlets.

No incluiremos la información en el archivo descriptor de la aplicación, aunque si lo hiciéramos, la


llamada al EJB seguiría siendo la misma.

Una vez que nos ha creado el servlet, debemos implementar la llamada, para ello utilizaremos el
asistente de código que nos permite insertar código generado dinámicamente.
Sobre el código del servlet, seleccionamos la opción Insert Code

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Nos aparecerán una serie de opciones, nosotros seleccionaremos la opción que llama a un Bean.
Marcaremos la opción Call Enterprise Bean.

Al seleccionar dicha opción, nos muestra una ventana dónde debemos indicar el Bean que vamos a
llamar desde el servlet. Buscamos el bean en el proyecto EJB y pulsamos sobre OK.

Podremos comprobar en el código que nos genera las librerías necesarias para realizar la llamada al
Bean de Session.
Ahora vamos a implementar el servlet para poder escribir el saludo escrito y enviado desde el EJB:
package paqueteservlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import paquetebean.BeanBuscadorEmpleadosRemote;

@WebServlet(name="ServletEmpleado", urlPatterns={"/ServletEmpleado"})
public class ServletEmpleado extends HttpServlet {
@EJB
private BeanBuscadorEmpleadosRemote beanBuscadorEmpleados;

protected void processRequest(HttpServletRequest request, HttpServletResponse response)


throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ServletEmpleado</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Llamada EJB empleados</h1>");
String respuesta;
int idempleado;
String numeroempleado = request.getParameter("txtnumero");
idempleado = Integer.parseInt(numeroempleado);
respuesta = beanBuscadorEmpleados.buscarEmpleado(idempleado);
out.println(respuesta);
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
Solamente nos quedaría realizar la llamada al Servlet. Para ello, sobre el proyecto WAR vamos a
seleccionar la página que trae por defecto index.jsp y la implementaremos para enviar el ID del
empleado y utilizar la tecnología EJB para encontrarlo.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<form name="form1" action="ServletEmpleado">
Escriba el ID del empleado a buscar
<input type="text" name="txtnumero"><br>
<input type="submit" value="Buscar Empleado">
</form>
</body>
</html>
Debemos recordar que las aplicaciones empresariales son un conjunto de elementos y contenedores
de los objetos, por lo que debemos ejecutarla en su conjunto con la tecla F6.
Cuando ejecutemos nuestra aplicación, veremos la página inicial index.jsp con el diseño que
hayamos realizado.

Una vez que pulsemos sobre el botón, comprobaremos que la respuesta desde el EJB llega
correctamente.

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 5. Implementación de Clases de
Entidad: Modelado de Relaciones de
Asociación de Datos

Objetivo
Conocer el papel desempeñado por las relaciones y su modelado dentro las clases de entidad en la
tecnología EJB.

Las claves principales de las entidades


Cada entidad tiene un identificador único de objeto. La entidad de un proveedor, por ejemplo, puede
ser identificada por su código de proveedor o su NIF. El identificador único, o clave principal,
permite a las aplicaciones cliente localizar una determinada instancia de entidad. A su vez, cada
entidad debe tener una clave principal. En este caso, una entidad puede tener una clave principal
simple o una clave principal compuesta. Las claves primarias simples emplean la anotación
javax.persistence.Id para expresar la propiedad o campo que es clave principal. La clase debe
implementar Serializable.

Por su parte, las claves principales compuestas deben corresponderse con una sola propiedad o un
solo campo persistente o un único conjunto de propiedades persistentes o campos. Si la clase es
mapeada a múltiples campos o propiedades, los nombres y tipos de los campos correspondientes a
la clave principal deben coincidir con los de la clase entidad. Además, estas claves compuestas han
de definirse en un clase con clave principal e indicarse mediante la notación
javax.persistence.EmbeddedId y javax.persistence.IdClass.

La clave principal, bien como propiedad o bien como campo de una clave primaria compuesta, debe
ser uno de los siguientes tipos del lenguaje Java:
 tipos primitivos de Java
 java.lang.String
 java.util.Date (el tipo temporal debería ser FECHA)
 java.sql.Date

Los tipos de punto flotante no se deben utilizar en las claves principales.


A la hora de concebir una clase de clave primaria se deben cumplir los siguientes requisitos:
 El modificador de control de acceso de la clase debe ser público.
 Las propiedades de la clase de clave principal deben ser públicas o protegidas
 La clase debe tener un constructor público predeterminado.
 La clase debe implementar los métodos hashCode () y equals (Object).
 La clase debe ser serializable.
 Una clave primaria compuesta debe estar representada y asigna a varios campos o
propiedades de la clase de entidad, o debe estar representada y tener asignada una clase
incrustada.
 Si la clase se asigna a varios campos o propiedades de la clase de entidad, los nombres y
tipos de los campos de clave principal o propiedades de la clase de clave principal deberán
coincidir con los de la clase de entidad.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
La siguiente clase de clave primaria es una clave compuesta, los campos IdOrder y itemId juntos
identifican de forma única a una entidad.
public final class LineItemKey implements Serializable {
public Integer orderId;
public int itemId;
public LineItemKey() {}

public LineItemKey(Integer orderId, int itemId) {


this.orderId = orderId;
this.itemId = itemId;
}

public boolean equals(Object otherOb) {


if (this == otherOb) {
return true;
}
if (!(otherOb instanceof LineItemKey)) {
return false;
}
LineItemKey other = (LineItemKey) otherOb;
return (
(orderId==null?other.orderId==null:orderId.equals
(other.orderId)
) && (itemId == other.itemId)
);
}

public int hashCode() {


return (
(orderId==null?0:orderId.hashCode())
^((int) itemId)
);
}

public String toString() {


return "" + orderId + "-" + itemId;
}

Variedad de relaciones entre entidades


Hay cuatro tipos de relaciones: uno a uno, uno-a-muchos, muchos-a-uno, y muchos-a-muchos.

Por ejemplo, veamos el siguiente diagrama y podremos entender en la práctica los diferentes
algunos de los diferentes tipos de relaciones enumerados.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Uno a uno: Cada instancia de la entidad se relaciona con una sola instancia de otra entidad. Por
ejemplo, para el modelo de un almacén físico en el que cada elemento depositado responde a un
control también único. Uno-a-uno utiliza la anotación javax.persistence.OneToOne anotación en la
propiedad persistente correspondiente o en el campo.
Uno a varios: Una instancia de la entidad puede estar relacionada con varias instancias de las otras
entidades. Un pedido de cliente, por ejemplo, puede estar constituido por varios elementos. Las
relaciones uno a muchos usan la anotación javax.persistence.OneToMany en cada propiedad o
campo correspondiente que se quiera hacer persistente.
Muchos-a-uno: Varias instancias de una entidad pueden estar relacionadas con una única instancia
de la otra entidad. Esta relación es la contraria de una relación uno-a-muchos. En el ejemplo de
código que hemos puesto antes, desde la perspectiva de LineItem la relación con la Order es de
muchos a uno.
Muchos-a-uno utiliza como anotación javax.persistence.ManyToOne en cada propiedad o campo
correspondiente que quiera hacerse persistir.
Muchos-a-muchos: Los casos de cada entidad pueden estar relacionados con varias instancias de
la otra. Por ejemplo, en la universidad cada curso tiene muchos alumnos, y cada estudiante puede
tomar varios cursos. Por lo tanto, en una solicitud de inscripción, los cursos y los estudiantes
tendrían una relación muchos-a-muchos. Para esta circunstancia se emplea la anotación
javax.persistence.ManyToMany sobre la propiedad o el campo correspondiente que queramos hacer
persistente.

Dirección de Relaciones de Entidad


La dirección de una relación puede ser bidireccional o unidireccional. Una relación bidireccional tiene
un lado propio y un lado inverso. En cambio, una relación unidireccional sólo cuenta con un lado. La
parte propia de una relación determina cómo la ejecución de la persistencia hará los cambios a la
relación dentro de la base de datos.
Las relaciones bidireccionales
En una relación bidireccional, cada entidad tiene un campo o propiedad de la relación que apunta o
guarda una referencia hacia la otra entidad. A través del campo de relación o de la propiedad, el
código de una clase de entidad puede acceder a su objeto relacionado. Si una entidad tiene un
campo relacionado, la entidad se dice que "conoce" su objeto así referenciado. Por ejemplo, si un
Pedido sabe cada uno de las instancias de cada Elemento que lo constituyen y si cada uno de esos
Elementos, a su vez, conoce a qué Pedido pertenece, entonces estamos ante un relación
bidireccional, porque a través de cada “parte” llegamos al “todo” al mismo tiempo que el “todo”
conoce cuáles son todas las “partes” que lo forman.
Las relaciones bidireccionales debe seguir estas reglas:
 El lado inverso de una relación bidireccional debe hacer referencia a su lado principal
mediante la posesión elemento mappedBy de la anotación @OneToOne, @ OneToMany, o @
ManyToMany. La elemento mappedBy designa la propiedad o el campo en la entidad que es
el propietario de la relación.
 El lado de muchos de una relación bidireccional de muchos-a-uno no debe definir el elemento
mappedBy. El lado de muchos es siempre la parte propietaria de la relación.
 En el caso de las relaciones bidireccionales uno a uno, el lado propietario corresponde a la
parte que contiene la clave externa correspondiente.
 Para las relaciones bidireccionales de muchos a muchos a ambos lados puede estar la parte
principal.
Las relaciones unidireccionales
En una relación unidireccional, sólo una entidad tiene un campo de relación o la propiedad que se
refiere a la otra. Por ejemplo, un Elemento tendría un campo de relación que identificara productos,
pero el Producto no tendría un campo de relación o propiedad de cada Elemento. En otras palabras,
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
el Elemento
conoce el Producto del que forma parte, pero el Producto no sabe qué Elementos se refieren o
apuntan a él.

Múltiples claves primarias en una entidad


Una de las restricciones de las entidades en JPA es que deben tener una clave primaria y además no
pueden tener más de una, en los casos de programación reales nos encontramos muchas veces con
la necesidad de tener dos claves primarias en una entidad.
¿Cómo hacer esto con JPA? Existen dos formas de poder definir más de una clave primaria por
entidad, en ambas soluciones es necesaria la creación de una clase que contenga las claves
primarias que deseamos usar.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
1) Con la anotación @ClassId
@Entity
@IdClass(EntidadPK.class)
public class Entidad {
@Id
private int id;
@Id
private String nombre;
...
public Entidad() { }
// Getters y Setters
}
public class EntidadPK {
int id;
String nombre;

public boolean equals(Object o) {


// Codigo que comprueba si las dos entidades son iguales
}

public int hashCode() {


// Segun las buenas practicas cuando se sobreescribe el metodo
// equals() hay que sobreescribir tambien el hashCode()
}
}
2) Con las anotaciónes @Embeddable y @EmbeddedId
@Entity
public class Entidad {
@EmbeddedId
private EntidadPK pk;
...
public Entidad() { }
// Getters y Setters
}

@Embeddable
public class EntidadPK {
int id;
String nombre;

public EntidadPK() { }

public boolean equals(Object o) {


// Codigo que comprueba si las dos entidades son iguales
}

public int hashCode() {


// Segun las buenas practicas cuando se sobreescribe el metodo
// equals() hay que sobreescribir tambien el hashCode()
}
}
Los campos soportados como clave primaria son tipos primitivos, clases "envoltorio" de tipos
primitivos, java.lang.String, java.uti.Date y java.sql.Date.
En ambos casos hay que implementar el método equals, y por extensión el hashCode, que indique al
framework cuando dos entidades con dos, tres, cuatro o las que sean claves primarias son iguales.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En el caso de una clase marcada con la anotación @Embeddable es necesario definir un constructor
estándar, aunque luego depende del framework que usemos puede que sea él el que genere ese
código en tiempo de ejecución.

Relaciones entre entities


En las secciones anteriores hemos visto cómo programar un Entity Bean de EJB 3.0. Pero en todo
diseño orientado a objetos, se establecen relaciones entre las diferentes entidades para representar
el modelo en cuestión. En esta sección veremos cómo implementar estas relaciones en JPA.

Tipos de relaciones
Existen cuatro tipos de relaciones que podemos establecer con JPA:
 1:1
 1:N
 N:1
 N:N
Para cada tipo de relación, existen además dos variantes: unidireccional y bidireccional. En total,
esto nos da ocho tipos de relaciones. Desde el punto de vista de la implementación, sin embargo,
los casos unidireccionales son muy similares a los bidireccionales. Exploraremos algunos ejemplos
de cada uno, pero nos focalizaremos en los casos relaciones bidireccionales. Analizaremos, además,
las consecuencias que estas implementaciones tienen en el modelo relacional resultante.

Relaciones 1:1
Cada instancia de una entidad está relacionada a una sola instancia de otra entidad. Se indica con la
anotación @OneToOne
@Entity
public class Pasajero {
...
@OneToOne
@JoinColumn(name="id_pasajero")
private Boleto boleto;
...
}

@Entity
public class Boleto {
...
@OneToOne(mappedBy="boleto")
private Pasajero pasajero;

...
}
En nuestro modelo de dominio, cada empleado tiene asociado un currículum:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Para implementar esta relación, debemos agregar en la clase Empleado un atributo que la
represente, utilizando la anotación @OneToOne:
@OneToOne(cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "curriculum")
private Curriculum curriculum;
La anotación @OneToOne, entonces, se utiliza para describir relaciones 1:1. Si pensamos en el
modelo de datos necesario para persistir la relación, tenemos dos opciones:
1. Incluir en la tabla de empleados una clave foránea a la tabla de currículum.
2. Incluir en la tabla de currículum una clave foránea a la tabla de empleados.
En este caso, dado que la relación es unidireccional con sentido Empleado -> Curriculum, lo natural
es que la tabla empleados tenga la clave foránea a la table curriculum. Para indicar la información
de esta clave foránea en la clase Empleado, utilizamos la anotación @JoinColumn. Según el código
que hemos visto, entonces, la columna con la clave foránea se llama curriculum. La especificación
de EJB 3.0 denomina a la clase que contiene la definición de la clave foránea en cualquier tipo de
relación como clase dueña de la relación.
El modelo de datos queda, entonces:

Dado que la relación es unidireccional, en la clase Curriculum no debemos incluir ninguna anotación
en particular. Pero si quisiéramos que fuera bidireccional, tendríamos que agregarle un atributo para
representarla, de la siguiente manera:
@OneToOne(mappedBy="curriculum")
private Empleado empleado;
Vemos que en este extremo de la relación no estamos definiendo la clave foránea. Como habíamos
dicho, la clave foránea sólo es necesaria en una tabla; en este caso, elegimos colocarla en la table
empleados. Dentro de la clase Curriculum, en cambio, utilizamos el atributo mappedBy para indicar
el nombre de la propiedad en la clase Empleado que define la relación.
En general, entonces, en una relación bidireccional existen dos extremos; uno dueño de la relación,
y otro subordinado. El extremo dueño utiliza la anotación @JoinColumn para definir la clave foránea.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
El extremo subordinado utiliza el atributo mappedBy de la anotación correspondiente para indicar el
nombre de la propiedad correspondiente en el extremo dueño.
¿Pero por qué necesitamos el atributo mappedBy? En nuestro caso, la relación entre ambas clases
se da en un único atributo para ambos extremos, por lo que el proveedor de persistencia podría
utilizar una convención y deducir el atributo correspondiente. La especificación no indica esta
convención, sin embargo, y por lo tanto se utiliza el atributo mappedBy para vincular los atributos
correspondientes a los dos extremos de la misma relación.
Analizaremos el atributo cascade de la anotación OneToMany más adelante.

Relaciones 1: N
Una entidad puede relacionarse a múltiples instancias de otra clase. Un ejemplo común es una
factura que tiene muchos detalles. Se indica con la anotación @OneToMany y comúnmente está
asociada a un Set de elementos.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ejemplo de asociación Bidireccional Definición del one to many
@Entity
public class Autobus {
...
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, mappedBy="autobus")
private Set<Boleto> boletos;

...
}
Definición del lado inverso de la relación
@Entity
public class Boleto {
...
@ManyToOne
@JoinColumn(name="id_autobus", nullable=false)
public Autobus getAutobus() {
return autobus;
}
...
}
Attributos de un @OneToMany
cascade
Opcional
Default: Un array vacío que contiene elementos del tipo CascadeType. Por default JPA no asigna
ninguna operación de cascada en una asociación, sin embargo se pueden utilizar los siguientes tipos
de operaciones en Cascada:
ALL - Se realizan los cambios en las entidades señaladas por la operación en cualquier operación de
persistencia realizada.
MERGE - Si se realiza una operación de actualización en la entidad se realizarán los cambios en las
entidades señaladas por el @OneToMany.
PERSIST -Si se realiza una operación de escritura en la entidad se agregarán las entidades
señaladas por el @OneToMany..
REFRESH - Si se realiza una actualización en la entidad se realizarán los cambios en las entidades
señaladas por el @OneToMany..
REMOVE - Si se realiza una operación que implique eliminar una entidad entidad se eliminarán las
entidades señaladas por el @OneToMany..

mappedBy
Opcional: Depende si es unidireccional o bidireccional
Default: Si la relación es unidireccional el proveedor de persistencia determinará el campo que
contiene la unión. Si la relación es bidireccional, es necesario definir el mappedBy en la forma
inversa de la relación. Es decir se utilizará por ejemplo el @ManyToOne que defina el lado opuesto
de la relación.

A su vez, la clase Curriculum contiene una lista de ItemCurriculum. Cada item representa una
entrada del curriculum:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En la representación del modelo relacional para esta relación, la tabla que almacena los items tendrá
la clave foránea a la tabla de los currículum. Aún así, la entidad que define la relación debe ser
Curriculum, no ItemCurriculum, dado que la relación es unidireccional con sentido Curriculum
ItemCurriculum. Entonces, debemos usar la anotación @JoinColumn en la clase Curriculum.
El modelo de datos para esta relación queda definido, entonces, de la siguiente manera:

En la implementación vemos el uso de las anotaciones indicadas previamente


@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "curriculum")
private List<ItemCurriculum> items = new Vector<ItemCurriculum>();
Si, en cambio, la relación fuese bidireccional, lo correcto sería usar la anotación @JoinColumn en la
clase ItemCurriculum, y el atributo mappedBy en la clase Curriculum:
public class Curriculum {

@OneToMany(cascade = CascadeType.ALL, mappedBy="curriculum")


private List<ItemCurriculum> items = new Vector<ItemCurriculum>();

// Otros atributos y métodos.


}

public class ItemCurriculum {

@ManyToOne(optional = false)
@JoinColumn(name = "curriculum")
private Curriculum curriculum;

// Otros atributos y métodos.


}
Nótese que en el extremo N (la clase ItemCurriculum) se utiliza la anotación @ManyToOne, que
veremos a continuación.

Relaciones N:1

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Muchas instancias de una clase se relacionan a una sola instancia de otra clase (es la versión inversa
de One to Many). Se indica con la anotación @ManyToOne
@Entity
public class Boleto {
...
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="id_autobus", referencedColumnName="id_autobus")
private Autobus autobus;
...
}
Para las relaciones N:1, el modelo relacional es similar al de las relaciones 1:N. La tabla que
representa el extreno N de la relación contiene una clave foránea a la tabla que representa el
extreno 1. En este caso, sin embargo, el extremo dueño de la relación es el extreno N. Por lo tanto,
la anotación @JoinColumn debe usarse en la clase que represente el extremo N.
La anotación para indicar este tipo de relación es @ManyToOne.
En nuestro modelo, el ejemplo de este tipo de relaciones es la existente entre Empleado y
CategoriaEmpleado, definida en el siguiente model de clases:

El modelo relacional involucra las tablas empleados y categorias_empleado:

Vemos que la implementación similar a la utilizada en el ejemplo de relación 1:N bidireccional, en el


extremo N (en este caso, la clase Empleado):
@ManyToOne(optional = false)
@JoinColumn(name = "categoria")
private CategoriaEmpleado categoria;
Dado que la relación es unidireccional, no es necesario modificar la clase CategoriaEmpleado. Si
quisiéramos que la relación fuese bidireccional, entonces la clase CategoriaEmpleado tendría un
atributo empleados anotado con @OneToMany. Lo mismo sucedería en el caso de tener una relación
1:N bidireccional. En otras palabras, las relaciones 1:N y N:1 bidireccionales se implementan de
manera similar, utilizando @OneToMany en el extreno 1 y @ManyToOne en el extremo N; lo único
que varía es el extremo en el que se usa la anotación @JoinColumn. Desde un punto de vista
semántico de la relación, no hay diferencia. Simplemente existe una entidad que desde el punto de
vista del modelo es más fuerte en la relación, y por eso decimos que la misma es 1:N o N:1.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Si analizamos el ejemplo de una relación 1:N bidireccional, vemos que la implementación es igual a
la de un relación N:1 bidireccional.

Relaciones N:N
Las instancias de una entidad se pueden relacionar con múltiples entidades de otra clase y
viceversa. Un ejemplo sería un estudiante que tiene muchas clases y una clase que tiene muchos
estudiantes a su vez. Se indica con la anotación @ManyToMany.
@Entity
public class Autobus {
...
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(
name="autobus_gasto", schema="public"
, joinColumns={
@JoinColumn(name="id_autobus", referencedColumnName="id_autobus"),
}
, inverseJoinColumns={
@JoinColumn(name="id_concepto_gasto",
referencedColumnName="id_concepto_gasto"),
}
)
private Set<ConceptoGasto> conceptoGastos;

@Entity
public class ConceptoGasto {
...
@ManyToMany(mappedBy="conceptoGastos")
private <Set>Autobus autobuses;
...
}
Como hemos visto para definir relaciones N:N, existe la anotación @ManyToMany, usada en ambos
extremos. El modelo relacional requiere que exista una tabla de relación que contenga registros con
pares de claves foráneas a cada tabla involucrada. La definición de esta tabla y sus claves foráneas
se realiza con la anotación @JoinTable, en la clase del extremo dueño de la relación.
Tomaremos como ejemplo la relación entre las clases Cliente y Proyecto, definida en el siguiente
modelo de clases:

Para persistir esta relación, necesitamos utilizar una tabla que contenga las relaciones entre ambas
clases. Esta tabla tendrá claves foráneas a las tablas en las que se persisten las clases Cliente y
Proyecto. El modelo de datos para esta relación es:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Para implementar esta relación, seleccionamos a la clase Proyecto como "dueña" de la misma. Esto
significa que en atributo clientes de esta clase vamos a definir la tabla de relación a utilizar, y las
claves foráneas.
@ManyToMany
@JoinTable(name = "clientes_proyectos",
joinColumns = {@JoinColumn(name = "proyecto", referencedColumnName = "codigo") },
inverseJoinColumns = { @JoinColumn(name = "cliente", referencedColumnName = "codigo") })
private Set<Cliente> clientes = new HashSet<Cliente>();

Con el atributo name de la anotación @JoinTable indicamos el nombre de la tabla de relación. Con
el atributo joinColumn definimos la clave foránea en la tabla clientes_proyectos a la tabla
proyectos. Con el atributo inverseJoinColumns definimos la clave foránea en la tabla
clientes_proyectos a la tabla clientes. Si alguna de las clases tuviera una clave compuesta, en
estos atributos deberíamos especificar todas las columnas de dicha clave.
En la clase Cliente sólo tenemos que anotar la relación con @ManyToMany, y utilizar el atributo
mappedBy para indicar que la relación está definida en el atributo clientes de la clase Proyecto:
@OneToMany(mappedBy = "clientes")
private Set<Proyecto> proyectos = new HashSet<Proyecto>();

Operaciones en cascada
Cuando trabajamos con las entidades, en ocasiones creamos un árbol de objetos, y queremos
persistir todo ese árbol al mismo tiempo. Para no tener que solicitar a JPA que persista los objetos
uno a uno, podemos indicar en la definición de las relaciones que algunas operaciones se propaguen
en cascada. Esto significa que, por ejemplo, persistiendo el objeto "raíz" del árbol que creamos, JPA
propagará la operación de persistencia a todos los objetos relacionados. Esta propagación se define
para cada relación en particular; de manera que, para una clase determinada, podemos definir qué
operaciones (si alguna) se propagarán para qué relaciones.

En nuestra aplicación, un Empleado está compuesto por un Curriculum, y cada Curriculum está
compuesto por un conjunto de ItemCurriculum. Es natural que queramos crear el empleado, su
curriculum, y los ítems del curriculum, y persistir todos estos objetos en una única operación.
Asimismo, en algún momento modificaremos los datos del empleado, y agregaremos ítems a su
currículum. También querremos, en este caso, propagar la operación de actualización.

Para definir, en una relación con cualquier cardinalidad, qué operaciones deben propagarse, se
utiliza el atributo cascade en la anotación de la relación. Este atributo puede tener los siguientes
valores:
CascadeType.PERSIST: se propaga la operación de persistir.
CascadeType.MERGE: se propaga la operación de sincronizar la base de datos con las
modificaciones realizadas al objeto.
CascadeType.REFRESH: se propaga la operación de actualizar el objeto con los datos de la base
de datos.
CascadeType.REMOVE: se propaga la operación de eliminar el objeto.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
CascadeType.ALL: valor de convenciencia que inca que se propagan todas las operaciones
anteriores.

En el atributo cascade se puede utilizar más de uno de estos valores. Por ejemplo, una relación 1:N
podría anotarse de la siguiente manera:
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})
Con estos valores en el atributo cascade, se propagarán las operaciones de persistencia y
sincronización de la base de datos, pero no las otras dos.
Si se utiliza el valor CascadeType.ALL, no debe utilizarse ningún otro valor.
Por defecto, JPA no propaga ninguna operación. Por lo tanto, si para una relación determinada
no especificamos CascadeType.PERSIST o CascadeType.ALL, deberemos persistir todos los objetos
explícitamente, uno a uno.

Estrategias de recuperación de relaciones


Cuando se busca un objeto que tiene relaciones con otros, particularmente en relaciones 1:N y N:N,
obtener todas las colecciones con las que está relacionado el objeto puede ser costoso en tiempo de
ejecución. Pensemos, por ejemplo, en una Compañía que tiene 100.000 empleados. Es esperable
que la mayor parte de los casos de uso en los que se requiera utilizar una Compañía, no sea
necesario utilizar todos sus Empleados. ¿Para qué obtenerlos, entonces?
Para estos casos, se pude definir en cualquier tipo de relación, que el/los objeto/s relacionados se
obtengan siempre al obtener el objeto "padre", o que se obtengan al momento de utilizarlos. Por
ejemplo, en el caso de de una relación 1:N, hasta que no realicemos una operación con el extremo
N de la relación, no es necesario cargar todos los objetos.
Cuando no queremos que un objeto u objetos relacionados se carguen inmediatamente, decimos
que esta relación es perezosa o lazy. Esta definición puede realizarse para cualquiera de los cuatro
tipos de relaciones que analizamos en esta sección, y es independiente de la estrategia de
propagación de operaciones establecida para la relación.
Para definir este comportamiento, se utiliza el atributo fetch de la anotación de una relación. Este
atributo puede tener uno de dos valores:
 FetchType.EAGER: es la estrategia por defecto. La relación se cargará al obtener el objeto.
 FetchType.LAZY: la estrategia perezosa; la relación se cargará al utilizarla por primera vez.
La especificación de JPA dice que utilizar FetchType.LAZY es un consejo para el proveedor de
persistencia. Es decir, la especificación no prescribe exactamente cómo se debe tratar la
relación en este caso.

Consecuencias del uso de relaciones LAZY


A pesar de que el uso de FetchType.LAZY es un consejo para los proveedores de persistencia, éstos
en general tienen mecanismos para tratar estos casos. ¿Pero cómo hacen para obtener las
relaciones al primer acceso? Dejar el atributo en null no es factible, dado que no se estaría
respetando la semántica del atributo. Analicemos el siguiente extracto de código para entender la
situación:
Empleado e = null.
// Obtenemos un empleado con JPA con un mecanismo que aún no hemos estudiado...
// Ahora la variable e referencia a un objeto
System.out.println(e.getNombre()); // Muestra el nombre del empleado.
System.out.println(e.getCurriculum().getItems().size()) // Muestra la cantidad de
items en el curriculum del empleado.
La última línea, si "no cargar la relación Curriculum -> ItemCurriculum" significa que el atributo
items de la clase Curriculum será null, generará una NullPointerException, lo cual es

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
semánticamente incorrecto, aún si esa colección estuviera vacía en la base de datos. En otras
palabras, si el Curriculum no tuviera items cargados, la última línea debería mostrar 0 sin generar
un error. Que una colección esté vacía no es lo mismo que la colección no exista. Lo mismo ocurre
con la relación Empleado -> Curriculum. Según el modelo de dominio, un Empleado siempre tiene
un Curriculum asociado, con lo cual es correcto que el programador realice operaciones sobre
e.getCurriculum() sin verificar previamente si el getter devuelve null.
Para no violar esta semántica, los proveedores de persistencia utilizan proxies. Estos proxies se
encargan de encapsular el comportamiento de obtener el objeto real de la relación (en los casos de
relaciones 1:1 y N:1) o la colección (en los casos de relaciones 1:N y N:N). A través de los proxies,
el proveedor de persistencia puede "interceptar" la llamada a algún método de ese objeto o
colección, y obtenerlos sólo cuando se los utilice.
Saber esto es importante. Si intentamos pasar un Entity Bean entre servidor y cliente, es
fundamental saber si el proveedor de persistencia inyectó un proxy para alguna relación; los proxies
no funcionarán en la capa del cliente, sino solamente en la capa del servidor.

Ver Video: Modelado de Relaciones de Asociación de Datos,


en la Unidad 5, en el Módulo 6,
en la plataforma elearning

Laboratorio: EJB de entidad


Objetivos
 Conocer el de la tecnología EJB con Beans de entidad.
 Persistencia de objetos y consultas a bases de datos mediante objetos POJO’s.

Enunciado
Vamos a realizar una aplicación que buscará un departamento y devolverá sus datos utilizando para
la lógica un Bean de entidad.
Para ello, utilizaremos la tecnología EJB y acceso a la base de datos mediante unidades de
persistencia.

Lo primero que vamos a realizar será crearnos un nuevo proyecto web Application.

Dejaremos todos los valores por defecto.


Sobre nuestro proyecto, vamos a agregarnos una unidad de persistencia, para ellos seleccionamos
Persistence Unit.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Dejaremos el nombre de la unidad de persistencia por defecto WebApplication3PU.
Seleccionaremos un proveedor, Toplink en nuestro ejemplo y configuraremos un acceso a datos
como hemos aprendido en el módulo. Nuestro origen de datos se llama CONEXIONORACLE.
Marcaremos None como estrategia de generación de la tabla.

Es imprescindible poner NONE para que no elimine los registros ni las tablas del servidor, de esta
forma, todo quedará administrado y mantendrá los datos originales de las tablas.

Veremos que nos ha creado el fichero persistence.xml para administrar nuestros objetos Entity de la
base de datos.

A continuación, vamos a crearnos un nuevo paquete que llamaremos packageJTA.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Sobre nuestro paquete generado, vamos a agregar los objetos de la base de datos para trabajar.
Agregaremos un objeto Entity Classes from Database de la carpeta Persistence.

Buscamos las tablas que vayamos a agregar como entidades de la base de datos. En nuestro
ejemplo, utilizaremos la tabla DEPT.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Dejamos los valores por defecto en la siguiente pantalla.

En las opciones de mapeo de la entidad, marcamos la colección como Collection.

Ahora vamos a agregar un servlet para poder hacer las consultas sobre las entidades.
Agregamos un servlet y escribimos el siguiente código:
package packageJTA;
import java.io.IOException;
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
import java.io.PrintWriter;
import java.util.*;
import javax.persistence.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NewServlet extends HttpServlet {
private void Pintar(PrintWriter out, short iddept)
{
EntityManagerFactory emf = Persistence.createEntityManagerFactory("WebApplication3PU");
EntityManager em = emf.createEntityManager();
Query consulta = em.createQuery("SELECT d FROM Dept d");
List<packageJTA.Dept> listadept = consulta.getResultList();
Dept dep = em.find(Dept.class,iddept);
if (dep == null)
{
out.println("<h4>No se ha encontrado el departamento</h4>");
}else{
out.println("Departamento encontrado: "+ dep.getDname());
}
out.println("<h4>Lista de departamentos</h4>");
out.println("<table border='1'>");
for (packageJTA.Dept d : listadept)
{
out.println("<tr>");
out.println("<td>"+d.getDeptno()+"</td>");
out.println("<td>"+d.getDname()+"</td>");
out.println("<td>"+d.getLoc()+"</td>");
out.println("</tr>");
}
out.println("</table>");
out.println("<a href=index.jsp'>Volver a la busqueda</a>");
}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)


throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>DATO ENCONTRADO!!</h1>");
String departamento = request.getParameter("txtnumero");
short iddept = Short.parseShort(departamento);
this.Pintar(out, iddept);
out.println("</body>");
out.println("</html>");
}catch (Exception ex)
{
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
out.println("<body>");
out.println("<h1>EXCEPCION</h1>");
out.println(ex.toString());
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
Después una página JSP para la llamada al servlet:
<%@page import="java.util.List"%>
<%@page import="javax.transaction.Transaction"%>
<%@page import="javax.persistence.*"%>
<%@page import="packageJTA.*"%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<form name="form1" action="NewServlet">
Numero departamento:
<input type="text" name="txtnumero"/>
<input type="submit" value="Buscar departamento"/>
</form>
</body>
</html>
Y el resultado es:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 6. Implementación de Clases de
Entidad: Modelado de Relaciones de Herencia
Objetivo
Conocer el papel desempeñado por las relaciones y su modelado dentro las clases de entidad en la
tecnología EJB.

Jerarquías de clases
En todo modelo de clases, realizamos generalizaciones y abstracciones que resultan en jerarquías de
clases. Elaboramos tales jerarquías por varios motivos. Uno de ellos es generalizar un
comportamiento y/o un estado, y abstraerlos en una superclase, para hacer uso de ellos en las
subclases a través de la herencia. Otro motivo es obtener un tratamiento polimórfico de los objetos.

En EJB 3.0, JPA permite instancias de clases que pertenezcan a una jerarquía de manera sencilla e
intuitiva. En EJB 2.x, realizar esto requería soluciones propietarias, poco intuitivas y escalables,
difíciles de implementar y mantener.

En el contexto de JPA, esto plantea dos problemáticas diferentes, que analizaremos a continuación.

Superclases no persistentes
Para casos en los que queremos hacer uso de herencia de clases, sin utilizar polimorfismo, las
superclases no representan supertipos de entidades, sino que sólo existen para abstraer un
comportamiento y/o un estado. En nuestra aplicación, un ejemplo de este tipo de abstracciones es
la clase Persona. En esta clase abstraemos el estado y el comportamiento de las entidades que
representan tanto personas físicas como jurídicas.
En este caso, no haremos uso de polimorfismo en el sentido en que nunca pretenderemos obtener y
operar con instancias de esta clase directamente. Nunca buscaremos una instancia de Persona.
Buscaremos, por ejemplo, instancias de Cliente o Empleado.
Para indicar a JPA que una superclase pertenece a una jerarquía de clases persistente, pero que no
representa un supertipo de entidades, utilizamos la anotación @MappedSuperclass.
Veamos la definición de la clase Persona:
import java.util.*;
import javax.persistence.*;
/**
* Superclase para las entidades que representan personas.
*
* @author Juan Garcia
*/
@MappedSuperclass
public abstract class Persona {
@TableGenerator(name = "secuencias", table="secuencias", pkColumnName = "nombre",
valueColumnName_
= "valor", pkColumnValue = "persona")
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "secuencias")
private Long codigo;
@Embedded
private Direccion direccion;
@OneToMany(cascade = CascadeType.ALL)

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@JoinColumn(name = "persona", updatable = false, insertable = false)
private Set<Contacto> contactos = new HashSet<Contacto>();
@Version
private long version;
// Otros atributos y métodos.
}
Utilizamos las anotaciones que ya estudiamos de JPA para describir los atributos persistentes. Las
subclases de Persona (Cliente y Empleado) podrán definir otros atributos de persistencia (por
ejemplo, en qué tabla se persisten) y también heredar los atributos definidos en Persona.

Estrategias de persistencia para jerarquías de clases


Otra situación es cuando la jerarquía de clases representa clases persistentes. Es el caso, por
ejemplo, de las clases Cliente, ClienteUnipersonal y ClienteCorporativo. Queremos poder utilizar
estas clases de manera polimórfica. Por ejemplo, en algún momento querremos mostrar una lista de
todos los clientes administrados por la aplicación, sin discriminar clientes corporativos de
unipersonales. Para esto, la clase Cliente, a pesar de ser abstracta, debe ser anotada con @Entity.
Para persistir este tipo de jerarquías, existen tres estrategias definidas por JPA:
 Single table per class hierarchy: usar una única tabla para toda una jerarquía de clases:
 Joined table: usar una tabla para cada clase de la jerarquía (incluidas las abstractas),
almacenando en cada tabla los atributos particulares de la clase correspondiente.
 Single table per concrete class: usar una tabla particular para cada clase concreta (es decir,
no definida como abstract) de la jerarquía.
Para seleccionar la estrategia en cada jerarquía se utiliza el atributo strategy de la anotación
@Inheritance, que debe ser de tipo InheritanceType.
Estrategia single table per class hierarchy
Con esta estrategia, todas las clases de una jerarquía se persisten en la misma tabla. La tabla
deberá tener todas las columnas correspondientes a todas las clases de la jerarquía. Como
consecuencia, las columnas que no correspondan a la superclase de la jerarquía no podrán ser
definidas en la base de datos como null.
Para que JPA pueda identificar a qué clase corresponde cada registro de la tabla, debe existir una
columna denominada discriminador. Esta columna contendrá un valor asociado a cada clase
concreta de la jerarquía. Para especificar esta columna, se usa la anotación
@DiscriminatorColumn. En cada clase concreta, se debe indicar el valor que identifica a esa clase
a través de la anotación @DiscriminatorValue.
La jerarquía que utilizaremos como ejemplo es la utilizada para representar clientes. Esta jerarquía
tiene tres clases:
Cliente: es la superclase de la jerarquía, con estado y comportamiento común a todos los clientes.
Es abstracta y extiende a la clase Persona.
ClienteUnipersonal: representa clientes unipersonales; es decir, clientes que son personas físicas.
ClienteCorporativo: representa clientes corporativos; es decir, clientes que son personas jurídicas.
A continuación vemos el modelo de clases de esta jerarquía:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Para implementar esta estrategia, utilizamos las anotaciones @Inheritance y
@DiscriminatorColumn en la superclase:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="clientes")
@DiscriminatorColumn(name = "tipo", discriminatorType = DiscriminatorType.STRING, length = 20)
public abstract class Cliente extends Persona {

// Atributos y métodos

}
Con estas anotaciones definimos:
 La estrategia de persistencia para la jerarquía.
 El nombre de la tabla única donde se persistirá toda la jerarquía.
 El nombre de la columna usada para discriminar entre las subclases concretas.
En las subclases, sólo debemos indicar el valor utilizado en la columna discriminadora para
identificar a la clase al recuperar instancias:
@Entity
@DiscriminatorValue("corporativo")
public class ClienteUnipersonal extends Cliente {

// Atributos y métodos

@Entity
@DiscriminatorValue("unipersonal")
public class ClienteCorporativo extends Cliente {

// Atributos y métodos

}
El modelo de datos involucra una única tabla:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Estrategia joined table
En esta estrategia, cada clase de la jerarquía de la jerarquía anotada con @Entity es persistida en
una tabla distinta. Para recuperar una instancia completa, JPA debe realizar operaciones join entre
todas las tablas involucradas. Esta estrategia permite utilizar el modelo de datos más correcto desde
un punto de vista de normalización de base de datos, con el potencial impacto en performance,
debido a las N operaciones join. Este problema pude no ser trivial si hay muchas clases en la
jerarquía, y muchos registros en la cada una de ellas.
En cada clase anotada con @Entity, entonces, podemos utilizar la anotación @Table para indicar la
tabla en la que se deberá persistir la clase. Todas las tablas deberán definir las columnas de clave
primaria definidas en la superclase.

Veremos como ejemplo la jerarquía de clases utilizada para representar los proyectos. En esta
jerarquía hay tres clases:
 Proyecto: superclase para todos los tipos de proyecto.
 ProyectoSimple: proyecto al que puede ser adjudicado a una única compañía; subclase de
Proyecto.
 ProyectoCombinado: proyecto que puede ser adjudicado a muchas compañías; subclase de
Proyecto.
El modelo de clases está representado en el siguiente diagrama:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Para implementar esta estrategia, debemos utilizar el valor InheritanceType.JOINED en el
atributo strategy de la anotación @Inheritance en la superclase de la jerarquía, la clase Proyecto:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "tipo")
@Table(name = "proyectos")
public abstract class Proyecto {

// Atributos y métodos

}
Dado que la clase Proyecto está anotada con @Entity, los atributos definidos en esta clase serán
persistidos en una tabla particular; en este caso, la tabla proyectos. Por otro lado, en las clases
ProyectoSimple y ProyectoCombinado establecemos la información de persistencia para sus
atributos particulares, e indicamos la tabla en la que se persistirán:

@Entity
@Table(name = "proyectos_simples")
@DiscriminatorValue("simple")
public class ProyectoSimple extends Proyecto {

// Atributos y métodos
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@Entity
@Table(name = "proyectos_combinados")
@DiscriminatorValue("combinado")
public class ProyectoCombinado extends Proyecto {

// Atributos y métodos

}
El próximo diagrama representa el modelo de datos resultante. Existe una tabla proyectos para la
clase Proyecto, una tabla proyectos_combinados para la clase ProyectoCombinado y una tabla
proyectos_simples para la clase ProyectoSimple.

Estrategia single table per concrete class


En esta estrategia, existe una tabla para cada clase concreta de la jerarquía. Por lo tanto, cada tabla
deberá tener las columnas necesarias para almacenar todos los atributos de la clase concreta y sus
superclases. Esta estrategia está definida como opcional en la especificación de JPA, por lo que
antes de utilizarla es necesario verificar que el proveedor de persistencia elegido la soporte.
Un ejemplo de esta estrategia es la jerarquía de clases de contactos para personas. Esta jerarquía
tiene la superclase Contacto, y dos subclases, ContactoTelefono y ContactoEMail. Vemos a
continuación el modelo de clases que vamos a implementar:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Aunque la jerarquía tiene tres clases, existirán solamente dos tablas: una para ContactoEMail y otra
para ContactoTelefono. Estas tablas tendrán, además de las particulares para la clase que
corresponda, las columnas para almacenar los atributos definidos en la clase Contacto.
Para implementar esta estrategia, en la clase Contacto debemos usar el valor
InheritanceType.TABLE_PER_CLASS en el atributo strategy de la anotación @Inheritance:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@IdClass(ContactoPK.class)
public abstract class Contacto {

// Atributos y métodos.

}
Luego, definimos las clases ContactoTelefono y ContactoEMail, indicando las tablas en las que se
persistirá cada una con la anotación @Table.
@Entity
@Table(name="contactos_telefono")
public class ContactoTelefono extends Contacto {

// Atributos y métodos.

@Entity
@Table(name="contactos_email")
public class ContactoEMail extends Contacto {

// Atributos y métodos.

}
El modelo de datos contiene entonces solamente dos tablas para las dos clases concretas, con todos
los atributos de las superclases y clases embebidas.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Comparando el modelo de datos utilizado para estrategia con los utilizados para los dos anteriores,
vemos que este es más difícil de mantener. Un cambio en cualquier superclase requiere la
modificación de tantas tablas como clases concretas tenga la jerarquía.

La elección de una estrategia de persistencia para una jerarquía de clases debe surgir de un análisis
cuidadoso de las características de la jerarquía y el uso que tendrá, para determinar cuál es el más
eficiente.

Ver Video: Modelado de Relaciones de Herencia,


en la Unidad 6, en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 7. Uso del Lenguaje de Consulta (Ql)
de Java Persistence
Objetivo
Conocer y manejar el lenguaje de consultas EJB QL.

Introducción
Una de las ventajas de la persistencia gestionada por contenedor es que le abstrae del almacén
persistente subyacente: no necesitamos saber cómo se almacenan nuestros beans o qué tipo de
base de datos se está utilizando. Sin embargo, una consecuencia de este requisito es que
necesitamos un lenguaje independiente de la base de datos para expresar las consultas. Por
ejemplo, si queremos tener una consulta que realice la siguiente búsqueda:
“Encontrar todos los empleados cuyo apellido sea García”.
Pues bien, antes de EJB 2.0, no existia un lenguaje estándar de este tipo, por lo que todos los
desarrolladores de contenedores EJB diseñaban el suyo propio. Sin embargo, con EJB 2.0 se
introdujo el lenguaje EJB QL, EJB Query Language.
EJB QL es un lenguaje cuya sintaxis se parece a SQL aunque también es diferente en algunos
aspectos. Igual que las relaciones, las instrucciones QL EJB son especificadas en los descriptores de
implementación y el contenedor general de la instrucci6n SQL correspondiente que no tiene que por
que ser SQL, para llevar a cabo una consulta.
El reto que EJB QL intenta resolver es asociar dos mundos diferentes:
• objetos Java
y filas de bases de datos.

Hoy por hoy, las bases de datos relacionales (RDBMS) todavía prevalecen, pero esto podria cambiar
en el futuro a medida que dichas bases de datos sea orientadas a objetos (OODBMS) y se hagan
cada vez más populares. EJB QL intenta abstraer este posible cambio de paradigma de modo que
con cualquier lenguaje de consulta que se utilice para tornar datos de la base de datos, nuestro
desarrollo EJB siga trabajando.
Realizar consultas en los Entity Beans disfruta de la misma importancia que definir la manera de
guardarlos, en unidades anteriores vimos algunas búsquedas y operaciones realizadas a través de
los métodos de la clase EntityManager.

En aquella ocasión los métodos indicaban que había dos maneras de buscar datos.
- La primera consiste en utilizar el lenguaje de consulta EJBL (Enterprise JavaBeans Query
Language), que veremos con detalle a continuación. Esta forma es siempre preferible puesto
que ya no trabaja a nivel de tablas sino a nivel de los Beans y por lo tanto es totalmente
independiente de la estructura de base de datos como decíamos algunos párrafos atrás .

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- La otra opción consiste en echar mano del SQL nativos de aquella base de datos sobre la que
queramos operar. Si no queda más remedio podremos optar por esta posibilidad. Algo que
puede motivar su empleo podría ser que debamos incluir en la consulta columnas de las
tablas de bases de datos que no están administradas por ningún Entity Bean. A estas
columnas no se puede acceder mediante EJB QL.
Hay por lo tanto una primera limitación importante en el lenguaje QL: Solo podemos consultar
aquellas columnas que hayan sido incluidas dentro de un EJB.

El EntityManager ofrece el método createNamedQuery(), que entra en ación cuando la


consulta se deposita mediante una de las anotaciones @NamedQuery o
@NamedNativeQuery. En la práctica este resulta, con diferencia, el mejor método para
realizar consultas.
Independientemente de qué método utilicemos siempre se nos devuelve una instancia de la Query.
Con esta instancia se incorporan parámetros necesarios a la consulta, que será ejecutada después
también con la de los métodos correspondientes. En cambio, si se utilizan sentencias de SQL clásica
los parámetros se establecerán, como acostumbra hacerse, en forma de interrogación en el string
de la consulta. En las consultas SQL se puede escoger entre parámetros de posición (una
interrogación seguida de una cifra) o parámetros denominados (dos puntos seguidos de un
denominador).
Cuando llamamos a uno de los métodos createQuery() o createNamedQuery() del EntityManager
siempre se obtiene como resultado una instancia de Query, siempre y cuando la sintaxis de la
consulta transmitida fuera correcta.
La diferencia se hace evidente si observamos un simple EJB-QL con este formato “SELECT EMPLEADO
FROM EMPLEADOS”. Aquí se seleccionan no solo las columnas de la tabla , sino un objeto entero del
tipo EMPLEADO. Si también se definieran relaciones de cantidad, se recibirían también de inmediato.
En este otro caso, la diferencia resulta también obvia cuando se observa “ SELECT distinct
EMPLEADO FROM EMPLEADOS E JOIN EMPLEADOS.VENTAS V WHERE V.CANTIDAD =
0”. Aquí se seleccionan EMPLEADOS cuyas ventas tienen asignada la cantidad 0. Condición previa
para que esta consulta funciones es una relación @OneToMany con el nombre ventas en la
clase empleados. Si se quisiera conseguir esto mediante SQL, se tendría que vincular la tabla de
empleados con la de ventas y asegurar mediante condiciones WHERE, que solo se contemplarían
aquellas filas en las que coincidan también los números de empleado.
Con EJB QL conseguimos hacer que funcione la aplicación con total independencia de una estructura
concreta de base de datos. Y esto es así gracias a que el mapeo de la base de datos lo realizan los
Entity Beans con sus anotaciones, que en caso necesario se pueden sobrescribir, si las columnas
deben llamarse de forma diferente en instalaciones sucesivas. Gracias a esta manera de realizar el
desarrollo, nuestras aplicaciones resultan altamente portables.
A la vez, gracias a este sistema podemos solventar el problema de tropezar con diferentes versiones
del SQL conforme a las diferentes bases de datos existentes en el mercado. Así, nos resultará
indiferente emplear Oracle o DB2 porque será tarea del EntityManager traducir las expresiones EJB-
QL a las SQL demandadas por motor de base de datos receptor.

Interfaz Query y los objetos derivados de ella


Dado que los métodos antes señalados y gestionados por el EntityManager acostumbran a devolver
un objeto derivado de la interaz Query, conviene que veamos detalladamente sus métodos más
importantes y su utilidad. En el siguiente cuadro aparecen enumerados dichos métodos de la
interfaz:
package javax.persistence;
public interface Query {
public List getResultList();
public Object getSingleResult() ;

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
public int executeUpdateO;
public Query setMaxResults(int maxResult();
public Query setFirstResult(int startPosition) ;
public Query setHint(stri ng hintName, Object value);
public Query setParameter(String name, Object value);
public Query setParameter(string name, Date value, TemporalType témporaiType);
public Query setParameter(String name, Calendar value, TemporalType temporal Type);
public Query setparameter(i nt position, object value);
public Query setParaineter(int position, Date value, TemporalType temporal Type);
public Query setParameter(int position, calendar value, TemporalType temporal Type);
public Query setFlushMode(FlushModeType flushMode);
}
Cuando invocamos a los métodos createQuery() y createNameQuery() pertenecientes a la clase
EntityManager obtenemos una instancia de la interfaz Query. Veamos un fragmento de código
ilustrativo de su uso. En primer lugar vemos la entidad y sus correspondientes anotaciones con la
inclusión de una SELECT en una de ella. Dicha select que anotado e identificada con
EMPLEADO.ENCONTRARTODOS. De este modo, hemos ampliado la clase/tabla EMPLEADO con un
nuevo método/consulta:
@Entity
@NamedQueries({
@NamedQuery( name=”EMPLEADO.ENCONTRARTODOS”,
query=”SELECT P FROM EMPLEADO P ORDER BY P.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
Public class EMPLEADO{

}
Acabamos de ver la declaración de la consulta mediante anotación. Veamos ahora cómo
obtendríamos una instancia de Query a partir de ella. Para ello necesitaremos un objeto derivado de
EntityManager que aquí llamaremos manager:
Query CONSULTA=manager.createNamedQuery( “EMPLEADO.ENCONTRARTODOS”)
Repasemos ahora los principales métodos de esta interfaz, su funcionalidad y empleo:
getResultList()
Podríamos decir que estamos ante el método más importante de esta interfaz. A través de él
realizamos una consulta y obtenemos un resultado. Dicho resultado es un objeto o instancia
derivado de la clase java.util.List. Podremos hacer uso de este objeto en diferentes contextos pero
para hacernos una idea de su empleo dentro de EJB conviene atender al siguiente fragmento de
código.
Por un lado vamos a tener declarada una entidad conforme a lo aprendido en las unidades
anteriores.
@Entity
@NamedQueries({
@NamedQuery( name=”EMPLEADO.ENCONTRARTODOS”,
query=”SELECT P FROM EMPLEADO P ORDER BY P.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
Public class EMPLEADO{

}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como vemos hemos creado una entidad mediante anotaciones. Una tabla EMPLEADO a partir de la
clase EMPLEADO. Y Luego hemos dado nombre a una consulta “EMPLEADO.ENCONTRARTODOS”. El
contenido de dicha consulta y, verdadera consulta en sí misma, lo hemos especificado en el segundo
parámetro de la anotación: ”SELECT P FROM EMPLEADO P ORDER BY P.NUM_EMPLEADO”.
De este modo, cuando llamemos al método EMPLEADO.ENCONTRARTODOS, será como si llamamos
a la SELECT que hemos definido.
Veamos ahora como procederíamos a hacer uso de este método dentro del código:
Hacemos una función OBTENEREMPLEADOS que nos devolverá un objeto List con los datos
buscados. Es decir, un listado con todos los empleados de nuestra tabla y ordenados por el número
de empleado que tenga asignado cada uno de ellos.

public List OBTENEREMPLEADOS(){


Query CONSULTA=manager.createNamedQuery( “EMPLEADO.ENCONTRARTODOS”)
List LISTA=CONSULTA.getResultList()
return LISTA

}
Como vemos al pasarle al método createNamedQuery el nombre de nuestro método recuperamos
una instancia Query sobre la que ya podemos aplicar el método getResultList para obtener los
resultados buscados.
Hay que aclarar que al realizar la consulta de esta forma, lo que obtenemos en una lista de objetos
empleado y dentro de cada empleado tendríamos disponibles sus atributos. Pero podemos hacer que
la lista devuelta sea una enumeración de datos pertenecientes a un atributo concreto de dicha clase.
Basta con cambiar la consulta de esta forma:
”SELECT P.APELLIDOS FROM EMPLEADO P ORDER BY P.NUM_EMPLEADO”
Como vemos, a través de la P.APELLIDOS estamos accediendo en la consulta a un atributo concreto
del objeto y no a todo el objeto en sí.
El código completo quedaría así:
@Entity
@NamedQueries({
@NamedQuery( name=”EMPLEADO.TODOSAPELLIDOS”,
query=”SELECT P.APELLIDOS FROM EMPLEADO P ORDER BY P.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
public class EMPLEADO{

}
En la llamada a lo anterior apenas tendríamos que cambiar al invocación al método correspondiente
dado que la Lista es capaz de almacenar referencias a instancias de objetos o bien a una relación de
atributos concretos, en nuestro caso simples String recuperables uno a uno a través de un Iterator.
public List OBTENEREMPLEADOS(){
Query CONSULTA=manager.createNamedQuery( “EMPLEADO.TODOSAPELLIDOS”)
List LISTA=CONSULTA.getResultList()
return LISTA

}
También podemos devolver varios valores por fila. Es decir, dos campos o atributos de una
tabla/clase. En ese caso, nuestra select adoptaría la siguiente definición:
”SELECT E.APELLIDOS, E.NOMBRE FROM EMPLEADO E ORDER BY E.NUM_EMPLEADO”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En el código ocuparía el lugar correspondiente dentro de la anotación de la entidad.
@Entity
@NamedQueries({
@NamedQuery( name=”EMPLEADO.TODOSAPELLIDOS”,
query=”SELECT E.APELLIDOS, E.NOMBRE FROM EMPLEADO E ORDER BY E.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
public class EMPLEADO{

}

Y la invocación no variaría en nada:


public List OBTENEREMPLEADOS(){
Query CONSULTA=manager.createNamedQuery( “EMPLEADO.TODOSAPELLIDOS”)
List LISTA=CONSULTA.getResultList()
return LISTA

}
¿Qué pasaría si combinamos en la consulta campos procedentes de varias tablas? Nada de
particular, el objeto List almacenaría las instancias entregadas como nuevas filas de su lista.
@Entity
@NamedQueries({
@NamedQuery( name=”EMPLEADO.VENTASXEMPLEADOS”,
query=”SELECT E.APELLIDOS, V.VENTAS FROM EMPLEADO E, VENTAS V WHERE
E.NUM_EMPLEADO=V.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
public class EMPLEADO{

}

@Table(name=”VENTAS”)
public class VENTAS{

}
Y la invocación no variaría en nada:
public List OBTENEREMPLEADOS(){
Query CONSULTA=manager.createNamedQuery( “EMPLEADO.TODOSAPELLIDOS”)
List LISTA=CONSULTA.getResultList()
return LISTA

getSingleResult()
Si estamos ante una consulta que solo puede recuperar una línea como resultado, entonces
podemos recogerla a través getSingleResult(). El resultado es del tipo object y se adaptará
al número de columnas seleccionadas previamente. Al igual que en el caso del método
getResultList(), se tratará o bien de una única instancia del tipo seleccionado y/o un
object[], que representará la lista de selección.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Si el resultado debe abarcar más de una línea, se produce un error del tipo
NonuniqueResultException. En cambio, si no se pudo seleccionar nada, el resultado será null.

executeUpdate()
Aparte de las consultas también se pueden utilizar en EJB QL, las instrucciones UPDATE y DELETE, que
pueden influenciar a toda una serie de Entity Beans. El método utilizado para ello
executeUpdate() devuelve el número de filas eliminadas o modificadas.
Este tipo de actualizaciones en lotes deben efectuarse siempre al inicio de una transacción, antes de
que se empiece a seleccionar beans por separado.
Es interesante que este tipo de instrucciones también se pueden definir mediante una anotación
@NamedQuery en la clase Bean

setMaxResults() y setFirstResult()
En muchas ocasiones resulta necesario al tratar datos, presentar su volumen de una manera
manejable mediante la paginación. En estos casos podremos utilizar los métodos
setMaxResultsO y setFirstResult(). Con setMaxResults() se transmite el número de
filas que se quieren obtener como máximo en el resultado. Con setFirstResult() se puede fijar
la posición inicial en la lista, empezando por 0, a partir de la cual debe empezar la selección de las
filas n.
Ambos métodos devuelven el Query como resultado y se pueden combinar entre ellos. Por ejemplo
el siguiente fragmento de código se sitúa en el registro cien devuelto por la consulta, pero nos
recupera los 25 registros siguientes a dicha posición y ninguno de los cien primeros salvo el último.
Query query = manager.createNamedQuery(“EMPLEADO.
TODOSEMPLEADOS”).setFirstResult(100).setMaxResults(25);
List lista = query.getResultList();
return lista;

setHint()
Resulta posible incluir requisitos específicos en la consulta mediante el método setHint(). Dicho
método emplea como primer parámetro una cadena de símbolos con el nombre de la propiedad y en
el segundo parámetro una instancia Object con el valor correspondiente. Veamos un ejemplo:
manager.createNamedQuery(“EMPLEADO.ENCONTRARAPELLIDO”).setHint(“org.hibernate.timeout”,
new integer(1000)).
En el código anterior invocamos en el primer parámetro un método determinado y el en segundo le
pasamos a dicho método un valor compatible.

setParameter(...)
A la hora de pasar parámetros a una consulta, disponemos en total de seis métodos diferentes con
el nombre setParameter. Tres de ellos trabajan con los parámetros en función de su denominación,
mientras que los otros tres operan sobre la posición de los mismos. Por lo tanto, contamos con dos
maneras básicas de operar:
- Identificando los parámetros con un nombre.
- Identificando los parámetros mediante su posición.
@Entity
@NamedQueries({

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@NamedQuery( name=”EMPLEADO.VENTASXEMPLEADOS”,
query=”SELECT E.APELLIDOS, V.VENTAS FROM EMPLEADO E, VENTAS V WHERE
E.NUM_EMPLEADO=V.NUM_EMPLEADO”)
})

@Table(name=”EMPLEADO”)
public class EMPLEADO{

}

@Table(name=”VENTAS”)
public class VENTAS{

}

Y la invocación no variaría en nada:


public List OBTENEREMPLEADO(){
Query CONSULTA=manager.createNamedQuery( “EMPLEADO.TODOSAPELLIDOS”)
List LISTA=CONSULTA.getResultList()
return LISTA

}
Cuando queremos definir un parámetro dentro de una expresión de EJB-QL debemos hacer uso de la
siguiente sintaxis “:nombre”, es decir, dos puntos y el identificador con el que queramos denominar
al parámetro. A su vez, agregamos dicho parámetro al código mediante la instrucción
setParameter(String, object). De este modo, quedarán conectadas la expresión EJB-QL y el código
en Java.
@Entity
@NamedQueries({
@NamedQuery(name=”EMPLEADO.ENCONTRARAPELLIDO”,
query=”SELECT a FROM EMPELADO E “ + “WHERE E.APELLIDO=?1”)
})

Public List ObtenerApellidoEmpleado(String apellidoBuscado){


Query query=manager.createNamedQuery (“EMPLEADO.ENCONTRARAPELLIDO”);
query.setParameter(1,apellidoBuscado);
List lista=query.getResultList();
return lista;
}
Si lo que pretendemos es identificar los parámetros mediante la posición que ocupan, entonces
debemos definirlos mediante un signo de interrogación y una cifra dentro de la expresión EJB-QL. El
método entonces necesario para proceder a la asociación en el código será setParameter(int,
Object).
El resto de métodos disponibles serán empleados cuando queramos transmitir valores de tipo
java.util.Date o java.util.Calendar. Si el contenido de la fecha es de tipo java.sql.Date, java.sql.Time
o java.sqlTimestamp entonces lo indicaremos mediante el tercer tipo de parámetro
javax.persistence.TemporalType.

setFlushModel()
Se encarga de actualizar en la base de datos los cambios producidos en el beans. Cuando el
EntityManager ejecuta una consulta, comprueba si administra actualmente algún beans en el que se
haya producido algún tipo de alteración del que la base de datos no aún no ha tenido constancia. Si
estamos en esta situación, entonces se ejecutan primero las modificaciones en base de datos y
luego la consulta en sí. Este es el procedimiento por defecto que tiene el valor AUTO.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ahora bien, también podemos personalizar este método setFlushModel mediante el valor COMMIT, el
cual traslada las modificaciones a la base de datos una vez han finalizado las transacciones y no
justo antes de realizar la consulta.
También el programador tiene a su disposición un método directo de actualización inmediata de la
base de datos llamado flush() y perteneciente a la clase EntityManager.

Composición del lenguaje QL


Como ya hemos dicho Query Language es un lenguaje de consultas. Técnicamente es un
subconjunto modificado de SQL, soportado por todos los servidores J2EE y que normalmente se
compila a un lenguaje nativo del servidor de aplicaciones.
El alcance de una query en EJB QL llega hasta el esquema abstracto relacionado con un Entity Bean.
De hecho, las consultas EJB QL se definen en el Deployment Descriptor de un entity bean.
EJB Query Language incorpora consultas SELECT y, a su vez, cada consulta tiene tres partes
- SELECT
- FROM
- WHERE (opcional)
A su vez la consulta puede tener parámetros que son pasados a los métodos del EntityManager que
vimos en los apartados anteriores.
Los métodos finder y select usan EJB QL para objetos de retorno e información del estado del entity
Bean. Así, un método select puede retornar una interfaz local o remota (o una colección); puede
hace consultas a una base de datos.
A su vez, un método select puede retornar un campo persistente (o una colección) de un Entity
Bean relacionado. Mientras que un metodo finder puede retornar solo una interfaz remota o local (o
una colección).
El método select no puede ser invocado por un cliente, porque no es expuesto en la interfaz local o
remota. Puede ser invocado solo por los métodos implementados en la clase entity bean. De este
modo, dichos métodos select usualmente son invocados por los métodos y son definidos en la clase
Entity Bean.
La sintaxis de una consulta EJB QL tiene cuatro sentencias:
SELECT, FROM, WHERE y ORDER BY.
SELECT Y FROM SON REQUERIDAS, pero WHERE y ORDER BY son opcionales.
SELECT define los tipos de objetos o valores retornados por la query. Algunos tipos de retorno son
una interface local, una interface remota, o un campo persistente.
FROM define el alcance de la expresión query mediante la declaración de una o más variables de
identificación, las cuales pueden ser referenciadas en el SELECT y WHERE.
WHERE es una expresión condicional que restringe los objetos o valores devueltos por la query.
Aunque es opcional, muchas queries usan esta expresión.
ORDER BY ordena los valores u objetos retornados en algún orden específico.

Veamos un ejemplo sencillo. Supongamos que tenemos un EntityBean denominado EMPLEADOBEAN.


A su vez, este bean define un método findall a partir de una interfaz denominada
EMPLEADOFIJOHOME y que retorna objetos del tipo EMPLEADOFIJO. En este orden de cosas
podríamos plantearnos una consulta como la siguiente
SELECT OBJECT(e)
FROM empleados e

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Los datos retornados serían todos los empleados. El método de búsqueda findall() y La expresión
FROM declararía una variable de identificación llamada e, omitiendo la palabra opcional AS. Si la
palabra AS fuera incluida, la expresión debería ser escrita como sigue:
FROM e AS empleados
Dentro de la sentencia FROM debemos tener presentes algunas consideraciones cuando queramos
emplear en ella una variable de identificador como acabamos de hacer. Así, un identificador es una
secuencia de uno o más caracteres válidos para EJB QL (letras, $, _).
El símbolo ‘?’ es un carácter reservado en EJB QL y no puede ser usado en una variable de
identificador.
Del mismo modo, las siguientes palabras están reservadas y no pueden ser usadas como
identificador:
AND
MEMBER
AS
NOT
BETWEEN
NULL
DISTINCT
OBJECT
EMPTY
OF
FALSE
OR
FROM
SELECT
IS
TRUE
IN
UNKNOWN
LIKE
WHERE
Así pues, una variable de identificación es un identificador declarado en la sentencia FROM. Aunque
las sentencias SELECT y WHERE pueden referenciar variables de identificación, estas no pueden
declararlas.
La sentencia FROM puede contener múltiples declaraciones, separadas por comas. Una declaración
puede referenciar otra variable de identificación que ha sido previamente declarada (a la izquierda).
En la siguiente sentencia FROM, la variable V referencia la variable E declarada anteriormente.
FROM EMPLEADO E, IN (E.VENTAS) AS V
Si una variable de identificación no es usada en la sentencia WHERE, esta declaración puede afectar
el resultado de la expresión QL. La siguiente query retorna todos los EMPLEADOS, tengan VENTAS o
no en su haber.
SELECT OBJECT(E) FROM EMPLEADOS E

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Por otra parte, el siguiente query declara la variable de identificación V, y busca todos los
EMPLEADOS que tengan alguna venta team:
SELECT OBJECT(E)
FROM EMPLEADO E, IN (E.VENTAS) AS V
La siguiente query retorna el mismo resultado que la anterior, pero la sentencia WHERE hace la
lectura mas fácil:
SELECT OBJECT(E)
FROM EMPLEADO E
WHERE E.VENTAS IS NOT EMPTY
Existen dos tipos de declaraciones:
 Declaraciones de Rango Variable: Una variable de identificación puede extenderse sobre el
abstract schema type de un entity bean. En el ejemplo siguiente, una variable de identificación
llamada E representa el esquema del llamado EMPLEADO:
FROM EMPLEADO E
También puede incluir el operador opcional AS:
FROM EMPLEADO AS E
 Declaraciones de miembros de colecciones: una variable de identificación puede representar
un miembro de una colección de entity beans. Una declaración de miembro de colección debe
incluir el operador IN, pero puede omitir el operador AS. En el siguiente ejemplo, la variable
de identificación V representa a un miembro de la colección VENTAS.
FROM EMPLEADO E, IN (E.VENTAS) AS V

Sentencia Where
La sentencia WHERE especifica una expresión condicional que limita el valor retornado por la
consulta. La expresión retorna todos los valores para los cuales la expresión es TRUE. La sentencia
WHERE es opcional, aunque se usa comúnmente en las queries. Si esta sentencia es omitida,
entonces la query retorna todos los valores.

Literales:
Cuando queremos incluir valores literales dentro de una consulta QL deberemos distinguir algunos
casos.
- Literales String: un literal string se cierra con comillas simples: ‘Jorge’. Si el string lleva una
comilla simple, esto se indica insertando dos comillas simples: ‘Jorge’’s’ .
- Literales numéricos: existen dos tipos, exactos y aproximados. Un literal numérico exacto es
un número sin punto decimal: 65, -233, +12. Un literal numérico aproximado es un valor
numérico con punto decimal: 57., -85.7, +2.1 .

Parámetros de entrada:
Ya vimos anteriormente que un parámetro de entrada es designado por un ‘?’ seguido por un
número entero. Por ejemplo, el primer parámetro de entrada es ?1, el segundo ?2, etc. Las
siguientes reglas se aplican a los parámetros de entrada:
- Sólo se pueden usar en la sentencia WHERE
- Su uso es restringido a expresiones condicionales
- Deben ser numerados, comenzando en 1.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- El número de parámetros de entrada en la sentencia WHERE no debe exceder el número de
parámetros en entrada en el correspondiente finder o método de selección.
- El tipo de parámetro de entrada debe coincidir con el argumento correspondiente en el finder
o método de selección.
Dentro de WHERE podemos hacer uso de operadores aritméticos, de comparación y lógicos:

Con la expresión BETWEEN determinamos el rango de valores que devolverá nuestra consulta. Las
siguientes expresiones son equivalentes:
p.age BETWEEN 15 AND 19
p.age >= 15 AND p.age <= 19
Las siguientes expresiones también son equivalentes:
p.age NOT BETWEEN 15 AND 19
p.age < 15 OR p.age > 19
IN: La expresión IN determina si un string pertenece o no a cierta cadena de caracteres.
En el siguiente ejemplo, si el país es UK la expresión es verdadera. Si el país es Perú, entonces es
falsa.
o.country IN (‘UK’, ‘US’, ‘France’)
LIKE: la expresión LIKE determina caracteres específicos que buscaremos en un string. Ej:
- (%) representa cero o mas caracteres
- (_) representa cualquier carácter individual
- ESCAPE se puede utilizar para buscar los caracteres _ y %

En la siguiente tabla podemos ver algunos ejemplos de su empleo dentro de expresiones de QL y los
valores que encontraría o no encontraría en su búsqueda:

Tambien EJB QL incluye diferentes funciones útiles, las cuales se encuentran listadas a continuación:
Sintaxis de la función Operación realizada

CONCAT (String, String) Concatenación de dos cadenas

LENGTH (String) Tamaño de una cadena

LOCATE (String, String [, start]) Localizar la posición de una subcadena


dentro de otra

SUBSTRING (String, start, lenght) Extraer una subcadena de otra

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
indicando la posición donde
comenzamos a extraerla y el tamaño de
la subcadena a extraer

MOD (int, int) Extraer el módulo de dos números.

Sentencia ORDER BY
Como su nombre lo dice, la sentencia ORDER BY ordena los valores retornados por la consulta.
Se puede especificar si queremos los objetos ordenados ascendente o descendentemente con las
palabras ASC (default) y DESC.

Restricciones
Hay una serie de restricciones importantes que conviene conocer bien en el lenguaje QL de EJB:
- Los comentarios no están permitidos.
- Para comparar valores de fechas y tiempo en una query EJB QL, se debe usar el tipo long
para representar los valores en milisegundos.
- No se debe usar los objetos java.util.Date ni java.sql.Time en comparaciones EJB QL.
- Como el soporte para los tipos BigDecimal y BigInteger es opcional en contenedores EJB 2.1,
las aplicaciones que usen estos tipos en una consulta EJB QL pueden no ser soportadas.
- Dos entity beans de tipos diferentes no pueden ser comparados.

Ver Video: Creación de un Bean con acceso a datos,


en la Unidad 7, en el Módulo 6,

Laboratorio: Persistencia POJO


Objetivos
 Conocer la persistencia EJB.
 Creación de clases POJO’s dentro del entorno Java JEE.

Enunciado
Vamos a realizar una aplicación que creará tablas en nuestra base de datos a partir de entidades de
un EJB.
Para ello, utilizaremos la tecnología EJB y acceso a la base de datos mediante unidades de
persistencia.
Vamos a visualizar un ejemplo en el que crearemos un acceso a la base de datos Oracle y nos
crearemos tablas desde entidades creadas en nuestro proyecto.
Nos creamos un nuevo proyecto.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Lo llamaremos AplicacionJTA.

Utilizaremos el servidor GlassFish y no seleccionaremos ningún Framework.

Ahora sobre nuestro proyecto, vamos a agregarnos una unidad de persistencia que es el objeto
encargado de conectar nuestras entidades con la base de datos.
Seleccionamos New  Other.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En la pestaña de Persistence, seleccionamos el objeto Persistence Unit.

Ahora nos debemos de crear una conexión sobre la base de datos Oracle. Dicha conexión quedará
guardada en nuestro IDE NetBeans para futuras acciones.
Seleccionamos del desplegable Data Source la opción New Data Source…

Nos aparecerá una ventana en la que debemos seleccionar la conexión de la base de datos y el
nombre del JNDI. Como JNDI pondremos CONNECTIONORACLE y seleccionáramos la opción New
Database Connection…

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Tendremos un desplegable dónde nos mostrarán los diferentes drivers para conexión de base de
datos instalados con NetBeans. Seleccionamos New Driver.

Buscamos el driver de Oracle.

Una vez que hemos seleccionado nuestro driver de Oracle, debemos configurar los elementos
necesarios para trabajar con el servidor.
Host: LOCALHOST
PORT: 1521
SERVICE ID: XE
USER NAME: SYSTEM
PASSWORD: 12345 (Password que hayamos creado para SYSTEM en Oracle)

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Pulsamos en siguiente y nos mostrará una pantalla en la que podríamos seleccionar el propietario de
la base de datos desde el que deseamos visualizar las tablas.
Dejamos por defecto nuestro usuario SYSTEM y finalizamos.

Ahora ya habremos vuelto a la ventana de Persistence Unit.


La opción más importante es CREATE o DROP AND CREATE.
Dichas opciones, permiten crear la base de datos o eliminar la base de datos (si existe) para
posteriormente eliminarla.
Si la base de datos existiera, la eliminaría para crearla!!!

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como podemos comprobar en la unidad de persistencia, podríamos cambiar las opciones cuando lo
necesitemos.

Nos habrá creado un fichero persistence.xml.

Ahora nos vamos a crear un paquete para poner ahí las entidades.

Lo llamaremos packagejta

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Sobre nuestro paquete, incluiremos una nueva Entity Class desde la carpeta Persistence.

Nuestra clase se llamará Jugador y nos crearemos una clave primary key de tipo Integer.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ahora vamos a implementar propiedades y características de la clase.
Nos creamos tres propiedades.
private String NombreJugador;
private String Posicion;
private int Calidad;

Vamos a encapsular los campos y crearnos sus métodos Getter y Setter.

Ahora vamos a implementar algo el código de la clase con constructores para facilitarnos la
programación posterior.
public Jugador()
{
this.NombreJugador = "";
this.Posicion = "";
this.Calidad = 0;
}
public Jugador(int idjugador, String nombrejugador, String posicion, int calidad)

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
{
this.id = idjugador;
this.NombreJugador = nombrejugador;
this.Posicion = posicion;
this.Calidad = calidad;
}
La creación de la tabla jugador en la base de datos la realizaremos desde un Servlet.
Nos creamos un nuevo Servlet sobre el proyecto.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Lo llamaremos ServletJTA

Incluimos su información en el descriptor de despliegue de la aplicación.

Ahora vamos a utilizar el editor de NetBeans para generarnos los objetos de la unidad de
persistencia. Para ello, seleccionamos con el botón derecho sobre nuestro código Persistence  Use
Entity Manager

Nos generará un método para acceder a la unidad de persistencia. Nosotros vamos a cambiar su
código para adaptarlo y lo renombraremos. Este es el códido del método que debemos realizar.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("AplicacionJTAPU");
public void CrearBBDD()
{

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
ArrayList<Jugador> jugadores = new ArrayList<Jugador>();
Jugador j = new Jugador();
j.setId(1);
j.setNombreJugador("Iniesta");
j.setCalidad(9);
j.setPosicion("Mediapunta");
jugadores.add(j);
j = new Jugador();
j.setId(2);
j.setNombreJugador("Xavi Alonso");
j.setCalidad(8);
j.setPosicion("Mediocentro");
jugadores.add(j);
j = new Jugador();
j.setId(3);
j.setNombreJugador("Iker Casillas");
j.setCalidad(10);
j.setPosicion("Portero");
jugadores.add(j);

for (Jugador jugador : jugadores)


{
em.persist(jugador);
}
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
} finally {
em.close();
}
}
Ahora vamos a implementar la llamada al servlet.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
this.CrearBBDD();
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ServletJTA</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>DATOS CREADOS CORRECTAMENTE</h1>");
out.println("</body>");
out.println("</html>");
} catch (Exception e) {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ServletJTA</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>EXCEPCION!!</h1>");

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
out.println("<h1>"+e.toString()+"</h1>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
A continuación, vamos a escribir un formulario en la página index.jsp que realizará la llamada al
Servlet
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<form name="form1" action="ServletJTA">
<input type="submit" value="Crear BBDD con jugadores">
</form>
</body>
</html>
Por último, agregamos el driver oracle

La estructura de nuestro proyecto quedaría de la siguiente forma:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ejecutamos la aplicación completa con la tecla F6 y comprobaremos su resultado.

Si hacemos la consulta a Oracle, veremos que ha almacenado los datos correctamente.

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 8. Desarrollo de Aplicaciones Java EE
Mediante el Uso de Mensajes

Objetivo
Conocer y manejar los beans controlados o conducidos a través de mensajes.

Introducción
El servicio de mensajería es un método de comunicación entre componentes de software o
aplicaciones. Es un sistema de estilo peer-to-peer, donde un cliente puede enviar y/o recibir
mensajes de cualquier otro cliente. Cada cliente se conecta a un agente de mensajería que le
permite crear, enviar, recibir y leer mensajes. Un servicio de mensajería permite comunicación
distribuida "libremente unida".

Un emisor envía un mensaje y el receptor lo recibe, pero no necesariamente deben estar disponibles
al mismo tiempo. Es más, tanto emisor como receptor deben conocer solamente el formato del
mensaje y dónde debe éste ser enviado. Esta característica lo diferencia de sistemas
"estrechamente unidos", como RMI, que requiere que la aplicación sepa los métodos de la aplicación
remota. El servicio de mensajería también se diferencia de los emails dada su naturaleza de
comunicación. La Java Message Service API (JMS) permite a las aplicaciones crear, enviar, recibir
y leer mensajes.
Por lo tanto, JMS es el API de Servicios de Mensajería de Java, hoy en día es un estándar de
mensajería para sistemas empresariales de mensajes, que permite a los componentes de
aplicaciones basados en la plataforma de Java 2 crear, enviar, recibir y leer mensajes.
JMS es considerado un middleware (capa media) en la comunicación entre
dos aplicaciones, haciendo posible que esta comunicación sea confiable de manera síncrona y
asíncrona.

Define un set de interfaces y semánticas para que los programas Java puedan comunicarse con
otros sistemas de mensajería. Fue creada como un estándar y apunta a la portabilidad de las
aplicaciones JMS, lo que no quita que uno pueda hacer aplicaciones de mensajería sofisticadas.
Además de permitir una comunicación "libremente unida", permite que sea asíncrona y confiable.
La comunicación asincrónica es una de las principales características de JMS y de los sistemas de
mensajería en general, pues permite que la aplicación origen envíe el mensaje, para que el sistema
o servidor de mensajes (middleware) lo reciba y lo envíe a la aplicación destino cuando esta se
conecte al servidor; como se puede entender a diferencia de una comunicación sincrónica
(cliente/servidor) en este tipo de comunicación no se requiere que la aplicación destino este
presente al momento del envío del mensaje.
La arquitectura de una aplicación JMS se compone de:
- Un proveedor JMS, que implementa las interfaces y provee características administrativas y
de control.
- Clientes JMS o nativos, que son aplicaciones o componentes que emiten y reciben mensajes.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- Mensajes, que son los objetos comunicados.
- Objetos administrados, que son objetos preconfigurados para ser usados por el cliente. Éstos
son o "connection factories" o "destinations".

Dominios de Mensajes
La especificación JMS implementa dos modelos o dominios de mensajes, los cuales define el tipo de
aplicación que se puede desarrollar, y estos son:
- Dominio punto a punto.
- Dominio publicador/suscriptor.
La posibilidad de implementación depende del proveedor JMS que se utilice, el proveedor JMS del
J2EE soporta ambos dominios, y un cliente JMS puede combinar ambos dominios para extender el
poder y la funcionalidad de los productos de mensajería.

Antes de JMS, los productos de mensajería soportaban comunicación point-to-point y


publish/subscribe. JMS provee un dominio separado para cada alternativa. Un proveedor JMS
independiente puede proveer una o ambas, pero un proveedor JEE debe implementar
necesariamente ambas.

Dominio punto a punto(PTP)


Este modelo implementa un tipo de conexión punto a punto, es decir con solo dos extremos en la
comunicación: un productor y un consumidor; está construido bajo el concepto de colas de
mensajes (queues) donde el primer mensaje que llega es el primero que se entrega o consume.

En esta metodología basada en la utilización de colas, un emisor envía un mensaje a la cola y el


receptor puede retirarlo de ella cuando quiera. La cola almacena los mensajes hasta que son
retirados o hasta que expiran.
Este modelo presenta las siguientes características:
- A una cola de mensajes puede conectarse más de un productor así como más de un
consumidor.
- Un mensaje puede ser leído por un solo consumidor.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- El productor y el consumidor de mensajes trabajan de forma independiente, es decir el
receptor del mensaje lo puede leer sin necesidad de que el cliente productor este en
ejecución y viceversa. No hay dependencia temporal entre ambos.
- Un consumidor de mensajes siempre tiene que confirmar la lectura o recepción del mismo a
la cola de mensajes, para que esté pueda ser vaciado, caso contrario una vez que el cliente
consumidor finalice o cierre su conexión con la cola, el mensaje podrá ser leído por otro
consumidor en el caso de existir o por el mismo una vez que establezca nuevamente la
conexión con la cola.

Qué son las colas de mensajes


Supongamos que existen 2 aplicaciones, Dib y Gaz. Dib sabe comer, y Gaz sabe hacer tostadas.
Cuando Dib tiene hambre, necesita realizarle un pedido a Gaz ("hazme 3 tostadas"). Usualmente,
cuando Dib se levanta por la mañana le pide a Gaz las tostadas, y espera hasta que estén listas. Y
este es el comportamiento que usamos generalmente en nuestras aplicaciones: al invocar a otra
aplicación nuestra, lo hacemos via un EJB, y esperamos una respuesta "en el momento" (sincrónica)
de la operación.
Ahora bien, hace unas semanas que Gaz consiguió un trabajo, así que no está durante toda la
mañana. Y Dib estudia de noche y vuelve tarde, cuando Gaz ya está durmiendo. ¿Cómo comunicar
entonces a estas dos aplicaciones, si ambas pueden no estar online en el mismo momento?
La solución a esto sería que Dib dejara una "petición" en algún lado (¿un papelito en la heladera?), y
Gaz lo leyera cuando tenga tiempo y pueda cocinar las tostadas para Dib.
Justamente, esta comunicación asincrónica es el principio de la cola de mensajes.

La cola de mensajes
Una cola de mensajes es un lugar común (la heladera) donde algunas aplicaciones publican
mensajes, que son consumidos por otras. Existen así 4 componentes principales en un sistema de
mensajería:
- publicador, es decir, quien publica un Mensaje en una Cola
- consumidor, quien consume Mensajes de una Cola
- mensaje, que tiene algún formato que tanto publicador como consumidor conocen.
- cola, que es el lugar donde publicadores y consumidores se conectan y comunican a través
de mensajes.
Es importante destacar que es un sistema asíncrono: el publicador y el consumidor no necesitan
estar disponibles a la vez, ya que la cola actúa de intermediario, guardando y distribuyendo los
mensajes a medida que el consumidor pueda atenderlos.

El API de JMS. Tipos de destinos


En JMS existen dos tipos de destinos: Queue (colas) y Topic.

Queue
En las Queue, existen uno o varios publicadores, y un consumidor. Los publicadores van dejando sus
mensajes en la cola, y son tomados en orden por el consumidor (y luego se van descartando). Si el
consumidor no está disponible, la cola va guardando ("encolando") los mensajes, de manera que el
consumidor pueda retomar su procesamiento cuando vuelva a estar online.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
a) Dominio publicador/suscriptor
En este modelo el cliente publicador direcciona los mensajes a un destino conocido para este
dominio como tema (topics), los cuales pueden ser recibidos por todos los suscriptores de ese
asunto. Los Topic siguen el modelo "publicador/subscriptor". Uno o varios consumidores se
"suscriben" al Topic, y van recibiendo los mensajes que se publican. Cuando se desconectan dejan
de recibir esos mensajes, y los pierden.
En JMS los clientes se suscriben a un tópico, el que se encarga de recibir los mensajes de los
publicadores y entregarlos a los subscriptores. En esta modalidad hay dependencia temporal
dado que un cliente suscrito puede consumir mensajes enviados solamente después de que se
suscribe. JMS da más flexibilidad y la confianza del método punto a punto vía las suscripciones
duraderas ("durable subscriptions") donde un subcriptor puede recibir mensajes aun estando
inactivo.

Las características presentes en este dominio son:


- Un tema de mensaje puede tener múltiples publicadores y múltiples suscriptores.
- Cada mensaje puede tener múltiples suscriptores.
- Los publicadores y suscriptores trabajan de forma sincronizada y dependiente. Un cliente que
se suscribe a un tema, puede consumir solo los mensajes publicados después de que el
cliente haya creado la suscripción y debe continuar activo para poder consumir los mensajes.

Objetos administrativos
Son objetos creados con herramientas de administración del proveedor JMS,y son el punto de enlace
de este con los clientes JMS.
Existen dos tipos de objetos administrativos:
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- ConnectionFactory: Son objetos que los clientes usan para establecer una conexión con el
proveedor JMS.
- Destination: Un destination es el objeto que un cliente usa para especificar el destino de los
mensajes producidos y la fuente de los mensajes a consumir, es decir, ¿a dónde envió y de
dónde recibió?
Estos dos objetos son dependientes y necesarios para establecer una comunicación entre el cliente y
el proveedor JMS, y son almacenados por el administrador en le JNDI (Java Naming and Directory
Interface) para que puedan ser accedidos de manera local o remota desde los clientes.

Conexiones
Las conexiones son objetos del API JMS cuya función es la de encapsular conexiones virtuales con el
proveedor JMS, y puede representar un socket abierto TCP/IP entre el proveedor y el cliente.
Este objeto es llamado dentro del API JMS como Connection y es usado por los clientes para crear
una o más sesiones.
Existen dos interfaces de conexión según el dominio que se vaya a implementar y son:
“QueueConnection” para un dominio punto a punto.
“TopicConnection” para un dominio publicador/suscriptor.

Sesiones
Las sesiones son entidades JMS que soportan la transaccionalidad y el consumo de mensajes
asincrónico, permitiendo crear productores de mensajes, consumidores de mensajes y mensajes.
Su implementación se la puede hacer por las interfaces TopicSession o QueueSession según el
dominio de mensajes utilizado por parte del cliente.

Productores y Consumidores de Mensajes


Un productor de mensajes es un objeto JMS creado por una Session, y es usado para enviar
mensajes a un destino. Su implementación en un dominio punto a punto es conocida como
QueueSender y en un dominio publicador/suscriptor se la conoce como TopicPublisher.
Un consumidor de mensajes igual que un productor es creado por una Session y se lo usa a
diferencia del productor para recibir los mensajes que fueron enviados o publicados en un destino.
Para un dominio punto a punto el objeto es del tipo QueueReceiver mientras que para un dominio
suscriptor/receptor se lo conoce como TopicSuscriber.
El consumo de mensajes en la especificación JMS se lo puede hacer de forma sincrónica y de
forma asincrónica:
- Sincrónica, a través de solicitar explícitamente el mensaje al destino, haciendo una llamada al
método receive, este método puede bloquear la ejecución de una rutina hasta que se recepte la
llegada de un nuevo mensaje o por un límite de tiempo determinado en caso de no recibir
ningún mensaje.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- Asincrónica, por medio de la implementación de un escuchador de mensajes o más conocido
como MessageListener, el cual llama automáticamente a la ejecución del método onMessage
cada vez que un mensaje llega a un determinado destino, pudiendo ejecutarse de manera
paralela varias llamadas a este método y las acciones que este ejecuta.

Mensajes
El principal propósito de un sistema de mensajería es el producir y consumir mensajes que puedan
ser usados por otras aplicaciones de software, siendo entonces los mensajes el corazón del sistema.
La estructura de un mensaje en JMS es:
- Una cabecera,
- Propiedades o atributos (opcionales) y,
- Cuerpo del mensaje (opcional).

Cabecera
Parte esencial de un mensaje java que contiene una serie de campos predefinidos que permite a los
proveedores y clientes identificar y encaminar los mensajes. La siguiente tabla lista los campos que
forma parte de la cabecera:
Campo Tipo de Dato Descripción
JMSMessageID String Número que identifica unívocamente al mensaje.
Solo se puede consultar una vez que esta enviado el
mensaje.
JMSDestination Destination El destino a donde se envía el mensaje.
JMSDeliveryMode int Puede ser de tipo PERSISTENT, entonces se envía una
única vez, o de tipo NON_PERSISTEN, de manera que
se envía como mucho una vez, lo cual incluye también
que no sea enviado nunca.
PERSISTENT y NON_PERSISTENT están definidas como
constantes.
JMSTimestamp long Hora a la que se envió el mensaje.
JMSExpiration long Hora hasta la cual el mensaje es válido, si es 0 quiere
decir que no caduca nunca.
JMSPriority int Prioridad del mensaje de 0 a 9, siendo 0 la más baja.
JMSCorrelationID String Este campo se usa para relacionar una respuesta a un
mensaje, se copia aquí el id de mensaje del mensaje al
que se está respondiendo.
JMSReplyTo Destination Especifica el lugar a donde se deben enviar las
respuestas al mensaje actual.
JMSType String Este campo lo puede usar el programa de mensajería
para almacenar el tipo del mensaje.
JMSRedelivered boolean Indica que el mensaje ha sido enviado con anterioridad
pero el destino no lo ha procesado, por lo que se renvía.
Propiedades: son campos que permiten fijar características adicionales a las de la cabecera, son
propiedades personalizadas para un mensaje en particular.
Cuerpo del mensaje: es el mensaje en sí, los tipos de mensajes soportados por JMS son:
- StreamMessage: Contiene un stream de datos que se escriben y leen de manera
secuencial.
- MapMessage: Contiene pares nombre-valor.
- TextMessage: Contiene un String.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- ObjectMessage: Contiene un objeto que implementa la interfaz Serializable, permitiendo
almacenar cualquier objeto de java.
- BytesMessage: Contiene un stream de bytes.
Por su naturaleza, los mensajes son asíncronos pues no hay dependencia temporal entre la
producción y el consumo de un mensaje. JMS ahonda esto y dice que los mensajes pueden ser
consumidos de forma:
- sincrónica: el cliente extrae explícitamente el mensaje vía el método "receive", que usa
timeout.
- asincrónica: el cliente registra un "message listener". Similar a un "event listener", el
mensaje es obtenido vía el método "onMessage".

Clientes JMS
Son las aplicaciones que consumen y producen los mensajes, para dichas acciones deben cumplir
una serie de requisitos en común antes de poder ejecutarlas, los mismos que son:
1. Obtener el objeto ConnectionFactory del JNDI.
2. Obtener un destino o fuente, mediante el objeto Destination a través de JNDI.
3. Establecer una conexión con el proveedor JMS a través del ConnectionFactory.
4. Usar Destination para establecer la sesión con el proveedor, para poder crear, enviar o recibir
los mensajes tras crear ya sea un productor o un consumidor de mensajes.

Ver Video: JavaEE implementando JMS, en la Unidad 8,


en el Módulo 6, en la plataforma elearning
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 9. Desarrollo de Beans Controlados
por Mensajes
Objetivo
Conocer y manejar los beans controlados o conducidos a través de mensajes.

Beans dirigidos por mensajes o Message Driven Bean


(MDB)
Una rápida definición de los beans dirigidos por mensajes o MDB puede ser la siguiente: Un bean
conducido por mensajes es un componente EJB 3.0 que funciona como un consumidor
asincrónico de mensajes. Un MDB no tiene un estado específico del cliente pero puede contener
estados de tratamiento de mensajes como una conexión a una base de datos o referencias de
objeto a otro EJB. Es similar a un stateless Session Bean pues sus instancias tienen una corta
vida, por no guardar un estado de un cliente específico y porque varias instancias pueden ser
ejecutadas al mismo tiempo.
Son el tercer tipo de beans propuestos por la última especificación de EJB. Viven en la lógica de
negocio. Actúan como un oyente para un tipo de mensaje en particular, tal como la API del servicio
de mensajes de Java. Así, los mensajes pueden enviarse desde cualquier componente J2EE (una
aplicación cliente, otro enterprise bean, o un componente Web) o por una aplicación o sistema JMS
que no use la tecnología J2EE. Esta circunstancia permite ahorrar recursos de servidor en
comparación con una recepción sincrónica directa de mensajes del servicio de mensajes de Java
(JMS). Además, estos beans permiten que las aplicaciones J2EE reciban mensajes JMS de forma
asíncrona.
Como hemos visto el apartado anterior, el servicio JMS funciona a través de colas de mensajes, que
es donde los clientes envían sus peticiones, y estas colas son controladas por los Message Driven
Beans, los cuales procesan los mensajes que hay en ellas y ejecutan ciertos servicios dependiendo
del mensaje procesado. Este tipo de beans se aproximan más a la forma conceptual de los Stateless
Session Bean en el sentido que son beans que no deben almacenar estado alguno. Cuando un
mensaje llega a la cola el contenedor hace una llamada al método onMessage del Message Driven
Bean y en este método el bean debería invocar a métodos de otros sesión bean o realizar la lógica
de negocio de debiera ejecutar. Es más conveniente no tener aquí lógica de negocio, sino hacer
invocaciones a métodos de otras clases que sí se encarguen de realizar lógica de negocio.
Una posible estructura es la de la imagen: una cola JMS se ubica entre el contenedor EJB y los
clientes. La idea es que el contenedor, quien maneja el pool de MDBs, y los clientes puedan
"contactarse" vía la cola JMS.

En resumidas cuentas, los beans dirigidos por mensajes pueden escuchar mensajes de un
servicio de mensajes JMS. Los clientes de estos beans nunca los llaman directamente, sino que es
necesario enviar un mensaje JMS para comunicarse con ellos.
Asimismo, cuando se produce la invocación de un método de un MDB desde un cliente, la llamada
no bloquea el código del cliente y el mismo puede seguir con su ejecución, sin tener que esperar
indefinidamente por la respuesta del servidor. De este modo, el hilo de ejecución de un cliente no se
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
bloquea cuando está esperando que se complete algún método de negocio de otro Enterprise
JavaBean.

Tampoco los beans dirigidos por mensajes necesitan objetos EJBObject porque los clientes no se
comunican nunca con ellos directamente. Un ejemplo de bean dirigido por mensajes podría ser un
bean ListenerNuevoCliente que se activara cada vez que se envía un mensaje comunicando que se
ha dado de alta a un nuevo cliente.
No representan directamente datos compartidos de la base de datos, pero pueden acceder y
actualizar estos datos.
Podemos hacer la siguiente analogía: los MDBs son a JMS lo que JDBC es al lenguaje de consultas
SQL.
En EJB 3.0, la clase de un MDB puede ser un POJO, o bien, no necesita implementar javax.ejb.
MessageDrivenBean, usando la anotación @MessageDriven. Además, las anotaciones son
usadas para varias características, incluidas el destino y las factories (topic o queue). Se puede usar
inyección para adquirir un MessageDrivenEntityContext.
Para implementar un Message Driven Bean se debe:
1. Configurar el proveedor del servicio de mensajería.
2. Crear la clase MDB.
3. Configurar la información del proveedor (vía @ActivationConfigProperty).
4. Añadir un miembro de datos para el MessageDrivenContext. Se puede usar "resource
injection" para no usar métodos get/set.
5. Implementar la interfaz apropiada de message listener. Para un MDB JMS, hay que
implementar la interfaz javax.jms.MessageListener y así tendremos disponible el método
onMessage.
Opcionalmente, se puede:
- Implementar javax.ejb.TimedObject. Se puede usar MessageDrivenContext para configurar
un javax.ejb.
- TimerService si este paso se implementa.
- Definir métodos de callback de ciclo de vida con anotaciones apropiadas (@PostConstruct y
@PreDestroy).
- Completar la configuración del MDB.
El modelo básico de comunicación efectiva consiste de 5 elementos:
1. Emisor: MessageProducer
2. Receptor: MessageConsumer con MessageListener
3. Mensaje: Message
4. Canal: Connection, Session, Topic/Queue, etc.
5. Retorno: de acuerdo a lo programado en onMessage

Diseño de una clase para un MDB:


Pensados para la mensajería asincrónica, suelen funcionan sobre un JMS y en ese sentido resultan
muy interesantes para la integración de sistemas.
Para declarar un MDB sólo hemos de establecer la anotación @MessageDriven a una clase que
implemente la interface MessageListener, e indicar el nombre de la cola del contenedor, la cuál es
accesible vía JNDI, que va a controlar el MDB. Veamos un ejemplo:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@MessageDriven( mappedName = "jms/Queue" )
public class AsynchronousService implements MessageListener {

public void onMessage( Message message ) {


TextMessage textMessage = (TextMessage)message;
System.out.println( textMessage.getText() );
}
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Un primer elemento a considerar es la interface de negocio que ha de ser una interfaz message-
listener determinada por el tipo de mensajería en uso para el bean.
Por su parte la clase bean MDB será señalada con la anotación @MessageDriven que especifica la
cola de mensajes que el MDB monitorea.
Esta clase necesita implementar la interfaz MessageListener, que define sólo al método
onMessage().
En resumen, cada MDB debe implementar una interfaz message-listener apropiada para el tipo de
mensajería que éste soporta, o podría designar su interfaz message-listener usando la anotación
@MessageDriven. En consecuencia, para declarar un MDB solo hace falta establecer la anotación
@MessageDriven a una clase que implemente la interfaz MessageListener, e indicar el nombre de la
cola del contenedor que va a controlar el MDB.
Cuando un mensaje llega a la cola de mensajes del MDB el contenedor llama al método onMessage()
de esta clase bean y le pasa el mensaje recibido mediante un parámetro.
Por otro lado, para enviar un mensaje, hay que referenciar al MDB, el cliente usa el API estándar
JMS para obtener la cola de mensajes mediante su nombre JNDI (cola/mdb) y entonces él envía el
mensaje a la cola.

Ciclo de Vida de MDB


Los MDBs también procesan lógica de negocio, pero un cliente nunca invoca a un método de un MDB
directamente. El sistema de mensajería asincrónica propone la utilización de una capa intermedia en
la comunicación entre el productor y el consumidor del mensaje. En EJB 3, esta capa se llama MOM
(Message-oriented middleware). Básicamente la MOM es un software que permite funcionar como
servidor de mensajería, reteniendo los mensajes del productor y enviándolos posteriormente al
consumidor en el momento en que esté disponible para recibirlo. Es un funcionamiento similar al de
un servidor de correo electrónico. Algunos ejemplos típicos de servidores de mensajería son
WebSphere MQ de IBM, SonicMQ, Advanced Queueing de Oracle y TIBCO.

Los siguientes eventos de ciclo de vida son soportados por el MDB: PostConstruct y PreDestroy

Diferencias con los beans de sesión y de entidad


La diferencia más visible es que los clientes no acceden a los beans dirigidos por mensajes mediante
interfaces, sino que un bean dirigido por mensajes sólo tienen una clase bean.
En muchos aspectos, un bean dirigido por mensajes es parecido a un bean de sesión sin estado.
 Las instancias de un bean dirigido por mensajes no almacenan ningún estado conversacional
ni datos de clientes.
 Todas las instancias de los beans dirigidos por mensajes son equivalentes, lo que permite al
contenedor EJB asignar un mensaje a cualquier instancia. El contenedor puede almacenar

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
estas instancias para permitir que los streams de mensajes sean procesados de forma
concurrente.
 Un único bean dirigido por mensajes puede procesar mensajes de múltiples clientes.
Las variables de instancia de estos beans pueden contener algún estado referido al manejo de los
mensajes de los clientes. Por ejemplo, pueden contener una conexión JMS, una conexión de base de
datos o una referencia a un objeto enterprise bean.
Cuando llega un mensaje, el contenedor llama al método onMessage del bean. El método onMessage
suele realizar un casting del mensaje a uno de los cinco tipos de mensajes de JMS y manejarlo de
forma acorde con la lógica de negocio de la aplicación. El método onMessage puede llamar a
métodos auxiliares, o puede invocar a un bean de sesión o de entidad para procesar la información
del mensaje o para almacenarlo en una base de datos.
Un mensaje puede enviarse a un bean dirigido por mensajes dentro de un contexto de transacción,
por lo que todas las operaciones dentro del método onMessage son parten de un única transacción.
Los message‐driven beans en cierto modo se parecen a los stateles ssession beans:
- No retienen datos acerca de un cliente específico.
- Todas las instancias de un message‐driven bean son equivalentes, por lo que el contenedor
puede realizar un pool con estas instancias para permitir transmisiones de mensajes
concurrentes.
- Un único message‐driven bean puede procesar mensajes de diferentes clientes.

Un ejemplo completo
Ejemplo avanzado donde se puede ver cómo un Message Driven Bean recibe un mensaje que algún
cliente ha enviado a un Topic y a su vez, responde renviando una respuesta al Topic al que se le
indica que responda en el propio mensaje recibido.
Se puede ver también el uso de los métodos con anotaciones:
@PostConstruct - para crear la conexión, ejecutado después de la llamada al constructor
@PreDestroy - que indica que dicho método se ejecuta antes de retirar el Enterprise Bean del
contenedor
El ReplyBean queda de la siguiente forma:
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.ejb.ActivationConfigProperty;
import javax.jms.ConnectionFactory;
import javax.jms.Topic;
import javax.jms.Connection;
import javax.jms.Session;
import javax.jms.MessageProducer;
import javax.jms.MessageListener;
import javax.jms.Message;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.JMSException;
import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.logging.Logger;
Esta clase ReplyMsgBean es un bean dirigido por mensaje que implementa la interfaz
javax.jms.MessageListener. La clase a su vez está definida como pública, nunca como final o
abstracta.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@MessageDriven(mappedName = "jms/Topic")
public class ReplyMsgBean implements MessageListener {
static final Logger logger = Logger.getLogger("ReplyMsgBean");
@Resource(mappedName = "jms/ConnectionFactory")
public ConnectionFactory connectionFactory;
@Resource
public MessageDrivenContext mdc;
Connection con = null;

public ReplyMsgBean() {
}

Aquí se crea la conexión.

@PostConstruct
public void makeConnection() {
try {
con = connectionFactory.createConnection();
} catch (Throwable t) {
// JMSException could be thrown
logger.severe(
"ReplyMsgBean.makeConnection:" + "Exception: "
+ t.toString());
}
}
El método onMessage se declara público, no final o static, marcado con un tipo void, es decir, sin
valor de retorno y con un argumento de tipo javax.jms.Message. Así, se encargará de ofrecer los
contenidos del mensaje y crear una conexión, sesión y producir la réplica, usando como destino el
campo JMSReplyTo para el envío del mensaje. De este modo, el método crea y envía un mensaje,
asignando el encabezado JMSCorrelationID del campo al ID del mensaje enviado y la propiedad ID.
Después se cerrará la conexión.
public void onMessage(Message inMessage) {
TextMessage msg = null;
Session ses = null;
MessageProducer producer = null;
TextMessage replyMsg = null;

try {
if (inMessage instanceof TextMessage) {
msg = (TextMessage) inMessage;
logger.info("ReplyMsgBean: Received message: " + msg.getText());
con = connectionFactory.createConnection();
ses = con.createSession(true, 0);

producer = ses.createProducer((Topic) msg.getJMSReplyTo());


replyMsg = ses.createTextMessage(
"ReplyMsgBean " + "Mensaje procesado: "
+ msg.getText());
replyMsg.setJMSCorrelationID(msg.getJMSMessageID());
replyMsg.setIntProperty(
"id",
msg.getIntProperty("id"));
producer.send(replyMsg);
con.close();
} else {
logger.warning(
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
"Error en el mensaje: "
+ inMessage.getClass().getName());
}
} catch (JMSException e) {
logger.severe(
"ReplyMsgBean.onMessage: JMSException: " + e.toString());
} catch (Throwable te) {
logger.severe(
"ReplyMsgBean.onMessage: Exception: " + te.toString());
}
}

Habilitamos el código para cerrar la conexión.


@PreDestroy
public void endConnection() throws RuntimeException {
System.out.println("En ReplyMsgBean.endConnection()");

if (con != null) {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

Ver Video: Configuración de mensajes en el servidor,


en la Unidad 9, en el Módulo 6, en la plataforma elearning

Laboratorio: Crear Servicio Mensajería


Objetivos
 Conocer la implementación y el funcionamiento de la tecnología JMS.
 Conocer cómo configurar el servidor para poder admitir servicios de mensajería JMS.

Enunciado
Vamos a realizar una aplicación que enviará mensajes al servidor utilizando la tecnología JMS.

Lo primero de todo será irnos a la pestaña Services dentro del entorno gráfico de NetBeans.

Iniciamos el servidor de aplicaciones con el botón derecho y seleccionando Start.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Una vez iniciado el servidor, debemos irnos a la consola de administración del contenedor para
poder visualizar las características propias de JMS. Para ello, seleccionamos la opción View Admin
Console.

Al entrar en la consola de administración de GlassFish, podremos visualizar que tenemos dos


opciones dentro de Recursos JMS.
Fabricas de Conexión y Recursos de destino.
En este apartado sería dónde podríamos configurar nuestros servicios de mensajería para poder
enviar y recibir mensajes mediante MDB.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Pulsamos sobre Nuevo para poder crearnos un nuevo conector sobre JMS.
Lo llamaremos jms/QueueFactory y debe estar activado.

Cuando pulsemos en guardar, veremos sus características.

Ahora pulsaremos sobre Recursos de destino y nos crearemos uno nuevo.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Llamaremos al JNDI jms/Queue y el nombre de nuestro destino será mi destino.
El tipo de recurso será javax.jms.Queue y debe estar activado.

Veremos sus características al guardarlo.

Ahora vamos a probarlo, para ello, nos creamos un nuevo proyecto Enterprise Application.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Llamaremos a la aplicación MiAplicacionMDB y crearemos los proyectos WAR Y EJB.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Sobre el proyecto WAR nos agregamos un nuevo Servlet.

Lo vamos a llamar GeneradorMensajes y lo incluiremos en un nuevo paquete llamado paquetemdb.

No agregaremos la información al descriptor de despliegue.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ahora escribimos la llamada a los recursos del servidor en el servlet escribiendo el siguiente código
dentro de la clase:

@Resource(mappedName="jms/QueueFactory")
javax.jms.QueueConnectionFactory queueConnection;
@Resource(mappedName="jms/Queue")
javax.jms.Queue queue;
Añadimos los import necesarios mediante el entorno NetBeans.

Hacemos un import a la librería import javax.jms.*;


import javax.jms.*;
Implementamos el código de processrequest del servlet:
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet GeneradorMensajes</title>");
out.println("</head>");
out.println("<body>");
Connection connection=queueConnection.createConnection();
Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer=session.createProducer(queue);
MapMessage message=session.createMapMessage();
String nombre = request.getParameter("txtnombre");
String apellido = request.getParameter("txtapellido");
String texto = request.getParameter("txttexto");
message.setString("nombre", nombre);

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
message.setString("apellido", apellido);
message.setString("texto", texto);
producer.send(message);
producer.close();
session.close();
connection.close();
out.println("<h1>Servlet Generador Mensajes</h1>");
out.println("El mensaje se ha enviado correctamente");
}catch (Exception ex)
{
out.println("<h1>Excepcion al enviar el mensaje</h1>");
out.println(ex.toString());
} finally {
out.println("</body>");
out.println("</html>");
out.close();
}
}
Una vez que hemos configurado el servlet para enviar mensajes, es el momento de crearnos un
objeto de la clase Message Driven Bean. Sobre el proyecto EJB agregamos un nuevo objeto
Message-Driven Bean.

Le indicaremos la opción Server Destinations nuestro recurso jms/Queue creado al principio del
laboratorio. Lo llamaremos BeanMDB.

Ahora implementamos el código del Bean.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
package paquetemdb;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
@MessageDriven(mappedName = "jms/Queue", activationConfig = {
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-
acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue =
"javax.jms.Queue")
})
public class BeanMDB implements MessageListener {
public BeanMDB() {
}
@Override
public void onMessage(Message message) {
System.out.println("Mensajes recibidos en el MDB...");
try {
MapMessage msg = (MapMessage) message;
System.out.println("Nombre:" + msg.getString("nombre"));
System.out.println("Apellido:" + msg.getString("apellido"));
System.out.println("Texto:" + msg.getString("texto"));
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
}
Ya tenemos todo configurado para enviar y consumir mensajes, nos quedaría una parte gráfica para
enviar los mensajes. Para ello, utilizaremos la página index.jsp del proyecto WAR.

Implementamos su código:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Enviar mensajes a la cola Queue JMS</h1>

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<form name="form1" action="GeneradorMensajes">
<table border="1">
<tr>
<th>Nombre</th>
<td>
<input type="text" name="txtnombre">
</td>
</tr>
<tr>
<th>Apellidos</th>
<td>
<input type="text" name="txtapellidos">
</td>
</tr>
<tr>
<th>Texto del mensaje</th>
<td>
<textarea name="txttexto" rows="4" cols="20">
</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="Enviar mensaje a la cola">
</td>
</tr>
</table>
</form>
</body>
</html>
Solo nos quedaría probar el proyecto.

Como podemos comprobar, el servlet ha enviado el mensaje.

Y hemos mostrado el mensaje en la consola para el consumidor.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 10. Interceptores

Objetivo
Conocer y manejar los interceptores en EJB.

Introducción. Interceptores y Entity Listener


Los Interceptores son introducidos por la especificación 3.0 y permite la ejecución de código antes
y/o después de la ejecución de un método. Sin duda la introducción de estos nuevos componentes
son más que útiles, pero hay que usarlos con cuidado, ya que pueden deteriorar en gran medida la
performance de una aplicación.
Un interceptor, como su propio nombre indica tiene por misión interceptar algo. Desde este punto de
vista, estamos ante una simple clase de Java cuyos métodos se ejecutan en el momento en que es
llamado el método de otra clase totalmente diferente. Podríamos decir que dicho método interceptor
salta en el intervalo que trascurre entre la llamada a un método y los métodos así invocados.
De este modo, el interceptor permite que podamos monitorizar o auditar el estado del sistema, por
ejemplo, el tiempo que trascurre entre llamadas a los métodos. Este tipo de actividades de
cronometraje, control del rendimiento y de la eficacia de nuestra aplicación o de puntos
determinados de nuestra aplicación son el tipo de situación en donde se muestra la idoneidad de los
interceptores y donde estos cobran sentido. Por otra parte, la presencia del interceptor permite
descargar o liberar al resto de métodos funcionales de estas tareas administrativas o auditoras.
En otras palabras, el interceptor nos abre un ámbito de desarrollo que sin ser paralelo o
multiproceso con respecto a la actividad principal, si que nos permite que podamos separar ciertas
tareas administrativas de lo que sería el proceso principal en sí de la aplicación.
El interceptor se encarga de envolver a un bean de sesión y de interceptar todas las llamadas al
mismo de los métodos.
Un interceptor tiene la función de interceptar una invocación a un método de negocio o un evento
callback de ciclo de vida. A su vez, puede ser un método definido en la clase bean o como una clase
aparte usando la anotación @Interceptors. Se puede usar tanto en session beans y/o message
driven beans, porque una de sus características más relevantes es que carece de estado.
De hecho, el ciclo de vida de una instancia de interceptor es la misma que de la instancia del bean
asociado a él.
Sin embargo, no se pueden implementar dentro de un bean de entidad. Para estos casos, se cuenta
con el Entity Listener que permiten interceptar los métodos de ciclo de vida:
@PostLoad
@PostPersist.
Por lo tanto, aquí no es posible hacer cálculos de tiempo, ni documentar el momento de la llamada
al método o su finalidad. No obstante cabe la opción de programar con código adicional el bean de
entidad para que registre estas actividades, pero no resulta demasiado recomendable porque
supone duplicar el código fuente y sobrecargar las clases involucradas para que realicen tareas que
en principio no les correspondería hacer. El Entity Listener, es la alternativa más aconsejable, dado
que centraliza todos eso método.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Tanto en el caso del Entity Listener como del Interceptor, la clase a vigilar es la que debe determinar
quien se encargará de controlarla.
Por ejemplo, mediante el Deployment Descriptor podemos definir un procedimiento común para
todos de tal manera que todos los session bean y message-driven beans sean auditados por un
interceptor determinado, mientras que los entity beans lo sean a su vez por un único entity listener.
No obstante, esta idea de reducir el procedimiento a un único y común controlador no resulta la
manera más óptima de proceder. Hay que tener en cuenta que no hay manera de activar o
desactivar sobre la marcha los controladores. Es decir, una vez estén definidos en el Deployment
Descriptor, dichos interceptores y entities listener serán llamados siempre, lo que supondrá una
sobrecarga del sistema que en muchos casos puede ser inasumible por innecesario.
En resumen:
- Los métodos interceptores pueden estar en la misma clase a interceptar o en otra aparte.
- Un interceptor se puede aplicar a un sólo método o a todos los de una clase
- Se pueden aplicar varios interceptores a un mismo bean (o método), la llamada pasa a
través de todos ellos.
- Actúan como filtros

La especificación EJB define dos clases de puntos de interceptación:


 la interceptación de método de negocios y
 la interceptación de devolución de llamadas de ciclo de vida
Un interceptor de método de negocios se aplica a invocaciones de métodos del Web Bean por
clientes del Web Bean:
public class TransactionInterceptor {

@AroundInvoke public Object manageTransaction(InvocationContext ctx) { ... }

}
Un interceptor de devolución de llamadas de ciclo de vida se aplica a invocaciones de devolución de
llamadas de ciclo de vida por el contenedor:

public class DependencyInjectionInterceptor {

@PostConstruct public void injectDependencies(InvocationContext ctx) { ... }

}
Una clase de interceptor puede interceptar métodos de devolución de llamadas de ciclo de vida y
métodos de negocios.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Los consejos a seguir para el uso apropiado de los mismos son:

 La clase que implementa el Interceptor debe ser lo más liviana posible, debido a que los
interceptores pueden ser Pasivados por el contenedor, esta operación es considerada muy
costosa, por lo tanto se tiene que tratar de disminuir al mínimo la serialización a disco.
 Utilizar interceptores a nivel de método (method-level Interceptors) y no a nivel de bean
(bean-level Interceptors). Esto permite que los interceptores se llamen únicamente cuando
sea necesario.
 Utilizar la menor cantidad de interceptores.

Interceptor
Veamos un fragmento de código completo para hacernos una primera idea de las características de
implementación de un interceptor:

El código anterior muestra la clase interceptora. Veamos ahora la clase interceptada:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
El modo más sencillo de definir un interceptor es dotar al método correspondiente con la anotación
@AroundInvoke.
El método puede nombrarse de cualquier manera y dar como resultado una instancia de tipo object,
a la vez que esperar como único parámetro una instancia de la interface InvocationContext:
public interface InvocationContext
{
public Object getBean();
public Method getMethod();
public Object[] getParameters();
public void setParameters(Object[] params);
public java.util.Map<String, Object>
getContextData();
public Object proceed() throws Exception;
}
A través de estos parámetros el método de escucha se consigue acceder al objeto:

De ese objeto podemos acceder con los método ilustrados en el cuadro anterior a los métodos
objetivo en concreto -getMethode()- , a sus parámetros - getParameters()-, a modificar dichos
parámetros –setParameters()- incluso antes de que se produzca la llamada al método en sí –
proceed().
Es importante subrayar que un interceptor se activa en el momento en el que se produce la llamada
a un método. Así, proceed() causa la invocación del próximo método. Retorna el resultado de esa
invocación, pero si el método de negocio retorna void entonces proceed retorna null.
Por su parte, con el método getContextData() se pude otorgar al método interceptor una instancia
de la clase Map. A través de esta clase diferentes clases interceptoras pueden intercambiar
información, siempre que todas ellas escuchen o vigilen las mismas llamadas a método. Veamos un
ejemplo:
import javax.interceptor.*;

public class ObtenerTiempo{


@AroundInvoke
Public Object timeTrace(InvocationContext invocation)
Throws Exception {
long inicio=System.currentTimeMillis();
try{
return invocation.proceed();
}finally{
Long final= System. currentTimeMillis();
String clase=invocation.getBean().toString();
String método=invocation.getMethod().getName();
System.out.println(clase +”:”+método+”- >”+ (final-inicio)+”milisegundos”);
}
}
}
www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como vemos en el código fuente anterior, el bloque finally se coló en el método de medición de
manera preventiva para controlar la posibilidad de que se produzca un error.
Vemos ahora como generamos la clase que ha de estar a la escucha mediante la anotación
@Interceptors que debe responder a la siguiente sintaxis:
@Target({CLASS, METHOD}) @Retention (RUNTIME)
Public @interface Interceptors {
Class[] value();
}
Dicha anotación puede realizarse a nivel de método o de clases. Si optamos por la segunda opción
quedarán involucrados en la supervisión todos los métodos existentes en dicha clase. Este sería el
caso que usamos en el siguiente código y que ligaría el interceptor definido en el código anterior con
una clase de un session bean.
@Stateful
@Interceptors(ObtenerTiempo.class)
public class TiempoAdministracionSocioBean
implements TiempoAdministracionSocioRemote {
//código
}
En el siguiente código podemos ver las dos clases interceptoras y los métodos interceptores dentro
de la misma clase:

Deployment Descriptor
Además del establecer el interceptor por el mecanismo ya visto de las anotaciones, también hemos
comentado que existe la posibilidad de definirlo dentro del Deployment Descriptor de nuestra
aplicación. En este caso estaríamos creando una clase interceptor applicable a todos los beans, esto
conviene tenerlo bien presente si es que optamos por esta opción.
En primer lugar, deberemos describir la clase interceptor, para ello disponemos de la etiqueta
dentro del archive ejb-jar.xml. Dicha etiqueta consta a su vez de otras etiquetas
encargadas de reflejar el nombre de la clase interceptora, así como todos los métodos
de la misma. Veamos un fragment de código de ejemplo:
<interceptors>
<interceptor>
<interceptor-class>server.CalcularRespuesta</interceptor-class>
<around-invoke>
<method-name>ObtenerTiempo</method-name>
</around-invoke>
</interceptor>
</interceptors>

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Como vemos hay una clase denominada CalcularRespuesta que cuenta con un método
ObtenerTiempo.
A continuación lo que corresponde hacer es conectar el bean con la clase del interceptor. En este
caso podremos mediante la etiqueta define el método que deberá activarse ante
el interceptor.
<interceptor-binding>
<ejb-name>AdministracionRespuestaEmpleadoBean</ejb-name>
<interceptor-class>server.CalcularTiempo<interceptor-class>
<method>
<method-name>InsertarEmpleado</method-name>
<method-params>
<method-param>java.util.vector</method-param>
</method-params>
</method>
</interceptor-binding>
En el fragmento anterior estamos configurando dos cuestiones:
- La supervisión de un método (InsertarEmpleado) mediante un interceptor (CalcularTiempo)
- El establecimiento de todos los métodos de la clase como supervisables.

No obstante, podemos definir un interceptor genérico para todos nuestros beans incluyendo un
asterisco dentro de la etiqueta
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>server.CalcularTiempo<interceptor-class>
</interceptor-binding>
Mediante la anotación @ExcludeDefaultInterceptors o la etiqueta
podemos forzar la supervisión por un interceptor de una clase
determinada. Por ejemplo en el nivel de método podría hacerse así:
@Stateful
@ExcludeDefaultInterceptors
@Interceptos(CalcularTiempo.class)
Public class TiempoAdministracionEmpleadoBean
Implements TiempoAdministracionEmpleadoRemoto {
//código
}
Mientras que para activar un interceptor común a todos los métodos de la clase a través del
Deployment Descriptor sería así:
<interceptor-binding>
<ejb-name>AdministracionEmpleadoBean</ejb-name>
<interceptor-class>server.CalcularTiempo<interceptor-class>
<exclude-default-interceptors>true<exclude-default-interceptors>
</interceptor-binding>
Si lo que queremos es que un interceptor definido en una clase no afecte a un método determinado
de la misma, entonces tenemos la anotación @ExcludeClassInterceptors. Por ejemplo:
@Stateful
@Interceptos(CalcularTiempo.class)
public class TiempoAdministracionEmpleadoBean
Implements TiempoAdministracionEmpleadoRemoto {
//código

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
@ExcludeClassInterceptors
Public vector<Grupodatos> getEstructura(){
Return getEstructura(null,null,null,true);
}
}
En el código anterior el método getEstructura queda excluido de la supervisión realizada por el
interceptor CalcularTiempo.
Cabe la posibilidad también de combinar las dos anotaciones anteriores -@ExcludeClassInterceptors
y @ExcludeDefaultInterceptors -, de este modo, haremos que un método no pueda ser supervisado
por ninguna otra clase.

Entity Listener
Como hemos dicho anteriormente, un interceptor no puede utilizarse en un entity bean. En este
caso, la supervisión ha de realizarse sobre los métodos del ciclo de vida propios del bean de entidad.
Serían los siguientes:

En este sentido un entity listener sería una clase de java normal, sólo que portadora de uno o varios
métodos definidos con las anotaciones propias del ciclo de vida que acabamos de mostrar en la
imagen anterior. Por ejemplo:

En la imagen anterior vemos dos métodos marcados con las anotaciones @PrePersist y @PostLoad.
Para que un listener de esta clase esté activo deberán cumplirse algunas condiciones:
- Un entity bean que acepte dicha clase como listener

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- bien, una definición del entity listener en el Deployment Descriptor que será aplicado, eso sí,
a todos los entity bean de la aplicación.
Del primer caso tendríamos una implementación del siguiente estilo:

Ahí tendríamos la clase implementada como EntityListener y nos queda su conexión en la clase con
las anotaciones del ciclo de vida:

La variable acct apunta a la clase Account, ligado todo a su vez al evento @PostPersist en el método
newAccountAlert encargado de enviar un mensaje con algunos datos informativos del proceso.
En el caso de que el entity bean y el listener tuvieran los mismos métodos del ciclo de vida, primero
sería llamado el método del listener y después el del entity.
Por su parte, en el Deployment Descriptor podremos definir el entity listener:
- bien en la etiqueta para un entity bean determinado.
- bien en la asignado por defecto a todos los entity bean.

<entity class=”server.TiempoEmpleado” access=”PROPERTY”


metadata-complete=”true”>
<table name=”EMPLEADO”/>

<entity-listeners>
<entity-listener class=”server.RegistrarActividad”>
<post-persist method-name=”postPersist”/>
<post-remove method-name=”postRemove”/>
<post-update method-name=”postUpdate”/>
<post-load method-name=”postLoad”/>
<entity-listener/>
<entity-listeners/>
</entity>
En la etiquetas post figuran los diferentes eventos del ciclo de vida y sus correspondientes métodos
del listener. Si lo que queremos es el mismo entity listener para todos los entity beans entonces
debemos eliminar la referencia a una clase concreta, en nuestro caso RegistrarActividad, y colocar
la etiqueta
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class=”server.RegistrarActividad”>
<post-persist method-name=”postPersist”/>
<post-remove method-name=”postRemove”/>
<post-update method-name=”postUpdate”/>

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
<post-load method-name=”postLoad”/>
<entity-listener/>
<entity-listeners/>
<persistence-unit-metadata/>
<persistence-unit-defaults/>

Ver Video: Interceptores, en la Unidad 10,


en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 11. Transacciones

Objetivo
Conocer y manejar las transacciones en EJB.

Introducción
En la actualidad las aplicaciones emplean en alguna ocasión transacciones. Este empleo tan
generalizado resulta lógico, puesto que con él aseguramos que una función compleja del sistema se
ejecuta o no con éxito.
A menudo debemos realizar varias operaciones de modificación de base de datos de una manera
conjunta. Por ejemplo pensemos en la transferencia de dinero entre dos cuentas corrientes. Esta
acción tan simple supone realizar dos UPDATE, cada una en una cuenta corriente de un usuario.
Pues bien, si una de la las dos falla o lo que es lo mismo, sólo una se produce correctamente
mientras que la otra no se termina de llevar a cabo, entonces habrá un problema. O bien, una
cuenta recibe un dinero que no figura como extraído de ninguna otra cuenta, o bien, se realiza un
desembolso desde una cuenta, pero dicha cantidad no se transfiera a ninguna parte. Por lo tanto,
necesitamos un sistema que garantice que todas las operaciones involucradas tienen éxito, o en el
caso de que una de las dos falle, la otra no llegue a ejecutarse o en el caso de que ya lo haya hecho,
se deshaga.

Así, los datos en la base de datos solo se modificarían cuando se pudiera realizar dicha tarea por
completo y sin errores. Si mientras tanto se produjera un error, la transacción se ocuparía de que
todas las modificaciones realizadas hasta el momento en la base de datos se cancelaran.
Imaginemos que no hubiera todavía ninguna protección de transacción, entonces tendríamos que
volver a establecer los datos modificados en caso de una cancelación, mediante la última copia de
seguridad y este escenario resultaría inasumible en una aplicación online.
Conviene subrayar que cuando hablamos de una protección de transacción estamos aludiendo
siempre al contenido de la base de datos, no al estado de las clases Java en la memoria principal.
Una vez se ha llamado un método en un session bean, se inicia esta transacción. Memoriza
prácticamente todo lo que el EntityManager modifica en la base de datos durante el proceso.
Siempre que se coloque un UPDATE O INSERT se ejecutará esto en la base de datos.
Durante la modificación transaccional de los datos, los cambios en las filas no serán advertidos por
los usuarios y permanecerán invisibles. Esto es así, porque la transacción bloquea los registros
mientras se ejecuta y pone a la cola en espera al resto de operaciones transaccionales que se
quieran realizar sobre los mismos hasta que no se termine. No obstante, también se puede
configurar una base de datos de manera que las transacciones lectoras reciban los datos aún no
liberados de otra transacción. Pero, entonces no se puede asegurar que los datos al final se
introduzcan exactamente así en las tablas.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Una vez ha finalizado el método invocado, finaliza normalmente también la transacción. Si no se
produce ningún error, se llega a lo que suele denominarse COMMIT, es decir, una confirmación de
todos los cambios producidos y una liberación de los bloqueos sobre las filas. En caso de error se
produce entonces el denominado ROLLBACK, lo que supone que la base de datos anulará todas las
modificaciones realizadas hasta el momento del fallo. Obviamente, según el número de cambios
realizados durante la transacción, estas operaciones necesitarán más o menos tiempo.

Pueden darse algunos problemas de concurrencia o simultaneidad. Si dos usuarios independientes


entre sí llaman a la vez al mismo método desde el servidor, se inicia para ambos una transacción
propia. Cada uno realiza sus cambios independientemente del otro. Ahora bien, si ambos necesitan
la misma fuente o conjuntos de registros para llevar sus operaciones a cabo, el que llegue más tarde
tendrá que esperar hasta que el otro termine. En este punto se puede llegar a un denominado
bloqueo mortal o “deadlock”. La transacción de un usuario A necesita un conjunto, que el usuario B
ha modificado pero aun no ha liberado y viceversa. Los sistemas de base de datos reconocen este
tipo de conflictos y por lo tanto los solucionan automáticamente, deteniendo una o ambas
transacciones, y ofreciendo al usuario el mensaje de errar que corresponda.
Así pues, ¿cual sería el principal objetivo de la transacción y su sistema de protección inherente?
Pues sin duda, salvaguardar la coherencia y consistencia de los registros almacenados en una base
de datos. Pero, dado que estas confirmaciones y cancelaciones se producen dentro del motor de
base de datos, queda pendiente el saber qué ocurre con la copia de registros depositada en la
memoria principal. Conviene subrayar entonces que si en un atributo de la clase bean ha sido
almacenado en memoria, pongamos por caso un pedido que ha terminado correctamente y ya ha
sido guardado, y entonces se produce un rollback, el atributo afectado no se cancelará
automáticamente del mismo modo que en el sistema de base de datos. Ahora bien, existe la
posibilidad de que los session beans puedan informarse del éxito o del fracaso de la transacción,
pero la cancelación de los valores guardados en los atributos del beans resultará una tarea del
desarrollador.
El proceso de transacción permite algunas personalizaciones mediante un sistema de anotación. Por
lo tanto, no siempre la modificación transaccional ocurrirá de una vez una vez llamado a un método
y mantenida hasta que dicho método concluya. Por lo tanto, resulta posible manejar manualmente
la administración de la transacción. Estos casos se denominan bean managed transaction. Ahora
bien, conviene advertir que dicha posibilidad debe utilizarse con cuidado, en situaciones o escenarios
de carácter excepcional dado que pueden distorsionar y resultar peligrosas dentro de un diseño de
arquitectura nítido.
En resumen, una transacción es un conjunto de tareas que se ejecutan atómicamente. Si una o
más tareas fallan entonces corresponde deshacer la transacción. Si todas las tareas son exitosas hay
que comprometerla. En este punto es donde suele decirse que la transacción está dotada de las
denominadas propiedades ACID:
• Atomicidad, Consistencia, aislamiento, Durabilidad
Pues bien, contamos con dos maneras de manejar transacciones en EJBs
- Transacciones declarativas que es la política por defecto: Supone una demarcación de
transacciones gestionada por el contenedor (CMT)
- Transacciones programáticas: Supone una demarcación de transacción manejada por el
bean (BMT)

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Las transacciones iniciadas por el cliente tienen como ventaja que un cliente es consciente de si la
transacción ha sido deshecha o comprometida, pero tienen el inconveniente de que implican
importantes problemas de rendimiento.

Container Managed Transaction


El Container Managed Transaction (CMT) es el servidor de aplicaciones encargado de controlar
completamente las transacciones conforme las prescripciones establecidas por desarrollador. En
este caso, el sistema mismo reconoce cuándo iniciar una transacción y cuándo finalizarla. Para ello
el desarrollador asigna diferentes atributos de transacción en el nivel de los métodos, a través de los
cuales puede definir y personalizar dicho comportamiento.
En el caso de que el desarrollador no fije ningún atributo, se entenderá que estamos ante un
supuesto estándar o predefinido. Cada método de un session bean, llamado desde un cliente,
necesitará protección de la transacción. Si ya se ha iniciado una transacción para el usuario, el
método llamado la utilizará, si no es así creará una nueva transacción. Si finaliza el método que ha
creado la transacción también finaliza la transacción. Si durante la transacción se llega a una
excepción o el desarrollador ha comunicado al manager de la transacción que todos los cambios
deben cancelare, al final se llega a un ROLLBACK, sino a un COMMIT: Este comportamiento es el
predefinido para todos los message-driven beans.

@TransactionAttribute
Cada método público de un session bean o message-driven bean puede dotarse de la anotación o
TransactionAttribute. De este modo el desarrollador configura cómo desea que el servidor de
aplicaciones controle el proceso de la transacción.
En este tipo enumerado tenemos los diferents valores que puede soportar dicho atributo de
transacción:

public enum TransactionAttributeType {


MANDATORY, REQUIRED, REQUIRES_NEW, SUPPORTS,
NOT_SUPPORTED, NEVER
}
@Target({method, type})
public @interface TransactionAttribute {
TransactionAttributeType value() default TransactionAttributeType.REQUiRED;
}
Esta anotación la podemos asignar tanto en la definición de un método como en la de una clase. Si
se quisiera determinar que cada método de un session bean siempre conduzca a una nueva tran-
sacción se puede proceder como se muestra a continuación donde vemos que aplicamos el atributo

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
a nivel de clase y esta queda extendida a la vez que todos los métodos que la integren funcionarán
de manera transaccional.
@stateful
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class CounterTestBean implements CounterTestRemote {
Sin embargo, lo más habitual será aplicar la anotación transaccional en el nivel de los métodos.
Conviene remarcar que estos atributos transaccionales solo son efectivos cuando el método
correspondiente es llamado a través del servidor de aplicaciones. Es decir, cuando un cliente, desde
dónde se encuentre, haya realizado un lookup en la interfaz local o remota de la clase bean y se
invoque a continuación un método. Si por el contrario nos encontramos ya en un session bean que
llama a su propio método, el servidor de aplicaciones no tendrá ninguna noticia al respecto. Se
tratará en este caso de una llamada de método normal, no transaccional. El atributo de la
transacción del método así será ignorada. Veamos un ejemplo de este escenario.
@Stateful
public class PRUEBABean implements PRUEBABEANRemoto {
@TransactionAttribute(TransactionAttributeType.REQUiRES_NEW)_
public void primerMetodo {
//Si un cliente llama este método, se inicia una nueva transacción segundoMetodo();
}
@TransactionAttribute(TransactionAttributeType.REQUiRES_NEW) public void segundoMetodoO {
// Si este método es llamado por primerMetodo
// no se crea ninguna transacción nueva, se utilizará
// la transacción del primer método.
// si es el Cliente el que llama este método, se iniciará
// una nueva transacción
}
Aunque en ambos métodos parecen necesitar una nueva transacción, sólo al llamar el primer
método se inicia la transacción, aunque durante su ejecución se utilice también el segundo método.
Los atributos de la transacción actúan por lo tanto siempre en una llamada a través del cliente, no
cuando un método sea llamado internamente por otro método. Será siempre el cliente el que active
la transacción personalizada. Como vemos en la siguiente ilustración que el “método b” actúe de
manera transaccional o no, dependerá de cómo se haya procedido a realizar su llamada.

Siempre nos queda la opción de declarar los atributos de la transacción dentro del Deployment
Descriptor. La etiqueta assembly-descriptor del archivo ejb-jar.xml consta de varias entradas de
container-transaction , que asignan un atributo de transacción a uno o más métodos. No hay problema
en que la etiqueta method aparezca tantas veces en una container-transaction como fuera necesaria. Por
su parte, deberá constar como mínimo de las entradas ejb-name y method-name , con lo cual
determinaremos, para qué método y desde qué bean se tiene que realizar aquí una entrada. Como
puede darse el caso de que en un mismo bean existan varios métodos con el mismo nombre y que
éstos solo diferencien entre sí por sus parámetros, la etiqueta method puede complementarse
también con la entrada method-param . Aquí se definirán cada uno de los parámetros
correspondientes al método en cuestión . Después de establecer uno o más métodos asignaremos
finalmente el auténtico atributo de transacción mediante la etiqueta trans-attribute .

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
NOT_SUPPORTED
Cuando un cliente invoca a un método con este atributo, se suspende la transacción que estuviera
puesta en marcha. Es decir, a partir de ese momento todas las operaciones de actualización no
serán realizadas de manera transaccional. Pero una vez finalice la ejecución del método, entonces
volverá a activarse cualquier posible transacción suspendida previamente.
Un escenario en el que resulta conveniente emplear este atributo sería en aquellos casos en los
cuales nos planteamos hacer un acceso a datos de sólo lectura. En estas circunstancias
optimizaríamos el rendimiento de nuestra aplicación, dado que una transacción siempre consume
más recursos que la ausencia de la misma.
Si queremos incluir este atributo de la transacción en el Deployment Descriptor le pondremos el
nombre de NotSupported.

SUPPORTS
Este atributo traslada al método que lo tenga asignado una transacción que ya estuviera en marcha
al ser llamado dicho método desde otro que la incluyera. Si, por el contrario, el método que invoca
al método con SUPPORTS no fuera transaccional, entonces, el método invocado no habilitaría la
transacción.
Por ejemplo, imaginemos que tenemos un cliente que llama a una página JSP a través de un método
de negocio con un bean de sesión que incorpora un atributo Required. Esto pondría en marcha una
transacción. Si este método a su vez invoca a otro bean de sesión y llama también a un método que
tenga el atributo supports, entonces este método operará también junto al otro de una manera
transaccional. Por consiguiente, como existe protección para la transacción y esta figura soportada
por los dos métodos involucrados, todos los cambios de la base de datos serán realizados bajo dicha
transacción. Si por el contrario la página JSP llama directamente a un método caracterizado con su-
pports y no hay ningún otro método involucrado en dicha llamada que opere de manera
transaccional, entonces, no existirá allí ninguna protección de transacción sobre las acciones que se
lleven a cabo.
Dentro del Deployment Descriptor, el atributo de transacción lleva el nombre supports.

REQUIRED
Sin duda, este es el atributo de transacción utilizado con mayor frecuencia. Establece en el método
una protección de transacción. Hasta tal punto es así que si durante la llamada aún no existe
ninguna transacción en marcha, se iniciará una. En cambio, Si ya existe alguna en ejecución,
entonces, se seguirá empleando la existente.
El atributo de la transacción lleva el nombre Requi red en el Deployment Descriptor.

REQUIRES NEW
Si lo que buscamos es realizar unas operaciones dentro de una transacción autónoma entonces
deberemos asignar a nuestro método el atributo.
RequiresNew. Con ello se podrán dar varias situaciones:
- Si no hay ninguna transacción en marcha en el momento en que llamemos al método,
entonces se iniciará una nueva.
- Si ya hay una transacción en marcha en el momento en el cual llamamos al método,
entonces se suspenderá dicha transacción y se creará una nueva. Una vez el método provisto
con RequiresNew finalice su labor, se detendrá también la transacción iniciada de nuevo y se
recuperará la ejecución de la transacción suspendida anteriormente. En este punto, carece de
importancia para la transacción externa cómo finaliza la interna. Incluso si una transacción
finaliza con un ROLLBACK, puede llegar la otra a un COMMIT y viceversa.
El atributo de transacción se llama RequiresNew en el Deployment Descriptor.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
MANDATORY
Con Mandatory determinamos que el método llamado sea siempre parte de una transacción
existente. Por lo tanto, resultará obligatoria la existencia de una transacción en ejecución, siempre
que uno de estos métodos sea invocado por un cliente. Si por el contrario no existiera ninguna
protección de transacción, se interrumpiría la llamada al método y se generaría un error del tipo
javax.ejb.E3B- TransactionRequiredException.
El atributo de transacción lleva el nombre Mandatory en el Deployment Descriptor.

NEVER
Never es un atributo de transacción bastante peculiar. Si lo llamamos desde un método con protección
de transacción, se producirá una EUBException. Solo si no existe ninguna protección se puede trabajar
el método como es debido. Tampoco se inicia ninguna nueva transacción para el método. ¿Cuál es
entonces su labor? Pues que todos lo cambios en la base de datos, que se ejecuten en un método de
este tipo se escriban de inmediato en las tablas de modo visible y permanezcan allí
independientemente de lo que ocurra en el método.
Tomando en cuenta lo anterior, podemos encontrar en nuestras aplicaciones un escenario como el
reflejada en el siguiente diagrama:

Ante estos dos casos en los que se llama a métodos, el comportamiento de los atributos
especificados en el CMT sería el siguiente para cada una de las situaciones reflejadas en el diagrama
anterior:

Veamos ahora un útil tabla resumen de todo lo comentado:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Bean Managed Transaction
Como dijimos anteriormente, también cabe la opción de controlar personalizadamente el
comportamiento de la transacción. Para ello podemos asignar un session bean con la anotación
@TransactionManagement y así establecer que será el bean quien se haga cargo del control. Un
ejemplo de esta implementación lo tenemos en el siguiente fragmento de código:
public enum Transact!onManagerType {
BEAN,
CONTAINER
}
@Target({type}) @Retention(runtime)
public @interface TransactionManagement {
TransactioriManagerType value() default TransactionManagerType.container;
}
Si en ese momento llamamos a un método de este vean, el Container ya no se preocupará de la
protección de la transacción. Aquella que estuviera en marcha porque el cliente la hubiera iniciado
ya, también seguirá utilizándose. Por el contrario, si lo que se pretende es que el método llamado
inicie su propia transacción, entonces deberá poseer una instancia de la clase userTransaction. Para ello
lo más cómo es hacerlo mediante el método getuserTransaction() de la clase EJBContext. Veamos unas líneas de
código que lo implementan:

@Stateless
@TransactionManagement(TransactionManagetnentType.BEAN)
public class CounterPRUEBABEAN implements CounterPRUEBABEANRemote {
@Resource
SessionCóntext ejbcontext;
public void Metodo() {
boolean error Aparecido = false;
userTransaction ut = ejbcontext,getuserTransaction();
try {
ut.begin();
if(errorAparecido)
ut.rollback(); else
ut.commit();
} catch (IllegalStateException e) {
} catch (SecurityException e) {
} catch (NotsupportedException e) {
} catch (SystemException e) {
} catch (RollbackException e) {
} catch (HeuristicMixedException e) {
} catch (HeuristicRollbackException e) { }
}
}
Estas líneas de código permiten ver cómo un stateless session bean se gestiona él mismo la
protección de su transacción. En este caso la transacción debe finalizar en el mismo método en el
que se ha creado. Esta restricción no es válida para stateful session beans.
No obstante, En vez de emplear el EJBContext, se puede inyectar una user-Transaction directamente
en un bean.
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class CounterTestBean implements CounterTestRemote { @Resource UserTransaction ut;
}

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Finalmente, otra opción para llegar a un UserTransaction consiste en colocar en establecer
"java:comp/env/userTransaction". De este modo un cliente también puede participar en
administración de la transacción desde fuera de un servidor de aplicaciones. Con ello conseguiremos
iniciar una transacción en el cliente, llamar uno o más métodos de los session beans y después
finalizar la transacción en el mismo cliente.
UserTransaction ut;
try {
initialContext ctx = new initialContextO;
ut = (UserTransaction)
ctx.lookup("java:comp/env/UserTransaction");
} catch (NamingException e) { }

Los métodos más importantes de la clase UserTransaction son begin() para iniciar una transacción,
commit() para finalizarla limpiamente y rollback() para anular todos los cambios. Además también
existe el método setRollbackonly(), que no finaliza aún la transacción pero ya indica que debe terminar
en todo caso con un rollback.
Con setTransactionTimeout() podemos establecer el número de segundos tras los cuales concluirá la
transacción. Si no se utiliza este método prevalecerán los valores estándar del gestor de la
transacción, lo cual pueden configurarse mediante el servidor de aplicaciones.
Por último, el método getstatus() nos da información acerca del estado actual de la transacción.
Este método devuelve constantes desde la interfaz javax.transaction.status cuyos valores son más
interesantes son STATUS_ACTIVE,STATUS_COMMITED o STATUS_MARKED_ROLLBACK.

También un message-driven bean puede asumir él mismo el control de la transacción. Todo lo que
se ha mostrado aquí se puede aplicar sin cambios al método onMessage() de este tipo de bean.
Como en los stateless session beans la transacción debe terminar en el mismo método en el que se
ha iniciado. No es posible recoger varias llamadas del método onMessage() en una transacción.
No es necesario que para cada método exista protección de transacción. Un stateless session bean
para la validación de un número de tarjeta de crédito o el número de un billete no necesita ninguna
transacción. Si un bean consta tan solo de estos métodos, se puede describir toda la clase con
NOT_SUPPORTED. Esto no significa obligatoriamente que los métodos no realicen ningún tipo de acceso a
la base de datos. Siempre y cuando estos sean tan solo de lectura por ejemplo para comprobar la
existencia de un número de cuenta, también funcionará correctamente sin protección de la tran-
sacción. En todo caso es mucho más grave olvidar la protección de transacción en un método que la
necesita que dársela a un método que no va a sacarle ninguna utilidad. Caracterizar todos los
métodos con NOT_SUPPORTED para darles después por separado un REQUIRED es peor que preocuparse
primero de que todos los métodos tengan protección de transacción y después cambiar algunos de
ellos.
En el siguiente fragmento de código destinado a actualizar el stock de un almacén, podemos ver un
ejemplo del empleo de este tipo de transacción personalizada con la invocación a los métodos:
 .begin();
 .commit();
 .rollback();
Lo vemos dentro de un bloque try/catch en prevención de posibles excepciones y la transacción se
declara mediante @Resource en javax.Transaction.UserTransaction ut:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ver Video: Creación de una transacción en CMT Contenedor de
Transacciones, en la Unidad 11, en el Módulo 6,
en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

Unidad 12. Excepciones

Objetivo
Conocer y manejar las excepciones en EJB.

Introducción
Suele decirse que en Java hay dos tipos de excepciones. Aquellas motivadas por la ejecución del
Runtime y aquellas otras producidas al realizar un chequeo de información, mensajes o datos. Las
chequeadas heredan de Exception e indican errores lógicos en la aplicación. Las no chequeadas, por
su parte heredan de RuntimeException e indican errores de programación o no recuperables
Pues bien para los EJBs se suele hacer otra distinción:
a) Excepciones de aplicación: Relacionadas con la lógica de negocio. Así, estas son excepciones
para reportar problemas en la ejecución de la lógica de negocio. Por ejemplo:
public void withdraw(float amount) throws OverdraftException
En este tipo de excepciones resulta una tarea del cliente recuperar o reportar estas excepciones.
Teniendo en cuenta que “El cliente" aquí no significa la aplicación cliente sino cualquiera que haya
realizado la invocación del método del EJB que lanza la excepción.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Por otro lado, las excepciones de aplicación tienen que ser subclases de Exception, pero no
subclases de RuntimeException.
Si se lanza una excepción de aplicación, y no se captura en el servidor, se manda al cliente. Es algo
similar a lo que ocurre con RMI “regular”, el cliente sencillamente invoca el método y obtiene una
excepción como resultado (de forma transparente).
Ejemplos de excepciones de aplicación son:
- CreateException: se produce cuando no puede crear una instancia
- FinderException: cuando dada la clave de una instancia no la puede localizar.
- y RemoveException.

b) Excepciones de sistema: Representan problemas en la ejecución del sistema.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En la siguiente ilustración podemos ver esquemáticamente diferentes tipos de errores que pueden
acontecer en un EJB:

Ahora bien, ¿Cuál es la ruta de retorno de las excepciones una vez ha saltado el error? Depende. En
el siguiente diagrama de secuencia podemos hacernos una idea de su recorrido:

De este modo está claro que el manejo de las excepciones se puede hacer a diferentes niveles
dentro del EJB.

Manejo de excepciones en el contenedor


En el manejo de las excepciones producidas en el contenedor deberemos tener en cuenta las
siguientes características:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Si estamos ante una excepción de aplicación gestionada por el contenedor entonces caben dos
posibilidades.
- Que hayan sido generadas por un método de negocio
- Que haya sido generadas en el contenedor.
En este último caso la excepción pasaría al cliente local o remoto. Lo que implica que la excepción
no se anularía automáticamente salvo que empleemos el método setRollbackOnly.
Si estamos ante una excepción del sistema y queremos manejarlas mediante el contenedor entonces
pueden acontecer cualquiera de las exceciones enumeradas en la siguiente lista de excepciones:

Como vemos dependerá de si el problema surge en el bean, en el método o en la transacción y


dentro de cada elemento dependerá específicamente de la excepción concreta que acontezca. Como
bien sabemos, cada excepción nos informa de un tipo de error específico.

Excepciones manejadas por el bean


El otro escenario posible sería manejar las excepciones en los métodos del Enterprise Bean. Aquí
deberíamos tener en cuenta un diagrama de flujo con el siguiente recorrido:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Manejo de excepciones por el cliente
Si lo que queremos es manejar la excepción en el cliente. El proceso de error acaece de esta
manera:

Si queremos manejar la excepción directamente en el código del cliente:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Excepciones en transacción
Las excepciones de anulación de una transacción trascurren del siguiente modo:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Cuando se trata de una excepción de una transacción requerida:

Ver Video: Excepciones, en la Unidad 12,


en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 13. Temporizador
Objetivo
Conocer y manejar los temporizadores en EJB.

Introducción
El temporizador se suele utilizar cuando deseamos realizar un proceso controlado temporalmente,
ya sea en una fecha determinada o cada cierto intervalo de tiempo. Básicamente, consiste en tener
la posibilidad de llamar periódicamente a un método, bien haciéndolo en una única ocasión o bien
cada cierto tiempo. Esto puede hacerse sin tener ningún tipo de relación con el cliente, puesto que el
primer impulse para activar el temporizador será realizado a través de una llamada explícita al
método en la capa de negocio. Por lo tanto, será el propio servidor de aplicaciones el que traslada
en ese momento el control de la aplicación guiado por el temporizador y el beans.
Para implementar el temporizador se suele utilizar un Stateless Session Bean o un Message-driven
Bean. Conviene subrayar que en la versión EJB 3.0 los Entities no están disponibles para el Timer
Service. Tampoco los beans de sesión de tipo Stateful pueden ser adaptados al uso de
temporizadores. De hacerlo se produciría un error de la clase IllegalStateException.
Los usos de los temporizadores son abundantes, puesto que permiten auditar la actividad del
recurso en funcionamiento de una manera periódica y registrar esa información en archivos log,
hacer mantenimientos de recursos cada cierta fecha u hora o enviar mensajes de aviso a quien
corresponda si no se han obtenido los resultados esperados.
Conviene, no obstante tener presente que un temporizador puede no comenzar a hacer su tarea con
toda la puntualidad que deseáramos. Una actividad desmesurada del servidor podría retrasar o
ralentizar el arranque del temporizador o que después fuera este llamado en varias ocasiones
sucesivas.
También cabe la posibilidad de que un mismo bean pueda iniciar varios Timers a la vez,
ejecutándose de manera autónoma pero simultanea. Todos llamarían al mismo método pero sería
posible saber qué temporizador llamó en cada ocasión, identificando así por separado su servicio. Es
más aún, los temporizadores son objetos persistentes que deberían superar incluso una caída del
servidor de tal manera que una vez se reincide el servidor, este deberá atender a todos los timer
ejecutados.
El método de procesamiento de eventos en el Timer es el siguiente:
El timer llama al método indicado del bean que lo creó y tiene dos formas de indicar a qué método
se debe invocar:
- Implementando la interfaz TimedObject
- Usando la anotación @Timeout

TimedObject y @Timeout
Para utilizar un temporizador en un stateless sesión bean o un message driven bean debemos
implementar la interfaz javax.ejb.TimedObject, dicha interfaz cuenta con el método ejbTimeout(), al
que se transmite una instancia del Timer.

Vemos un ejemplo de implementación mediante TimedObject:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
También podemos emplear la opción de la anotación @Timeout que cuenta con el método
@javax.ejb.Timeout.

Como vemos en el código anterior, este método timeout reclama:


- Una instancia de un temporizador como parámetro.
- No puede tener ningún valor de retorno
- No debe generar ninguna excepción
- Puede tener cualquier nombre
Y ahora observemos un ejemplo de implementación mediante @Timeout:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Interfaz TimerService
La ventaja de utilizar como temporizador un stateless session bean reside en que se pueden ofrecer
métodos al cliente a través de la interfaz para iniciar y detener el temporizador.
Para ello el bean tiene que convertirse en temporizador cuando llama a uno de los cuatro métodos
existentes y propios de una instancia de la clase javax.ejb.TimerService. Para ello, el bean hará uso
del método getTimerService() perteneciente a la clase EJBContext o usará la anotación @Resource.
Estas situaciones las podemos ver en los fragmento de código del apartado anterior.

La interfaz TimerService a nuestra disposición cuenta con los siguientes métodos:

Con el método getTimers() un bean obtiene acceso a todos los temporizadores que estén activos y
conectados a sus respectivas clases bean. De este modo, podremos parar cada temporizador o
conocer el momento en el que cada servicio vaya a ser ejecutado de nuevo.
El resto de métodos ofrecen la posibilidad de configurar el temporizador a través de sus
correspondientes parámetros, tal y como se esquematiza cada uno de ellos en las siguientes
ilustraciones:

Temporizador de una sola acción conforme a un día fijado

Temporizador de una sola acción con comienzo en una fecha determinada e intervalo de repetición
establecido en milisegundos en su segundo parámetro.

Temporizador de una sola acción con inicio dentro de un cierto número de milisegundos.

Temporizador con inicio en unos milisegundos y repetición cada cierto número de milisegundos.
El temporizador cuenta con tres excepciones:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- IllegalArgumentException
- IllegalStateException
- EJBException

Interfaz Timer
El método Timeout que vimos anteriormente devuelve una instancia de la clase Timer mediante la
cual:
- es posible detener el temporizador
- conocer cuando volverá a ejecutarse de nuevo.
Pues bien, esta interfaz cuenta con varios métodos:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
a) cancel(): Para detener el Timer.
b) getNextTimeout(): Para conocer la fecha y hora en que se iniciará de nuevo el temporizador.
c) getHandle(): Para obtener un manejador del temporizador que puede ser guardado en un
archivo o una base de datos y así poder acceder a él más tarde.
d) getInfo(): Para recoger el objeto al que se ha asociado el temporizador cuando vue creado.
e) getTimeRemaining(): Número de milisegundos que quedan hasta la siguiente ejecución del
temporizador.

Creación de un objeto timer


A la hora de implementar un temporizador debemos tener en cuenta la siguiente secuencia de
elementos en los que pueden estar involucrados en bean y su contexto ejb:

Dicho diagrama llevado ya al código implica lo siguiente:

El código anterior muestra un método que genera un temporizador que se ejecutará en un segundo
y que sólo será llamado en una ocasión, de ahí que tenga el valor null en el segundo parámetro.
También podemos configurar el temporizador a través del contexto de la sesión del siguiente modo:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Veamos un ejemplo simulado completo. En este caso tenemos un método de un a través del cual
podríamos detener diferentes temporizadores liberando la memoria del proceso. Para ello el
temporizador se iniciará un segundo después de la llamada y se ejecutará periódicamente cada
segundo después. Así, la clase bean implementa una interfaz remota y crea dentro de su método
startMonitor() el temporizador deseado con el nombre HSP. A su vez el método stopMonitor()
comprueba todos los temporizadores que han sido generados. Ahora bien, cada vez que uno de esos
temporizadores lleve la denominación HSP, dicho objeto será cancelado mediante la llamada a
cancel(). Cada segundo, el método timeout() devuelve la cantidad de memoria libre que hay
disponible.
public class AlarmSchedulerBean implements AlarmSchedulerRemote {
@Resource TimerService timerService;
public static final String COMANDO = "HSP";
public void startMonitor() {
timerService.createTimer(1 * 1000, 1 * 1000, COMANDO);
}

public void stopMonitor() {


for (Object obj : timerService.getTimers()) {
Timer timer = (Timer) obj;
String info = (String)timer.getInfo();
if (info.equals(COMANDO)) {
timer.cancel();
}
}
}

@Timeout
public void timeout(Timer timer) {
String info = (String)timer.getInfo();
if (info.equals(COMANDO)) {
System.out.println("Liberando memoria: "+ Runtime.getRuntime().freeMemory());
}
}
}

Recomendaciones finales
Conviene tener presentes algunas pautas importantes a la hora de utilizar temporizadores:
- Si un bean crea varios temporizadores debe usar atributo info para distinguir quien llama al
método de timeout (todos llaman al mismo)
- Si se cae el servidor, los temporizadores creados sobreviven a la caída. En este caso, los
eventos perdidos se disparan todos al arrancar de nuevo.
- El método Timeout puede ser transaccional
- El contexto de seguridad en el que se ejecuta el método Timeout debe ser especificado en
configuración

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Ver Video: Temporizador, en la Unidad 13, en el Módulo 6,
en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 14. Seguridad

Objetivo
Conocer y establecer unos EJB seguros en nuestras aplicaciones.

Introducción
Obviamente los requisitos de seguridad de nuestra aplicación dependen del sentido que le demos a
la misma. Así, por ejemplo si nos planteamos realizar un sitio web comercial, deberemos dejar paso
a cualquier usuario para que curiosee por nuestras páginas y contenidos sin ponerle ningún
impedimento a su navegación. Si desde el primer momento reclamáramos algunos datos de su parte
como email o darse de alta en nuestro sistema, seguramente, sería razón suficiente para que
abandonara nuestra tienda virtual y buscara en internet otra con contenidos similares y menos
exigente en su primera toma de contacto.
Otra situación bien distinta es que dentro de esa misma tienda, transparente y accesible, llegue un
momento en que el usuario quiera realizar un pedido. En ese momento, resulta obligatorio que el
cliente se identifique para que podamos gestor el envío del producto y la transacción económico con
todas las garantías para ambas partes. Será en este punto de la aplicación donde reclamemos que el
usuario nos aporte información sobre su persona y así poder crear un vínculo de confianza entre
ambos usuario y tienda virtual. Datos como su tarjeta de crédito, cuenta bancaria, nif, email de
contacto, etc. etc. resultarán imprescindibles y no resultará violenta su petición, sino bien justificada
y comprensible por el propio cliente.
Hay una segunda parte. Y es que dentro de nuestra aplicación también sólo determinadas personas
deben tener acceso a determinadas áreas. En este caso, no estamos hablando de los usuarios
particulares que navegan por nuestro sitio web, sino por los propios gestores o administradores de
nuestra aplicación. Sólo personas debidamente autorizadas podrán realizar cambios en nuestros
productos, nuestro diseño de página, alteración de precios, etc. Y en este sentido corresponde
otorgar permisos con diferente grado de maniobra dentro de la aplicación para poder realizar esos
cambios.
A través del breve ejemplo anterior podemos enseguida comprobar que en seguridad web hay que
hablar de diferentes niveles.
a) Seguridad técnica: corresponde a la transferencia segura y confiada de datos entre un
usuario/cliente y un servidor web. Aquí debemos asegurar que el cliente envía los datos al
servidor correspondiente y no a otro. Justo a aquél en el que se registró y que los datos no
va a ser interceptados por terceras personas o aplicación que puedan hacer un uso no
previsto de tales datos. Bien, estos problemas de comunicación sin duda importantes, salen
fuera del ámbito de control de Java y han de resolverse por otras vías que aquí no van a ser
revisadas.
b) Autorización funcional: consiste, básicamente, en establecer a quién se le permite hacer
qué dentro de nuestro sistema. Para ello deberemos fijar qué ámbitos de nuestra aplicación
son accesibles, qué se puede hacer dentro de ellos y sobre todo quién puede hacerlo. Para
ello, si alguien cliente, usuario, administrador, etc. intenta llamar a un método o función de
nuestro sitio web, deberemos estar en condiciones de identificarlo. Si el elemento a
identificar no coincidiera con lo esperado, entonces la aplicación debería estar en disposición
de rechazarlo. En el caso de EJB contamos con una excepción destinada a este propósito:
EJBAccessException.
En resumen, cuando diseñamos la seguridad de nuestra aplicación se deben cumplir las siguientes
características:
- La portabilidad no se debe ver afectada

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
- Transparencia, Aislamiento y Abstracción:
- Los desarrolladores de los beans no tienen por qué conocer nada sobre la seguridad
- Los desarrolladores de aplicaciones pueden manejar la seguridad sin modificar el código de
los beans
- Extensibilidad
- Flexibilidad: Los mecanismos de seguridad no deben imponer políticas de seguridad.
- Independencia de implementación
- Interoperabilidad. Entre servidores, entre vendedores …

La arquitectura de seguridad respondería al siguiente diagrama de flujo:

Dentro de este planteamiento hay dos conceptos claves:


- Autenticación: asegura que el usuario es quien dice ser.
- Autorización: verifica qué operaciones puede realizar el usuario. La hace el contenedor JEE
que debe ser configurado adecuadamente.
- Del mismo modo, también hay dos tipos de identidades en JEE:
- Principal: Usuario autenticado en el dominio de seguridad JEE
- Rol: Grupo de Principales que comparten un conjunto común de permisos.
La asignación de identidades depende del contendor y se hace en el momento de la puesta en
marcha de la aplicación:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
La autenticación del emisor de la llamada responde al siguiente diagrama:

La identificación y la autenticación dependerán de la infraestructura que tengamos a nuestra


disposición. Sin embargo, la autorización sí que será una tarea a realizar por el contenedor EJB.
En este punto tenemos a nuestra disposición varias estrategias de autorización:

Autorización declarativa
La estrategia de autorización declarativa se realiza por medio de anotaciones o bien de
descriptores de despliegue en los que hay que:
a) especificar la declaración del rol de seguridad
b) la asignación de permisos de métodos
c) la asignación de identidades de seguridad.
Antes de Java EE 5, podíamos especificar información de autenticación y autorización para
componentes de la capa web así como para componentes con tecnología Enterprise JavaBeans,
también conocidos como enterprise beans, sólo en los deployment descriptors. Sin embargo, Java
EE 5 simplificó las cosas mediante la incorporación de anotaciones de seguridad. Estas anotaciones
se encuentran especificadas en JSR 250: Common Annotations for the Java Platform. Estas
anotaciones simplifican la autorización para enterprise beans y para componentes web. Esta
simplificación es especialmente importante para enterprise beans.
Trasladado al código resultaría así en el caso de las anotaciones:

Mediante la anotación @DeclareRoles, aplicada al nivel de clases, lo que estamos haciendo es


asignar a un servidor de aplicación unos roles denominado “auction-admin” y “auction-user” al que
debemos darle un nombre. Como vemos se pueden establecer una lista de identificadores
separándolos con una coma y fijándolos como String. Con ello ese servidor quedará identificado y
luego se podrá comprobar si la llamada al método proviene de ese servidor.
Mientras que esta declaración de rol realizada a través de los descriptores de despliegue o
Deployment Descriptor, quedaría así:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Por su parte, la asignación de permisos a métodos resultaría del siguiente modo:

Partimos de una serie de usuarios o principales a los cuales hay que asociarlos con un rol, después
esos roles deberán tener acceso a una serie de beans y dentro de esos beans a unos métodos
concretos de cada uno de ellos.
Para estos caso usamos la anotación @RolesAllowed que puede fijar tanto en el nivel de clases como
en el de método qué roles debe tener un usuario para poder hacer uso de los métodos así marcados.
En los fragmentos de código siguiente vemos que para llamar a los métodos de la clase bBean se
debe tener el roll “HR”.

En este caso siguiente el rol reclamado sería “admin” para la llamada a los métodos de la clase
aBean:

Aplicado al Deployment Descriptor, la asociación entre un roll determinado y el correspondiente


permiso a un método quedaría del siguiente modo echando mando de las etiquetas
principalmente:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Otro ejemplo de declaración de permisos mediante descriptor de despliegue sería el siguiente
combinando diferentes métodos y roles:

Aquí vemos unos métodos getAllAuctionsOfSeller y getSeller que no reclamarían una comprobación
de roles. Para ello está la etiqueta De tal forma que cualquier rol puede hacer uso de
ellos, mientras que para el método closeAuction, únicamente el rol auction-admin resultaría
autorizado para operar con él
El equivalente a la etiqueta en anotación es @PermitAll también empelable tanto a
nivel de clase como de método. Suele usarse sobre todo a nivel de método en aquellos casos donde
para la clase se haya usado un @RolesAllowed concreto. De esta forma, se puede aislar un método
concreto de la misma para que pueda ser llamado por cualquier rol, mientras que para el resto
regiría el rol principal declarado sobre la clase en su @RolesAllowed:
@Stateful
@RolesAllowed(“ADMIN”)
public class GrabarPedido implements GrabarPedidoRemoto {
@PermitAll
public void ObtenerNumPedidosHoy(){
//código
}

public void RegistrarPedido(Vecto<Datos> datos){


//codigo
}

}
Nos queda ahora la declaración de la identidad de seguridad. La identidad con la cual un bean llama
a otro bean es la identidad del que le llama a él por defecto y, por defecto, corresponde al use-
caller-identity. Esto quiere decir que todos los métodos del bean deben transcurrir bajo el rol del
cliente que ha realizado la llamada. Este forma de operar no es válida en los message driven bean
porque éstos siempre carecen de un usuario asignado.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
No obstante, es posible cambiarla, por ejemplo, para que un bean llame a otro con una identidad
configurada mediante @Runas. Esta anotación sólo se puede emplear en el nivel de clase y se aplica
a todo los métodos de la dicha clase. Su cometido es que podamos fijar para qué roles funcionan
esos métodos cuando son llamados desde otro bean.
Esta identidad RunAs responde al siguiente diagrama:

En el siguiente diagrama de secuencia tenemos resumido el proceso de llamada a métodos entre


beans y los requisitos de seguridad. Un cliente bean con identidad Admin hace que el Bean A
funcione como miembro y adopte la identidad de Admin a su vez para trasladarla al Bean B.
En el segundo caso un cliente bean con identidad de Cliente Miembro traslada esa identidad al Bean
A y este interactúa con dicha identidad ante el Bean B. Pero en ambos casos el Bean B tiene una
identidad de miembro con independencia de los diferentes roles que puede asumir el Bean A que
como vemos depende de cómo sea el cliente que provoca su llamada.

Si esto lo llevamos al descriptor de despliegue, deberíamos configurar el runas a través de su propia


etiqueta del siguiente modo:

Autorización programática
La otra estrategia es la autorización programática que supone el uso explícito de los APIs de
seguridad por parte del código de los componentes. Proporciona flexibilidad ya que, por ejemplo, un
mismo método puede comportarse de forma distinta en función del usuario o servidor que lo
reclame.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Por programa se puede averiguar el usuario/servidor y el rol con el que actúa gracias a los métodos
definidos en su EJBContext:
- isCallerInRole
- getCallerPrincipal
isCallerInRole(String roleName) permite al proveedor del bean codificar comportamientos distintos
para un mismo método en función del role de seguridad del usuario/servidor que reclame el uso de
dicho método. Es mejor proporcionar diferentes métodos y usar las declaraciones en el descriptor
de despliegue para especificar si un role puede o no acceder al método. Veamos un ejemplo:

En el siguiente diagrama de secuencia vemos el comportamiento de la identificación realizada por el


método isCallerInRole:

En el diagrama anterior, el valor devuelto es false, por lo tanto el usuario no es autenticado y habría
que codificar la respuesta oportuna.
Podemos mapear los roles de bean a los de aplicación a través del descriptor de despliegue de la
siguiente forma:

El método GetCallerPrincipal de la interfaz de EJBContext se utiliza para identificar una llamada


utilizando un objeto java.security.Principal. Se recupera la información sobre la identidad de

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
seguridad del cliente. Este método se utiliza para implementar la seguridad programática. Aquí
vemos un fragmento de código en el que comprobamos la identidad del elemento que provoca está
utilizando un objeto:

Vemos el código anterior expresado mediante un diagrama de secuencia:

Como vemos primero intentamos identificar al usuario y ver si se corresponde con el rol “auction-
admin”. El resultado es false puesto que se trata de un “auction-user” por lo tanto echamos mano
del método getCallerPrincipal para a través de su método getName obtener una cadena con el rol
del usuario que demandó el método.

Ejemplo completo utilizando el descriptor de despliegue:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Responsabilidades del administrador
Cuando planteamos el diseño de una política de seguridad pueden surgir muchas dudas y tareas de
cómo llevarla a cabo:

No obstante, conviene tener presente algunas consideraciones:


 Los mecanismos de seguridad no deberían ser implementados dentro de los EJBs
 Las políticas de seguridad no deberían estar codificadas de manera rígida, puesto que la
misma aplicación, cuando se despliega sobre diferentes entornos puede requerir diferentes
políticas.
 El proveedor de un bean no debería involucrarse en la seguridad.
 El proveedor del bean se debería limitar a ofrecer referencias a roles para la provisión de
seguridad (qué roles se asumen definidos) a través de los descriptores de despliegue
Por lo tanto, para estas cuestiones se recomienda la división de funciones especializadas dentro del
entorno de desarrollo y mantenimiento de la aplicación. En la siguiente ilustración podemos ver las
funciones más características de este reparto de tareas:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
A cada una de ellas correspondería una función concreta tal y como vemos en esta otra ilustración:

Los proveedores EJB se encargarán de establecer las referencias a los roles de seguridad. Por su
parte los ensambladores de la aplicación definirán los roles de seguridad, y vincularán esas
referencias a roles con los verdaderos roles. El encargado de desplegar la aplicación, asignará los
roles a grupos de usuarios y, finalmente, el administrador del sistema creará los grupos de usuarios,
gestionará la política de seguridad y administrará los servicios de seguridad.
Como vemos unos son meros asignadores de elementos y relaciones, mientras que otros tienen
capacidad para crear, definir y modificar.

Ver Video: Implementando Seguridad, en la Unidad 14,


en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Unidad 15. Uso de las Mejores Prácticas de la
Tecnología EJB

Objetivo
Conocer las maneras más recomendables de implementar EJBs para obtener una funcionalidad
óptima.

Introducción
Ya sabemos que el bean de sesión se mantiene a lo largo de la sesión del cliente con la finalidad de
dar representar flujo de trabajo, estado de aplicación, lógica y utilidades de empresa. Un bean de
sesión con estado puede mantener datos entre las diferentes peticiones de un cliente; pero no
ocurre así con un bean de sesión sin estado.

Con o sin estado


La limitación inherente a los beans sin estado nos puede hacer creer que sean de escasa utilidad.
Para una primera aproximación a estos bean hagamos una diferencia:
Supongamos que tenemos clientes JSP y cada uno accede a su EJB de sesión con estado, cada
cliente implica la creación de un objeto (create()). N clientes implican N beans de sesión con
estado:

Supongamos que utilizamos beans de sesión sin estado. En este contexto el servidor tiene mayores
oportunidades de aplicar mecanismos de optimización. El servidor mantiene un pool de
objetos disponibles y es capaz de reutilizar objetos para múltiples clientes. Pero siempre de forma
sucesiva o sincronizada, el servidor asigna un hilo a cada petición de un cliente, de tal forma que
no libera el hilo para otra petición a menos que la primera haya terminado:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Veámoslo desde el punto de vista del código. En la implementación del bean tenemos el método
ejbCreate():
public void ejbCreate() {
System.out.println("--->Llamada a ejbCreate() de " + getClass().getName());
}
Además en el cliente creamos dos EJBs:
try {

//// Creo un contexto


Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
Context ctx = new InitialContext(props);

/// Creo una referencia a objeto remoto


Object objRef = ctx.lookup("ejb/Calculador");
CalculadorHome home = (CalculadorHome)javax.rmi.PortableRemoteObject.narrow(objRef,
CalculadorHome.class);
Calculador cal = home.create();

//// ... Uso el EJB

/**************************************************************************
* Liberamos el objeto: la instancia se devuelve al pool de bean de sesión.
* IMPORTANTE: la persistencia del objeto en memoría viene determinada por
* el servidor EJB.
**************************************************************************/
cal.remove();

/**************************************************************************
* Creamos una segunda referencia
**************************************************************************/
Calculador cal2 = home.create();

//// ... Uso el EJB

cal2.remove();
ctx.close();

} catch (Exception e){


e.printStackTrace();
}
La pregunta es: ¿Qué diferencias existen en función de si el bean mantiene o no el estado?. Para la
respuesta veamos el comportamiento de cada caso:
Con un bean de sesión con estado nos encontramos que cada create() implica un ejbCreate(). En la
consola del servidor veremos que hay una invocación a ejbCreate() por cada create():
15:59:31,859 INFO [STDOUT] --->Llamada a setSessionContext() de calculador.CalculadorBean
15:59:31,859 INFO [STDOUT] --->Llamada a ejbCreate() de calculador.CalculadorBean
15:59:31,890 INFO [STDOUT] --->Llamada a ejbRemove() de calculador.CalculadorBean
15:59:31,890 INFO [STDOUT] --->Llamada a setSessionContext() de calculador.CalculadorBean
15:59:31,890 INFO [STDOUT] --->Llamada a ejbCreate() de calculador.CalculadorBean
15:59:31,906 INFO [STDOUT] --->Llamada a ejbRemove() de calculador.CalculadorBean
En conclusión, cada create() del cliente ha implicado un ejbCreate() del servidor EJB.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
En un bean de sesión sin estado, la respuesta del servidor es diferente:
13:58:23,046 INFO [STDOUT] --->Llamada a setSessionContext() de calculador.CalculadorBean
13:58:23,046 INFO [STDOUT] --->Llamada a ejbCreate() de calculador.CalculadorBean

Se puede observar que aunque se han creado sucesivamente dos objetos con create(), el servidor
EJB sólo ha invocado una vez a ejbCreate(). La razón es sencilla, el servidor creará un bean sólo
cuando no haya beans remotos en la reserva. En este caso, aunque hay dos create(), el servidor
invoca un ejbCreate() por una sencilla razón: el primer EJB está en el pool y no es necesario crear
un segundo bean. Otro aspecto importante es que, aunque se ha realizado remove() en el cliente,
no se ha invocado ejbRemove() por parte del servidor, es decir, el servidor mantiene objetos en
reserva (en el pool) y no los borra a menos que sea necesario.
Dicho de forma abstracta, estos tipos de beans tienen diferentes tipos de ciclos de vida.

Sin estado, pero ¿qué ocurre con los atributos?


El hecho de que no tenga estado no significa que no pueda tener variables atributos. Pero hay un
aspecto que no debemos olvidar: es el servidor EJB el que se interpone y controla la vida del bean
sin estado. Por tanto, no debería asumir nada sobre los valores de esas variables atributos. Como se
ha podido ver en el ejemplo anterior, el servidor mantiene el primer bean en reserva para activarlo
en la segunda petición del cliente, esto implica que se mantienen los valores de cualquier variable
atributo. Por tanto, estas variables se comportan como variables globales (lo que puede llevar a
efectos laterales indeseados)

Con estado, pero ¿qué ocurre con el rendimiento?


En el ejemplo anterior se puede deducir que los bean de sesión con estado pueden resultar un
mecanismo excesivamente costoso desde el punto de vista del rendimiento. Afortunadamente los
servidores EJB tienen mecanismos de optimización. El más conocido es semejante al funcionamiento
del swapping de memoria. Para los que lo hayan olvidado y por decirlo brevemente, el swapping
funciona así: si una aplicación (o parte de ella) no se está usando, se sitúa en un espacio secundario
de almacenamiento temporal (disco). En el momento que el procesador la necesita se restaura
(activa) desde este espacio temporal.
De manera semejante, el servidor EJB puede almacenar en un espacio temporal los beans de sesión
con estado. A este mecanismo se le llama pasivación. La inversa (restaurar en memoria de trabajo
el bean desde el almacenamiento temporal) se conoce como activación. El algoritmo que controla
ambos mecanismos no pertenece al standar J2EE, es específico al fabricante. El servidor invocará el
correspondiente método del bean como una forma de aviso del cambio de estado (la
implementación es obligada pero pueden estar vacios):
public void ejbActivate() {
System.out.println("--->Llamada a ejbActivate() de " + getClass().getName());
}

public void ejbPassivate() {


System.out.println("--->Llamada a ejbPassivate() de " + getClass().getName());
}
El contenedor EJB no activa ni pasiviza beans de sesión sin estado.

Elegir
Llegado a este punto uno puede seguir preguntándose cuando utilizar beans de sesión con estado o
sin estado, más aún, cuando usar beans de entidad o beans de sesión. No hay normas
inquebrantables, aunque si hay orientaciones generales:

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.
Usaremos beans de sesión con estado para aplicaciones de carrito de la compra, workflow, etc., es
decir, en aquellas aplicaciones en las que el mantenimiento de datos de sesión sea crucial.
Usaremos beans de sesión sin estado para cálculos, ordenamientos de estructuras de datos, reglas
de negocio, etc., es decir, para aquellas aplicaciones en las que el servicio se de en el contexto de
petición y no en el de sesión.

Los beans de entidad se han pensado para representar entidades de negocio que requieren acceso a
bases de datos. Aunque en circunstancias especiales, empujados por imperativos de rendimiento se
puede usar un bean de sesión para accesos a datos. Pero en estas circunstancias se debe tener en
cuenta que puede que no aprovechemos los servicios de acceso a datos que nos puede dar el
servidor EJB, como por ejemplo, la gestión de un pool de conexiones.

Ver Video: Usos de EJB Buenas practicas, en la Unidad 15,


en el Módulo 6, en la plataforma elearning

Actividades
“Recuerde que para un seguimiento óptimo de la unidad es imprescindible realizar las actividades
que encontrará en la unidad correspondiente de la plataforma eLearning”.

www.learning.es
Para uso exclusivo de los alumnos de LEARNING & TRAINING CLOUD, S.L.

También podría gustarte