Story Transcript
Introducción a EJB
¿ Qué es EJB ? (1)
EJB (Enterprise JavaBean) es una tecnología J2EE para la implementación de la capa modelo de una aplicación
Soporte para persistencia Soporte para implementación de fachadas (ocultación APIs de transacciones y seguridad)
Las versiones anteriores (EJB 1.x y 2.x) fueron muy criticadas
Difíciles de usar El soporte para persistencia permitía programar de manera independiente del tipo de BD (relacional, objetual, etc.), pero era muy poco potente
No permitía realizar muchos tipos de consultas usuales (e.g. muchos tipos de JOINs, GROUP BYs, etc.), borrados/actualizaciones en masa, etc. ¿Es posible definir un API de Persistencia que sea completamente independiente del tipo de base datos, y que sea funcionalmente completa y eficiente?
¿ Qué es EJB ? (2)
Debido a las complejidades/deficiencias de EJB 1.x/2.x, surgieron diversos proyectos
Hibernate
www.hibernate.org Mapeador objeto/relacional Open Source
TopLink
Permite mapear objetos JavaBean a una BD relacional (internamente utiliza el API de JDBC) Soporta relaciones entre objetos y herencia No oculta el tipo de BD (relacional), pero sí la BD concreta (Oracle, MySQL, PostgreSQL, etc.) Proporciona API + lenguaje de consultas de búsqueda y borrados/actualizaciones en masa
www.oracle.com Mapeador objeto/relacional de Oracle
JDO (Java Data Objects)
http://java.sun.com/products/jdo Especificación Java para persistencia (existían varias implementaciones), pero que no tuvo suficiente éxito
¿ Qué es EJB ? (3)
Debido a las complejidades/deficiencias de EJB 1.x/2.x, surgieron diversos proyectos (cont)
Spring
www.springframework.org Framework MVC Open Source En lo que respecta a la capa modelo, Spring incluye un soporte para definir fachadas del modelo más sencillo que el de EJB 1.x/2.x
Todos estos frameworks se pueden usar dentro de un contenedor J2EE o fuera de él (aplicaciones standalone)
¿ Qué es EJB ? (y 4)
EJB 3.0 (la versión actual) incluye
El nuevo “API de Persistencia de Java” Un modelo más sencillo para la implementación de fachadas Por compatibilidad, incluye las APIs del modelo anterior (EJB 2.1)
El API de Persistencia de Java (1)
Inspirado en Hibernate, TopLink y JDO Mapeador objeto/relacional al estilo Hibernate/TopLink
Consta de
En consecuencia, no oculta que el tipo de BD sea relacional Actualmente Hibernate y TopLink implementan el API de Persistencia de Java Se puede usar en entornos J2SE (fuera de un contenedor J2EE) y sin el resto de componentes de EJB Anotaciones El API propiamente dicha EJB-QL
Anotaciones
El desarrollador puede anotar las clases persistentes (llamadas “entidades”) para que la implementación del API de Persistencia sepa cómo mapear las instancias a la BD (e.g. indica el nombre de la tabla, los nombres de las columnas a las que mapear los atributos, etc.)
El API de Persistencia de Java (y 2)
El API propiamente dicha
javax.persistence
Objetos principales
EntityManager: permite crear, encontrar por clave primera, y eliminar objetos persistentes, y crea objetos Query Query: permite lanzar consultas en EJB-QL Internamente las implementaciones usan el API de JDBC (transparentemente al programador)
EJB-QL (EJB Query Language)
Lenguaje de consultas de búsqueda y borrados/actualizaciones en masa La implementación traduce al SQL de la BD que se esté usando
Implementación de fachadas (1)
Pueden ser locales o remotas Ocultan las APIs de transacciones y seguridad al desarrollador Las versiones anteriores de EJB también proporcionaban lo anterior, pero con un modelo de programación más complejo Tipos de fachadas
Session Beans Message-Driven Beans
Session Beans
Fachadas “normales” (operaciones síncronas) Hay que definir una interfaz y una implementación Variantes
Stateless Session Beans (SLSB) Stateful Session Beans (SFSB)
Implementación de fachadas (y 2)
Message-Driven Beans (MDB)
Son fachadas del modelo que implementan casos de uso por los que el cliente no puede esperar a que terminen Funcionan bajo el paradigma del envío de mensajes
El cliente envía un mensaje (y continúa con otras cosas) El mensaje llega a una cola de mensajes Un pool de instancias del MDB procesa los mensajes de la cola
Ejemplo: En una tienda de comercio electrónico, el caso de uso correspondiente a la compra de los productos del carrito, puede implementarse con un MDB
Puede llevar asociado acciones del tipo: comprobar la validez del número de tarjeta, realización del pago, etc., que pueden consumir mucho tiempo Mientras tanto, el usuario debería poder seguir navegando por la tienda Finalmente, el MDB puede informar al usuario del estado de su pedido enviándole un correo
Ejemplo: MiniPortal (1)
Entidades
Un JavaBean (UserProfile) para representar la información de registro
@Entity public class UserProfile { private String loginName; private String encryptedPassword; private String firstName; // Resto de atributos ... // Constructores ... @Id public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; }
Ejemplo: MiniPortal (2) @Column(name="enPassword") public String getEncryptedPassword() { return encryptedPassword; } public void setEncryptedPassword(String encryptedPassword) { this.encryptedPassword = encryptedPassword; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } // Resto de propiedades ... }
Ejemplo: MiniPortal (3)
En el ejemplo anterior
Se usan anotaciones definidas en javax.persistence @Entity permite especificar que la clase es una entidad Se podría haber anotado la clase con @Table para especificar el nombre de la tabla en la que se guardarán las instancias de la clase
Los métodos get de las propiedades se pueden anotar para especificar cómo mapear las propiedades a columnas Por defecto, cada propiedad (definida por la presencia de métodos get/set) se mapea a una columna con el mismo nombre que el de la propiedad
Por defecto, se asume que el nombre de la tabla coincide con el de la clase
Cuando el nombre de una columna es distinto, la propiedad se puede anotar con @Column para especificar su nombre
La propiedad que corresponde a la clave primaria se anota con @Id
Ejemplo: MiniPortal (4)
Fachadas: definición
Se definen mediante una interfaz (por defecto, local) En el caso de MiniPortal, corresponde a la interfaz de la fachada del modelo
public interface UserFacadeDelegate { public void registerUser(String loginName, String clearPassword, UserProfileDetailsVO userProfileDetailsVO) throws DuplicateInstanceException; public LoginResultVO login(String loginName, String password, boolean passwordIsEncrypted) throws InstanceNotFoundException, IncorrectPasswordException; public UserProfileVO findUserProfile(); public void updateUserProfileDetails( UserProfileDetailsVO userProfileDetailsVO); public void changePassword(String oldClearPassword, String newClearPassword) throws IncorrectPasswordException; }
Ejemplo: MiniPortal (5)
Fachadas: implementación
@Stateful public class UserFacadeEJB implements UserFacadeDelegate { private String loginName; @PersistenceContext (unitName=GlobalNames.PERSISTENCE_UNIT) private EntityManager entityManager; public void registerUser(String loginName, String clearPassword, UserProfileDetailsVO userProfileDetailsVO) throws DuplicateInstanceException { if (entityManager.find(UserProfile.class, loginName) == null) { UserProfile userProfile = new UserProfile( loginName, encryptedPassword, userProfileDetailsVO.getFirstName(), userProfileDetailsVO.getSurname(), userProfileDetailsVO.getEmail(), userProfileDetailsVO.getLanguage(), userProfileDetailsVO.getCountry()); entityManager.persist(userProfile);
Ejemplo: MiniPortal (6) } else { throw new DuplicateInstanceException( userProfile.getLoginName(), UserProfile.class.getName()); } } // Resto de casos de uso ... }
Ejemplo: MiniPortal (7)
En el ejemplo anterior
Se usa la anotación @Stateful (definida en javax.ejb) para especificar que UserFacadeEJB es un SFSB El desarrollador no crea las instancias de las clases de implementación de los Session Beans, sino que lo hace la implementación de EJB Se usa la anotación @PersistenceContext en la declaración del atributo entityManager para que la implementación de EJB lo inicialice antes de ejecutar cualquier método del Session Bean
Ejemplo: MiniPortal (8)
En el ejemplo anterior (cont)
Métodos find y persist en EntityManager
find: recupera el objeto a partir de la clave primaria (aunque en este caso, sólo se usa para comprobar si ya existía un usuario registrado con este nombre) persist: inserta el objeto en la BD La implementación de cada método construye la consulta SQL y la ejecuta vía JDBC
Ambos métodos pueden realizar su trabajo porque pueden acceder en tiempo de ejecución a las anotaciones de la clase UserProfile
find recibe como primer parámetro la clase persist recibe una instancia (y a partir de ella se puede obtener la clase)
Ejemplo: MiniPortal (9)
Creación de una instancia de un Session Bean
Se crea automáticamente cuando se busca mediante JNDI Ejemplo InitialContext initialContext = ... UserFacadeDelegate userFacade = (UserFacadeDelegate) initialContext.lookup(userFacadeJNDIName);
Si el Session Bean es un SFSB, el cliente tiene que guardar una referencia a él
NOTA: en MiniBank y MiniPortal este código lo encapsulan las factorías de la fachadas del modelo
MiniPortal guarda la referencia en la sesión (HttpSession)
La clase cliente obtiene un Proxy del Session Bean Clase cliente
UserFacadeDelegate
Delega directa o indirectamente
Proxy
UserFacadeEJB
Ejemplo: MiniPortal (y 10)
Proxy del Session Bean
Delega directa o indirectamente en la clase de implementación Utiliza las APIs de transacciones y seguridad, de manera transparente al programador
Por defecto, cada operación se ejecuta en una transacción (y si ésta invoca una operación de otra fachada, ésta se engancha en la misma transacción) Por defecto, cualquier cliente puede invocar cualquier operación
Si el Session Bean es remoto, realiza invocaciones remotas
Invocación de operaciones
Ejemplo
userFacade.registerUser(loginName, clearPassword, userProfileDetailsVO);
Ejemplo: MiniBank (1)
Entidades
Account AccountOperation
Fachada
AccountFacadeDelegate (SLSB)
La interfaz de la fachada del modelo
Ejemplo de EJB-QL
En la implementación de findAccountsByUserIdentifier en la fachada: List accounts = entityManager.createQuery( "SELECT a FROM Account a " + "WHERE a.userIdentifier = :userIdentifier " + "ORDER BY a.accountIdentifier"). setParameter("userIdentifier", userIdentifier). setMaxResults(count+1). setFirstResult(startIndex-1). getResultList();
Ejemplo: MiniBank (y 2)
Ejemplo de EJB-QL (cont)
La sintaxis de EJB-QL es parecida a SQL (para que sea fácil de aprender) No usa nombres de tablas ni columnas
Account es el nombre de la entidad accountIdentifier y userIdentifier son nombres de propiedades de la entidad La implementación del API de Persistencia
Averigua el nombre de la tabla y las columnas correspondientes a las propiedades haciendo uso de las anotaciones insertadas en la clase Account Traduce la consulta EJB-QL a una consulta SQL La ejecuta vía JDBC Recupera las filas y devuelve una lista de objetos Account
Arquitecturas típicas (1)
Aplicación Web: arquitectura en 3 capas Fichero EAR
Navegador
V+C = fichero WAR + M = ficheros JAR con EJBs + entidades
BD
Contenedor J2EE (APIs Web + EJB) E.g. JBoss AS o {Tomcat+ librería “Embeddable JBoss EJB”}
Aplicación Web: arquitectura en 4 capas
En general, peor opción que la arquitectura en 3 capas (las llamadas al modelo son remotas)
Navegador
Fichero WAR
Ficheros JAR
V+C
M = EJBs + entidades
Contenedor Web (APIs Web) E.g. Tomcat
Contenedor EJB E.g. JBoss EJB Server
BD
Arquitecturas típicas (2) Aplicación standalone: arquitectura en 3 capas
Buena opción cuando hay múltiples clientes y una arquitectura Web no es conveniente
Cliente (V+C)
M = ficheros JAR con EJBs + entidades
BD
Contenedor EJB o J2EE E.g. JBoss EJB Server o JBoss AS
Aplicación standalone: arquitectura en 2 capas
Buena opción cuando hay un único cliente y la arquitectura no plantea problemas Cliente (V+C+M)
BD
Arquitecturas típicas (y 3)
Aplicación standalone: arquitectura en 2 capas (cont)
Implementación de la capa modelo
Usando sólo el API de Persistencia
Requiere una implementación del API de Persistencia (e.g. Hibernate, TopLink, etc.) El desarrollador tiene que usar el API de transacciones (y el de seguridad) para implementar los casos de uso, o alternativamente usar un framework que facilite su implementación (e.g. Spring)
Usando el API de Persistencia y EJBs
Requiere una librería (e.g. JBoss Embeddable EJB) que implemente el API de Persistencia y el API propio de EJB (Session Beans) El desarrollador implementa el modelo de la misma manera que si se ejecutase dentro de un contenedor J2EE o de EJBs