Session Beans y Entity Beans Ignacio Ramos Zapata Departamento de Ingeniería Telemática Universidad Carlos III de Madrid [email protected] Contenido Ÿ Caso de estudio Ÿ Gestión de recursos – Pooling de instancias – Activación/pasivación 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 2 1 Caso de estudio: Entity Bean Ÿ Ejemplo entity bean: Cabin – modela un camarote en un barco crucero – Interfaz component: CabinRemote – Interfaz home: CabinHomeRemote – Clase: CabinBean – la palabra Remote se suele añadir a los nombres de los interfaces remotos para distinguirlos de interfaces locales (que se introdujeron en la especificación 2.0 de los EJB) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 3 CMP Entity Bean Ÿ Cabin es un entity bean CMP, la persistencia por tanto está gestionada por el contenedor Ÿ La clase bean ha de proporcionar la implementación de los métodos que gestionan el ciclo de vida del bean – Determinados por la interfaz javax.ejb.EntityBean Ÿ Es necesario especificar en el deployment descriptor los campos cuya persistencia va a gestionar el container Ÿ Dicha persistencia es independiente de la base de datos (los hace muy portables) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 4 2 Home Interface: CabinHomeRemote package com.titan.cabin; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.FinderException; public interface CabinHomeRemote extends javax.ejb.EJBHome { public CabinRemote create(Integer id) throws CreateException, RemoteException; public CabinRemote findByPrimaryKey(Integer pk) throws FinderException, RemoteException; } Ÿ CreateException, FinderException -> excepciones que el Objeto Home lanza 2005 – cuando no puede crear una instancia – cuando dada una clave, no puede encontrar la instancia del EJB Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 5 Primary Key Class Ÿ Identifica de manera a una instancia de un bean Ÿ Tiene que implementar el interfaz java.io.Serializable Ÿ Tiene que ser una clase – Se puede usar el tipo String – No sirven atributos primitivos como int o float, en su lugar hay que usar wrappers Java tales como Double o Integer 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 6 3 Component Interface: CabinRemote package com.titan.cabin; import java.rmi.RemoteException; public interface CabinRemote extends javax.ejb.EJBObject { public public public public public public public public String getName()throws RemoteException; void setName(String str)throws RemoteException; int getDeckLevel()throws RemoteException; void setDeckLevel(int level)throws RemoteException; int getShipId()throws RemoteException; void setShipId(int sp)throws RemoteException; int getBedCount()throws RemoteException; void setBedCount(int bc)throws RemoteException; } Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 2005 7 Clase bean: CabinBean (I) package com.titan.cabin; import javax.ejb.EntityContext; import javax.ejb.CreateException; public abstract class CabinBean implements javax.ejb.EntityBean { public Integer ejbCreate(Integer id) throws CreateException { this.setId(id); return id; } public void ejbPostCreate(Integer id) throws CreateException { } […] El container extiende esta clase (abstracta) y se encarga de proporcionar el código necesario para asegurar la persistencia 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 8 4 Clase bean: CabinBean (II) […] public abstract void setId(Integer id); public abstract Integer getId(); public abstract void setShipId(int ship); public abstract int getShipId( ); public abstract void setName(String name); public abstract String getName( ); public abstract void setBedCount(int count); public abstract int getBedCount( ); public abstract void setDeckLevel(int level); public abstract int getDeckLevel( ); […] El container es responsable de salvar el estado de aquellos campos especificados en el deployment descriptor Hay que proporcionar setters y getters como métodos abstractos (que el container se encarga de implementar) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 9 Clase bean: CabinBean (III) public void setEntityContext(EntityContext ctx) { // Not implemented. } public void unsetEntityContext() { // Not implemented. } qejbActivate/ejbPosivate public void ejbActivate() { asociados al proceso de // Not implemented. } activación/pasivación public void ejbPassivate() { qejbLoad/ejbStore se // Not implemented. invocan cuando el EJB se } carga o se almacena su public void ejbLoad() { estado en la DB // Not implemented. qejbRemove se invoca } antes de destruir el EJB public void ejbStore() { // Not implemented. } public void ejbRemove() { // Not implemented. } } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 10 5 Comentarios sobre el Cabin Bean Ÿ El método ejbCreate debe tener un método create en el Home interface con la misma signatura Ÿ El Home de entity beans siempre debe definir al menos el método findByPrimaryKey Ÿ En entity beans con persistencia manejada por contendor no necesitan implementarlo (lo hace el contenedor) Ÿ Los métodos de acceso a atributos persistentes los implementa directamente el contendor 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 11 Deployment descriptor CabinEJB (I) <!DOCTYPE ejb-jar PUBLIC “...> <ejb-jar><enterprise-beans> <entity> <ejb-name>CabinEJB</ejb-name> <home>com.titan.cabin.CabinHomeRemote</home> <remote>com.titan.cabin.CabinRemote</remote> <ejb-class>com.titan.cabin.CabinBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <abstract-schema-name>Cabin</abstract-schema-name> - 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 12 6 Deployment descriptor CabinEJB (II) <cmp-field><field-name>shipId</field-name></cmp-field> <cmp-field><field-name>name</field-name></cmp-field> <cmp-field><field-name>deckLevel</field-name></cmp-field> <cmp-field><field-name>bedCount</field-name></cmp-field> <cmp-field><field-name>id</field-name></cmp-field> <primkey-field>id</primkey-field> ... </entity> </enterprise-beans> <assembly-descriptor> ... </assembly-descriptor> </ejb-jar> 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 13 Creación de una tabla Cabin en la BD Ÿ Con la herramienta de instalación (deployment) Ÿ create table CABIN ( ID int tprimary key NOT NULL, SHIP_ID int, BED_COUNT int, NAME char(30), DECK_LEVEL INT ) Ÿ Se utiliza para mantener la persistencia. Se suele definir una tabla por cada clase y una columna por cada variable 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 14 7 Mapping entre Objetos y DB Relacionales 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 15 Pool de Conexiones Ÿ Los entity beans requieren frecuentes pero cortas interacciones con la DB – El acceso a los campos cuya persistencia es gestionada por el contenedor – No suele ser gran cantidad de información Ÿ Usar un pool de conexiones puede mejorar el rendimiento – Minimiza el tiempo necesario para abrir y la conexión con la DB – Permite controlar el número de conexiones abiertas 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 16 8 Cliente de CabinEJB (I) package com.titan.clients; import com.titan.cabin.CabinHomeRemote; import com.titan.cabin.CabinRemote; import import import import import import 2005 javax.naming.InitialContext; javax.naming.Context; javax.naming.NamingException; javax.rmi.PortableRemoteObject; java.rmi.RemoteException; java.util.Properties; Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 17 Cliente de CabinEJB (I) // imports public class Client1 { public static void main(String [] args) { try { Context jndiContext = getInitialContext(); Object ref = jndiContext.lookup("CabinHomeRemote"); CabinHomeRemote home = (CabinHomeRemote) PortableRemoteObject. narrow(ref,CabinHomeRemote.class); if ( ref != null ) { System.out.println("Found Cabin Home"); } CabinRemote cabin_1=home.create(new Integer(1)); cabin_1.setName("Master Suite"); cabin_1.setDeckLevel(1); cabin_1.setShipId(1); cabin_1.setBedCount(3); 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 18 9 Cliente de CabinEJB (II) Integer pk = new Integer(1); CabinRemote cabin_2 = home.findByPrimaryKey(pk); System.out.println(cabin_2.getName()); System.out.println(cabin_2.getDeckLevel()); System.out.println(cabin_2.getShipId()); System.out.println(cabin_2.getBedCount()); } catch (java.rmi.RemoteException re) {re.printStackTrace();} catch (javax.naming.NamingException ne) {ne.printStackTrace();} catch (javax.ejb.CreateException ce) {ce.printStackTrace();} catch (javax.ejb.FinderException fe) {fe.printStackTrace();} } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 19 Cliente de CabinEJB (III) public static Context getInitialContext() throws javax.naming.NamingException{ Properties p = new Properties(); //... specify the JNDI Properties specific to the vendor p.put(Context.INITIAL_CONTEXT_FACTORY, “weblogic.jndi.WLInitialcontextFactory”); p.put(Context.PROVIDER_URL, “t3://localhost:7001”); return new javax.naming.InitialContext(p); } } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 20 10 Pasos del cliente 1. Obtención de una conexión de directorio al contenedor (mediante el servicio JNDI) 2. Hacer un lookup en ese directorio (espacio de nombres) del bean buscado 3. Hacer un narrow de la referencia obtenida 4. Hacer un casting del resultado al objeto de tipo HomeRemote 5. Llamar a create sobre el objeto HomeRemote y obtener el objeto EJB 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 21 Obtención de una conexión de directorio al contenedor (mediante el servicio JNDI) Ÿ El objeto InitialContext recibe un objeto Properties que le indica: – dónde está el servidor EJB – Utility class para crear el InitialContext (dependiente del JNDI service provider) Ÿ El contexto inicial es como la raíz del sistema de ficheros Ÿ JNDI permite que el cliente vea los elementos del servidor EJB como directorios en un sistema de ficheros común Ÿ El proceso de obtención es “parecido” a obtener una conexión al driver de JDBC Ÿ Los parámetros concretos del Properties dependen de la implementación Ÿ Lo practicaréis en la práctica (J2EE 1.3 SDK Reference Implementation) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 22 11 Lookup en el espacio de nombres del bean buscado Ÿ Object ref = jndiContext.lookup("CabinHomeRemote"); Ÿ El cliente da el nombre del objeto HomeRemote buscado (en el JNDI Global Environment) Ÿ Veremos que cuando un bean actúa como cliente de otro bean, busca su Home en su JNDI Environment Naming Context (ENC) (un directorio creado al instalar el bean): “java:com/env” (inicial) “java:comp/env/ejb” (para los beans a los que accede) – También se puede acceder mediante el JNDI a propiedades y otros recursos del contenedor, paso de parámetros en inicialización, etc. 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 23 Narrow y casting Ÿ CabinHomeRemote home = (CabinHomeRemote) PortableRemoteObject. narrow(ref,CabinHomeRemote.class); Ÿ El narrow es una “especie” de casting para objetos remotos (RMI sobre IIOP) Ÿ Comprueba si se puede hacer el casting del objeto a la clase indicada y devuelve la referencia al Object – el protocolo se originó en CORBA, como CORBA admite muchos lenguajes, no todos tienen un casting nativo Ÿ No hace falta hacer narrow si la referencia devuelta tiene directamente el tipo adecuado – p.ej. create devuelve un objeto CabinRemote (no necesita narrow) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 24 12 Caso de estudio: Session Bean Ÿ Ejemplo de session bean: TravelAgent 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 25 Component Interface: TravelAgentRemote package com.titan.travelagent; import java.rmi.RemoteException; import javax.ejb.FinderException; public interface TravelAgentRemote extends javax.ejb.EJBObject { // String elements follow the format // "id, name, deck level" public String [] listCabins(int shipID, int bedCount) throws RemoteException; } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 26 13 Home Interface: TravelAgentHomeRemote package com.titan.travelagent; import java.rmi.RemoteException; import javax.ejb.CreateException; public interface TravelAgentHomeRemote extends javax.ejb.EJBHome { public TravelAgentRemote create() throws RemoteException, CreateException; } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 27 Clase bean: TravelAgentBean (I) public class TravelAgentBean implements javax.ejb.SessionBean { public void ejbCreate()throws CreateException { // Do nothing. } public String [] listCabins(int shipID, int bedCount) { try { javax.naming.Context jndiContext = new InitialContext(); Object obj = jndiContext.lookup("java:comp/env/ejb/CabinHomeRemote"); CabinHomeRemote home = (CabinHomeRemote) javax.rmi.PortableRemoteObject. narrow(obj,CabinHomeRemote.class); 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 28 14 Clase bean: TravelAgentBean (II) [...] Vector vect = new Vector(); for (int i = 1; ; i++) { Integer pk = new Integer(i); CabinRemote cabin = null; try { cabin = home.findByPrimaryKey(pk); } catch(javax.ejb.FinderException fe) { break; } // Check to see if the bed count and ship ID match. if (cabin != null && cabin.getShipId() == shipID && cabin.getBedCount() == bedCount) { String details = i+","+cabin.getName()+","+cabin.getDeckLevel(); vect.addElement(details); } } [...] Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 2005 29 Clase bean: TravelAgentBean (III) [...] String [] list = new String[vect.size()]; vect.copyInto(list); return list; } catch(Exception e) {throw new EJBException(e);} } private javax.naming.Context getInitialContext() throws javax.naming.NamingException { Properties p = new Properties(); // ... Specify the JNDI properties specific to the vendor. return new javax.naming.InitialContext(p); } [...] 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 30 15 Clase bean: TravelAgentBean (IV) [...] public public public public void void void void ejbRemove(){} ejbActivate(){} ejbPassivate(){} setSessionContext (javax.ejb.SessionContext cntx){} } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 31 Cliente de TravelAgentEJB (I) public class Client_3 { public static int SHIP_ID = 1; public static int BED_COUNT = 3; public static void main(String [] args) { try { Context jndiContext = getInitialContext(); Object ref = jndiContext.lookup("TravelAgentHome"); TravelAgentHomeRemote home = (TravelAgentHomeRemote) PortableRemoteObject. narrow(ref,TravelAgentHomeRemote.class); TravelAgentRemote travelAgent = home.create(); [...] 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 32 16 Cliente de TravelAgentEJB (II) [...] // Get a list of all cabins on ship 1 with a bed count of 3. String list [] = travelAgent.listCabins(SHIP_ID,BED_COUNT); for(int i = 0; i < list.length; i++){ System.out.println(list[i]); } } catch(java.rmi.RemoteException re){re.printStackTrace();} catch(Throwable t){t.printStackTrace();} System.exit(0); } static public Context getInitialContext() throws Exception { Properties p = new Properties(); //specify the JNDI properties specific to thevendor return new InitialContext(p); } } 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 33 Patrón FAÇADE Ÿ Esconde al cliente la complejidad del modelo de EJBs 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 34 17 Excepciones Ÿ RemoteException: (RMI) problemas de comunicación remota Ÿ NamingException: (JNDI) problemas en el servicio de nombres (p.ej. no se encuentra el nombre buscado) Ÿ Y otras Ÿ Además, la aplicación debería definir sus propias excepciones, que se lanzan cuando hay problemas en el ejecución en la lógica de negocio 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 35 Contenido Ÿ Caso de estudio Ÿ Gestión de recursos – Pooling de instancias – Activación/pasivación 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 36 18 Pooling de instancias Ÿ Los clientes no acceden a las instancias directamente, sino a través de objetos EJB (implementación del component interface) Ÿ El servidor mantiene un pool de instancias, que se asocian a los objetos EJB cuando se requiere Ÿ Manejo de recursos más eficiente Ÿ Se aplica a entity beans y a stateless session beans 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 37 Ciclo de vida de la instancia 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 38 19 Asignación de una instancia del pool 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 39 Swapping de instancias Ÿ Los stateless session beans no mantienen ningún estado – cada cliente puede usar para cada invocación a un método del objeto EJB una instancia distinta – Los stateless session beans se declaran como tales en el deployment descriptor (pero se codifican de la misma forma que los stateful) 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 40 20 Ejemplo swapping 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 41 Activación/pasivación Ÿ Los stateful session beans no participan en pooling de instancias – el estado de la conversación con el cliente debe mantenerse durante toda la vida del servicio al cliente Ÿ El servidor usa activación/pasivación para optimizar la gestión de recursos: – Pasivación: disociación del objeto EJB y la instancia del bean, y serialización del estado de la instancia a almacenamiento secundario – Activación: restauración del estado de la instancia relativa al objeto EJB Ÿ Mecanismo transparente al usuario 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 42 21 Proceso activación/pasivación 2005 Software de Comunicaciones (c) UC3M Natividad Martínez, Ignacio Ramos Zapata 43 22