Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 4.00/4.00
Question 1
Correct
Flag question
Question text
a.
Como esta en la imagen con Java SE-1.8
1/4
b.
Se debe modificar la imagen y seleccionar el de alternate JRE con el jdk de nuestro Java que tenemos
instalado.
c.
En la imagen se debe modificar y colocar Java SE-10
d.
En la imagen se debe modificar y colocar Java SE-17
Feedback
Respuesta correcta
Question 2
Correct
Flag question
Question text
Cuando se modifica algo en el proyecto EJB del servidor que debemos hacer para que funcionen los
cambios, si cuando hacemos el cambio el servidor está prendido (deployado).
a.
No debemos hacer nada ya que funcionan los cambios correctamente.
b.
Debemos para el servidor y parar el cliente , y arrancar el cliente para que los cambios funcionen.
c.
Debemos parar el servidor y prenderlo nuevamente para que los cambios funcionen.
d.
Debemos parar solo el cliente y luego darle start para que funcione.
Feedback
Respuesta correcta
Question 3
Correct
Flag question
2/4
Question text
En la VC descargamos la última versión de Eclipse (2023-03), vimos como debemos configurar varios
aspectos para que nuestros proyectos funcionen correctamente.
Que archivo debemos modificar para que no tenga problemas cada vez que deseamos arrancar Eclipse ?
a.
starteclipse.bat
b.
standalone.bat
c.
adduser.bat
d.
eclipse.ini
Feedback
Respuesta correcta
Question 4
Correct
Flag question
Question text
3/4
Las letras rojas en la consola nos están indicando que tenemos un error al ejecutar el cliente.
Select one:
Feedback
4/4
Cuestionario de VC 1: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
Question text
Cuando se modifica algo en el proyecto EJB del servidor que debemos hacer para que
funcionen los cambios, si cuando hacemos el cambio el servidor está prendido
(deployado).
a.
Debemos para el servidor y parar el cliente , y arrancar el cliente para que los cambios
funcionen.
b.
Debemos parar el servidor y prenderlo nuevamente para que los cambios funcionen.
c.
No debemos hacer nada ya que funcionan los cambios correctamente.
d.
Debemos parar solo el cliente y luego darle start para que funcione.
Feedback
Respuesta correcta
1/1
Cuestionario de VC 2: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 4.00/4.00
Question 1
Correct
Flag question
Question text
En que lugar colocamos el nombre del datasource que hace referencia al esquema de la
base de datos que vamos a trabajar
a.
Dentro de jndi.properties
b.
Dentro de la carpeta entidades
c.
En el archivo persistence.xml
d.
Dentro del archivo orm.mxl
Feedback
Respuesta correcta
Question 2
1/3
Correct
Flag question
Question text
a.
Guarda el String correspondiente al enumerado
b.
Guarda dos datos el ordinal y el string
c.
Como no se especifica no se guarda nada en ese campo
d.
Guarda el numero del orden que se encuentra el dato ubicado en la clase enum
Feedback
Respuesta correcta
The correct answer is: Guarda el numero del orden que se encuentra el dato ubicado en
la clase enum
Question 3
Correct
Flag question
Question text
Cual opción tenia en el proyecto creado y mostrado hoy, adentro del archivo
properties.xml, para trabajar con la base de datos, en la property que dice :
a.
create-drop
2/3
b.
create
c.
update
d.
drop-create
Feedback
Respuesta correcta
Question 4
Correct
Flag question
Question text
Para utilizar entidades que debemos configurar luego de creado el proyecto EJB
a.
El agregado de servltes
b.
seleccionar el JPA dentro de java facets
c.
crear dentro del paquete servicios las entidades
d.
crear un paquete con las entidades
Feedback
Respuesta correcta
3/3
Cuestionario de VC 1: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 4.00/4.00
Question 1
Correct
Flag question
Question text
Select one:
Feedback
Question 2
Correct
Flag question
Question text
Select one:
1/3
Feedback
Question 3
Correct
Flag question
Question text
Para utilizar entidades que debemos configurar luego de creado el proyecto EJB
a.
crear un paquete con las entidades
b.
seleccionar el JPA dentro de java facets
c.
El agregado de servltes
d.
crear dentro del paquete servicios las entidades
Feedback
Respuesta correcta
Question 4
Correct
Flag question
Question text
Cual de los siguientes drivers de oracle es el más recomendado para trabajar con
nuestras versiones de Oracle y Java:
a.
2/3
ojdbc7.jar
b.
ojdbc14.jar
c.
ojdbc6.jar
d.
ojdbc11.jar
Feedback
Respuesta correcta
3/3
Cuestionario de VC 4 - Semana 6: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 3.00/3.00
Question 1
Correct
Flag question
Question text
a.
La List no admite valores repetidos y la Set si.
b.
La Set no admite valores repetidos y la List si.
c.
La Set admite valores repetidos y la List no
d.
Las dos admiten valores repetidos
Feedback
Respuesta correcta
The correct answer is: La Set no admite valores repetidos y la List si.
Question 2
Correct
1/2
Mark 1.00 out of 1.00
Flag question
Question text
a.
Ramo - Flor
b.
Libro - Autor
c.
Estudiante - Materia
d.
Rol - Funcionalidad
Feedback
Respuesta correcta
Question 3
Correct
Flag question
Question text
La prueba de la Unidad Curricular del miércoles que viene va a ser en la mañana y con
materiales para consultar.
Select one:
Feedback
2/2
Cuestionario de VC 3 - Semana 6: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 4.00/4.00
Question 1
Correct
Flag question
Question text
Cuando probamos el ejercicio del proyecto PermasEJB, que tenia una relación de 1 a N
entre Persona y Mascota, en los servicios con qué método del Entity Manager creamos
las Personas y las Mascotas ?
a.
insert
b.
merge
c.
create
d.
persist
Feedback
Respuesta correcta
Question 2
1/3
Correct
Flag question
Question text
a.
La Set no admite valores repetidos y la List si.
b.
La Set admite valores repetidos y la List no
c.
La List no admite valores repetidos y la Set si.
d.
Las dos admiten valores repetidos
Feedback
Respuesta correcta
The correct answer is: La Set no admite valores repetidos y la List si.
Question 3
Correct
Flag question
Question text
Select one:
Feedback
2/3
Question 4
Correct
Flag question
Question text
a.
Libro - Autor
b.
Estudiante - Materia
c.
Ramo - Flor
d.
Rol - Funcionalidad
Feedback
Respuesta correcta
3/3
Cuestionario de VC 2 Semana 5: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 5.00/5.00
Question 1
Correct
Flag question
Question text
Cuando probamos el ejercicio del proyecto PermasEJB, que tenia una relación de 1 a N
entre Persona y Mascota, en los servicios con qué método del Entity Manager creamos
las Personas y las Mascotas ?
a.
persist
b.
merge
c.
create
d.
insert
Feedback
Respuesta correcta
Question 2
1/4
Correct
Flag question
Question text
a.
La Set no admite valores repetidos y la List si.
b.
La Set admite valores repetidos y la List no
c.
Las dos admiten valores repetidos
d.
La List no admite valores repetidos y la Set si.
Feedback
Respuesta correcta
The correct answer is: La Set no admite valores repetidos y la List si.
Question 3
Correct
Flag question
Question text
a.
Calle
b.
Usuario
c.
Persona
2/4
d.
Piso
Feedback
Respuesta correcta
Question 4
Correct
Flag question
Question text
a.
Libro - Autor
b.
Estudiante - Materia
c.
Rol - Funcionalidad
d.
Ramo - Flor
Feedback
Respuesta correcta
Question 5
Correct
Flag question
Question text
3/4
De acuerdo a lo visto en la VC y un link que está en la semana 5 y 6, se deben anotar
colocando el nombre del grupo en una planilla para seleccionar fecha y hora para hacer
una meet para comentar como van con el proyecto colaborativo de la semana 5 y 6.
Select one:
Feedback
4/4
Cuestionario de VC 1 Semana 5: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 2.00/4.00
Question 1
Incorrect
Flag question
Question text
Select one:
Feedback
Question 2
Incorrect
Flag question
Question text
1/3
a.
Rol - Funcionalidad
b.
Ramo - Flor
c.
Libro - Autor
d.
Estudiante - Materia
Feedback
Respuesta incorrecta.
Question 3
Correct
Flag question
Question text
a.
Piso
b.
Persona
c.
Usuario
d.
Calle
Feedback
Respuesta correcta
2/3
Question 4
Correct
Flag question
Question text
Cuando probamos el ejercicio del proyecto PermasEJB, que tenia una relación de 1 a N
entre Persona y Mascota, en los servicios con qué método del Entity Manager creamos
las Personas y las Mascotas ?
a.
create
b.
merge
c.
persist
d.
insert
Feedback
Respuesta correcta
3/3
Cuestionario de VC 1: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 3.00/3.00
Question 1
Correct
Flag question
Question text
a.
En el cliente
b.
En el servidor en el bean de sesion que maneja la entidad
c.
No hay una opción correcta.
d.
En el servidor dentro de la entidad .
Feedback
Respuesta correcta
Question 2
1/3
Correct
Flag question
Question text
Select one:
Feedback
Question 3
Correct
Flag question
Question text
Para persistir en la base de datos tenemos que usar el EntityManager, para eso, para dar
de alta precisamos el metodo :
a.
persist
b.
save
c.
dispatch
d.
insert table
Feedback
Respuesta correcta
2/3
persist
3/3
Cuestionario de VC 1: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 3.00/4.00
Question 1
Correct
Flag question
Question text
Para poder aprobar esta unidad curricular no es necesario contestar los cuestionarios
luego de las Vc .
Select one:
Feedback
Question 2
Correct
Flag question
Question text
c.
1
1/3
d.
2
Feedback
Respuesta correcta
Question 3
Incorrect
Flag question
Question text
Select one:
Feedback
Question 4
Correct
Flag question
Question text
a.
En buildpath y dentro de este en Projects y lo colocamos en classPath
2/3
b.
En buildpath y dentro de este en Projects y lo colocamos en modulePath
c.
En buildpath y dentro de este en Source y lo colocamos en classPath
d.
En buildpath y dentro de este en Libraries y lo colocamos en classPath
Feedback
Respuesta correcta
3/3
Cuestionario - individual: Attempt review
ev1.utec.edu.uy/moodle/mod/quiz/review.php
State Finished
Marks 80.00/80.00
Question 1
Correct
Flag question
Question text
Select one:
Feedback
Question 2
Correct
Flag question
Question text
a.
1/8
Aplicaciones distribuidas
b.
Proveen mecanismos de seguridad
c.
Los componentes de lógica de negocios no son reutilizables
d.
Multicapa
e.
Basada en componentes
f.
Depende de la plataforma
Feedback
Respuesta correcta
Question 3
Correct
Flag question
Question text
Los servlets son componentes Web que se ejecutan en el lado del cliente
Select one:
Feedback
Question 4
2/8
Correct
Flag question
Question text
Los componentes web contienen la lógica que resuelve las necesidades del negocio.
Select one:
Feedback
Question 5
Correct
Flag question
Question text
Select one:
Feedback
Question 6
Correct
Flag question
Question text
Select one:
3/8
Feedback
Question 7
Correct
Flag question
Question text
Select one:
Feedback
Question 8
Correct
Flag question
Question text
Select one:
a.
Una unidad de software modular y funcional que se comunica con otros componentes
b.
Es una pequeña aplicación cliente que se ejecuta en la máquina virtual Java instalada
en el navegador web
c.
Son objetos que sirven para comunicar la capa servidor con la cliente
4/8
Feedback
Respuesta correcta
The correct answer is: Una unidad de software modular y funcional que se comunica con
otros componentes
Question 9
Correct
Flag question
Question text
Select one:
Feedback
Question 10
Correct
Flag question
Question text
Los componentes Web Java EE son servlets o páginas web creadas usando la
tecnología JavaServer Faces y / o la tecnología JSP
Select one:
Feedback
Question 11
Correct
5/8
Mark 5.00 out of 5.00
Flag question
Question text
Un cliente web a veces se llama un cliente pesado porque suelen realizar consultas a la
base de datos y tener reglas de negocios complejas.
Select one:
Feedback
Question 12
Correct
Flag question
Question text
Los módulos web son empaquetados en archivos comprimidos con una extensión .war
Select one:
Feedback
Question 13
Correct
Flag question
Question text
Un EJB es:
Select one:
a.
6/8
Un componente de negocio que se ejecuta en el servidor
b.
Un componente Web que se ejecuta en el servidor
c.
Un servidor Java EE que proporciona contenedores
Feedback
Respuesta correcta
Question 14
Correct
Flag question
Question text
Las Aplicaciones Clientes y los Applets son componentes que se ejecutan en el lado del
cliente
Select one:
Feedback
Question 15
Correct
Flag question
Question text
Select one:
7/8
Feedback
Question 16
Correct
Flag question
Question text
Generalmente hay un sólo tipo de cliente Java EE que son los clientes Swing
Select one:
Feedback
8/8
Tipos de EJBs
● Bean de sesión: representa un proceso o una acción de negocio. En general,
cualquier llamada a un servicio debería comenzar con una llamada a un bean de
sesión. Conceptualmente se asocian los beans de sesión con los verbos:
agregarProducto, chequearStockProducto, etc.
● Beans dirigidos por mensajes (MDBs): pueden escuchar mensajes de un servicio de
mensajes JMS (Java Message Service). Los clientes de estos beans nunca los
llaman directamente, sino que es necesario enviar un mensaje JMS para
comunicarse con ellos. Un ejemplo de bean dirigido por mensajes podría ser un
bean ListenerNuevoProducto que se activa cada vez que se envía un mensaje
comunicando que se ha dado de alta a un nuevo producto.
Bean de Sesión
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.
Existe una correspondencia uno a 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.
Los beans de sesión pueden ser de tres tipos: con estado, sin estado, y singleton.
Sintaxis JNDI
Existen tres espacios de nombres JNDI que se utilizan para las búsquedas: java:global ,
java:module , y java:app .
● java:global es la manera portable de encontrar EJBs remotos mediante búsquedas
JNDI. Las direcciones JNDI son de la siguiente forma:
application name]
java:global[/ module name/
/ enterprise bean name[
interface name]
/
● java:module se utiliza para buscar EJBs locales dentro del mismo módulo. Las
direcciones JNDI son de la siguiente forma:
java:module/ enterprise bean name/ interface name]
[
● La java:app se utiliza para buscar EJBs locales envasados
dentro de la misma
aplicación. Es decir, el EJB se empaqueta en un archivo EAR que contiene múltiples
módulos Java EE. Las direcciones JNDI son de la siguiente forma:
java:app[/module name] enterprise bean name[
/ interface name]
/
Por ejemplo: supongamos que tengo un EJB llamado MiPrimerEJB, que se empaqueta
dentro del archivo web miPrimerApp.war y el nombre del módulo es miPrimerApp. El
nombre JNDI portable es java:module/MiPrimerEJB . Un nombre JNDI equivalente
utilizando el java:global es java:global/miPrimerApp/MiPrimerEJB .
Para crear un EJB que permita el acceso remoto, o bien debe
● Anotar la interfaz de negocio del EJB con @Remote
@Remote
public interface InterfaceName { ... }
● O anotar con @Remote la clase del EJB y especificando la interfaz o interfaces de
negocio:
@Remote(InterfaceName.class)
public class BeanName implements InterfaceName { ... }
La interfaz remota define los métodos de negocio y el ciclo de vida que son específicos para
el EJB. Por ejemplo, la interfaz remota de un bean llamado StockProductosBean podría
tener los métodos de negocio agregarProducto y quitarProducto
El acceso de un cliente a un EJB que implementa una interfaz de negocio remota se lleva a
cabo a través de inyección de dependencia o de búsqueda JNDI.
● Para obtener una referencia a la interfaz de negocio remota de un EJB a través de la
inyección de dependencias, se debe utilizar la anotación javax.ejb.EJB y especificar
el nombre de interfaz de negocio remota:
@EJB
Ejemplo ejemplo;
● Para obtener una referencia a una interfaz de negocios remota de un EJB a través
de la búsqueda JNDI, se debe utilizar el método lookup del
javax.naming.InitialContext:
ExampleRemote example = (ExampleRemote)
InitialContext.lookup("java:global/myApp/ExampleRemote");
Aplicaciones empresariales
En la actualidad cada vez más se necesita el desarrollo de aplicaciones empresariales. Qué
son las aplicaciones empresariales? Son sistemas que integran distintas partes del negocio,
por ejemplo, recursos humanos, contabilidad, manejo de recursos, etc. Gracias a este tipo
de aplicaciones, las empresas pueden aumentar su rendimiento a un bajo costo, teniendo
todo integrado en un mismo sistema.
Modelo Java EE
El modelo Java EE tiene como protagonistas el lenguaje de programación Java y la
máquina virtual de Java.
Las características fundamentales de este tipo de aplicaciones son la productividad,
portabilidad y seguridad.
Java EE es un conjunto de especificaciones Java que brindan la funcionalidad necesaria
para el desarrollo de aplicaciones empresariales. Este tipo de aplicaciones pueden ser muy
complejas, ya que pueden acceder datos de una gran variedad de fuentes y que requieran
que la aplicación sea distribuida a una gran cantidad de clientes.
Java EE incluye muchos componentes de Java Standard Edition, llamada Java SE. JavaSE
es un kit de desarrollo de software que se utiliza para escribir applets y aplicaciones con el
lenguaje de programación Java. Este kit es el que han utilizado hasta el momento para las
materiales Java que ya tuvieron. Java EE no es un reemplazo de Java SE: Java SE
proporciona el soporte de lenguaje básico sobre el que Java EE ejecuta.
El modelo Java EE define una arquitectura para la implementación de servicios como
aplicaciones de varios niveles que ofrecen a escalabilidad, accesibilidad y capacidad de
gestión necesaria para aplicaciones empresariales.
Si pensamos en una aplicación empresarial estándar, necesitaremos 3 capas:
● Capa de presentación: encargada de desplegar y obtener información para el
usuario
● Capa de negocios: encargada de los procesos y reglas de negocio
● Capa de acceso a datos: toda aplicación requiere alguna forma de persistencia (leer
/ almacenar datos)
Las aplicaciones Java EE se suelen distribuir en tres lugares diferentes:
● La máquina cliente
● La máquina servidor (Servidor Java EE)
● Base de datos o sistemas legados (Sistema legado: se trata de un sistema
informático que ha quedado obsoleto pero continúa siendo utilizado por el usuario y
no se quiere o no se puede reemplazar o actualizar de forma sencilla)
Java EE divide el trabajo necesario para implementar esta arquitectura en las siguientes
partes:
● La lógica de negocio y presentación, implementados por el desarrollador
● Los servicios del sistema estándar, proporcionados por la plataforma Java EE
Java EE promueve la construcción de sistemas independientes de la plataforma.
Posee una especificación es abierta, por lo que puede ser implementada por cualquier
proveedor. Para esto, el proveedor deberá de seguir el estándar, cumpliendo con los
procesos de certificación existentes. Debe cumplir lo que dice el estándar, pero eso no
significa que sólo deba contemplar lo que el estándar establece.
Un servidor de aplicaciones que sea Java EE certificado, deberá proveer los servicios que
define la especificación. Con esto se logra que una aplicación que se ejecuta en un servidor
de aplicaciones A, pueda ejecutarse en un servidor de aplicación B.
Aplicaciones distribuídas
Java EE usa un modelo de varios niveles donde se distribuyen las aplicaciones de la
empresa.
En ésta un objeto está asociado con un nombre, donde los nombres los proporciona un
servicio de nombres, notificando a distintos componentes y resolviendo las referencias de
clientes para estos componentes de servicio.
La lógica de la aplicación se divide en componentes de acuerdo a su función, y los
componentes de una aplicación Java EE pueden estar instalados en distintas máquinas,
dependiendo de la capa a la que pertenece el componente de aplicación.
Las aplicaciones de multicapa Java EE son generalmente consideradas como aplicaciones
de tres capas, porque están distribuidas en tres lugares: máquina cliente, la máquina del
servidor Java EE, y la base de datos.
Seguridad
Aunque otros modelos de aplicaciones empresariales requieren medidas de seguridad
específicas para cada aplicación, el entorno de seguridad de Java EE permite que las
medidas de seguridad se definan durante el despliegue (deploy) o momento de instalación
de la aplicación.
Estas medidas protegen a los desarrolladores de aplicaciones de la complejidad de la
implementación de elementos de seguridad.
La plataforma Java EE proporciona reglas de control de acceso estándar declarativas que
están definidas por el desarrollador e interpretadas cuando se realiza el deploy o despliegue
de la aplicación.
Arquitectura
Java EE define un estándar para el desarrollo de aplicaciones empresariales multicapa
basadas en componentes .
La lógica de la aplicación se divide en componentes de acuerdo a su función, y cada
componente puede ser instalado en una máquina diferente dependiendo de la capa a la que
pertenezca
Las aplicaciones se dividen en capas dependiendo de su funcionalidad como pueden ser:
● Componentes de la capa de cliente corriendo en la máquina cliente
● Componentes de la capa web corriendo en el servidor Java EE
● Componentes de la capa de negocio corriendo en el servidor Java EE
● Software de la capa EIS (Enterprise Information System) corriendo en un servidor
EIS, con bases de datos.
Componente Java EE
Un componente es una unidad de software “autosuficiente” y funcional que se ensambla
dentro de una aplicación Java EE y se comunica con otros componentes.
Para que un componente pueda ser ejecutado, debe de ser previamente desplegado
(deploy) en el contenedor correspondiente de un servidor Java EE
La especificación Java EE define los siguientes componentes Java EE:
● Los clientes de aplicaciones y applets son componentes que se ejecutan en el
cliente.
● Servlet Java, Java Server Faces, y Java Server Pages (JSP) son componentes web
que se ejecutan en el servidor.
● Enterprise JavaBeans (EJBs) son componentes de negocio que se ejecutan en el
servidor.
Los componentes Java EE están escritos en Java y se compilan de la misma forma que
cualquier otro programa en el lenguaje. Las diferencias entre los componentes Java EE y
las clases de Java "estándar" son que los componentes Java EE se ensamblan en una
aplicación Java EE, que se verifican de estar bien formados y de acuerdo con la
especificación Java EE, y que se implementan en la producción, en la que están
gestionados por el servidor Java EE.
Los clientes de Java EE
Un cliente Java EE es un cliente web, una aplicación de escritorio o un applet.
Clientes web
Un cliente web se compone de dos partes:
● Páginas web dinámicas que contienen varios tipos de lenguaje de marcado (HTML,
XML, etc.), que son generados por los componentes Web que se ejecutan en la
capa web
● Un navegador web, lo que hace que las páginas sean mostradas
Un cliente web a veces se llama un cliente ligero. Los clientes ligeros no suelen consultar
bases de datos, ejecutar reglas de negocio complejas, ni conectarse con otras aplicaciones.
Cuando se utiliza un cliente ligero, las operaciones “pesadas” las realizan los bean
enterprises que se ejecutan en el servidor Java EE, en el que pueden aprovechar la
seguridad, velocidad, servicios, y la fiabilidad de las tecnologías del lado del servidor Java
EE.
Aplicación de escritorio
Una aplicación de escritorio se ejecuta en una máquina cliente y brinda una forma más
amigable para que los usuarios manejen las tareas que requieren una interfaz de usuario
más rica y más customizada que la de un lenguaje de marcas (HTML).
Normalmente tiene una interfaz gráfica de usuario basada en Swing o AWT, pero también
podría ser tan simple como una interfaz de línea de comandos.
Las aplicaciones de escritorio acceden directamente a los beans enterprise que se ejecutan
en la capa de negocio.
Applets
Un applet es una pequeña aplicación cliente que se ejecuta en la máquina virtual Java
embebida en el navegador web. En las máquinas cliente necesitará el plugin de Java y,
posiblemente un certificado de seguridad para que el applet pueda ejecutarse con éxito en
el navegador web.
JavaBeans
Las capas servidor y cliente pueden incluir componentes JavaBeans para comunicar estas
dos capas que servirán de puente entre ambas.
Los componentes JavaBeans son clases Java que tienen propiedades y métodos get y set
para acceder a las mismas. Los componentes JavaBeans utilizados de esta manera suelen
ser simples en su diseño e implementación, pero deben ajustarse a las convenciones de
nombres y de diseño descritos en la arquitectura de componentes JavaBeans.
Los componentes JavaBeans no son considerados componentes Java EE por parte de la
especificación Java EE.
Componentes web
Los componentes Web Java EE son servlets o páginas web creadas usando la tecnología
JavaServer Faces y / o la tecnología JSP (páginas JSP).
Los servlets son clases Java que procesan en forma dinámica peticiones y construyen
respuestas.
Las páginas JSP son documentos basados en texto que se ejecutan como servlets pero
permiten un enfoque más natural para la creación de contenido estático.
JavaServer Faces se basa en servlets y JSP y proporciona un marco de componentes de
interfaz de usuario para las aplicaciones web.
Las páginas HTML estáticas y los applets se incluyen con los componentes web, pero no se
consideran componentes web según la especificación Java EE.
Las clases de utilidades del lado del servidor también pueden ser incluidas con los
componentes web y, al igual que las páginas HTML, no se consideran componentes web.
Componentes de negocio
Es la lógica que resuelve las necesidades del negocio. Es manejado por los javabeans, ya
sea en la capa de negocio o de la capa web.
Un bean enterprise recibe datos de los programas clientes, los procesa (si es necesario), y
los envía a la capa del sistema de información empresarial para su almacenamiento.
Un bean enterprise también recupera datos desde el almacenamiento, los procesa (si es
necesario), y los envía de vuelta al programa cliente.
Hay tres tipos de beans enterprise: beans de sesión (con o sin estado), beans de entidad
(manejados por el bean o por el contenedor) y beans dirigidos a mensaje.
Un bean de sesión representa una conversación temporal con un cliente. Cuando el cliente
finaliza su ejecución, el bean de sesión y sus datos desaparecen.
Por el contrario, un bean de entidad representa datos persistentes almacenados en una fila
de una tabla/relación de una base de datos. Si el cliente se termina o si se apaga el
servidor, los servicios subyacentes se aseguran de grabar el bean.
Un bean dirigidoamensaje combina las características de un bean de sesión y de un
oyente de Java Message Service (JMS), permitiendo que un componente de negocio reciba
asíncronamente mensajes JMS.
Capa Enterprise Information System
Esta capa maneja el software EIS e incluye sistemas de infraestructura de la empresa, tales
como la planificación de recursos empresariales (ERP), sistemas de bases de datos, etc.
Por ejemplo, los componentes de aplicaciones Java EE pueden necesitar acceso a los
sistemas de información de la empresa para la conectividad de la base de datos.
Java EE Contenedores
La arquitectura Java EE está basada en componentes y es independiente de la plataforma,
lo que hace que las aplicaciones Java EE sean más fáciles de escribir porque la lógica de
negocio está organizada en componentes que son reutilizables.
Además, el servidor Java EE proporciona servicios como un contenedor para cada tipo de
componente.
Servicios de contenedor
Los contenedores son la interfaz entre un componente y la funcionalidad específica de la
plataforma de bajo nivel que soporta el componente.
Antes de que pueda ser ejecutado un ejb o un componente de aplicación cliente, deben ser
empaquetados en un módulo Java EE y desplegados en su contenedor.
El proceso de deploy implica especificar valores de contenedor para cada componente en la
aplicación Java EE y para la aplicación Java EE en sí.
Se pueden personalizar valores de servicios tales como la seguridad, la gestión de
transacciones, Java Naming and Directory Interface API de búsquedas (JNDI), y
conectividad remota.
Como la arquitectura Java EE proporciona servicios configurables, los mismos
componentes de una aplicación Java EE pueden comportarse de forma diferente en función
de donde se desplieguen. Por ejemplo, un ejb puede tener la configuración de seguridad
que permite un cierto nivel de acceso a los datos de base de datos en un entorno de
producción y otro nivel de acceso a la base de datos en otro entorno de producción.
Tipos de contenedores
El proceso de despliegue instala los componentes de aplicaciones Java EE en los
contenedores Java EE.
● Servidor Java EE: Un servidor Java EE proporciona contenedores EJB y web.
● Enterprise JavaBeans (EJB): gestiona la ejecución de los ejbs para las
aplicaciones Java EE.
● Contenedor web: Gestiona la ejecución de páginas web, servlets, y algunos
componentes EJB para aplicaciones Java EE.
● Contenedor de cliente de aplicación: Gestiona la ejecución de los componentes
de cliente de aplicaciones. Los clientes de aplicación y su contenedor se ejecutan en
el cliente.
● Contenedor de applets: Gestiona la ejecución de applets. Consta de un navegador
web y Java Plugin que se ejecuta en el cliente.
Servidores Java EE
Los servidores Java EE representan el ambiente en el que ejecutan los componentes.
Estos componentes se denominan componentes serverside o componentes de aplicación
JEE.
Puede tratarse de
● Componentes web (JSP / Servlets / JSF)
● Componentes de negocio (EJB)
Estos componentes ejecutan en un contenedor
Servidor de aplicaciones Java EE
Un servidor de aplicaciones Java EE es una implementación de la especificación Java EE.
Java EE provee estándares que permiten a un servidor de aplicaciones servir como
contenedor de los componentes que conforman dichas aplicaciones. Debe servir como
contenedor web y contenedor ejb.
Entre los servidores de aplicación Java EEmás conocidos están WebLogic de Oracle,
WebSphere de IBM, ambos licenciados, y dentro de los libres se encuentran JOnAs, JBoss,
Geronimo, Glassfish, etc.
Mucha gente confunde
Tomcat como un servidor de aplicaciones; sin embargo, es
solamente un contenedor web.
Java EE y empaquetado de aplicaciones
Una aplicación Java EE se empaqueta en una o más unidades. Cada unidad contiene
● Un componente funcional como ejbs, página web, servlets, o un applet
● Un descriptor de despliegue opcional que describe su contenido. Estos descriptores
de despliegue contienen información específica de cada componente empaquetado
y son un mecanismo para configurar el comportamiento de la aplicación en el
momento del ensamble o del despliegue.
Una vez que se empaqueta la aplicación Java EE, está lista para ser desplegada.
Para el despliegue se utiliza la herramienta de despliegue de la plataforma para especificar
la información específica de la ubicación, la lista de los usuarios que pueden acceder a ella,
el nombre de la base de datos, entre otras cosas. Una vez desplegado en el servidor, la
aplicación está lista para ser utilizada.
Empaquetado
Una aplicación Java EE se empaqueta en:
● archivo Java Archive (JAR)
● archivo Archivo Web (WAR)
● archivo EAR (Enterprise Archive).
Una aplicación Java EE se empaqueta en un archivo enterprise (.ear) que contiene toda la
aplicación junto con el descriptor de despliegue que proporciona información sobre la
aplicación y sus componentes.
Un descriptor de despliegue es un documento XML donde describe la configuración de
despliegue de una aplicación, un módulo o un componente. Como la información de
descriptor de despliegue es declarativa se puede cambiar sin la necesidad de modificar el
código fuente.
Es en tiempo de ejecución que el servidor Java EE lee el descriptor de despliegue y actúa
sobre la aplicación, módulo o componente en consecuencia sin necesidad de recompilar el
código fuente.
Existen 2 tipos de descriptores de despliegue:
● Descriptores de despliegue JEE (JEE deployment descriptor): configuran las
opciones de despliegue de cualquier componente de Java Empresarial
● Descriptores de despliegue del entorno de ejecución (runtime deployment
descriptor): configuran opciones del entorno de ejecución de nuestra aplicación
empresarial, tales como las opciones de caché en el servidor
Un módulo Java EE consta de uno o más componentes de Java EE para el mismo tipo de
contenedor y, opcionalmente, descriptores de despliegue de ese tipo.
Un descriptor de despliegue del módulo Enterprise Bean, por ejemplo, declara atributos de
transacción y las autorizaciones de seguridad para un bean enterprise. Un módulo Java EE
puede implementarse como un módulo independiente.
Los módulos Java EE son de los siguientes tipos:
● Módulos EJB: contiene los beans de empresa y, opcionalmente, un descriptor de
despliegue EJB. Estos módulos son empaquetados como archivos JAR con
extensión .jar.
● Módulos web: contienen las clases de los servlets, archivos web, archivos utilitarios,
imágenes y HTML, y, opcionalmente, un descriptor de despliegue de aplicaciones
Web. Estos módulos son empaquetados como archivos JAR con una extensión .war
(archivo web).
● Módulos cliente: contienen las clases y, opcionalmente, un descriptor de despliegue
de aplicaciones de cliente. Estos módulos se empaquetan como archivos JAR con
una extensión .jar.
● Los módulos adaptadores de recursos, contienen todas las interfaces Java, clases,
bibliotecas nativas, y, opcionalmente, un descriptor de despliegue del adaptador de
recursos. Estos módulos son empaquetados como archivos JAR con una extensión
.rar (archivo adaptador de recursos).
Roles de desarrollo
El uso de módulos reutilizables hacen posible dividir el desarrollo de aplicaciones y el
proceso de implementación en distintos roles para que diferentes personas puedan realizar
diferentes partes del proceso.
Los dos primeros papeles, Java EE proveedor de productos y proveedor de herramientas,
implican la compra e instalación del producto y herramientas Java EE.
Después que el software es comprado e instalado, los componentes Java EE pueden ser
desarrollados por los proveedores de componentes de aplicaciones, ensamblados por los
ensambladores de aplicaciones, y desplegados por los implantadores de aplicaciones.
En una organización grande, cada una de estas funciones podrían ser ejecutados por
diferentes individuos o equipos. Esta división del trabajo funciona porque cada una de las
funciones anteriores genera un archivo portátil que es la entrada para una función
subsiguiente. Por ejemplo, en la fase de desarrollo componente de aplicación, un
desarrollador de software bean enterprise proporciona archivos JAR EJB. En el papel
conjunto de aplicación, otro desarrollador puede combinar estos archivos JAR EJB en una
aplicación Java EE y guardarlo en un archivo EAR. En el papel de implantación de
aplicaciones, un administrador de sistemas en el sitio del cliente utiliza el archivo EAR para
instalar la aplicación Java EE en el servidor.
Los diferentes roles no siempre son ejecutados por diferentes personas.
Proveedor del producto Java EE
El proveedor de productos de Java EE es la empresa que diseña y pone a disposición para
su compra las APIs de la plataforma Java EE y otras características definidas en la
especificación Java EE. Son típicamente los fabricantes de servidores de aplicaciones que
implementan la plataforma Java EE de acuerdo con la especificación Java EE.
Proveedor de herramientas
El proveedor de la herramienta es la empresa o persona que desarrolla, monta y crea
herramientas para los paquetes utilizados por los proveedores de componentes,
ensambladores, y quienes los despliegan.
Proveedor de componentes de aplicación
El proveedor de componentes de aplicación es la empresa o persona que crea
componentes web, beans de empresa, applets u clientes de aplicaciones para su uso en
aplicaciones Java EE.
Bean Enterprise Developer
Se trata de un desarrollador de bean de empresa que realiza las siguientes tareas:
● Escribe y compila el código fuente
● Especifica el descriptor de despliegue (opcional)
● Empaqueta los archivos .class y descriptor de despliegue en el archivo JAR EJB
Web Component Developer
Se trata de un desarrollador de componentes web que realiza las siguientes tareas:
● Escribe y compila el código fuente del servlet
● Escribe JavaServer Faces, JSP y archivos HTML
● Especifica el descriptor de despliegue (opcional)
● Empaqueta el descriptor .class, .jsp y archivos .html en el archivo WAR
Desarrollador de aplicaciones de cliente
Se trata de un desarrollador de aplicaciones cliente que realiza las siguientes tareas:
● Escribe y compila el código fuente
● Especifica el descriptor de despliegue para el cliente (opcional)
● Empaqueta los archivos .class y descriptor de despliegue en el archivo JAR
Ensamblador de aplicación
El ensamblador de la aplicación es la empresa o persona que recibe los módulos de
aplicación de los proveedores de componentes y los empaqueta en un archivo EAR.
Realiza las siguientes tareas:
● Se ensambla archivos JAR EJB y WAR creados en las fases anteriores en una
aplicación Java EE archivo (EAR)
● Especifica el descriptor de despliegue de la aplicación Java EE (opcional)
● Verifica que el contenido del archivo EAR están bien formadas y cumplen con la
especificación Java EE
Administrador de aplicación
El programa de implementación de aplicaciones y administrador sea la empresa o persona
que configura y despliega los clientes de aplicaciones, aplicaciones web, componentes
JavaBeans Enterprise y las aplicaciones Java EE, administra la infraestructura
computacional y de redes, donde los componentes y aplicaciones Java EE corren, y
supervisa el entorno de ejecución. Las responsabilidades incluyen controles de transacción
de ajuste y los atributos de seguridad y especificando las conexiones a bases de datos.
Durante la configuración, el programa de implementación sigue las instrucciones
suministradas por el proveedor del componente de aplicación para resolver las
dependencias externas, especifique la configuración de seguridad, y asignar atributos de
transacción. Durante la instalación, el programa de implementación mueve los componentes
de la aplicación en el servidor y genera las clases e interfaces específicos del contenedor.
Un administrador del programa de implementación o el sistema realiza las siguientes tareas
para instalar y configurar una aplicación o componentes Java EE:
● Configura la aplicación Java EE o componentes para el entorno operativo
● Verifica que los contenidos de la oreja, JAR, y / o archivos WAR están bien formadas
y cumplen con la especificación Java EE
● Despliega (instala) la aplicación Java EE o componentes en el servidor Java EE
¿Qué es JPA?
Java Persistence API (JPA) nos brinda un estándar para poder gestionar datos relacionales
en aplicaciones java, de tal forma que además simplifica el desarrollo de la persistencia de
datos.
JPA establece una interface común que es implementada por un proveedor de persistencia,
tales como Hibernate, EclipseLink u otro. Podemos elegir en cualquier momento el
proveedor que más se adecue a nuestras necesidades. Así, es el proveedor quién realiza el
trabajo, pero siempre funcionando bajo la API de JPA.
Para los ejemplos del curso utilizaremos Hibernate, pero si lo prefieren pueden utilizar otro
en cualquier momento.
Hibernate es un framework open source de mapeo y persistencia para ser utilizado en Java.
Sus librerías ya vienen con el servidor de aplicaciones WildFly por lo que no tendremos que
agregar librerias adicionales.
Para entender JPA, tendremos que tener claro el concepto de persistencia. La persistencia
o el almacenamiento permanente, es una de las necesidades básicas de cualquier sistema
de información de cualquier tipo. Persistir objetos Java en una base de datos relacional
implica serializar un árbol de objetos Java en una base de datos de estructura tabular y
viceversa. Es vital poder mapear objetos Java para optimizar velocidad y eficiencia de la
base de datos.
Entidades
Una entidad es un objeto de dominio persistencia liviano. Por lo general, una entidad
representa una tabla en una base de datos relacional, y cada instancia de la entidad
corresponde a una fila de esa tabla.
Una entidad tiene campos o propiedades que son persistentes.
Ejemplo de entidad
@Entity
@Table(name = "PERSONA")
public class Persona {
@Id
@GeneratedValue
private Long id;
@Column(nullable=false)
private String nombre;
@Column(nullable=true)
private Date fechaNacimiento;
@Transient
private int edad;
// Getters y Setters
}
La anotación @Table nos permite configurar el nombre de la tabla donde queremos
almacenar la entidad mediante el atributo name.
En el ejemplo de la entidad Persona, los campos persistentes son el id, nombre y
fechaNacimiento. El campo edad no se almacenará en la base de datos ya que está
anotado como transient. Este campo puede ser calculado a partir de la fecha de nacimiento,
es por eso que no necesita ser almacenado en la base de datos.
Propiedades persistentes
Si la entidad utiliza las propiedades persistentes, la entidad debe seguir las convenciones
JavaBeans: esto implica el uso de métodos get y set.
En el ejemplo de la entidad Persona, si utiliza las propiedades persistentes y tiene una
variable de instancia privada denominada nombre, la clase define un getNombre y
setNombre.
Tipos de acceso
JPA permite definir dos tipos de acceso:
● Acceso a variable
● Acceso a propiedad
El tipo de acceso que usará una entidad está definido por el lugar donde situemos sus
anotaciones de mapeo. Si las anotaciones están en las variables estaremos indicando a
JPA que debe realizar acceso a variable. Si, por el contrario situamos las anotaciones de
mapeo en los métodos getter, estaremos indicando un acceso a propiedad.
A efectos prácticos, no existe diferencia alguna entre ambas opciones.
Tipos enumerados
JPA puede mapear los tipos enumerados (enum) mediante la anotación Enumerated:
@Enumerated
private Sexo sexo;
La configuración por defecto de JPA mapeará cada valor ordinal de un tipo enumerado a
una columna de tipo numérico en la base de datos.
public enum Sexo {
FEMENINO,
MASCULINO
}
Si la propiedad sexo tiene el valor Sexo.FEMENINO, en la columna correspondiente de la
base de datos de insertará el valor 0.
Si quiero forzar a la base de datos a utilizar una columna de texto en lugar de una columna
numérica: de esta manera, el valor almacenado será el nombre del valor enum, y no su
valor ordinal:
@Enumerated(EnumType.STRING)
private Sexo sexo;
Transient
Ciertas propiedades de una entidad pueden no representar su estado. Por ejemplo,
imaginemos que tenemos una entidad que representa a una persona:
@Entity
public class Persona {
@Id
@GeneratedValue
private Long id;
private String nombre;
private String apellidos
private Date fechaNacimiento;
private int edad;
// getters y setters
}
Podemos considerar que la propiedad edad no representa el estado de Persona, ya que si
no es actualizada cada cumpleaños, terminará conteniendo un valor erróneo. Como su valor
puede calcularse a partir de la fecha de nacimiento, no vamos a guardarlo en la base de
datos. Para indicar al proveedor de persistencia que ignore una propiedad cuando realice el
mapeo, usamos la anotación @Transient:
@Transient
private int edad;
Ahora, para obtener el valor de edad utilizamos su método getter:
public int getEdad() {
// calcular la edad y devolverla
}
Colecciones
Una entidad puede tener propiedades de tipo java.util.Collection y/o java.util.Map que
contengan tipos básicos. Los elementos de estas colecciones serán almacenados en una
tabla diferente a la que contiene la entidad donde están declarados. El tipo de colección
tiene que ser concreto (como ArrayList o HashMap) y nunca una interface.
private ArrayList<String> nombres;
Podemos customizar la configuración de la siguiente manera
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "NOMBRES")
private ArrayList<String> nombres;
@ElementCollection permite definir el tipo de lectura (temprana o demorada).
@CollectionTable nos permite definir el nombre de la tabla donde queremos almacenar los
elementos de la colección. Si nuestra colección es de tipo Map, podemos añadir la
anotación @MapKeyColumn(name = "NOMBRE_COLUMNA"), la cual nos permite definir el
nombre de la columna donde se almacenarán las claves del Map.
Tipos embeddable
Los tipos embeddable son objetos que no tienen identidad: esto significa que para ser
persistidos deben ser primero insertados dentro de una entidad. Cada propiedad del tipo
embeddable será mapeada a la tabla de la entidad que lo contenga, como si fuera una
propiedad declarada en la propia entidad. Definimos un tipo insertable con la anotación
@Embeddable:
@Embeddable
public class Direccion {
private String calle;
private int codigoPostal;
// ...
}
Y lo insertamos en una entidad con la anotación @Embedded
@Entity
public class Persona {
// ...
@Embedded
private Direccion direccion;
}
Ahora, la tabla que contenga las entidades de tipo Persona contendrá sus propias
columnas, más las definidas en el tipo embeddable Direccion.
Las claves
Cada entidad tiene un identificador de objeto único. Una entidad de un cliente, por ejemplo,
puede ser identificado por un número de cliente. El identificador único, o una clave principal,
permite localizar una instancia de entidad en particular.
Cada entidad debe tener una clave principal. Una entidad puede tener una clave simple o
compuesta.
Las claves primarias simples utilizan el javax.persistence.Id anotación para indicar la
propiedad de clave primaria en el campo.
Las claves primarias compuestas se utilizan cuando una clave principal se compone de más
de un atributo, que corresponde a un conjunto de propiedades persistentes individuales o
campos. Las claves primarias compuestas deben ser definidas en una clase aparte de clave
primaria. Las claves primarias compuestas se denotan usando las anotaciones
javax.persistence.EmbeddedId y javax.persistence.IdClass.
Las Entidades poseen una identidad que las diferencie del resto
● Propiedad marcada con la anotación @Id
● Debe admitir valores null, p.e.: Integer en lugar de int
● La identidad de una entidad va a ser gestionada por el proveedor de persistencia
● Propiedad de identidad anotada: @GeneratedValue
La anotación @GeneratedValue permitirá la generación de forma totalmente automática y
transparente de una clave primaria cada vez que sea necesario insertar un nuevo
objeto/registro. Para esta generación JPA define cuatro estrategias:
Claves simples
@GeneratedValue(strategy=GenerationType.IDENTITY)
MySQL y SQLServer tienen un tipo de columna autonumérica (AUTO_INCREMENT e
IDENTITY respectivamente) ideal para ser usadas como clave primaria. Asimismo,
PostgreSQL cuenta con el tipo SERIAL que simula esta funcionalidad creando secuencias.
Podemos usar esta característica mediante este tipo de generador:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
En el caso de Oracle, al no tener esta funcionalidad obtendremos el correspondiente error:
Oracle10gDialect does not support identity key generation
@GeneratedValue(strategy=GenerationType.SEQUENCE)
Una secuencia es un objeto o tipo de datos que genera valores numéricos únicos dentro de
esa secuencia. Ese valor se define dentro de un rango, y se va incrementando según un
valor de incremento a medida que se vayan solicitando nuevos valores (por ejemplo en
Oracle con la sentencia NOMBRE_SEQ.nextval).
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private Long id;
Se pueden definir secuencias específicas para cada clave (o una común a varias de ellas)
con la anotación @SequenceGenerator. Esta anotación tiene como parámetros opcionales
allocationSize, que indica el incremento numérico del avance de la secuencia y cuyo valor
por omisión es 50 (por lo que probablemente queramos definirlo a un valor que nos resulte
más conveniente como por ejemplo 1) y initialValue cuyo valor por defecto es 1 tal y como
cabría esperar.
@Entity
public class EntityA{
@Id
@SequenceGenerator(name="entA", sequenceName="entityA_seq", allocationSize =
1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="entA")
private Long id;
....
@Entity
public class EntityB{
@Id
@SequenceGenerator(name="entB", sequenceName="entityB_seq", allocationSize =
1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="entB")
private Long id;
@GeneratedValue(strategy=GenerationType.AUTO)
Delega en el proveedor la elección de la estrategia que considere oportuna en función de la
BD subyacente.
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
Es la estrategia más cómoda, pero debemos conocer qué hace nuestro framework ya que el
estándar le da vía libre y es posible que el resultado no sea el deseado.
@GeneratedValue(strategy=GenerationType.TABLE)
Por último, veremos la estrategia más portable de todas ya que se puede emplear de igual
manera en cualquier BD. Se basa en utilizar una tabla con dos columnas, una de tipo texto
con el nombre que identifica al generador de claves primarias (tendremos uno por cada
tabla) y otra de tipo numérico con el último valor que fue asignado como PK para un registro
de esa tabla.
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
private Long id;
Claves múltiples
Con la anotación @Id indicamos un atributo que puede ser de cierto tipo como clave
primaria, pero ¿qué pasaría si nuestra clave primaria es múltiple?
Frente a esta situación, lo que haremos es crear una clase que contenga todos los atributos
de nuestra clave múltiple, y la marcaremos con la anotación @Embeddable que permite que
una clase pueda ser incluída en una entidad y sus atributos formen parte de su mapeo a la
BD.Por ejemplo:
@Embeddable
public class EntityPK implements Serializable{
private Long idRef1;
private Long idRef2;
//getters y setters
Ahora nuestra clave primaria estará compuesta por los dos atributos de esta clase y la
usaremos con la anotación @EmbeddedId:
@Entity
public class EntityA{
@EmbeddedId
EntityPK entityPK;
Operaciones en cascada
Las entidades que utilizan relaciones a menudo tienen dependencias en la existencia de la
otra entidad en la relación.
Por ejemplo, un elemento de línea es parte de un pedido; si se elimina la orden, el elemento
de línea también debería eliminarse. Esto se llama una eliminación en cascada.
El tipo enumerado javax.persistence.CascadeType define las operaciones en cascada que
pueden aplicarse.
Operación en
cascada Descripción
ALL Todas las operaciones en cascada se aplicarán a la entidad
relacionada. All es equivalente a especificar cascade={DETACH,
MERGE, PERSIST, REFRESH, REMOVE}
DETACH Si la entidad matriz se separa del contexto de persistencia, también
puede separar la entidad relacionada.
MERGE Cuando una entidad es actualizada (se va a grabar), su entidad
relacionada debe ser actualizada también.
PERSIST Cuando una entidad es persistida (se crea), su entidad relacionada
debe ser persistida también.
REFRESH Cuando una entidad es refrescada /se refresca con los datos de la base
de datos), su entidad relacionada debe ser refrescada también.
REMOVE Cuando una entidad es removida (se borra), su entidad relacionada
debe ser removida también.
Algunos ejemplos
@OneToOne
@Entity
public class Departamento implements Serializable {
…
}
@Entity
public class Empleado implements Serializable {
@OneToOne(fetch=FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.RE
MOVE},optional=false)
private Direccion direccion;
…
}
Configuramos la opción fetch a LAZY, de forma que cuando recuperemos un objeto de la
entidad Empleado no recupere la instancia de Dirección asociada. Luego pusimos cascade
a PERSIST y REMOVE, de forma que cuando persistamos un empleado que tenga
asociada una nueva Direccion, éste también se persistirá, y como no tiene sentido que
exista una dirección sin un empleado asociado, si eliminamos la instancia del Empleado
también eliminará la instancia de Direccion asociada. También hemos establecido la opción
optional a false, de forma que no permitimos que se persista una instancia de Empleado si
no está asociada con una instancia de Direccion. Por último, con la opción orphanRemoval
a true indicamos que cualquier instancia de Direccion que no esté asociada a una instancia
de Empleado será eliminada de la base de datos.
Ahora vamos a convertir la relación onetoone unidireccional en bidireccional. Bastaría con
añadir a la entidad Direccion un atributo haciendo referencia a la entidad Empleado y anotar
el atributo con @OneToOne.
@OneToOne(fetch=FetchType.LAZY,mappedBy="direccion”)
private Empleado empleado;
Agregamos la opción mappedBy con la que indicamos el atributo de la entidad propietaria
de la relación (Empleado en nuestro caso). De esta forma a través de una instancia de la
entidad Direccion podemos recuperar la instancia de la entidad Empleado asociada.
@OneToMany
@Entity
public class Libro implements Serializable {
…
}
@Entity
public class Biblioteca implements Serializable {
@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.ALL})
private List<Libro> libros;
…
}
La opción fetch
está en LAZY, de forma que cuando recuperemos un objeto de la entidad
cascade
Biblioteca no recupere las instancias de Libro asociadas. Luego pusimos a todo, de
forma que cuando persistamos, borremos o modifiquemos una Biblioteca sus libros también
se actualizarán
@ManyToOne
@Entity
public class Biblioteca implements Serializable {
@Id
@GeneratedValue
private Long id;
…
}
@Entity
public class Libro implements Serializable {
@ManyToOne(fetch=FetchType.LAZY,optional=false)
@JoinColumn(name="id")
private Biblioteca biblioteca;
…
}
La anotación @JoinColumn o @JoinColumns se usa para especificar cual es el campo de la
tabla que actúa de clave foránea o clave foránea compuesta, respectivamente.
@ManyToMany
@Entity
public class Clase{
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
private int id;
private String name;
@ManyToMany
private List<Profesor> profesores;
….
@Entity
public class Profesor{
@Id
@GeneratedValue( strategy = GenerationType.AUTO )
private int id;
private String name;
@ManyToMany(mappedBy="profesores")
private List<Clase> clases;
….
Herencia
La herencia es el concepto de la base de cualquier lenguaje orientado a objetos, por lo
tanto, podemos utilizar las relaciones de herencia o estrategias entre las entidades. JPA
admiten tres tipos de estrategias de herencia: SINGLE_TABLE, JOINED_TABLE y
TABLE_PER_CONCRETE_CLASS.
SINGLE_TABLE: Una sola tabla para guardar toda la jerarquía de clases. Tiene la ventaja
de ser la opción que mejor rendimiento da, ya que sólo es necesario acceder a una tabla
(está totalmente desnormalizada). Tiene como inconveniente que todos los campos de las
clases hijas tienen que admitir nulos, ya que cuando guardemos un tipo, los campos
correspondientes a los otros tipos de la jerarquía no tendrán valor.
JOINED_TABLE: Una tabla para el padre de la jerarquía, con las cosas comunes, y otra
tabla para cada clase hija con las cosas concretas. Es la opción más normalizada, y por lo
tanto la más flexible (puede ser interesante si tenemos un modelo de clases muy
cambiante), ya que para añadir nuevos tipos basta con añadir nuevas tablas y si queremos
añadir nuevos atributos sólo hay que modificar la tabla correspondiente al tipo donde se
está añadiendo el atributo. Tiene la desventaja de que para recuperar la información de una
clase, hay que ir haciendo join con las tablas de las clases padre.
TABLE_PER_CONCRETE_CLASS: Una tabla independiente para cada tipo. En este caso
cada tabla es independiente, pero los atributos del padre (atributos comunes en los hijos),
tienen que estar repetidos en cada tabla. En principio puede tener serios problemas de
rendimiento, si estamos trabajando con polimorfismo, por los SQL UNIONS que se tienen
que hacer para recuperar la información. Sería la opción menos aconsejable. Tanto es así
que en la versión 3.0 de EJBs, aunque está recogida en la especificación, no es obligatoria
su implementación.
Ejemplo
Aquí tenemos un ejemplo clásico de herencia donde tenemos una Persona que puede ser
un Alumno o un Profesor.
Vamos a ver ahora como implemento esta realidad con la estrategia SINGLE_TABLE
@Entity
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
@DiscriminatorColumn( name="tipo" )
public abstract class Persona {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String apellido;
private String nombre;
// SETTERS AND GETTERS
}
@Entity
@DiscriminatorValue( value="ALUMNO" )
public class Alumno extends Persona implements Serializable {
private int generacion;
// GETTERS AND SETTERS
}
@Entity
@DiscriminatorValue( value="PROFESOR" )
public class Profesor extends Persona implements Serializable {
private String gradoDocente;
// GETTERS AND SETTERS
}
La tabla física que se genera es la siguiente:
Id Tipo Nombre Apellido Generacion GradoDocente
1 Juan Perez
2 Maria Gonzalez
Alumno
Id Generacion
1 2005
Profesor
Id GradoDocente
2 grado 3
Unidades de persistencia
La agrupación de entidades en una aplicación se llama unidad de persistencia.
La unidad de
persistence.xml
persistencia de la aplicación se define en un archivo llamado . Este
archivo debe existir dentro del directorio METAINF de la aplicación.
El archivo persistence.xml tiene muchas funciones, pero la más importante es la de listar
todas las entidades, nombrar la unidad de persistencia y brindar los datos necesarios para
almacenar los datos en la base de datos elegida.
Un ejemplo de archivo de persistencia es:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.1">
<persistenceunit name="ejemploJPA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jtadatasource>java:/XAOracleDS</jtadatasource>
<class>com.ejemplo.Curso</class>
<class>com.ejemplo.Materia</class>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.hbm2ddl.auto" value="createdrop"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistenceunit>
</persistence>
Qué es
JPQL es un lenguaje de consulta orientado a objetos definido en la especificación de Java
Persistence API (JPA).
JPQL es usado para hacer consultas contra las entidades almacenadas en una base de
datos relacional. Su sintaxis es muy similar a la de SQL, pero mientras SQL trabaja
directamente con bases de datos relacionales, registros y campos; JPQL lo hace con clases
Java e instancias.
Además de recuperar objetos a través de las consultas SELECT, JPQL también soporta
consultas de actualización y borrado como lo son el UPDATE y DELETE.
Sintaxis
Veamos primero la sintaxis de este tipo de consultas empezando con un ejemplo.
SELECT m FROM Materia m
Esta query lo que hace es obtener todas las instancias de la clase Materia de la base de
datos. El SELECT se utiliza para seleccionar cierta información desde el FROM.
El “FROM Materia m” indica que m es un alias para la clase Materia, mientras que el
“SELECT m” indica que la expresión m se utiliza para acceder a la clase Materia a la que
refiere el alias o a sus propiedades.
Si quisiera obtener el nombre de las materias:
SELECT m.nombre FROM Materia m
También puede querer obtener los ids y nombres de todas las materias:
SELECT m.id, m.nombre FROM Materia m
Puedo querer eliminar los resultados duplicados usando la clausula DISTINCT:
SELECT DISTINCT p.nombre FROM Materia m
También puedo utilizar funciones agregadas como el COUNT, SUM, MAX, MIN, AVG, etc.
Si quisiera saber la cantidad de materias que tengo:
SELECT COUNT(m) FROM Materia m
El WHERE permite restringir los resultados devueltos por una consulta, en base a ciertos
criterios lógicos.
SELECT m FROM Materia m
WHERE m.capacidad < 50
En esta sentencia estoy obteniendo todas las instancias de Materia que tengan una
capacidad de menos de 50 estudiantes. También puedo agregar más condiciones:
SELECT m FROM Materia m
WHERE m.capacidad < 50 AND m.tipo = ‘CIENCIAS’
En este caso se obtienen las materias con capacidad menor a 50 estudiantes y que sean de
tipo CIENCIAS.
Puedo utilizar los operadores lógicos AND, OR y NOT.
SELECT m FROM Materia m
WHERE m.capacidad < 50 AND NOT (m.tipo = ‘CIENCIAS’)
Ahora estoy obteniendo las materias con capacidad menor a 50 estudiantes y que NO sean
de tipo CIENCIAS.
También puedo utilizar el BETWEEN para comparar entre rangos:
SELECT m FROM Materia m
WHERE m.capacidad BETWEEN 20 AND 50
Otro operador de comparación muy útil es [NOT] LIKE (NOT es opcional), el cual nos
permite comparar una cadena de texto completa o solo una parte de ella:
SELECT m FROM Materia m
WHERE m.nombre LIKE 'A%'
En esta consulta se obtienen todas las instancias de Materia cuyo nombre comience con A.
Parámetros
Podemos agregar parámetros en forma dinámica a nuestras sentencias JPQL de dos
maneras: por posición y por nombre.
Por posición:
SELECT m FROM Materia m
WHERE m.nombre = ?1
Por nombre:
SELECT m FROM Materia m
WHERE m.nombre = :nombre
Cuando quiera ejecutar la consulta tendré que pasar el o los valores que sustituyan a los
parámetros definidos.
Para poder ordenar los resultados de nuestras consultas, podemos utilizar la cláusula
ORDER BY que admite ordenamiento ascendente (ASC que es el por default) o
descendente (DESC):
SELECT m FROM Materia m
ORDER BY m.capacidad DESC
Aquí se retornan las materias ordenadas por capacidad de mayor a menor.
SELECT m FROM Materia m
WHERE m.tipo = ‘CIENCIAS’
ORDER BY m.capacidad DESC, m.nombre ASC
Ahora estoy obteniendo todas las materias de tipo CIENCIAS ordenadas por capacidad de
mayor a menor y el forma alfabética.
Resumiendo:
Una sentencia select puede tener 6 cláusulas:
SELECT, FROM, WHERE, GROUP BY, HAVING, and ORDER BY.
El SELECT y FROM son obligatorias, pero el WHERE, GROUP BY, HAVING, y ORDER BY
son opcionales.
La sintaxis de alto nivel sería:
QL_statement ::= select_clause from_clause
[where_clause][groupby_clause][having_clause][orderby_clause]
Donde
● El SELECT define los tipos de objetos o valores que retorna la query.
● El FROM define el alcance de la query definiendo una o más variables de
identificación que podrán ser referenciadas en el SELECT y WHERE. Una variable
de identificación representa uno de los siguientes elementos:
○ El nombre del esquema abstracto de una entidad
○ Un elemento colección de una relación
○ Un elemento de un solo valor de una relación
○ Un miembro de una colección que es el lado múltiple de una relación one to
many.
● El WHERE es una expresión condicional que restringe los objetos o valores que
retorna la query.
● El GROUP BY agrupa resultado de acuerdo a un conjunto de propiedades.
● El HAVING es usado junto con el GROUP BY para restringir los resultados de
acuerdo a la expresión.
● El ORDER BY ordena los objetos o valores retornados por la query.
Los named parameters son los parámetros de consulta con el prefijo dos puntos ( : ). Estos
parámetros se setean utilizando el método javax.persistence.Query.setParameter (String
nombre, Object valor)
Los named parameters son case sensitive y pueden ser utilizados por ambas consultas
dinámicas y estáticas.
En el método obtenerMateriaPorTipo, el named parameter es “tipo”.
En vez de los named parameters pueden utilizarse parámetros posicionales en las
consultas. Los parámetros posicionales van precedidos de un signo de interrogación ( ? ),
seguido de la posición numérica del parámetro de la consulta. El método
Query.setParameter(integer position, Object value) se utiliza para establecer los valores de
los parámetros.
Reescribiendo el método de obtenerMateriasPorTipo con parámetros posicionales sería:
public List obtenerMateriasPorTipo(String tipoMateria) {
return em.createQuery(
"SELECT m FROM Materia m WHERE m.tipo LIKE ?1")
.setParameter(1, tipoMateria)
.setMaxResults(10)
.getResultList();
}
Por último puedo querer ejecutar sentencias SQL nativas en vez de una sentencia JPQL:
String sql = "SELECT * FROM MATERIA";
Query query = em.createNativeQuery(sql);
// ...
Estas consultas SQL nativas también pueden ser definidas de manera estática:
@Entity
@NamedNativeQuery(name=”Materia.obtenerTodas”, query="SELECT * FROM MATERIA")
public class Materia {
// ...
}
Manejo de Entidades
Entity Manager
Las entidades son gestionadas por el gestor de entidades, que está representado por el
javax.persistence.EntityManager. Cada instancia del EntityManager, se asocia con un
contexto de persistencia: un conjunto de instancias de entidades manejadas que existen en
cierto almacén de datos.
Un contexto de persistencia define el alcance bajo el cual instancias de entidades son
creadas, persistidas y removidas. La interfaz EntityManager define los métodos que se
utilizan para interactuar con el contexto de persistencia.
La interfaz EntityManager
La API EntityManager crea y elimina instancias de entidad persistentes, encuentra las
entidades por la clave primaria de la entidad, y permite ejecutar consultas en las entidades.
Métodos callback
Los métodos callback
son métodos que se ejecutan cuando se producen ciertos eventos
relacionados con el ciclo de vida de una entidad. Estos eventos se clasifican en cuatro
categorías:
● Eventos de persistencia (métodos callback asociados anotados con @PrePersists y
@PostPersist: antes y después de persistir)
● Eventos de actualización (métodos callback asociados anotados con @PreUpdate y
@PostUpdate: antes y después de actualizar)
● Eventos de borrado (métodos callback asociados anotados con @PreRemove y
@PostRemove: antes y después de remover)
● Eventos de carga (método callback asociado anotado con @PostLoad: luego de
cargar)
@Entity
public class Materia{
...
@PrePersist
@PreUpdate
private void validar() {
// validación de parámetros antes de persistir/actualizar la entidad
}
}
El método validar() se ejecutará ante 2 eventos: el momento antes de realizarse la
persistencia (@PrePersist), y el momento previo a la actualización (@PreUpdate).
Al escribir métodos callback, debemos seguir algunas reglas para que nuestro código sea
válido:
● Un método callback no puede ser declarado static ni final
● Cada anotación de ciclo de vida puede aparecer una y solo una vez en cada entidad
● Un método callback solo puede tirar excepciones de tipo unchecked (de runtime)
● Un método callback no puede invocar métodos de las clases EntityManager y/o
Query
Clases listener
Cuando necesitamos aplicar un mismo método callback a varias entidades, es preferible
extraer de la entidad este método y ponerlo en una clase externa, la cual podrá ser aplicada
a varias entidades. Estas son las clases listener:
public class ValidadorListener {
@PrePersist
@PreUpdate
public void validar(Materia materia) {
// validar parametros antes de persistir/actualizar la entidad
}
}
Ahora debemos aplicar el listener a las entidades que querramos:
@Entity
@EntityListeners(ValidadorListener.class)
public class Materia { ... }
En tiempo de ejecución, cuando se produzca un evento que se encuentre definido en la
clase listener, el proveedor de JPA pasará a su método validar() una referencia de la
entidad Materia.
También existe la anotación @EntityListeners puede hacer referencia a varias clases
listener usando un array de objetos .class. Cuando una entidad es asociada con varias
clases listener, los métodos callback de dichas clases que hagan referencia a un mismo
evento serán invocados en el orden en que fueron declarados dentro del array.
Así mismo, los métodos callback de las clases listener serán invocados de manera previa a
los métodos callback que hagan referencia al mismo tipo de evento y que estén declarados
dentro de la entidad:
@Entity
@EntityListeners({
ValidadorListener.class,
OtroListener.class})
public class Materia {
// ...
@PrePersist
@PreUpdate
private void validar() {
// validar parámetros antes de persistir y actualizar la entidad
}
}
En este ejemplo, los métodos @PrePersist y @PreUpdate se ejecutarán en este orden:
ValidatorListener, OtroListener, Materia.
JPA
Java Persistence API
¿Que es JPA?
Gestor
BD
Tipos de EJBs
Un EJB suele estar compuesto por una clase de implementación y cero o mas interfaces de
negocio. La clase de implementación contiene las implementaciones de los métodos de
negocio. Debe estar anotada con: @Stateless, @Stateful o @Singleton
Las interfaces de negocio contienen las declaraciones de los métodos de negocio visibles al
cliente y son implementadas por el bean.
Sin estado
Un EJB Stateless es una clase java sin estado, es decir, no debería tener atributos, sólo
métodos a los que se pueda llamar de forma independiente. Este tipo de EJB no mantienen
estado conversacional ni presentan problemas de concurrencia.
Para que el contenedor de aplicaciones lo maneje, sólo hay que ponerle la anotación
@Stateless
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@Stateless
@LocalBean
public class SinEstadoBean {
public void holaMundo(String texto){
System.out.println(“Hola mundo: ”+texto);
}
}
Es una clase con un método al que se le pasa un texto y muestra en consola “Hola mundo”
seguido del texto pasado.
La anotación @Stateless es la que lo convierte en un EJB y le indica al contenedor de
aplicaciones que debe encargarse de manejarlo.
La anotación @LocalBean indica que a esta clase no se va a acceder de forma remota
(desde fuera de nuestra aplicación). Esta anotación es opcional, ya que por defecto se
asume que el bean no va a ser accedido de forma remota.
Para los EJB sin estado, el contenedor de aplicaciones va a crear varias instancias de estas
clase y le pasará estas instancias a quien las necesite. Como son clases sin estado, el
contenedor dará cualquiera de las instancias que tiene al que la necesite y no se
preocupará de entregar siempre la misma al mismo cliente.
Con estado
Un EJB con estado es una clase en la que sí hay atributos y cuyo valor es importante y
debe conservarse entre llamadas a métodos.
El contenedor de aplicaciones instanciará, al igual que con los EJB sin estado, un número
determinado de ellos, asegurandose de dar siempre al mismo cliente/usuario la misma
instancia. De esta manera, el cliente puede guardar en él datos que sean propios de él y
que necesiten conservarse mientras está trabajando con la aplicación.
Un ejemplo típico es el carrito de la compra de una web. Los productos que el usuario va
añadiendo al carrito se guardarían en un EJB con estado.
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Remove;
import javax.ejb.Stateful;
@Stateful
@LocalBean
public class ConEstadoBean {
@EJB
SinEstadoBean sinEstadoBean;
// Estado
private String estado;
public void setEstado(String estado){
this.estado = estado;
}
@Remove
public void mostrarEstado(){
sinEstadoBean.holaMundo(estado);
}
}
Esta clase utiliza la anotación @Stateful para indicar que es un EJB con estado. La
anotación @LocalBean, al igual que antes, es opcional e indica que este bean no se va a
utilizar de forma remota.
Esta clase tiene un atributo de tipo String llamado estado y un método setEstado que le da
un valor. Como se trata de un EJB con estado, este estadose conservará para la llamada a
mostrarEstado().
La anotación @Remove en el método mostrarEstado() se usa para indicar al contenedor
que ya hemos terminado de usar este EJB con estado. Cuando encuentra esta llamada el
contenedor sabe que puede darle este EJB a otro que lo necesite pues ya fue usado.
Tenemos también el atributo @EJB SinEstadoBean sinEstadoBean que utilizaremos para
realizar la llamada a nuestro holaMundo de modo de mostrar en consola el estado. Como
SinEstadoBean es un EJB controlado por el contenedor de aplicaciones, no hacemos
nosotros el new de esta clase, la anotamos con @EJB y es el contenedor quien se
encargará de pasarnos una de las instancias que tiene de SinEstadoBean y podremos
usarla.
Singleton
Un EJB Singleton es una clase Java que el contenedor de aplicaciones instanciará una
única vez y será compartida en la aplicación por los clientes. Está pensada para guardar los
datos que son comunes a todos los usuarios o clientes de nuestra aplicación.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
@Singleton
@Startup
public class SingletonBean {
@PostConstruct
public void init() {
System.out.println("SingletonBean arranca");
}
@PreDestroy
public void destroy() {
System.out.println("SingletonBean termina");
}
}
La anotación @Singleton convierte a esta clase Java en un Singleton.
La anotación @Startup nos sirve para indicarle al contenedor de aplicaciones que debe
arrancar este EJB al inicio. Si no ponemos la anotación, el bean no arranca hasta que
alguien lo necesite.
En general la anotación @Startup no se utiliza, salvo que este bean realice algo que
necesite ser hecho en el momento de arrancar el contenedor de aplicaciones/nuestra
aplicación.
Cuando este EJB arranque se ejecutará lo que esté dentro del método con @PostConstruct.
Si no hay ningún método con esta anotación, no se hará nada en el arranque, pero si hay
algún método anotado de esta manera, se ejecutará después de cargar el bean, pero antes
de que empiece a usarse. Es un método de inicialización de la clase.
Si queremos realizar alguna acción cuando el bean se vaya a destruir (al finalizar nuestra
aplicación), debemos anotar el método que queramos que se ejecute con @PreDestroy.
Apuntes de Aplicaciones Enterprise
Contenido
Página 1
Implementar herencia con estrategia SIMPLE
Característica: una tabla para toda la jerarquía.
Se persistió una instancia de Profesor y otra de Alumno, y se obtuvo una tabla en la base de
datos con la siguiente estructura y contenido:
Página 2
Se implementó de la siguiente manera en el servidor:
Persona.java
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="tipo")
public class Persona implements java.io.Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(length=20)
private String nombre;
@Column(length=20)
private String apellido;
public Persona() {
super();
}
// getters y setters
}
}
Página 3
Alumno.java
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@DiscriminatorValue(value="ALUMNO")
public class Alumno extends Persona implements Serializable {
public Alumno() {
super();
}
//getters y setters
}
Profesor.java
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@DiscriminatorValue(value="PROFESOR")
public class Profesor extends Persona implements Serializable {
public Profesor() {
super();
}
//getters y setters
}
Página 4
PersonasBeanRemote.java
package com.servicios;
import java.util.List;
import javax.ejb.Remote;
import com.entidades.*;
@Remote
public interface PersonasBeanRemote {
PersonasBean.java
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.*;
import com.entidades.*;
@Stateless
public class PersonasBean implements PersonasBeanRemote {
@PersistenceContext
private EntityManager em;
public PersonasBean() {
}
@Override
public void crear(Profesor profesor) {
em.persist(profesor);
em.flush();
}
@Override
public void crear(Alumno alumno) {
Página 5
em.persist(alumno);
em.flush();
}
@Override
public List<Persona> obtenerTodos() {
TypedQuery<Persona> query = em.createQuery("SELECT p FROM Persona
p ",Persona.class);
return query.getResultList();
@Override
public Profesor buscarProfesor(Long id) {
Profesor p = em.find(Profesor.class, id);
return p;
}
@Override
public Alumno buscarAlumno(Long id) {
Alumno a = em.find(Alumno.class, id);
return a;
}
persistence.xml
Página 6
<property name="hibernate.show_sql" value="true" />
<property
name="javax.persistence.schema-generation.create-database-schemas" value="true"/>
</properties>
</persistence-unit>
</persistence>
orm.xml
Página 7
En el cliente se implementó la siguiente clase para realizar la prueba:
package com.cliente;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.*;
import com.servicios.PersonasBeanRemote;
altasPersonas(person);
Página 8
}
per.crear(new Profesor("Jose","Granada","grado4"));
per.crear(new Alumno("Ana","Marquez",2019));
per.crear(new Profesor("Marta","Dinardi","grado2"));
per.crear(new Alumno("Daniel","Ventos",2020));
per.crear(new Alumno("Luis","Fontes",2020));
per.crear(new Alumno("Antonio","Rios",2020));
per.crear(new Alumno("Joaquin","Beal",2020));
per.crear(new Alumno("Emiliano","Silva",2019));
per.crear(new Profesor("Sergio","Trias","grado 2"));
Es un profesor
Jose --- Granada-- grado : grado4
Es un Alumno
Ana --- Marquez-- generacion : 2019
Es un profesor
Marta --- Dinardi-- grado : grado2
Es un Alumno
Daniel --- Ventos-- generacion : 2020
Es un Alumno
Luis --- Fontes-- generacion : 2020
Es un Alumno
Antonio --- Rios-- generacion : 2020
Es un Alumno
Joaquin --- Beal-- generacion : 2020
Página 9
Es un Alumno
Emiliano --- Silva-- generacion : 2019
Es un profesor
Sergio --- Trias-- grado : grado 2
Página 10
Se persistió una instancia de Profesor y otra de Alumno, y se obtuvo las siguientes tablas en
la base de datos con la siguiente estructura y contenido:
Una tabla PERSONAS con los dos registros (un profesor y un alumno) y su ID
correspondiente:
Una tabla PROFESORES sólo con el registro del profesor, con el ID que le corresponde y
con el atributo propio del profesor (gradoDocente).
Una tabla ALUMNOS sólo con el registro del alumno, con el ID que le corresponde y con el
atributo propio del alumno (generacion).
Página 11
Se implementó de la siguiente manera en el servidor:
Persona.java
package com.entidades;
import javax.persistence.*;
@Entity
@Table(name="PERSONAS")
@Inheritance(strategy=InheritanceType.JOINED)
public class Persona implements java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PER"
)
@SequenceGenerator(name = "SEQ_PER", initialValue = 1, allocationSize = 1)
public Persona() {
super();
}
// getters y setters
}
Página 12
Alumno.java
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="ALUMNOS")
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Alumno extends Persona implements Serializable {
public Alumno() {
super();
}
// getters y setters
}
Profesor.java
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="PROFESORES")
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Profesor extends Persona {
public Profesor() {
super();
}
// getters y setters
}
Página 13
PersonasBeanRemote.java
package com.servicios;
import java.util.List;
import javax.ejb.Remote;
import com.entidades.*;
@Remote
public interface PersonasBeanRemote {
PersonasBean.java
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.*;
import com.entidades.*;
@Stateless
public class PersonasBean implements PersonasBeanRemote {
@PersistenceContext
private EntityManager em;
public PersonasBean() {
}
@Override
public void crear(Profesor profesor) {
em.persist(profesor);
em.flush();
}
@Override
public void crear(Alumno alumno) {
em.persist(alumno);
em.flush();
}
}
Página 14
Archivos de configuración en el servidor:
persistence.xml
orm.xml
Página 15
En el cliente se implementó la siguiente clase para realizar la prueba:
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.*;
import com.servicios.PersonasBeanRemote;
String
ruta="ejb:/Herencia_2_EJB/PersonasBean!com.servicios.PersonasBeanRemote";
PersonasBeanRemote person = (PersonasBeanRemote)
InitialContext.doLookup(ruta);
try{
person.crear(a);
} catch(Exception e) {
System.out.println("Error al crear Alumno");
System.out.println(e.getMessage());
}
}
}
Para hacer el listado total, se hace de la misma forma que con una sola tabla. Fijarse el
ejemplo anterior.
Página 16
Implementar una caso de ManyToMany
Dado una entidad Libro, que puede tener muchos Autores, y que un Autor puede estar en
muchos Libros, tenemos una relación de N a N.
Entidades
Entidad Libro:
package com.entidades;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="LIBROS")
public class Libro implements Serializable {
@Id
@SequenceGenerator(name = "SEQ_LIB", initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_LIB")
Página 17
private String nombre;
// Estas anotaciones hacen crear una tabla(auxiliar) en SQL con las dos id de cada
// entidad que tiene la relación N a N
@JoinTable(
name = "LIBROS_AUTORES",
joinColumns = @JoinColumn(name = "FK_LIBRO", nullable = false),
inverseJoinColumns = @JoinColumn(name="FK_AUTOR", nullable = false)
)
@ManyToMany(cascade=CascadeType.ALL ,fetch = FetchType.EAGER)
this.autores.add(autor);
}
public Libro() {
super();
}
// Getters y Setters
Página 18
public Set<Autor> getAutores() {
return autores;
}
Entidad Autor
package com.entidades;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="AUTORES")
public class Autor implements Serializable {
@Column
private String nombre;
@ManyToMany( mappedBy="autores")
private Set <Libro> lib;
Página 19
public Autor() {
super();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Set<Libro> getLib() {
return lib;
}
public void setLib(Set<Libro> lib) {
this.lib = lib;
}
Servicios Bean
LibroBeanRemote
package com.servicios;
import javax.ejb.Remote;
import com.entidades.Libro;
@Remote
public interface LibroBeanRemote {
Página 20
LibroBean
package com.servicios;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.entidades.Libro;
@Stateless
public class LibroBean implements LibroBeanRemote {
@PersistenceContext
private EntityManager em;
public LibroBean() {
}
@Override
public void crearLibro(Libro libro) {
// Importante
// El uso de merge en lugar de persist
// Nos sirve para dar de alta los autores
// Ya que los que ya estan creados
// no los da de alta nuevamente
em.merge(libro);
em.flush();
}
AutoresBeanRemote
package com.servicios;
import javax.ejb.Remote;
import com.entidades.Autor;
@Remote
Página 21
public interface AutoresBeanRemote {
AutoresBean
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import com.entidades.Autor;
/**
* Session Bean implementation class AutoresBean
*/
@Stateless
public class AutoresBean implements AutoresBeanRemote {
@PersistenceContext
private EntityManager em;
public AutoresBean() {
@Override
public void crearAutor(Autor autor) {
em.persist(autor);
em.flush();
@Override
public Autor ObtenerAutor(Long id) {
Autor autor=em.find(Autor.class, id);
return autor;
}
Página 22
@Override
public Autor ObtenerAutor(String nombre) {
TypedQuery<Autor> query ;
query = em.createQuery("SELECT a FROM Autor a WHERE a.nombre LIKE
:nombre", Autor.class).setParameter("nombre", nombre);
return query.getSingleResult();
}
Archivo ORM.xml
Cliente_MTM_1.java
package com.cliente;
import java.util.HashSet;
Página 23
import java.util.Set;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.Autor;
import com.entidades.Libro;
import com.servicios.AutoresBeanRemote;
import com.servicios.LibroBeanRemote;
String ruta="MTM_EJB//LibroBean!com.servicios.LibroBeanRemote";
String ruta2="MTM_EJB//AutoresBean!com.servicios.AutoresBeanRemote";
// Nuevos Autores
Autor autor1 = new Autor();
autor1.setNombre("Maria Barrios");
// Nuevos Libros
Libro libro1 = new Libro();
libro1.setNombre("El hombre y las computadoras");
libro1.addAutor(autor1);
libro1.addAutor(autor4);
vari.crearLibro(libro1);
Página 24
System.out.println("Se creo el primer Libro");
autor4=vari2.ObtenerAutor("Ana Paladino");
System.out.println(autor4.getNombre()+" "+autor4.getId());
vari.crearLibro(libro2);
autor1=vari2.ObtenerAutor("Maria Barrios");
System.out.println(autor1.getNombre()+" "+autor1.getId());
libro3.addAutor(autor1);
vari.crearLibro(libro3);
Página 25
Página 26
APLICACIONES
ENTERPRISE
Semestre 2
Página 1 de 77
MÉTODOS ASÍNCRONOS ............................................................................................................................................................................................. 21
TIPOS DE EJBS .......................................................................................................................................................................................23
SIN ESTADO .................................................................................................................................................................................................................. 23
CON ESTADO ................................................................................................................................................................................................................ 24
SINGLETON................................................................................................................................................................................................................... 25
WILDFLY EN ECLIPSE .........................................................................................................................................................................26
CAMBIAR EL PUERTO DEL WILDFLY ........................................................................................................................................................................ 26
CÓMO INICIAR EL WILDFLY ...................................................................................................................................................................................... 27
CÓMO DETENER EL WILDFLY ................................................................................................................................................................................... 28
CÓMO HACER DEPLOY DE UN PROYECTO ................................................................................................................................................................. 29
COMO HACER UNDEPLOY DE UN PROYECTO ............................................................................................................................................................ 30
DEPLOY EN CALIENTE O HOT DEPLOY ...................................................................................................................................................................... 30
Como configurar el hot deploy..................................................................................................................................................................... 30
JAVA PERSISTENCE API .....................................................................................................................................................................32
¿QUÉ ES JPA? .............................................................................................................................................................................................................. 32
ENTIDADES .................................................................................................................................................................................................................. 32
Requisitos de una entidad .............................................................................................................................................................................. 32
Los campos persistentes y propiedades de la entidad ........................................................................................................................ 33
Campos persistentes .............................................................................................................................................................................................................. 34
Propiedades persistentes ..................................................................................................................................................................................................... 34
Tipos de acceso................................................................................................................................................................................................... 34
Lectura temprana y lectura demorada .................................................................................................................................................... 34
Tipos enumerados ............................................................................................................................................................................................. 35
Transient .............................................................................................................................................................................................................. 35
Colecciones........................................................................................................................................................................................................... 36
Tipos Embeddable............................................................................................................................................................................................. 36
Las claves.............................................................................................................................................................................................................. 37
Claves simples ........................................................................................................................................................................................................................... 37
@GeneratedValue(strategy = GenerationType.IDENTITY) ........................................................................................................................... 37
@GeneratedValue(strategy = GenerationType.SEQUENCE) ........................................................................................................................ 38
@GeneratedValue(strategy = GenerationType.AUTO) .................................................................................................................................... 38
@GeneratedValue(strategy = GenerationType.TABLE).................................................................................................................................. 38
Claves múltiples ........................................................................................................................................................................................................................ 39
LA MULTIPLICIDAD DE RELACIONES DE ENTIDADES.............................................................................................................................................. 39
Dirección en Relaciones de Entidades ....................................................................................................................................................... 39
Las relaciones Bidireccionales........................................................................................................................................................................................... 40
Las relaciones Unidireccionales........................................................................................................................................................................................ 40
Las Consultas y Dirección de Relación........................................................................................................................................................................... 40
Operaciones en cascada ................................................................................................................................................................................. 40
Algunos Ejemplos .............................................................................................................................................................................................. 41
@OneToOne ................................................................................................................................................................................................................................ 41
@OneToMany ............................................................................................................................................................................................................................ 42
@ManyToOne ............................................................................................................................................................................................................................ 42
@ManyToMany ......................................................................................................................................................................................................................... 42
HERENCIA .................................................................................................................................................................................................................... 43
SINGLE_TABLE ................................................................................................................................................................................................... 43
JOINED_TABLE ................................................................................................................................................................................................... 43
TABLE_PER_CONCRETE_CLASS .................................................................................................................................................................. 43
Ejemplo ................................................................................................................................................................................................................. 44
UNIDADES DE PERSISTENCIA .................................................................................................................................................................................... 46
MANEJO DE ENTIDADES ....................................................................................................................................................................47
ENTITY MANAGER ...................................................................................................................................................................................................... 47
La interfaz EntityManager ............................................................................................................................................................................ 47
Página 2 de 77
Entity Managers manejados por contenedor ......................................................................................................................................... 47
La gestión del ciclo de vida de una entidad ............................................................................................................................................ 47
Persistiendo una entidad ............................................................................................................................................................................... 49
Buscando una entidad..................................................................................................................................................................................... 50
Actualizando una entidad ............................................................................................................................................................................. 50
Eliminando una entidad ................................................................................................................................................................................. 51
Sincronización de datos de la entidad a la base de datos ................................................................................................................. 51
MÉTODOS CALLBACK ................................................................................................................................................................................................. 51
CLASES LISTENER ........................................................................................................................................................................................................ 52
JAVA PERSISTENCE QUERY LANGUAGE .......................................................................................................................................54
QUÉ ES .......................................................................................................................................................................................................................... 54
SINTAXIS ....................................................................................................................................................................................................................... 54
Parámetros .......................................................................................................................................................................................................... 55
Resumiendo ......................................................................................................................................................................................................... 56
ACTUALIZACIÓN DE DATOS Y BORRADO .................................................................................................................................................................. 56
Resumiendo ......................................................................................................................................................................................................... 57
EJECUTANDO SENTENCIAS JPQL .............................................................................................................................................................................. 57
QUERY VS QUERY TIPADA ........................................................................................................................................................................................ 58
CONSULTAS NATIVAS SQL ........................................................................................................................................................................................ 58
IMPLEMENTACIÓN DE HERENCIAS Y RELACIONES .................................................................................................................59
IMPLEMENTAR HERENCIA CON ESTRATEGIA SIMPLE ......................................................................................................................................... 59
Servidor ................................................................................................................................................................................................................. 59
Persona.java................................................................................................................................................................................................................................ 60
Alumno.java ................................................................................................................................................................................................................................ 60
PersonasBeanRemote.java .................................................................................................................................................................................................. 61
PersonasBean.java ................................................................................................................................................................................................................... 61
Archivos de configuración en el servidor ................................................................................................................................................. 62
persistence.xml ......................................................................................................................................................................................................................... 62
orm.xml ......................................................................................................................................................................................................................................... 62
Cliente .................................................................................................................................................................................................................... 63
IMPLEMENTAR HERENCIA TIPO JOINED ................................................................................................................................................................ 64
Servidor ................................................................................................................................................................................................................. 65
Persona.java................................................................................................................................................................................................................................ 65
Alumno.java ................................................................................................................................................................................................................................ 66
Profesor.java............................................................................................................................................................................................................................... 66
PersonasBeanRemote.java .................................................................................................................................................................................................. 67
PersonasBean.java ................................................................................................................................................................................................................... 67
Archivos de configuración en el servidor ................................................................................................................................................. 68
persistence.xml ......................................................................................................................................................................................................................... 68
orm.xml ......................................................................................................................................................................................................................................... 68
Cliente .................................................................................................................................................................................................................... 69
IMPLEMENTAR UNA CASO DE MANYTOMANY ....................................................................................................................................................... 70
Entidades .............................................................................................................................................................................................................. 70
Entidad Libro ............................................................................................................................................................................................................................. 70
Entidad Autor............................................................................................................................................................................................................................. 71
Servidor ................................................................................................................................................................................................................. 72
LibroBeanRemote .................................................................................................................................................................................................................... 72
LibroBean .................................................................................................................................................................................................................................... 73
AutoresBeanRemote............................................................................................................................................................................................................... 73
AutoresBean ............................................................................................................................................................................................................................... 73
Archivos de configuración en el servidor ................................................................................................................................................. 74
orm.xml ......................................................................................................................................................................................................................................... 74
Cliente .................................................................................................................................................................................................................... 75
Cliente_MTM_1.java ................................................................................................................................................................................................................ 75
Tablas en SQL ..................................................................................................................................................................................................... 76
Página 3 de 77
INTRODUCCIÓN A APLICACIONES ENTERPRISE
APLICACIONES EMPRESARIALES
MODELO JAVA EE
El modelo Java EE tiene como protagonistas el lenguaje de programación Java y la máquina virtual de Java.
Las características fundamentales de este tipo de aplicaciones son la productividad, portabilidad y
seguridad.
Java EE es un conjunto de especificaciones Java que brindan la funcionalidad necesaria para el desarrollo
de aplicaciones empresariales. Este tipo de aplicaciones pueden ser muy complejas, ya que pueden acceder
datos de una gran variedad de fuentes y que requieran que la aplicación sea distribuida a una gran cantidad
de clientes.
Java EE incluye muchos componentes de Java Standard Edition, llamada Java SE. JavaSE es un kit de
desarrollo de software que se utiliza para escribir applets y aplicaciones con el lenguaje de programación
Java. Este kit es el que han utilizado hasta el momento para las materiales Java que ya tuvieron. Java EE no
es un reemplazo de Java SE: Java SE proporciona el soporte de lenguaje básico sobre el que Java EE ejecuta.
El modelo Java EE define una arquitectura para la implementación de servicios como aplicaciones de varios
niveles que ofrecen a escalabilidad, accesibilidad y capacidad de gestión necesaria para aplicaciones
empresariales.
Si pensamos en una aplicación empresarial estándar, necesitaremos 3 capas:
• Capa de presentación: Encargada de desplegar y obtener información para el usuario.
• Capa de negocios: Encargada de los procesos y reglas de negocio.
• Capa de acceso a datos: Toda aplicación requiere alguna forma de persistencia (leer / almacenar
datos).
Página 4 de 77
Las aplicaciones Java EE se suelen distribuir en tres lugares diferentes:
• La máquina cliente.
• La máquina servidor (Servidor Java EE).
• Base de datos o sistemas legados (Sistema legado: se trata de un sistema informático que ha quedado
obsoleto pero continúa siendo utilizado por el usuario y no se quiere o no se puede reemplazar o
actualizar de forma sencilla).
Java EE divide el trabajo necesario para implementar esta arquitectura en las siguientes partes:
• La lógica de negocio y presentación, implementados por el desarrollador.
• Los servicios del sistema estándar, proporcionados por la plataforma Java EE.
APLICACIONES DISTRIBUÍDAS
Java EE usa un modelo de varios niveles donde se distribuyen las aplicaciones de la empresa.
En ésta un objeto está asociado con un nombre, donde los nombres los proporciona un servicio de nombres,
notificando a distintos componentes y resolviendo las referencias de clientes para estos componentes de
servicio.
La lógica de la aplicación se divide en componentes de acuerdo a su función, y los componentes de una
aplicación Java EE pueden estar instalados en distintas máquinas, dependiendo de la capa a la que
pertenece el componente de aplicación.
Las aplicaciones de multicapa Java EE son generalmente consideradas como aplicaciones de tres capas,
porque están distribuidas en tres lugares: máquina cliente, la máquina del servidor Java EE, y la base de
datos.
SEGURIDAD
Aunque otros modelos de aplicaciones empresariales requieren medidas de seguridad específicas para
cada aplicación, el entorno de seguridad de Java EE permite que las medidas de seguridad se definan
durante el despliegue (deploy) o momento de instalación de la aplicación.
Estas medidas protegen a los desarrolladores de aplicaciones de la complejidad de la implementación de
elementos de seguridad.
La plataforma Java EE proporciona reglas de control de acceso estándar declarativas que están definidas
por el desarrollador e interpretadas cuando se realiza el deploy o despliegue de la aplicación.
Página 5 de 77
ARQUITECTURA
COMPONENTE JAVA EE
Un componente es una unidad de software “autosuficiente” y funcional que se ensambla dentro de una
aplicación Java EE y se comunica con otros componentes.
Para que un componente pueda ser ejecutado, debe de ser previamente desplegado (deploy) en el
contenedor correspondiente de un servidor Java EE.
La especificación Java EE define los siguientes componentes Java EE:
• Los clientes de aplicaciones y applets son componentes que se ejecutan en el cliente.
• Servlet Java, Java Server Faces, y Java Server Pages (JSP) son componentes web que se ejecutan en el
servidor.
• Enterprise JavaBeans (EJBs) son componentes de negocio que se ejecutan en el servidor.
Los componentes Java EE están escritos en Java y se compilan de la misma forma que cualquier otro
programa en el lenguaje. Las diferencias entre los componentes Java EE y las clases de Java "estándar" son
que los componentes Java EE se ensamblan en una aplicación Java EE, que se verifican de estar bien
formados y de acuerdo con la especificación Java EE, y que se implementan en la producción, en la que
están gestionados por el servidor Java EE.
Página 6 de 77
LOS CLIENTES DE JAVA EE
CLIENTES WEB
Un cliente web se compone de dos partes:
• Páginas web dinámicas que contienen varios tipos de lenguaje de marcado (HTML, XML, etc.), que son
generados por los componentes Web que se ejecutan en la capa web.
• Un navegador web, lo que hace que las páginas sean mostradas.
Un cliente web a veces se llama un cliente ligero. Los clientes ligeros no suelen consultar bases de datos,
ejecutar reglas de negocio complejas, ni conectarse con otras aplicaciones. Cuando se utiliza un cliente
ligero, las operaciones “pesadas” las realizan los bean enterprises que se ejecutan en el servidor Java EE,
en el que pueden aprovechar la seguridad, velocidad, servicios, y la fiabilidad de las tecnologías del lado del
servidor Java EE.
APLICACIÓN DE ESCRITORIO
Una aplicación de escritorio se ejecuta en una máquina cliente y brinda una forma más amigable para que
los usuarios manejen las tareas que requieren una interfaz de usuario más rica y más customizada que la
de un lenguaje de marcas (HTML).
Normalmente tiene una interfaz gráfica de usuario basada en Swing o AWT, pero también podría ser tan
simple como una interfaz de línea de comandos.
Las aplicaciones de escritorio acceden directamente a los beans enterprise que se ejecutan en la capa de
negocio.
APPLETS
Un applet es una pequeña aplicación cliente que se ejecuta en la máquina virtual Java embebida en el
navegador web. En las máquinas cliente necesitará el plugin de Java y, posiblemente un certificado de
seguridad para que el applet pueda ejecutarse con éxito en el navegador web.
JAVABEANS
Las capas servidor y cliente pueden incluir componentes JavaBeans para comunicar estas dos capas que
servirán de puente entre ambas.
Los componentes JavaBeans son clases Java que tienen propiedades y métodos get y set para acceder a las
mismas. Los componentes JavaBeans utilizados de esta manera suelen ser simples en su diseño e
implementación, pero deben ajustarse a las convenciones de nombres y de diseño descritos en la
arquitectura de componentes JavaBeans.
Los componentes JavaBeans no son considerados componentes Java EE por parte de la especificación Java
EE.
Página 7 de 77
JAVA COMMUNICATIONS SERVER EE
El cliente se comunica con la capa de negocio que se ejecuta en el servidor Java EE ya sea directamente o,
como en el caso de un cliente que se ejecuta en un navegador, pasando a través de páginas web o servlets
que se ejecutan en la capa web.
COMPONENTES WEB
Los componentes Web Java EE son servlets o páginas web creadas usando la tecnología JavaServer Faces
y/o la tecnología JSP (páginas JSP).
Los servlets son clases Java que procesan en forma dinámica peticiones y construyen respuestas.
Las páginas JSP son documentos basados en texto que se ejecutan como servlets pero permiten un enfoque
más natural para la creación de contenido estático.
JavaServer Faces se basa en servlets y JSP y proporciona un marco de componentes de interfaz de usuario
para las aplicaciones web.
Las páginas HTML estáticas y los applets se incluyen con los componentes web, pero no se consideran
componentes web según la especificación Java EE.
Las clases de utilidades del lado del servidor también pueden ser incluidas con los componentes web y, al
igual que las páginas HTML, no se consideran componentes web.
Página 8 de 77
COMPONENTES DE NEGOCIO
Es la lógica que resuelve las necesidades del negocio. Es manejado por los JavaBeans, ya sea en la capa de
negocio o de la capa web.
Un bean enterprise recibe datos de los programas clientes, los procesa (si es necesario), y los envía a la
capa del sistema de información empresarial para su almacenamiento.
Un bean enterprise también recupera datos desde el almacenamiento, los procesa (si es necesario), y los
envía de vuelta al programa cliente.
Hay tres tipos de beans enterprise: beans de sesión (con o sin estado), beans de entidad (manejados por el
bean o por el contenedor) y beans dirigidos a mensaje.
Un bean de sesión representa una conversación temporal con un cliente. Cuando el cliente finaliza su
ejecución, el bean de sesión y sus datos desaparecen.
Por el contrario, un bean de entidad representa datos persistentes almacenados en una fila de una
tabla/relación de una base de datos. Si el cliente se termina o si se apaga el servidor, los servicios
subyacentes se aseguran de grabar el bean.
Un bean dirigido-a-mensaje combina las características de un bean de sesión y de un oyente de Java
Message Service (JMS), permitiendo que un componente de negocio reciba asíncronamente mensajes JMS.
Página 9 de 77
JAVA EE CONTENEDORES
La arquitectura Java EE está basada en componentes y es independiente de la plataforma, lo que hace que
las aplicaciones Java EE sean más fáciles de escribir porque la lógica de negocio está organizada en
componentes que son reutilizables.
Además, el servidor Java EE proporciona servicios como un contenedor para cada tipo de componente.
SERVICIOS DE CONTENEDOR
Los contenedores son la interfaz entre un componente y la funcionalidad específica de la plataforma de
bajo nivel que soporta el componente.
Antes de que pueda ser ejecutado un ejb o un componente de aplicación cliente, deben ser empaquetados
en un módulo Java EE y desplegados en su contenedor.
El proceso de deploy implica especificar valores de contenedor para cada componente en la aplicación Java
EE y para la aplicación Java EE en sí.
Se pueden personalizar valores de servicios tales como la seguridad, la gestión de transacciones, Java
Naming and Directory Interface API de búsquedas (JNDI), y conectividad remota.
Como la arquitectura Java EE proporciona servicios configurables, los mismos componentes de una
aplicación Java EE pueden comportarse de forma diferente en función de donde se desplieguen. Por
ejemplo, un ejb puede tener la configuración de seguridad que permite un cierto nivel de acceso a los datos
de base de datos en un entorno de producción y otro nivel de acceso a la base de datos en otro entorno de
producción.
TIPOS DE CONTENEDORES
El proceso de despliegue instala los componentes de aplicaciones Java EE en los contenedores Java EE.
Página 10 de 77
• Servidor Java EE: Un servidor Java EE proporciona contenedores EJB y web.
• Enterprise JavaBeans (EJB): Gestiona la ejecución de los EJBs para las aplicaciones Java EE.
• Contenedor web: Gestiona la ejecución de páginas web, servlets, y algunos componentes EJB para
aplicaciones Java EE.
• Contenedor de cliente de aplicación: Gestiona la ejecución de los componentes de cliente de
aplicaciones. Los clientes de aplicación y su contenedor se ejecutan en el cliente.
• Contenedor de applets: Gestiona la ejecución de applets. Consta de un navegador web y Java Plugin
que se ejecuta en el cliente.
SERVIDORES JAVA EE
Los servidores Java EE representan el ambiente en el que ejecutan los componentes. Estos componentes se
denominan componentes serverside o componentes de aplicación JEE.
Puede tratarse de:
• Componentes web (JSP / Servlets / JSF).
• Componentes de negocio (EJB)
Una aplicación Java EE se empaqueta en una o más unidades. Cada unidad contiene:
• Un componente funcional como ejbs, página web, servlets, o un applet.
• Un descriptor de despliegue opcional que describe su contenido. Estos descriptores de despliegue
contienen información específica de cada componente empaquetado y son un mecanismo para
configurar el comportamiento de la aplicación en el momento del ensamble o del despliegue.
Una vez que se empaqueta la aplicación Java EE, está lista para ser desplegada.
Para el despliegue se utiliza la herramienta de despliegue de la plataforma para especificar la información
específica de la ubicación, la lista de los usuarios que pueden acceder a ella, el nombre de la base de datos,
entre otras cosas. Una vez desplegado en el servidor, la aplicación está lista para ser utilizada.
Página 11 de 77
EMPAQUETADO
Una aplicación Java EE se empaqueta en un archivo enterprise (.ear) que contiene toda la aplicación junto
con el descriptor de despliegue que proporciona información sobre la aplicación y sus componentes.
Un descriptor de despliegue es un documento XML donde describe la configuración de despliegue de una
aplicación, un módulo o un componente. Como la información de descriptor de despliegue es declarativa
se puede cambiar sin la necesidad de modificar el código fuente.
Es en tiempo de ejecución que el servidor Java EE lee el descriptor de despliegue y actúa sobre la aplicación,
módulo o componente en consecuencia sin necesidad de recompilar el código fuente.
Un módulo Java EE consta de uno o más componentes de Java EE para el mismo tipo de contenedor y,
opcionalmente, descriptores de despliegue de ese tipo.
Un descriptor de despliegue del módulo Enterprise Bean, por ejemplo, declara atributos de transacción y
las autorizaciones de seguridad para un bean enterprise. Un módulo Java EE puede implementarse como
un módulo independiente.
Página 12 de 77
ROLES DE DESARROLLO
PROVEEDOR DE HERRAMIENTAS
El proveedor de la herramienta es la empresa o persona que desarrolla, monta y crea herramientas para
los paquetes utilizados por los proveedores de componentes, ensambladores, y quienes los despliegan.
Página 13 de 77
WEB COMPONENT DEVELOPER
Se trata de un desarrollador de componentes web que realiza las siguientes tareas:
• Escribe y compila el código fuente del servlet.
• Escribe JavaServer Faces, JSP y archivos HTML.
• Especifica el descriptor de despliegue (opcional).
• Empaqueta el descriptor .class, .jsp y archivos .html en el archivo WAR.
ENSAMBLADOR DE APLICACIÓN
El ensamblador de la aplicación es la empresa o persona que recibe los módulos de aplicación de los
proveedores de componentes y los empaqueta en un archivo EAR.
Realiza las siguientes tareas:
• Se ensambla archivos JAR EJB y WAR creados en las fases anteriores en una aplicación Java EE archivo
(EAR).
• Especifica el descriptor de despliegue de la aplicación Java EE (opcional).
• Verifica que el contenido del archivo EAR están bien formadas y cumplen con la especificación Java EE.
ADMINISTRADOR DE APLICACIÓN
El programa de implementación de aplicaciones y administrador sea la empresa o persona que configura y
despliega los clientes de aplicaciones, aplicaciones web, componentes JavaBeans Enterprise y las
aplicaciones Java EE, administra la infraestructura computacional y de redes, donde los componentes y
aplicaciones Java EE corren, y supervisa el entorno de ejecución. Las responsabilidades incluyen controles
de transacción de ajuste y los atributos de seguridad y especificando las conexiones a bases de datos.
Durante la configuración, el programa de implementación sigue las instrucciones suministradas por el
proveedor del componente de aplicación para resolver las dependencias externas, especifique la
configuración de seguridad, y asignar atributos de transacción. Durante la instalación, el programa de
implementación mueve los componentes de la aplicación en el servidor y genera las clases e interfaces
específicos del contenedor.
Un administrador del programa de implementación o el sistema realiza las siguientes tareas para instalar
y configurar una aplicación o componentes Java EE:
• Configura la aplicación Java EE o componentes para el entorno operativo.
• Verifica que los contenidos de la oreja, JAR, y / o archivos WAR están bien formadas y cumplen con la
especificación Java EE.
• Despliega (instala) la aplicación Java EE o componentes en el servidor Java EE.
Un enterprise java bean (EJB) es un componente del lado del servidor que encapsula la lógica de negocio
de una aplicación.
La lógica de negocio es el código que contiene las reglas de negocio y de proceso de una aplicación. En una
aplicación de stock de productos, por ejemplo, los EJBs pueden implementar su lógica de negocio en los
métodos “agregarProducto” o “chequearStockProducto”. Al invocar estos métodos, se puede acceder a los
servicios de stock de productos que proporciona la aplicación.
TIPOS DE EJBS
• Bean de sesión: Representa un proceso o una acción de negocio. En general, cualquier llamada a un
servicio debería comenzar con una llamada a un bean de sesión. Conceptualmente se asocian los beans
de sesión con los verbos: agregarProducto, chequearStockProducto, etc.
• Beans dirigidos por mensajes (MDBs): Pueden escuchar mensajes de un servicio de mensajes JMS
(Java Message Service). Los clientes de estos beans nunca los llaman directamente, sino que es
necesario enviar un mensaje JMS para comunicarse con ellos. Un ejemplo de bean dirigido por mensajes
podría ser un bean ListenerNuevoProducto que se activa cada vez que se envía un mensaje
comunicando que se ha dado de alta a un nuevo producto.
Página 15 de 77
BEAN DE SESIÓN
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.
Existe una correspondencia uno a 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.
Los beans de sesión pueden ser de tres tipos: con estado, sin estado, y singleton.
Un MDB es un EJB que permite a las aplicaciones Java EE procesar mensajes de forma asíncrona. Este tipo
de bean en general actúa como un receptor de mensajes JMS, que es similar a un detector de eventos.
Página 16 de 77
Los mensajes se pueden enviar por cualquiera de los componentes de Java EE (un cliente de aplicación, un
EJB, o un componente web) o por una aplicación JMS o un sistema que no utiliza la tecnología Java EE. Los
MDBs pueden procesar mensajes JMS u otros tipos de mensajes.
En muchos aspectos, un MDB es parecido a un bean de sesión sin estado.
• Las instancias de un MDB no almacenan ningún estado conversacional ni datos de clientes.
• Todas las instancias de los MDBs son equivalentes, lo que permite al contenedor EJB asignar un mensaje
a cualquier instancia. El contenedor puede almacenar estas instancias para permitir que los streams de
mensajes sean procesados de forma concurrente.
• Un único MDB 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. Pueden contener una conexión JMS, una conexión de base de datos o una referencia a un
EJB.
Cuando llega un mensaje, el contenedor EJB llama al método “onMessage” del bean. El método onMessage
suele realizar un casteo 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.
Un mensaje puede enviarse a un MDB 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 clientes van a acceder a los EJBs de dos maneras posibles: a través de una vista sin interfaz o a través
de una interfaz de negocio (local o remota).
Todos los métodos públicos del bean (incluyendo aquellos definidos en superclases) están disponibles en
la vista sin interfaz.
Los clientes que utilizan la vista sin interfaz de un EJB pueden invocar cualquier método público de la clase
de implementación del EJB o cualquier superclase de la implementación.
Una interfaz de negocio es una interfaz estándar de lenguaje de programación Java que contiene los
métodos de negocio del EJB.
Un cliente puede acceder a un bean de sesión sólo a través de los métodos definidos en la interfaz de
negocio del bean o por medio de los métodos públicos de un EJB con una vista sin interfaz.
Es importante tener un modelo de interfaces bien diseñado ya que esto simplifica el desarrollo y
mantenimiento de la aplicación Java EE.
No sólo las interfaces limpias y las vistas sin interfaz protegen a los clientes de cualquier complejidad en el
nivel de EJB, sino que también permiten a los EJBs cambiar internamente sin afectar a los clientes. Por
ejemplo, si cambia la implementación de un método de negocio de bean de sesión, no se tendrá que
modificar el código del cliente. Pero si tuviera que cambiar las definiciones de métodos de las interfaces, es
posible que tenga que modificar el código del cliente también. Por lo tanto, es importante que el diseño de
las interfaces y los accesos de vista sin interfaz estén pensados cuidadosamente para evitar que los clientes
deban realizar cambios al acceder a los EJBs.
Los beans de sesión pueden tener más de una interfaz de negocio. Los beans de sesión deben, pero no están
obligados a, implementar una interfaz o interfaces de negocio.
Si el bean no expone ninguna interfaz remota o local, entonces el contenedor tiene que dejar disponible una
vista sin interfaz. En cambio, si el bean expone al menos una interfaz remota o una local, entonces el
contenedor no provee una vista sin interfaz (a menos que se pida explícitamente usando la anotación
LocalBean.
Página 17 de 77
USANDO EJBS EN CLIENTES
El cliente de un EJB obtiene una referencia a una instancia de un bean enterprise, ya sea a través de la
inyección de dependencia, mediante anotaciones de lenguaje de programación Java, o búsqueda JNDI,
utilizando la sintaxis de Java Naming and Directory Interface para encontrar la instancia del EJB.
La inyección de dependencia es la forma más sencilla de obtener una referencia a un EJB. La inyección de
dependencia es una técnica popular en el desarrollo de aplicaciones empresariales java, en donde un
componente especifica los recursos de los que depende.
Un inyector, típicamente un contenedor, proporciona los recursos al componente. Aunque la inyección de
dependencia puede ser implementado de varias maneras, en general se realiza con anotaciones.
Los clientes que ejecutan en un entorno gestionado por el servidor Java EE, JavaServer Faces aplicaciones
web, servicios web JAXRS, otros EJBs, o clientes de aplicaciones Java EE soportan la inyección de
dependencias utilizando anotaciones java.
Una anotación java una es una forma de añadir metadatos al código fuente Java que están disponibles para
la aplicación en tiempo de ejecución.
Las aplicaciones que se ejecutan fuera de un entorno gestionado por el servidor Java EE, tales como
aplicaciones Java SE, deben realizar una búsqueda explícita. JNDI soporta una sintaxis global para la
identificación de los componentes de Java EE para simplificar las operaciones de búsqueda este explícita.
SINTAXIS JNDI
Existen tres espacios de nombres JNDI que se utilizan para las búsquedas: java:global , java:module , y
java:app .
• java:global es la manera portable de encontrar EJBs remotos mediante búsquedas JNDI. Las direcciones
JNDI son de la siguiente forma:
java:global[/application name]/module name/enterprise bean name[/interface name]
• java:module se utiliza para buscar EJBs locales dentro del mismo módulo. Las direcciones JNDI son de
la siguiente forma:
java:module/enterprise bean name/[interface name]
• La java:app se utiliza para buscar EJBs locales envasados dentro de la misma aplicación. Es decir, el EJB
se empaqueta en un archivo EAR que contiene múltiples módulos Java EE. Las direcciones JNDI son de
la siguiente forma:
java:app[/module name]/enterprise bean name[/interface name]
Por ejemplo: supongamos que tengo un EJB llamado MiPrimerEJB, que se empaqueta dentro del archivo
web miPrimerApp.war y el nombre del módulo es miPrimerApp. El nombre JNDI portable es
java:module/MiPrimerEJB. Un nombre JNDI equivalente utilizando el java:global es
java:global/miPrimerApp/MiPrimerEJB.
Página 18 de 77
Ya sea para permitir el acceso local o remoto depende de los siguientes factores.
• Alto acoplamiento: Por ejemplo, si un bean de sesión que procesa los pedidos de cliente llama a otro
bean de sesión que envía correo electrónico con la confirmación al cliente, estos EJBs están
estrechamente unidos. Estos son buenos candidatos para el acceso local. Encajan entre sí como una
unidad lógica, que normalmente se llaman entre sí a menudo y se beneficiarían del aumento de
rendimiento que es posible con el acceso local.
• Tipo de cliente: Si un EJB se accede por clientes de la aplicación, se debe permitir el acceso remoto. En
un entorno de producción, estos clientes casi siempre se ejecutan en máquinas distintas de aquellas en
las que se ejecuta el servidor JavaEE. Si los clientes que acceden al EJB son componentes web u otros
EJBs, el tipo de acceso depende de cómo desea distribuir sus componentes: si van en el mismo servidor
o en otros.
• La distribución de componentes: Las aplicaciones Java EE son escalables porque sus componentes
pueden ser distribuidos a través de múltiples máquinas. En una aplicación distribuida, por ejemplo, el
servidor en el que los componentes web corren puede no ser el mismo en el que los EJBs están
desplegados. En este escenario distribuido, los EJBs deben permitir el acceso remoto.
• Rendimiento: Debido a factores tales como la latencia de la red, las llamadas remotas puede ser más
lentas que las llamadas locales. Por otro lado, si distribuye componentes entre los diferentes servidores,
es posible mejorar el rendimiento general de la aplicación.
Si no se está seguro de qué tipo de acceso debe tener un EJB, debería elegir el acceso remoto ya que da más
flexibilidad. Esto permitirá distribuir sus componentes para escalar la aplicación.
También es posible que un EJB permita el acceso remoto y local. Si este es el caso, se necesitará una interfaz
remota y otra local. La misma interfaz de negocio no puede ser a la vez una interfaz local y remota.
La vista sin interfaz de un EJB es una vista local. Los métodos públicos de la clase de implementación de un
EJB están expuestos a los clientes locales que acceden a la vista sin interfaz del EJB. Los EJBs que utilizan la
vista sin interfaz no implementan una interfaz de negocio.
La interfaz de negocio local define los métodos y el ciclo de vida del bean.
Si interfaz de negocio del bean no está anotada con @Local o @Remote , y si la clase de bean no especifica
la interfaz mediante @Local o @Remote, la interfaz de negocio es por defecto una interfaz local.
Para construir un EJB que permite sólo el acceso local, se puede seguir uno de los siguientes pasos:
• Crear una clase de implementación de EJB que no implementa una interfaz de negocio, lo que significa
que el bean expone una vista sin interfaz a los clientes. Por ejemplo:
@LocalBean
public class myBean {...}
Página 19 de 77
• Especificar la interfaz mediante la anotación @Local y el nombre de la interfaz. Por ejemplo:
@Local(InterfaceName.class)
public class BeanName implements InterfaceName { ... }
Los clientes no utilizan el operador new para obtener una nueva instancia de un EJB que utiliza una vista
sin interfaz
• Para obtener una referencia a una interfaz de negocio local de un EJB utilizando la búsqueda JNDI, se
debe utilizar el método lookup de javax.naming.InitialContext:
EjemploLocal ejemploLocal = (EjemploLocal)
InitialContext.lookup ("java:module/EjemploLocal");
Página 20 de 77
Para crear un EJB que permita el acceso remoto, o bien debe:
• Anotar la interfaz de negocio del EJB con @Remote:
@Remote
public interface InterfaceName { ... }
• O anotar con @Remote la clase del EJB y especificando la interfaz o interfaces de negocio:
@Remote(InterfaceName.class)
public class BeanName implements InterfaceName { ... }
La interfaz remota define los métodos de negocio y el ciclo de vida que son específicos para el EJB. Por
ejemplo, la interfaz remota de un bean llamado StockProductosBean podría tener los métodos de negocio
agregarProducto y quitarProducto.
El acceso de un cliente a un EJB que implementa una interfaz de negocio remota se lleva a cabo a través de
inyección de dependencia o de búsqueda JNDI.
• Para obtener una referencia a la interfaz de negocio remota de un EJB a través de la inyección de
dependencias, se debe utilizar la anotación javax.ejb.EJB y especificar el nombre de interfaz de negocio
remota:
@EJB
Ejemplo ejemplo;
• Para obtener una referencia a una interfaz de negocios remota de un EJB a través de la búsqueda JNDI,
se debe utilizar el método lookup del javax.naming.InitialContext:
ExampleRemote example = (ExampleRemote)
InitialContext.lookup("java:global/myApp/ExampleRemote");
Los archivos anteriores se empaquetan ya sea en un archivo JAR EJB (un módulo independiente que se
almacena el EJB) o dentro de un módulo de archivo de la aplicación Web (WAR).
MÉTODOS ASÍNCRONOS
Los EJBs pueden implementar métodos asincrónicos: son métodos donde se devuelve el control al cliente
a través del contenedor antes de invocar el método en la instancia de bean de sesión. El resultado del
método se devuelve al contenedor y no al cliente, por lo que el cliente no percibe demoras y puede seguir
trabajando.
Este tipo de métodos se utilizan normalmente para operaciones de larga duración, para las tareas de uso
intensivo del procesador, para tareas en segundo plano, para aumentar el rendimiento de aplicaciones, o
para mejorar el tiempo de respuesta de la aplicación.
Página 21 de 77
Ejemplo:
@Asynchronous
public void enviarMail(String texto) {
...
}
Página 22 de 77
TIPOS DE EJBS
Un EJB suele estar compuesto por una clase de implementación y cero o más interfaces de negocio. La clase
de implementación contiene las implementaciones de los métodos de negocio. Debe estar anotada con:
@Stateless, @Stateful o @Singleton
Las interfaces de negocio contienen las declaraciones de los métodos de negocio visibles al cliente y son
implementadas por el bean.
SIN ESTADO
Un EJB Stateless es una clase java sin estado, es decir, no debería tener atributos, sólo métodos a los que se
pueda llamar de forma independiente. Este tipo de EJB no mantienen estado conversacional ni presentan
problemas de concurrencia.
Para que el contenedor de aplicaciones lo maneje, sólo hay que ponerle la anotación @Stateless
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
@Stateless
@LocalBean
public class SinEstadoBean {
Es una clase con un método al que se le pasa un texto y muestra en consola “Hola mundo” seguido del texto
pasado.
La anotación @Stateless es la que lo convierte en un EJB y le indica al contenedor de aplicaciones que debe
encargarse de manejarlo.
La anotación @LocalBean indica que a esta clase no se va a acceder de forma remota (desde fuera de
nuestra aplicación). Esta anotación es opcional, ya que por defecto se asume que el bean no va a ser
accedido de forma remota.
Para los EJB sin estado, el contenedor de aplicaciones va a crear varias instancias de estas clase y le pasará
estas instancias a quien las necesite. Como son clases sin estado, el contenedor dará cualquiera de las
instancias que tiene al que la necesite y no se preocupará de entregar siempre la misma al mismo cliente.
Página 23 de 77
CON ESTADO
Un EJB con estado es una clase en la que sí hay atributos y cuyo valor es importante y debe conservarse
entre llamadas a métodos.
El contenedor de aplicaciones instanciará, al igual que con los EJB sin estado, un número determinado de
ellos, asegurandose de dar siempre al mismo cliente/usuario la misma instancia. De esta manera, el cliente
puede guardar en él datos que sean propios de él y que necesiten conservarse mientras está trabajando con
la aplicación.
Un ejemplo típico es el carrito de la compra de una web. Los productos que el usuario va añadiendo al
carrito se guardarían en un EJB con estado.
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Remove;
import javax.ejb.Stateful;
@Stateful
@LocalBean
public class ConEstadoBean {
@EJB
SinEstadoBean sinEstadoBean;
// Estado
private String estado;
@Remove
public void mostrarEstado(){
sinEstadoBean.holaMundo(estado);
}
Esta clase utiliza la anotación @Stateful para indicar que es un EJB con estado. La anotación @LocalBean,
al igual que antes, es opcional e indica que este bean no se va a utilizar de forma remota.
Esta clase tiene un atributo de tipo String llamado estado y un método setEstado que le da un valor. Como
se trata de un EJB con estado, este estado se conservará para la llamada a mostrarEstado().
La anotación @Remove en el método mostrarEstado() se usa para indicar al contenedor que ya hemos
terminado de usar este EJB con estado. Cuando encuentra esta llamada el contenedor sabe que puede darle
este EJB a otro que lo necesite pues ya fue usado.
Tenemos también el atributo @EJB SinEstadoBean sinEstadoBean que utilizaremos para realizar la
llamada a nuestro holaMundo de modo de mostrar en consola el estado. Como SinEstadoBean es un EJB
controlado por el contenedor de aplicaciones, no hacemos nosotros el new de esta clase, la anotamos con
@EJB y es el contenedor quien se encargará de pasarnos una de las instancias que tiene de SinEstadoBean
y podremos usarla.
Página 24 de 77
SINGLETON
Un EJB Singleton es una clase Java que el contenedor de aplicaciones instanciará una única vez y será
compartida en la aplicación por los clientes. Está pensada para guardar los datos que son comunes a todos
los usuarios o clientes de nuestra aplicación.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
@Singleton
@Startup
public class SingletonBean {
@PostConstruct
public void init() {
System.out.println("SingletonBean arranca");
}
@PreDestroy
public void destroy() {
System.out.println("SingletonBean termina");
}
Página 25 de 77
WILDFLY EN ECLIPSE
Por default cuando instalamos el WildFly, el mismo correr en el puerto 8080. Hay veces que tenemos otras
aplicaciones corriendo en ese puerto, por lo que debemos cambiarlo.
Existen varias formas de hacerlo. Veamos como hacerlo desde el Eclipse.
En la solapa Servers, ir dentro del WildFly a “XML Configuration” Ports y allí JBoss Web.
Botón derecho sobre JBoss Web y click en Change Value. Ahí modificamos el número de puerto por el
deseado y enter.
Ahora ya podrán iniciar el WildFly donde verán que se levanta en este nuevo puerto.
Página 26 de 77
CÓMO INICIAR EL WILDFLY
Página 27 de 77
CÓMO DETENER EL WILDFLY
Página 28 de 77
CÓMO HACER DEPLOY DE UN PROYECTO
Hay varias formas de hacerlo. Puede ser con botón derecho sobre el proyecto Run us Run on server.
O dentro de la solapa Servers WildFly Add and Remove.
Cuando se realiza un deploy verificar que el proyecto quede en estado [Started, Synchronized].
Página 29 de 77
COMO HACER UNDEPLOY DE UN PROYECTO
Cuando se realiza un deploy de un proyecto que tiene EJBs, en la consola deberíamos ver algo así:
Para verificar que el proyecto que contiene EJBs haya quedado bien en el WildFly, aparte de verificar que
el estado del proyecto sea Started, revisar en la consola que aparezcan las rutas JNDI del / de los ejbs en
cuestión. De esta manera sabremos que los EJBs quedaron deployados de forma correcta.
Página 30 de 77
Página 31 de 77
JAVA PERSISTENCE API
¿QUÉ ES JPA?
Java Persistence API (JPA) nos brinda un estándar para poder gestionar datos relacionales en aplicaciones
java, de tal forma que además simplifica el desarrollo de la persistencia de datos.
JPA establece una interface común que es implementada por un proveedor de persistencia, tales como
Hibernate, EclipseLink u otro. Podemos elegir en cualquier momento el proveedor que más se adecue a
nuestras necesidades. Así, es el proveedor quién realiza el trabajo, pero siempre funcionando bajo la API
de JPA.
Para los ejemplos del curso utilizaremos Hibernate, pero si lo prefieren pueden utilizar otro en cualquier
momento.
Hibernate es un framework open source de mapeo y persistencia para ser utilizado en Java. Sus librerías
ya vienen con el servidor de aplicaciones WildFly por lo que no tendremos que agregar librerías
adicionales.
Para entender JPA, tendremos que tener claro el concepto de persistencia. La persistencia o el
almacenamiento permanente, es una de las necesidades básicas de cualquier sistema de información de
cualquier tipo. Persistir objetos Java en una base de datos relacional implica serializar un árbol de objetos
Java en una base de datos de estructura tabular y viceversa. Es vital poder mapear objetos Java para
optimizar velocidad y eficiencia de la base de datos.
ENTIDADES
Una entidad es un objeto de dominio persistencia liviano. Por lo general, una entidad representa una tabla
en una base de datos relacional, y cada instancia de la entidad corresponde a una fila de esa tabla.
Una entidad tiene campos o propiedades que son persistentes.
Página 32 de 77
Ejemplo de entidad
@Entity
@Table(name = "PERSONA")
@Id
@GeneratedValue
private Long id;
@Column(nullable=false)
private String nombre;
@Column(nullable=true)
private Date fechaNacimiento;
@Transient
private int edad;
// Getters y Setters
}
La anotación @Table nos permite configurar el nombre de la tabla donde queremos almacenar la entidad
mediante el atributo name.
Para definir un atributo de una entidad (Entity) que no se desee persistir, debe emplearse la anotación
@Transient. La anotación @Lob especifica que la propiedad debe ser persistida en un Blob o Clob.
Página 33 de 77
Las entidades pueden utilizar campos persistentes, propiedades persistentes, o una combinación de ambos.
Si las anotaciones de mapeo se aplican a las variables de instancia de la entidad, la entidad utiliza campos
persistentes. Si las anotaciones de mapeo se aplican a los métodos getter de la entidad, la entidad utiliza las
propiedades persistentes.
CAMPOS PERSISTENTES
Si la clase de entidad utiliza campos persistentes, el acceso se realiza en tiempo de ejecución.
Todos los campos que NO sean anotados con javax.persistence.Transient o no marcados como
@Transient se guardarán en el almacén de datos.
En el ejemplo de la entidad Persona, los campos persistentes son el id, nombre y fechaNacimiento. El campo
edad no se almacenará en la base de datos ya que está anotado como transient. Este campo puede ser
calculado a partir de la fecha de nacimiento, es por eso que no necesita ser almacenado en la base de datos.
PROPIEDADES PERSISTENTES
Si la entidad utiliza las propiedades persistentes, la entidad debe seguir las convenciones JavaBeans: esto
implica el uso de métodos get y set.
En el ejemplo de la entidad Persona, si utiliza las propiedades persistentes y tiene una variable de instancia
privada denominada nombre, la clase define un getNombre y setNombre.
TIPOS DE ACCESO
JPA permite definir dos tipos de acceso:
• Acceso a variable.
• Acceso a propiedad.
El tipo de acceso que usará una entidad está definido por el lugar donde situemos sus anotaciones de
mapeo. Si las anotaciones están en las variables estaremos indicando a JPA que debe realizar acceso a
variable. Si, por el contrario situamos las anotaciones de mapeo en los métodos getter, estaremos
indicando un acceso a propiedad. A efectos prácticos, no existe diferencia alguna entre ambas opciones.
La propiedad adjunto es un objeto que representa un archivo adjunto (un objeto que puede ser de gran
tamaño). Como el costo de crear este objeto al leer la entidad que lo contiene es muy alto, lo marcamos
como una propiedad de lectura demorada con la anotación @Basic(fetch = FetchType.LAZY) .
El comportamiento por defecto de la mayoría de tipos Java es el contrario (lectura temprana). Este
comportamiento, a pesar de ser implícito, puede ser declarado explícitamente de la siguiente manera:
Página 34 de 77
@Basic(fetch = FetchType.EAGER)
private Archivo adjunto;
Hay que tener ciertos cuidados cuando configuramos atributos con lectura demorada. Si, por ejemplo,
marcamos todas las propiedades de tipo int, String o Date de una entidad con lectura demorada, cada vez
que accedemos por primera vez a cada una de ellas el proveedor de persistencia tendrá que hacer una
llamada a la base de datos para leerla.
Esto va a hacer que se realicen muchas llamadas a la base de datos cuando con solo una (al crear la entidad
en memoria) podrían haberse leído todas con muy bajo costo. Por este motivo hay que tener mucho cuidado
al configurar este tipo de atributos porque puede afectar considerablemente el rendimiento de nuestra
aplicación.
La anotación @Basic solo puede ser aplicada a tipos primitivos, sus correspondientes clases wrapper,
BigDecimal, BigInteger, Date, arrays, algunos tipos del paquete java.sql, enums, y cualquier tipo que
implemente la interface Serializable.
Además del atributo fetch, la anotación @Basic admite otro atributo, optional, el cual permite definir si la
propiedad sobre la que se está aplicando la anotación puede contener el valor null.
TIPOS ENUMERADOS
JPA puede mapear los tipos enumerados (enum) mediante la anotación Enumerated:
@Enumerated
private Sexo sexo;
La configuración por defecto de JPA mapeará cada valor ordinal de un tipo enumerado a una columna de
tipo numérico en la base de datos.
public enum Sexo {
FEMENINO,
MASCULINO
}
TRANSIENT
Ciertas propiedades de una entidad pueden no representar su estado. Por ejemplo, imaginemos que
tenemos una entidad que representa a una persona:
@Entity
public class Persona {
@Id
@GeneratedValue
private Long id;
Podemos considerar que la propiedad edad no representa el estado de Persona, ya que si no es actualizada
cada cumpleaños, terminará conteniendo un valor erróneo. Como su valor puede calcularse a partir de la
fecha de nacimiento, no vamos a guardarlo en la base de datos. Para indicar al proveedor de persistencia
que ignore una propiedad cuando realice el mapeo, usamos la anotación @Transient:
@Transient
private int edad;
COLECCIONES
Una entidad puede tener propiedades de tipo java.util.Collection y/o java.util.Map que contengan tipos
básicos. Los elementos de estas colecciones serán almacenados en una tabla diferente a la que contiene la
entidad donde están declarados. El tipo de colección tiene que ser concreto (como ArrayList o HashMap) y
nunca una interface.
private ArrayList nombres;
@CollectionTable nos permite definir el nombre de la tabla donde queremos almacenar los elementos de
la colección. Si nuestra colección es de tipo Map, podemos añadir la anotación @MapKeyColumn(name =
"NOMBRE_COLUMNA"), la cual nos permite definir el nombre de la columna donde se almacenarán las claves
del Map.
TIPOS EMBEDDABLE
Los tipos embeddable son objetos que no tienen identidad: esto significa que para ser persistidos deben
ser primero insertados dentro de una entidad. Cada propiedad del tipo embeddable será mapeada a la tabla
de la entidad que lo contenga, como si fuera una propiedad declarada en la propia entidad. Definimos un
tipo insertable con la anotación @Embeddable:
@Embeddable
public class Direccion {
private String calle;
private int codigoPostal;
// ...
}
Página 36 de 77
@Entity
public class Persona {
// ...
@Embedded
private Direccion direccion;
}
Ahora, la tabla que contenga las entidades de tipo Persona contendrá sus propias columnas, más las
definidas en el tipo embeddable Direccion.
LAS CLAVES
Cada entidad tiene un identificador de objeto único. Una entidad de un cliente, por ejemplo, puede ser
identificado por un número de cliente. El identificador único, o una clave principal, permite localizar una
instancia de entidad en particular.
Cada entidad debe tener una clave principal. Una entidad puede tener una clave simple o compuesta.
Las claves primarias simples utilizan el javax.persistence.Id anotación para indicar la propiedad de
clave primaria en el campo.
Las claves primarias compuestas se utilizan cuando una clave principal se compone de más de un atributo,
que corresponde a un conjunto de propiedades persistentes individuales o campos. Las claves primarias
compuestas deben ser definidas en una clase aparte de clave primaria. Las claves primarias compuestas se
denotan usando las anotaciones javax.persistence.EmbeddedId y javax.persistence.IdClass.
Las Entidades poseen una identidad que las diferencie del resto:
• Propiedad marcada con la anotación @Id
• Debe admitir valores null, p.e.: Integer en lugar de int
• La identidad de una entidad va a ser gestionada por el proveedor de persistencia.
• Propiedad de identidad anotada: @GeneratedValue
CLAVES SIMPLES
@GeneratedValue(strategy = GenerationType.IDENTITY)
MySQL y SQLServer tienen un tipo de columna autonumérica (AUTO_INCREMENT e IDENTITY
respectivamente) ideal para ser usadas como clave primaria. Asimismo, PostgreSQL cuenta con el tipo
SERIAL que simula esta funcionalidad creando secuencias. Podemos usar esta característica mediante este
tipo de generador:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Página 37 de 77
@GeneratedValue(strategy = GenerationType.SEQUENCE)
Una secuencia es un objeto o tipo de datos que genera valores numéricos únicos dentro de esa secuencia.
Ese valor se define dentro de un rango, y se va incrementando según un valor de incremento a medida que
se vayan solicitando nuevos valores (por ejemplo en Oracle con la sentencia NOMBRE_SEQ.nextval).
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
Se pueden definir secuencias específicas para cada clave (o una común a varias de ellas) con la anotación
@SequenceGenerator. Esta anotación tiene como parámetros opcionales allocationSize, que indica el
incremento numérico del avance de la secuencia y cuyo valor por omisión es 50 (por lo que probablemente
queramos definirlo a un valor que nos resulte más conveniente como por ejemplo 1) y initialValue cuyo
valor por defecto es 1 tal y como cabría esperar.
@Entity
public class EntityA{
@Id
@SequenceGenerator(name="entA", sequenceName="entityA_seq", allocationSize = 1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="entA")
private Long id;
....
@Entity
public class EntityB{
@Id
@SequenceGenerator(name="entB", sequenceName="entityB_seq", allocationSize = 1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="entB")
private Long id;
@GeneratedValue(strategy = GenerationType.AUTO)
Delega en el proveedor la elección de la estrategia que considere oportuna en función de la BD subyacente.
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
Es la estrategia más cómoda, pero debemos conocer qué hace nuestro framework ya que el estándar le da
vía libre y es posible que el resultado no sea el deseado.
@GeneratedValue(STRATEGY = GENERATIONTYPE.TABLE)
Por último, veremos la estrategia más portable de todas ya que se puede emplear de igual manera en
cualquier BD. Se basa en utilizar una tabla con dos columnas, una de tipo texto con el nombre que identifica
al generador de claves primarias (tendremos uno por cada tabla) y otra de tipo numérico con el último
valor que fue asignado como PK para un registro de esa tabla.
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
private Long id;
Página 38 de 77
CLAVES MÚLTIPLES
Con la anotación @Id indicamos un atributo que puede ser de cierto tipo como clave primaria, pero ¿qué
pasaría si nuestra clave primaria es múltiple?
Frente a esta situación, lo que haremos es crear una clase que contenga todos los atributos de nuestra clave
múltiple, y la marcaremos con la anotación @Embeddable que permite que una clase pueda ser incluida en
una entidad y sus atributos formen parte de su mapeo a la BD. Por ejemplo:
@Embeddable
public class EntityPK implements Serializable{
private Long idRef1;
private Long idRef2;
//getters y setters
Ahora nuestra clave primaria estará compuesta por los dos atributos de esta clase y la usaremos con la
anotación @EmbeddedId:
@Entity
public class EntityA{
@EmbeddedId
EntityPK entityPK;
• One to many: Una instancia de la entidad puede estar relacionada con varias instancias de las otras
entidades. Por ejemplo, una biblioteca que puede tener muchos libros. Se utiliza la anotación
javax.persistence.OneToMany en la propiedad o campo persistente correspondiente.
• Many to one: Múltiples instancias de una entidad pueden estar relacionados con una sola instancia de
la otra entidad. Esta multiplicidad es lo contrario de una relación uno-a-muchos. Por ejemplo: un libro
que pertenece a una biblioteca, y la misma puede tener muchos libros. Se utiliza la anotación
javax.persistence.ManyToOne en la propiedad o campo persistente correspondiente.
• Many to many: En este caso varias instancias de una entidad pueden relacionarse con múltiples
instancias de otras entidades. Por ejemplo, cada curso de la universidad tiene muchos estudiantes, y
cada estudiante puede tomar varios cursos. Se utiliza la anotación javax.persistence.ManyToMany en
la propiedad o campo persistente correspondiente.
Página 39 de 77
LAS RELACIONES BIDIRECCIONALES
En una relación bidireccional, cada entidad tiene un campo de relación o propiedad que se refiere a la otra
entidad. A través del campo de relación o de propiedad, el código de una clase de entidad puede tener
acceso a su objeto relacionado. Si una entidad tiene un campo relacionado, se dice que la entidad a "conoce"
su objeto relacionado. Por ejemplo, si CustomerOrder conoce que LineItem tiene y si LineItem conoce al
CustomerOrder que pertenece, se dice que tienen una relación bidireccional.
Las relaciones bidireccionales deben seguir estas reglas.
• El lado inverso de una relación bidireccional debe referirse a su lado propietario mediante el uso de la
mappedBy de la relación @OneToOne , @OneToMany , o @ManyToMany. El mappedBy designa la propiedad o
campo en la entidad que es el dueño de la relación.
• El lado Many de relaciones Many to one bidireccionales no debe definir el elemento mappedBy. El lado
Many es siempre el lado propietario de la relación.
• Para relaciones one to one bidireccionales, el lado propietario corresponde a la parte que contiene la
clave externa correspondiente.
• Para relaciones Many to many bidireccionales, cada lado puede ser la parte propietaria.
OPERACIONES EN CASCADA
Las entidades que utilizan relaciones a menudo tienen dependencias en la existencia de la otra entidad en
la relación.
Por ejemplo, un elemento de línea es parte de un pedido; si se elimina la orden, el elemento de línea también
debería eliminarse. Esto se llama una eliminación en cascada.
El tipo enumerado javax.persistence.CascadeType define las operaciones en cascada que pueden
aplicarse.
Página 40 de 77
OPERACIÓN
DESCRIPCIÓN
EN CASCADA
Todas las operaciones en cascada se aplicarán a la entidad relacionada. All es
ALL
equivalente a especificar cascade={DETACH, MERGE, PERSIST, REFRESH, REMOVE}
Cuando una entidad es actualizada (se va a grabar), su entidad relacionada debe ser
MERGE
actualizada también.
Cuando una entidad es persistida (se crea), su entidad relacionada debe ser
PERSIST
persistida también.
Cuando una entidad es refrescada /se refresca con los datos de la base de datos), su
REFRESH
entidad relacionada debe ser refrescada también.
Cuando una entidad es removida (se borra), su entidad relacionada debe ser
REMOVE
removida también.
ALGUNOS EJEMPLOS
@OneToOne
@Entity
public class Departamento implements Serializable {
…
}
@Entity
public class Empleado implements Serializable {
@OneToOne(fetch=FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.REMOVE},
optional=false)
private Direccion direccion;
…
}
Configuramos la opción fetch a LAZY, de forma que cuando recuperemos un objeto de la entidad Empleado
no recupere la instancia de Dirección asociada.
Luego pusimos cascade a PERSIST y REMOVE, de forma que cuando persistamos un empleado que tenga
asociada una nueva Direccion, éste también se persistirá, y como no tiene sentido que exista una dirección
sin un empleado asociado, si eliminamos la instancia del Empleado también eliminará la instancia de
Direccion asociada.
También hemos establecido la opción optional a false, de forma que no permitimos que se persista una
instancia de Empleado si no está asociada con una instancia de Direccion.
Por último, con la opción orphanRemoval a true indicamos que cualquier instancia de Direccion que no
esté asociada a una instancia de Empleado será eliminada de la base de datos.
Ahora vamos a convertir la relación one-to-one unidireccional en bidireccional. Bastaría con añadir a la
entidad Direccion un atributo haciendo referencia a la entidad Empleado y anotar el atributo con
@OneToOne.
@OneToOne(fetch=FetchType.LAZY,mappedBy="direccion”)
private Empleado empleado;
Página 41 de 77
Agregamos la opción mappedBy con la que indicamos el atributo de la entidad propietaria de la relación
(Empleado en nuestro caso). De esta forma a través de una instancia de la entidad Direccion podemos
recuperar la instancia de la entidad Empleado asociada.
@OneToMany
@Entity
public class Libro implements Serializable {
…
}
@Entity
public class Biblioteca implements Serializable {
@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.ALL})
private List libros;
…
}
La opción fetch está en LAZY, de forma que cuando recuperemos un objeto de la entidad Biblioteca no
recupere las instancias de Libro asociadas.
Luego pusimos cascade a todo, de forma que cuando persistamos, borremos o modifiquemos una
Biblioteca sus libros también se actualizarán.
@ManyToOne
@Entity
public class Biblioteca implements Serializable {
@Id
@GeneratedValue
private Long id;
…
}
@Entity
public class Libro implements Serializable {
@ManyToOne(fetch=FetchType.LAZY,optional=false)
@JoinColumn(name="id")
private Biblioteca biblioteca;
…
}
La anotación @JoinColumn o @JoinColumns se usa para especificar cuál es el campo de la tabla que actúa de
clave foránea o clave foránea compuesta, respectivamente.
@ManyToMany
@Entity
public class Clase{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@ManyToMany
private List profesores;
…
Página 42 de 77
@Entity
public class Profesor{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@ManyToMany(mappedBy="profesores")
private List clases;
…
HERENCIA
La herencia es el concepto de la base de cualquier lenguaje orientado a objetos, por lo tanto, podemos
utilizar las relaciones de herencia o estrategias entre las entidades. JPA admiten tres tipos de estrategias
de herencia: SINGLE_TABLE, JOINED_TABLE y TABLE_PER_CONCRETE_CLASS.
SINGLE_TABLE
Una sola tabla para guardar toda la jerarquía de clases.
Tiene la ventaja de ser la opción que mejor rendimiento da, ya que sólo es necesario acceder a una tabla
(está totalmente desnormalizada).
Tiene como inconveniente que todos los campos de las clases hijas tienen que admitir nulos, ya que
cuando guardemos un tipo, los campos correspondientes a los otros tipos de la jerarquía no tendrán valor.
JOINED_TABLE
Una tabla para el padre de la jerarquía, con las cosas comunes, y otra tabla para cada clase hija con las cosas
concretas.
Es la opción más normalizada, y por lo tanto la más flexible (puede ser interesante si tenemos un modelo
de clases muy cambiante), ya que para añadir nuevos tipos basta con añadir nuevas tablas y si queremos
añadir nuevos atributos sólo hay que modificar la tabla correspondiente al tipo donde se está añadiendo el
atributo.
Tiene la desventaja de que para recuperar la información de una clase, hay que ir haciendo join con las
tablas de las clases padre.
TABLE_PER_CONCRETE_CLASS
Una tabla independiente para cada tipo. En este caso cada tabla es independiente, pero los atributos del
padre (atributos comunes en los hijos), tienen que estar repetidos en cada tabla.
En principio puede tener serios problemas de rendimiento, si estamos trabajando con polimorfismo, por
los SQL UNIONS que se tienen que hacer para recuperar la información. Sería la opción menos
aconsejable.
Tanto es así que en la versión 3.0 de EJBs, aunque está recogida en la especificación, no es obligatoria su
implementación.
Página 43 de 77
EJEMPLO
Aquí tenemos un ejemplo clásico de herencia donde tenemos una Persona que puede ser un Alumno o un
Profesor.
Vamos a ver ahora como implemento esta realidad con la estrategia SINGLE_TABLE:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn( name="tipo" )
public abstract class Persona {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Entity
@DiscriminatorValue(value="ALUMNO")
public class Alumno extends Persona implements Serializable {
@Entity
@DiscriminatorValue( value="PROFESOR" )
public class Profesor extends Persona implements Serializable {
Página 44 de 77
La tabla física que se genera es la siguiente:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Entity
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Alumno extends Persona implements Serializable {
@Entity
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Profesor extends Persona implements Serializable {
Id Nombre Apellido
1 Juan Perez
2 Maria Gonzalez
Alumno
Id Generacion
1 2005
Página 45 de 77
Profesor
Id GradoDocente
1 grado 3
UNIDADES DE PERSISTENCIA
Página 46 de 77
MANEJO DE ENTIDADES
ENTITY MANAGER
Las entidades son gestionadas por el gestor de entidades, que está representado por el
javax.persistence.EntityManager. Cada instancia del EntityManager, se asocia con un contexto de
persistencia: un conjunto de instancias de entidades manejadas que existen en cierto almacén de datos.
Un contexto de persistencia define el alcance bajo el cual instancias de entidades son creadas, persistidas y
removidas. La interfaz EntityManager define los métodos que se utilizan para interactuar con el contexto
de persistencia.
LA INTERFAZ ENTITYMANAGER
La API EntityManager crea y elimina instancias de entidad persistentes, encuentra las entidades por la clave
primaria de la entidad, y permite ejecutar consultas en las entidades.
// Getters y Setters
}
Para que JPA pueda persistir esta entidad, necesita un archivo de configuración XML llamado
persistence.xml, el cual debe estar ubicado en el directorio META-INF de nuestra aplicación.
Para este ejemplo sería:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistenceunit name="ejemploJPA" transactiontype="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.ejemplo.Curso</class>
<class>com.ejemplo.Materia</class>
<properties>
<property name="eclipselink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="eclipselink.jdbc.url"
value="oracle:thin:@myhost:l521:MYSID"/>
<property name="eclipselink.jdbc.user" value="APP"/>
<property name="eclipselink.jdbc.password" value="APP"/>
<property name="eclipselink.ddlgeneration" value="createtables"/>
</properties>
</persistenceunit>
</persistence>
El archivo persistence.xml tiene toda la información necesaria para almacenar los datos en la base de datos
elegida, como el nombre de la unidad de persistencia, el tipo de transacciones que vamos a utilizar, las
clases que deseamos que sean manejadas por el proveedor de persistencia, y los parámetros para conectar
con nuestra base de datos.
El concepto de transacción representa un contexto de ejecución dentro del cual podemos realizar varias
operaciones como si fuera una sola, de manera que o todas ellas son ejecutadas, o el proceso entero falla.
JPA nos permite configurar en cada unidad de persistencia el tipo de transacción que queremos usar, que
puede ser:
• Manejada por la aplicación (RESOURCE_LOCAL).
• Manejada por el contenedor (JTA).
Para JPA, una entidad puede estar en uno de los dos estados siguientes:
• Managed (gestionada).
• Detached (separada).
Página 48 de 77
Cuando persistimos una entidad automáticamente se convierte en una entidad GESTIONADA. Todos los
cambios que efectuemos sobre ella dentro del contexto de una transacción se verán reflejados también en
la base de datos, de forma transparente para la aplicación.
El segundo estado en el que puede estar una entidad es SEPARADO, en el cual los cambios realizados en la
entidad no están sincronizados con la base de datos. Una entidad se encuentra en estado separado antes
de ser persistida por primera vez, y cuando tras haber estado gestionada es separada de su contexto de
persistencia.
...
Modificamos el nombre de la entidad materia después de haber sido persistida, pero como estoy dentro de
la misma transacción que realizó la persistencia los datos se sincronizarán con la base de datos. Es
importante tener presente que esta sincronización puede no ocurrir hasta que se complete la transacción
e internamente se realice el commit en la base de datos (el momento en que la sincronización se lleve a
cabo depende enteramente de la implementación concreta del proveedor de persistencia que usemos). Lo
que podemos hacer en este caso es forzar a que cualquier cambio pendiente se guarde en la base de datos
en el momento que querramos invocando el método flush() de EntityManager:
em.persist(materia);
materia.setNombre("otro nombre");
em.flush();
También podemos realizar la sincronización en sentido inverso, actualizando una entidad con los datos que
se encuentran en la base de datos. Esto es útil cuando persistimos una entidad, y tras haber cambiado su
estado deseamos recuperar el estado persistido y deshacer los últimos cambios realizados sobre la entidad.
Esto lo realizamos con el método refresh() del EntityManager:
em.persist(materia);
materia.setNombre("otro nombre");
em.refresh(materia);
Página 49 de 77
Otro método del EntityManager es el contains():
boolean gestionada = em.contains(materia);
El método contains() devuelve true si el objeto Java que le pasamos como parámetro se encuentra en
estado gestionado por el proveedor de persistencia, y false en caso contrario.
La operación persist se propaga a todas las entidades relacionadas con la entidad llamante que tienen la
propiedad cascade ALL o PERSIST en la anotación relación:
public Materia crearMateria(Curso curso, String nombre, int capacidad) {
Materia materia = new Materia(nombre, capacidad);
curso.getMaterias().add(materia);
em.persist(materia);
return materia;
}
Obteniendo un objeto real: puedo realizarlo a través del método find. Este método del EntityManager se
utiliza para buscar entidades a partir de la clave primaria de la entidad:
Materia materia = em.find(Materia.class, id);
Obteniendo una referencia a los datos persistidos: nos permite obtener una referencia a los datos
almacenados en la base de datos, de manera que el estado de la entidad será leído de forma demorada. Se
lee en el primer acceso a cada propiedad y no en el momento de la creación de la entidad:
Materia materia = em.getReference(Materia.class, id);
Separa la materia del contexto de persistencia llamando al método detach(). La última línea, sin embargo,
indica al proveedor de persistencia que vuelva a gestionar la entidad, y que sincronice los cambios en la
base de datos.
Página 50 de 77
ELIMINANDO UNA ENTIDAD
Cuando invocamos al método remove del EntityManager la entidad es eliminada de la base de datos y
separada del contexto de persistencia. Sin embargo, la entidad seguirá existiendo como objeto Java en
nuestro código hasta que el ámbito de la variable termine:
em.remove(materia);
materia.setNombre("ya no soy una entidad, soy solo un objeto Java");
Si el remove método se invoca en una entidad nueva, la operación del remove se ignora. Si el remove se
invoca en una entidad detached, el remove lanzará una IllegalArgumentException o la confirmación de
transacción fallará.
Si se invoca en una entidad que ya se haya removido, el remove será ignorado. Los datos de la entidad se
eliminarán de la memoria de datos cuando se termina la transacción, o como resultado de la operación
flush.
En el siguiente ejemplo, todas las Materias asociadas al curso se removerán, esto es porque la lista de
materias tiene cascade=ALL:
public void removeCurso(Integer cursoId) {
try {
Curso curso = em.find(Curso.class, cursoId);
em.remove(curso);
} ...
MÉTODOS CALLBACK
Los métodos callback son métodos que se ejecutan cuando se producen ciertos eventos relacionados con
el ciclo de vida de una entidad. Estos eventos se clasifican en cuatro categorías:
• Eventos de persistencia: Métodos callback asociados anotados con @PrePersists y @PostPersist:
antes y después de persistir.
• Eventos de actualización: Métodos callback asociados anotados con @PreUpdate y @PostUpdate:
antes y después de actualizar.
• Eventos de borrado: Métodos callback asociados anotados con @PreRemove y @PostRemove: antes
y después de remover.
• Eventos de carga: Método callback asociado anotado con @PostLoad: luego de cargar.
Página 51 de 77
@Entity
public class Materia{
...
@PrePersist
@PreUpdate
private void validar() {
// validación de parámetros antes de persistir/actualizar la entidad
}
}
CLASES LISTENER
Cuando necesitamos aplicar un mismo método callback a varias entidades, es preferible extraer de la
entidad este método y ponerlo en una clase externa, la cual podrá ser aplicada a varias entidades. Estas son
las clases listener:
public class ValidadorListener {
@PrePersist
@PreUpdate public void validar(Materia materia) {
// validar parametros antes de persistir/actualizar la entidad
}
}
En tiempo de ejecución, cuando se produzca un evento que se encuentre definido en la clase listener, el
proveedor de JPA pasará a su método validar() una referencia de la entidad Materia.
También existe la anotación @EntityListeners puede hacer referencia a varias clases listener usando un
array de objetos .class. Cuando una entidad es asociada con varias clases listener, los métodos callback de
dichas clases que hagan referencia a un mismo evento serán invocados en el orden en que fueron
declarados dentro del array.
Así mismo, los métodos callback de las clases listener serán invocados de manera previa a los métodos
callback que hagan referencia al mismo tipo de evento y que estén declarados dentro de la entidad:
Página 52 de 77
@Entity
@EntityListeners({ ValidadorListener.class, OtroListener.class})
public class Materia {
// ...
@PrePersist
@PreUpdate
private void validar() {
// validar parámetros antes de persistir y actualizar la entidad
}
}
En este ejemplo, los métodos @PrePersist y @PreUpdate se ejecutarán en este orden: ValidatorListener,
OtroListener, Materia.
Página 53 de 77
JAVA PERSISTENCE QUERY LANGUAGE
QUÉ ES
JPQL es un lenguaje de consulta orientado a objetos definido en la especificación de Java Persistence API
(JPA).
JPQL es usado para hacer consultas contra las entidades almacenadas en una base de datos relacional. Su
sintaxis es muy similar a la de SQL, pero mientras SQL trabaja directamente con bases de datos relacionales,
registros y campos; JPQL lo hace con clases Java e instancias.
Además de recuperar objetos a través de las consultas SELECT, JPQL también soporta consultas de
actualización y borrado como lo son el UPDATE y DELETE.
SINTAXIS
Esta query lo que hace es obtener todas las instancias de la clase Materia de la base de datos. El SELECT se
utiliza para seleccionar cierta información desde el FROM. El “FROM Materia m” indica que m es un alias
para la clase Materia, mientras que el “SELECT m” indica que la expresión m se utiliza para acceder a la
clase Materia a la que refiere el alias o a sus propiedades.
También puede querer obtener los ids y nombres de todas las materias:
SELECT m.id, m.nombre FROM Materia m
También puedo utilizar funciones agregadas como el COUNT, SUM, MAX, MIN, AVG, etc. Si quisiera saber la
cantidad de materias que tengo:
SELECT COUNT(m) FROM Materia m
El WHERE permite restringir los resultados devueltos por una consulta, en base a ciertos criterios lógicos.
SELECT m FROM Materia m
WHERE m.capacidad < 50
En esta sentencia estoy obteniendo todas las instancias de Materia que tengan una capacidad de menos de
50 estudiantes. También puedo agregar más condiciones:
Página 54 de 77
SELECT m FROM Materia m
WHERE m.capacidad < 50 AND m.tipo = ‘CIENCIAS’
En este caso se obtienen las materias con capacidad menor a 50 estudiantes y que sean de tipo CIENCIAS.
Ahora estoy obteniendo las materias con capacidad menor a 50 estudiantes y que NO sean de tipo
CIENCIAS.
Otro operador de comparación muy útil es [NOT] LIKE (NOT es opcional), el cual nos permite comparar una
cadena de texto completa o solo una parte de ella:
SELECT m FROM Materia m
WHERE m.nombre LIKE 'A%'
En esta consulta se obtienen todas las instancias de Materia cuyo nombre comience con A.
PARÁMETROS
Podemos agregar parámetros en forma dinámica a nuestras sentencias JPQL de dos maneras: por posición
y por nombre.
Por posición:
SELECT m FROM Materia m
WHERE m.nombre = ?1
Por nombre:
SELECT m FROM Materia m
WHERE m.nombre = :nombre
Cuando quiera ejecutar la consulta tendré que pasar el o los valores que sustituyan a los parámetros
definidos.
Para poder ordenar los resultados de nuestras consultas, podemos utilizar la cláusula ORDER BY que admite
ordenamiento ascendente (ASC que es el por default) o descendente (DESC):
SELECT m FROM Materia m
ORDER BY m.capacidad DESC
Página 55 de 77
SELECT m FROM Materia m
WHERE m.tipo = ‘CIENCIAS’
ORDER BY m.capacidad DESC, m.nombre ASC
Ahora estoy obteniendo todas las materias de tipo CIENCIAS ordenadas por capacidad de mayor a menor
y el forma alfabética.
RESUMIENDO
Una sentencia SELECT puede tener 6 cláusulas: SELECT, FROM, WHERE, GROUP BY, HAVING, and ORDER BY.
El SELECT y FROM son obligatorias, pero el WHERE, GROUP BY, HAVING, y ORDER BY son opcionales.
La sintaxis de alto nivel sería:
QL_statement ::= select_clause from_clause
[where_clause][groupby_clause][having_clause][orderby_clause]
Donde:
• El SELECT define los tipos de objetos o valores que retorna la query.
• El FROM define el alcance de la query definiendo una o más variables de identificación que podrán ser
referenciadas en el SELECT y WHERE. Una variable de identificación representa uno de los siguientes
elementos:
o El nombre del esquema abstracto de una entidad.
o Un elemento colección de una relación.
o Un elemento de un solo valor de una relación.
o Un miembro de una colección que es el lado múltiple de una relación One-To-Many.
• El WHERE es una expresión condicional que restringe los objetos o valores que retorna la query.
• El GROUP BY agrupa resultado de acuerdo a un conjunto de propiedades.
• El HAVING es usado junto con el GROUP BY para restringir los resultados de acuerdo a la expresión.
• El ORDER BY ordena los objetos o valores retornados por la query.
En la sentencia anterior se actualizan las instancias de Materia donde el tipo es CIENCIAS, poniéndoles
capacidad de 20 estudiantes.
De esta manera borro las materias que no tengan capacidad para estudiantes.
Página 56 de 77
RESUMIENDO
La sintaxis es:
update_statement :: = update_clause [where_clause]
delete_statement :: = delete_clause [where_clause]
El UPDATE y DELETE determinan el tipo de entidades que serán actualizadas o borradas. El WHERE es
opcional y se usa para restringir el alcance de los datos actualizados o borrados.
El método createNamedQuery se utiliza para crear consultas estáticas o consultas que se definen en los
metadatos mediante el uso de la anotación javax.persistence.NamedQuery. El elemento name de
@NamedQuery especifica el nombre de la consulta que se utilizará con el método createNamedQuery.
Por ejemplo: En el entity de Materia puedo definir:
@NamedQuery (
name = "Materia.obtenerPorTipo",
query = "SELECT m FROM Materia m WHERE m.tipo LIKE :tipo"
)
Los named parameters son los parámetros de consulta con el prefijo dos puntos ( : ). Estos parámetros se
setean utilizando el método javax.persistence.Query.setParameter (String nombre, Object valor).
Los named parameters son case sensitive y pueden ser utilizados por ambas consultas dinámicas y
estáticas.
En el método obtenerMateriaPorTipo, el named parameter es “tipo”.
En vez de los named parameters pueden utilizarse parámetros posicionales en las consultas. Los
parámetros posicionales van precedidos de un signo de interrogación ( ? ), seguido de la posición numérica
Página 57 de 77
del parámetro de la consulta. El método Query.setParameter(integer position, Object value) se utiliza para
establecer los valores de los parámetros.
Reescribiendo el método de obtenerMateriasPorTipo con parámetros posicionales sería:
public List obtenerMateriasPorTipo(String tipoMateria) {
return em.createQuery(
"SELECT m FROM Materia m WHERE m.tipo LIKE ?1")
.setParameter(1, tipoMateria)
.setMaxResults(10)
.getResultList();
}
Para obtener todas las materias, por ejemplo, tengo 2 formas de hacerlo:
Query query = em.createQuery("SELECT m FROM Materia m");
List resultados = query.getResultList();
o
TypedQuery query = em.createQuery("SELECT m FROM Materia m", Materia.class);
List resultados = query.getResultList();
El objeto Query y el TypedQuery definen ambos un método getResultList, pero la versión de Query retorna
una lista de un tipo de dato no genérico, en vez de uno parametrizado (genérico).
Las queries tipadas también puedo utilizarlas de forma análoga con las named queries:
TypedQuery query = em.createNamedQuery("Materia.obtenerTodas", Materia.class);
List resultados = query.getResultList();
Es una buena práctica utilizar Queries tipadas, de esa manera ya le indicamos de antemano que tipo de dato
nos debe retornar.
Por último puedo querer ejecutar sentencias SQL nativas en vez de una sentencia JPQL:
String sql = "SELECT * FROM MATERIA";
Query query = em.createNativeQuery(sql);
// ...
Estas consultas SQL nativas también pueden ser definidas de manera estática:
@Entity
@NamedNativeQuery(name=”Materia.obtenerTodas”, query="SELECT * FROM MATERIA")
public class Materia {
// ...
}
Página 58 de 77
IMPLEMENTACIÓN DE HERENCIAS Y RELACIONES
Se persistió una instancia de Profesor y otra de Alumno, y se obtuvo una tabla en la base de datos con la
siguiente estructura y contenido:
SERVIDOR
Se implementó de la siguiente manera en el servidor:
Página 59 de 77
PERSONA.JAVA
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="tipo")
public class Persona implements java.io.Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(length=20)
private String nombre;
@Column(length=20)
private String apellido;
public Persona() {
super();
}
// getters y setters
ALUMNO.JAVA
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@DiscriminatorValue(value="ALUMNO")
public class Alumno extends Persona implements Serializable {
public Alumno() {
super();
}
//getters y setters
}
Página 60 de 77
PERSONASBEANREMOTE.JAVA
package com.servicios;
import java.util.List;
import javax.ejb.Remote;
import com.entidades.*;
@Remote
public interface PersonasBeanRemote {
PERSONASBEAN.JAVA
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.*;
import com.entidades.*;
@Stateless
public class PersonasBean implements PersonasBeanRemote {
@PersistenceContext
private EntityManager em;
public PersonasBean() {
@Override
public void crear(Profesor profesor) {
em.persist(profesor);
em.flush();
}
@Override
public void crear(Alumno alumno) {
em.persist(alumno);
em.flush();
}
@Override
public List<Persona> obtenerTodos() {
TypedQuery<Persona> query = em.createQuery("SELECT p FROM Persona p",
Persona.class);
return query.getResultList();
}
Página 61 de 77
@Override
public Profesor buscarProfesor(Long id) {
Profesor p = em.find(Profesor.class, id);
return p;
}
@Override
public Alumno buscarAlumno(Long id) {
Alumno a = em.find(Alumno.class, id);
return a;
}
}
PERSISTENCE.XML
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="Herencia_1_EJB">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/HerenciaDS</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>com.entidades.Persona</class>
<class>com.entidades.Alumno</class>
<class>com.entidades.Profesor</class>
<validation-mode>AUTO</validation-mode>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
<property name="javax.persistence.schema-generation.create-database-
schemas" value="true"/>
</properties>
</persistence-unit>
</persistence>
ORM.XML
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd">
<persistence-unit-metadata>
<persistence-unit-defaults>
<access>FIELD</access>
</persistence-unit-defaults>
</persistence-unit-metadata>
<entity class="com.entidades.Persona" access="FIELD">
<table name="PERSONAS">
</table>
Página 62 de 77
</entity>
</entity-mappings>
CLIENTE
En el cliente se implementó la siguiente clase para realizar la prueba:
package com.cliente;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.*;
import com.servicios.PersonasBeanRemote;
altasPersonas(person);
}
}
}
per.crear(new Profesor("Jose","Granada","grado4"));
per.crear(new Alumno("Ana","Marquez",2019));
per.crear(new Profesor("Marta","Dinardi","grado2"));
Página 63 de 77
per.crear(new Alumno("Daniel","Ventos",2020));
per.crear(new Alumno("Luis","Fontes",2020));
per.crear(new Alumno("Antonio","Rios",2020));
per.crear(new Alumno("Joaquin","Beal",2020));
per.crear(new Alumno("Emiliano","Silva",2019));
per.crear(new Profesor("Sergio","Trias","grado 2"));
}
}
Página 64 de 77
Se persistió una instancia de Profesor y otra de Alumno, y se obtuvo las siguientes tablas en la base de datos
con la siguiente estructura y contenido:
Una tabla PERSONAS con los dos registros (un profesor y un alumno) y su ID correspondiente:
Una tabla PROFESORES sólo con el registro del profesor, con el ID que le corresponde y con el atributo
propio del profesor (gradoDocente).
Una tabla ALUMNOS sólo con el registro del alumno, con el ID que le corresponde y con el atributo propio
del alumno (generacion).
SERVIDOR
Se implementó de la siguiente manera en el servidor:
PERSONA.JAVA
package com.entidades;
import javax.persistence.*;
@Entity
@Table(name="PERSONAS")
@Inheritance(strategy=InheritanceType.JOINED)
public class Persona implements java.io.Serializable{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PER")
@SequenceGenerator(name = "SEQ_PER", initialValue = 1, allocationSize = 1)
private Long id;
Página 65 de 77
private String nombre;
private String apellido;
public Persona() {
super();
}
// Getters y setters
}
ALUMNO.JAVA
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="ALUMNOS")
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Alumno extends Persona implements Serializable {
public Alumno() {
super();
}
// Getters y setters
}
PROFESOR.JAVA
package com.entidades;
import java.io.Serializable;
import javax.persistence.*;
@Entity
@Table(name="PROFESORES")
@PrimaryKeyJoinColumn(referencedColumnName="id")
public class Profesor extends Persona {
public Profesor() {
super();
}
// Getters y setters
}
Página 66 de 77
PERSONASBEANREMOTE.JAVA
package com.servicios;
import java.util.List;
import javax.ejb.Remote;
import com.entidades.*;
@Remote
public interface PersonasBeanRemote {
PERSONASBEAN.JAVA
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.*;
import com.entidades.*;
@Stateless
public class PersonasBean implements PersonasBeanRemote {
@PersistenceContext
private EntityManager em;
public PersonasBean() {
@Override
public void crear(Profesor profesor) {
em.persist(profesor);
em.flush();
}
@Override
public void crear(Alumno alumno) {
em.persist(alumno);
em.flush();
}
}
Página 67 de 77
ARCHIVOS DE CONFIGURACIÓN EN EL SERVIDOR
PERSISTENCE.XML
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
<persistence-unit name="Herencia_2_EJB">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/HerenciaDS</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<validation-mode>AUTO</validation-mode>
<properties>
<property name = "hibernate.dialect" value =
"org.hibernate.dialect.Oracle10gDialect"/>
<property name = "hibernate.hbm2ddl.auto" value = "create-drop" />
<property name = "hibernate.show_sql" value = "true" />
<property name="javax.persistence.schema-generation.create-database-
schemas" value="true"/>
</properties>
</persistence-unit>
</persistence>
ORM.XML
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd">
<persistence-unit-metadata>
<persistence-unit-defaults>
<access>FIELD</access>
</persistence-unit-defaults>
</persistence-unit-metadata>
<entity class="com.entidades.Persona" access="FIELD">
<table name="PERSONAS"></table>
<inheritance strategy="JOINED"/></entity>
<entity class="com.entidades.Profesor" access="FIELD">
<table name="PROFESORES">
</table></entity>
<entity class="com.entidades.Alumno" access="FIELD">
<table name="ALUMNOS">
</table></entity></entity-mappings>
Página 68 de 77
CLIENTE
En el cliente se implementó la siguiente clase para realizar la prueba:
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.*;
import com.servicios.PersonasBeanRemote;
String ruta =
"ejb:/Herencia_2_EJB/PersonasBean!com.servicios.PersonasBeanRemote";
PersonasBeanRemote person = (PersonasBeanRemote)
InitialContext.doLookup(ruta);
try {
person.crear(p);
} catch(Exception e) {
System.out.println("Error al crear Profesor");
System.out.println(e.getMessage());
}
try{
person.crear(a);
} catch(Exception e) {
System.out.println("Error al crear Alumno");
System.out.println(e.getMessage());
}
}
}
Para hacer el listado total, se hace de la misma forma que con una sola tabla. Fijarse el ejemplo anterior.
Página 69 de 77
IMPLEMENTAR UNA CASO DE MANYTOMANY
Dado una entidad Libro, que puede tener muchos Autores, y que un Autor puede estar en muchos Libros,
tenemos una relación de N a N.
Vamos a verlo en un Ejemplo.
ENTIDADES
ENTIDAD LIBRO
package com.entidades;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="LIBROS")
public class Libro implements Serializable {
@Id
@SequenceGenerator(name = "SEQ_LIB", initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_LIB")
private Long id;
// Estas anotaciones hacen crear una tabla(auxiliar) en SQL con las dos id de
cada entidad que tiene la relación N a N
@JoinTable(
name = "LIBROS_AUTORES",
joinColumns = @JoinColumn(name = "FK_LIBRO", nullable = false),
inverseJoinColumns = @JoinColumn(name="FK_AUTOR", nullable = false)
)
@ManyToMany(cascade=CascadeType.ALL ,fetch = FetchType.EAGER)
private Set<Autor> autores;
Página 70 de 77
public void addAutor(Autor autor) {
if(this.autores == null){
this.autores = new HashSet<>();
}
this.autores.add(autor);
}
public Libro() {
super();
}
// Getters y Setters
ENTIDAD AUTOR
package com.entidades;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
@Entity
@Table(name="AUTORES")
public class Autor implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "SEQ_AUT", initialValue = 1, allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_AUT")
private Long id;
Página 71 de 77
@Column
private String nombre;
public Autor() {
super();
}
SERVIDOR
Se implementó de la siguiente manera en el servidor:
LIBROBEANREMOTE
package com.servicios;
import javax.ejb.Remote;
import com.entidades.Libro;
@Remote
public interface LibroBeanRemote {
Página 72 de 77
LIBROBEAN
package com.servicios;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import com.entidades.Libro;
@Stateless
public class LibroBean implements LibroBeanRemote {
@PersistenceContext
private EntityManager em;
public LibroBean() {
@Override
public void crearLibro(Libro libro) {
// Importante: El uso de merge en lugar de persist nos sirve para dar de alta
los autores ya que los que ya estan creados no los da de alta nuevamente.
em.merge(libro);
em.flush();
}
}
AUTORESBEANREMOTE
package com.servicios;
import javax.ejb.Remote;
import com.entidades.Autor;
@Remote
public interface AutoresBeanRemote {
AUTORESBEAN
package com.servicios;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import com.entidades.Autor;
Página 73 de 77
@Stateless
public class AutoresBean implements AutoresBeanRemote {
@PersistenceContext
private EntityManager em;
public AutoresBean() {
@Override
public void crearAutor(Autor autor) {
em.persist(autor);
em.flush();
}
@Override
public Autor ObtenerAutor(Long id) {
Autor autor=em.find(Autor.class, id);
return autor;
}
@Override
public Autor ObtenerAutor(String nombre) {
TypedQuery<Autor> query ;
query = em.createQuery("SELECT a FROM Autor a WHERE a.nombre LIKE :nombre",
Autor.class).setParameter("nombre", nombre);
return query.getSingleResult();
}
}
ORM.XML
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd">
<persistence-unit-metadata>
<persistence-unit-defaults>
<access>FIELD</access>
</persistence-unit-defaults>
</persistence-unit-metadata>
<entity class="com.entidades.Libro" access="FIELD">
<table name="LIBROS">
</table>
</entity>
<entity class="com.entidades.Autor" access="FIELD">
<table name="AUTORES">
</table>
</entity>
</entity-mappings>
Página 74 de 77
CLIENTE
CLIENTE_MTM_1.JAVA
package com.cliente;
import java.util.HashSet;
import java.util.Set;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.entidades.Autor;
import com.entidades.Libro;
import com.servicios.AutoresBeanRemote;
import com.servicios.LibroBeanRemote;
String ruta="MTM_EJB//LibroBean!com.servicios.LibroBeanRemote";
String ruta2="MTM_EJB//AutoresBean!com.servicios.AutoresBeanRemote";
// Nuevos Autores
Autor autor1 = new Autor();
autor1.setNombre("Maria Barrios");
// Nuevos Libros
Libro libro1 = new Libro();
libro1.setNombre("El hombre y las computadoras");
libro1.addAutor(autor1);
libro1.addAutor(autor4);
vari.crearLibro(libro1);
autor4=vari2.ObtenerAutor("Ana Paladino");
System.out.println(autor4.getNombre()+" "+autor4.getId());
Página 75 de 77
Libro libro2 = new Libro();
libro2.setNombre("Encontrando la solucion de Java EE");
libro2.addAutor(autor4);
vari.crearLibro(libro2);
autor1=vari2.ObtenerAutor("Maria Barrios");
System.out.println(autor1.getNombre()+" "+autor1.getId());
libro3.addAutor(autor1);
vari.crearLibro(libro3);
TABLAS EN SQL
Como quedaron las tablas en sql.
Autores
Libros
Página 76 de 77
Libros_Autores
Página 77 de 77