Title: Tema 6 - Enterprise JavaBeans
1Tema 6 - Enterprise JavaBeans
- Dr. Diego Lz. de Ipiña Gz. de Artaza
- http//paginaspersonales.deusto.es/dipina
- http//paginaspersonales.deusto.es/dipina/cursos/J
2EECesine.zip - dipina_at_eside.deusto.es
2Enterprise JavaBeans
- Tecnología por excelencia para el desarrollo de
componentes en la parte servidora con la
plataforma J2EE - Deben de conformar a la especificación de J2EE y
sólo se pueden ejecutar en un contenedor de EJBs - Última especificación EJB 2.1 disponible en
http//java.sun.com/products/ejb/docs.html - Los contenedores de EJBs son lo que hacen a esta
tecnología tan atractiva, ya que ofrecen soporte
para - Transacciones
- Seguridad
- Persistencia
- tanto de manera programática como declarativa
3Beneficios de EJBs
- Aplicaciones basadas en EJBs son difíciles de
desarrollar (tecnología difícil de asimilar), sin
embargo - Aplicaciones basadas en EJBs nos permiten
concentrarnos en la lógica de negocio, sin
preocuparnos de transacciones y connection
pooling provista por contenedor - Los EJBs son componentes ? REUTILIZACIÓN
- Clara separación entre desarrollo, explotación y
administración de una aplicación EJB - El contenedor de EJBs gestiona transacciones,
detalles de manejo de estado, multi-threading,
connection pooling, seguridad y otros detalles de
bajo nivel que el desarrollador no necesita
conocer.
4Puesto de EJB container en una aplicación de
empresa
5Cuando usar EJBs?
- No siempre, para simples aplicaciones web con
servlets y JSPs sobra - Si necesitas alta disponibilidad y escalabilidad
entonces usa EJBs - JDO y Hibernate
6Tecnologías usadas por EJBs
- EJBs hacen uso
- RMI
- RMI-IIOP
- JNDI (Java Naming and Directory Interface)
- JMS (Java Messaging Service)
7Categorías de EJBs
- 3 tipos de Enterprise JavaBeans
- Entity Beans representan datos de negocio y
proveen acceso a datos a través de métodos - Session Beans modelan procesos de negocio que
son accedidos de manera síncrona - Message-driven Beans modelan procesos de negocio
que son accedidos de manera asíncrona, permiten
el uso de JMS desde EJBs
8Contenedores de EJBs
- JBoss http//www.jboss.org
- Contenedor más popular en el mundo y open source
- Download http//prdownloads.sourceforge.net/jboss
/jboss-3.2.3.zip?download - Documentación http//www.jboss.org/modules/html/d
ocs/jbossj2ee.pdf - Otros muy conocidos y muy usados comercialmente
BEA WebLogic, IBM Websphere o Oracle10g
9Escribiendo tu primer EJB
- Seleccionar un contenedor de EJBs vamos a usar
jboss-4.0.1sp1 disponible en http//www.jboss.org - Pasos a seguir para desarrollar un EJB
- Escribir la clase del bean
- Escribir el descriptor de explotación (deployment
descriptor) - Crear un fichero de explotación
- Desarrollar el bean
- Escribir la aplicación cliente para probar el
bean - Ejemplo ? EJB que suma dos números
10Escribiendo el bean Adder I
- Crea un directorio con el nombre de la aplicación
(adder) y crea un subdirectorio en él llamado
es/deusto/ejb donde guardarás los ficheros
AdderHome.java, Adder.java y AdderBean.java y
otro llamado META-INF donde guardaras un fichero
de configuración XML. - package es.deusto.ejb
- import java.rmi.RemoteException
- import javax.ejb.CreateException
- import javax.ejb.EJBHome
- public interface AdderHomeRemote extends EJBHome
- AdderRemote create() throws RemoteException,
CreateException -
11Escribiendo el bean Adder II
- package es.deusto.ejb
- import javax.ejb.EJBObject
- import java.rmi.RemoteException
- public interface AdderRemote extends EJBObject
- public int add(int a, int b) throws
RemoteException -
12Escribiendo el bean Adder III
- package es.deusto.ejb
- import java.rmi.RemoteException
- import javax.ejb.SessionBean
- import javax.ejb.SessionContext
- public class AdderBean implements SessionBean
- public int add(int a, int b)
- System.out.println("from AdderBean")
- return (a b)
-
- public void ejbCreate()
- public void ejbRemove()
- public void ejbActivate()
- public void ejbPassivate()
- public void setSessionContext(SessionContext
sc)
13Escribiendo el deployment descriptor
META-INF/ejb-jar.xml
- lt?xml version"1.0" encoding"UTF-8"?gt
- lt!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems,
Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http//java.sun.com/dtd/ejb-jar_2_0.dtd"gt - ltejb-jargt
- ltdescriptiongtYour first EJB application
lt/descriptiongt - ltdisplay-namegtAdder Applicationlt/display-namegt
- ltenterprise-beansgt
- ltsessiongt
- ltejb-namegtAdderEJBlt/ejb-namegt
- lthomegtes.deusto.ejb.AdderHomeRemotelt/homegt
- ltremotegtes.deusto.ejb.AdderRemotelt/remotegt
- ltejb-classgtes.deusto.ejb.AdderBeanlt/ejb-clas
sgt - ltsession-typegtStatelesslt/session-typegt
- lttransaction-typegtBeanlt/transaction-typegt
- lt/sessiongt
- lt/enterprise-beansgt
- lt/ejb-jargt
14Creando un archivo (.jar) de explotación
- cd ltadder-dirgt
- adder-dirgtset CLASSPATHltjboss-dirgt\server\default
\lib\jboss-j2ee.jar. - adder-dirgtjavac es\deusto\ejb\.java
- adder-dirgtjar cvf adder.jar es/deusto/ejb/
META-INF/ejb-jar.xml - adder-dirgtcopy adder.jar ltjboss-dirgt\server\defaul
t\deploy
15Explotación del EJB adder
- Al copiar el fichero .jar a ltjboss-dirgt\server\de
fault\deploy, la siguiente información será
visualizada si JBoss es arrancado - 180857,970 INFO MainDeployer Starting
deployment of package fileJBOSS_HOME/server/de
fault/deploy/adder.jar - 180858,140 INFO EjbModule Creating
- 180858,160 INFO EjbModule Deploying AdderEJB
- 180858,280 INFO EjbModule Created
- 180858,280 INFO EjbModule Starting
- 180858,341 INFO EjbModule Started
- 180858,341 INFO MainDeployer Deployed
package file/F/DocMan/tools/jboss-3.0.6_tomcat-
4.1.18/server/default/deploy/adder.jar - 180858,341 INFO MainDeployer Starting
deployment of package file/F/DocMan/tools/jboss
-3.0.6_tomcat-4.1.18/server/default/deploy/ejb-man
agement.jar - 180858,451 INFO EjbModule Creating
- 180858,491 INFO EjbModule Deploying MEJB
- 180858,511 INFO EjbModule Created
- 180858,511 INFO EjbModule Starting
- 180858,531 INFO EjbModule Started
16EJBs en detalle
- Un Enterprise Java Bean no consta de una sola
clase sino que también tiene dos (realmente
cuatro, si contamos que pueden ser locales y
remotos) interfaces - HomeRemote/HomeLocal interfaces
- Remote/Local interfaces
- Se puede implementar o bien una tupla
HomeRemote/Remote, o HomeLocal/Local o las 4 a la
vez - Los interfaces locales fueron añadidos en EJB 2.0
- La clase bean contiene la implementación de las
reglas de negocio - Las clases home y remote sirven como entrada a un
bean de empresa desde un cliente - Todo EJB se construye implementando o extendiendo
clases del paquete javax.ejb.
17El interfaz Home
- Lleva a cabo operaciones de ciclo de vida crear,
buscar y eliminar un EJB - Debe extender la interfaz javax.ejb.EJBHome o
javax.ejb.EJBLocalHome - EJBHome deriva de java.rmi.Remote, es usado para
identificar interfaces cuyos métodos pueden ser
invocados desde una virtual machine no local
18El interfaz Remote
- Ofrece los métodos de negocio disponibles a
clientes remotos - Un interfaz remoto debe extender el interfaz
javax.ejb.EJBObject, el cual a su vez también
deriva de java.rmi.Remote - La versión local de Remote deriva de
javax.ejb.EJBLocalObject
19La clase del bean de empresa
- Provee la implementación de los métodos de ciclo
de vida en la interfaz home así como los métodos
de negocio en la interfaz remota - Un EJB puede ser
- Session bean que implementa javax.ejb.SessionBean
- Entity bean que implementa javax.ejb.EntityBean
- Message-driven bean implementa javax.ejb.MessageDr
ivenBean - Un EJB debe ofrecer la implementación de los
métodos callback invocados por el contenedor y
definidos en javax.ejb.SessionBean o
javax.ejb.EntityBean (ejbCreate, ejbPostCreate,
ejbFind, etc.)
20Descriptor de explotación
- Especifica meta-información para el contenedor de
EJB - Contiene la siguiente información
- El nombre del EJB
- El tipo
- El nombre completo del home interface
- El nombre completo del remote interface
- El nombre completo de la clase que implementa el
bean
21Escribiendo aplicaciones cliente
- Un cliente de un EJB no invoca métodos
directamente en el bean - Solamente puede ver los interfaces home y remote
- Las aplicaciones cliente acceden al bean de
empresa a través de JNDI - Vamos a ver dos ejemplos de aplicación cliente
- Clase simple llamada BeanClient
- JSP que demuestra como usar un bean de empresa
desde un servlet o JSP
22Java Naming and Directory Interface (JNDI) I
- Un servicio de nombre permite encontrar un objeto
dado su nombre - DNS nombres dominio ? direcciones IP
- EJB nombre EJB ? referencia a EJB
- Para comunicarse con un EJB una aplicación
cliente sólo necesita saber el nombre - Un servicio de directorio extiende un servicio de
nombres puesto que asocia atributos que describen
el objeto - El paquete javax.naming ofrece la funcionalidad
de JNDI
23Java Naming and Directory Interface (JNDI) II
- javax.naming.Context
- Ofrece el método
- public Object lookup (String name) throws
javax.naming.NamingException - javax.naming.InitialContext
- Implementa la interfaz Context, nos permite desde
un programa buscar un EJB
24Obteniendo una referencia a un EJB I
- Crear un objeto java.util.Properties
- Añadir las propiedades (la clase que implementa
la factoría del naming service y su localización)
a java.util.Properties - Construcción de un objeto javax.naming.InitialCont
ext - Uso del método lookup de javax.naming.Context
para obtener una referencia al home del bean,
pasándole el nombre del bean
25Obteniendo una referencia a un EJB II
- Properties properties new Properties()
- properties.put(Context.INITIAL_CONTEXT_FACTORY,
- "org.jnp.interfaces.NamingContextFactory")
- properties.put(Context.PROVIDER_URL,
- "localhost1099")
- try
- // Get an initial context
- InitialContext jndiContext new
InitialContext(properties) - // Get a reference to the Bean
- Object ref jndiContext.lookup("AdderEJB")
- catch (NamingException e)
26Creando una instancia de un bean
- Usando JNDI hemos obtenido una referencia al home
interface del bean - Para llamar al método create del home interface
de Adder tenemos que hacer un downcast - Para conformar con RMI-IIOP en vez de
(AdderHomeRemote) se utiliza el método narrow de
la clase javax.rmi.PortableRemoteObject - AdderHomeRemote home (AdderHomeRemote)PortableRe
moteObject.narrow(ref, AdderHomeRemote.class) - Una vez obtenido el objeto home podemos crearlo
usando el método create - AdderRemote adder home.create()
- Finalmente podemos usar ese bean
- int i adder.add(2, 5)
27Una clase cliente para Adder I
- package es.deusto.client
- import javax.naming.
- import javax.rmi.PortableRemoteObject
- import java.util.Properties
- import es.deusto.ejb.AdderRemote
- import es.deusto.ejb.AdderHomeRemote
- public class BeanClient
- public static void main(String args)
- // preparing properties for constructing an
InitialContext object - Properties properties new Properties()
- properties.put(Context.INITIAL_CONTEXT_FACTORY
, "org.jnp.interfaces.NamingContextFactory") - properties.put(Context.PROVIDER_URL,
"localhost1099") - try
- // Get an initial context
- InitialContext jndiContext new
InitialContext(properties)
28Una clase cliente para Adder II
- // Get a reference to the Bean
- Object ref jndiContext.lookup("AdderEJB")
- System.out.println("Got reference")
- // Get a reference from this to the Bean's
Home interface - AdderHomeRemote home (AdderHomeRemote)
- PortableRemoteObject.narrow (ref,
AdderHomeRemote.class) - // Create an Adder object from the Home
interface - AdderRemote adder home.create()
- System.out.println ("2 5 "
adder.add(2, 5)) -
- catch(Exception e)
- System.out.println(e.toString())
-
-
29Compilando y ejecutando BeanClient
- adder-dirgtset CLASSPATHltjboss-dirgt\client\jbossal
l-client.jarltjboss-dirgt\client\log4j.jar. - adder-dirgtjavac es\deusto\client\BeanClient.java
- adder-dirgtjava es.deusto.client.BeanClient
- Respuesta
- Got context
- Got reference
- 2 5 7
30Llamando a adder desde un JSP I
- lt_at_ page import"javax.naming."gt
- lt_at_ page import"javax.rmi.PortableRemoteObject"gt
- lt_at_ page import"java.util.Properties"gt
- lt_at_ page import"es.deusto.ejb.Adder"gt
- lt_at_ page import"es.deusto.ejb.AdderHome"gt
- lt
- // preparing a Properties object for
constructing - // an initial context
- Properties properties new Properties()
- properties.put(Context.INITIAL_CONTEXT_FACTORY,
- "org.jnp.interfaces.NamingContextFactory")
- properties.put(Context.PROVIDER_URL,
"localhost1099") - try
- // Get an initial context
- InitialContext jndiContext new
InitialContext(properties) - System.out.println("Got context")
31Llamando a adder desde un JSP II
- // Get a reference to the Bean
- Object ref jndiContext.lookup("Adder")
- System.out.println("Got reference")
- // Get a reference from this to the Bean's
Home interface - AdderHome home (AdderHome)
- PortableRemoteObject.narrow (ref,
AdderHome.class) - // Create an Adder object from the Home
interface - Adder adder home.create()
- out.println ("2 5 " adder.add(2, 5))
-
- catch(Exception e)
- System.out.println(e.toString())
-
- gt
32Instalando adder.ear en Jboss I
- Necesario crear un enterprise archive .ear que
contiene - Adder.war ? parte web de nuestra aplicación
(servlets/jsps) - Adder-ejb.jar ? parte de los EJBs
- Application.xml ? deployment descriptor que
documenta la relación entre el .war y el .jar de
esta aplicación
33Instalando adder.ear en Jboss II
- lt?xml version"1.0" encoding"UTF-8"?gt
- lt!DOCTYPE application PUBLIC '-//Sun
Microsystems, Inc.//DTD J2EE Application 1.2//EN'
'http//java.sun.com/j2ee/dtds/application_1_2.dtd
'gt - ltapplicationgt
- ltdisplay-namegtAdderlt/display-namegt
- ltdescriptiongtThis is the implementaion of the
Adder applicationlt/descriptiongt - ltmodulegt
- ltejbgtadder-ejb.jarlt/ejbgt
- lt/modulegt
- ltmodulegt
- ltwebgt
- ltweb-urigtadder.warlt/web-urigt
- ltcontext-rootgt/lt/context-rootgt
- lt/webgt
- lt/modulegt
- lt/applicationgt
34Instalando adder.ear en Jboss III
- adder-ejb.jar ? contiene todas las clases
correspondientes a los EJBs ejb-jar.xml
(deployment descriptor de EJBs) - adder.war ? contiene todos los JSPs y servlets
web.xml clases clientes para comunicarse con
EJBs
35Instalando adder.ear en Jboss IV
- Usamos magia de Ant para generar el fichero .ear
36Session Beans
- Es un bean de empresa que implementa lógica de
negocio para sus clientes - Puede realizar operaciones
- Procesar ordenes
- Encriptar y desencriptar datos,
- Buscar datos en una base de datos, etc.
- Siguiendo patrón de diseño Fachada, los sesión
beans son los componentes con los que se
comunican servlets y JSPs - Los beans de sesión viven tanto tiempo como el
cliente que los usa - Incluso a veces más tiempo dado que el contenedor
los coloca en un pool de beans
37Stateful y Stateless Session Beans
- Un stateful session bean está asociado con un
cliente único - Retiene información específica a un cliente
- Mantiene estado conversacional
- Análogo a javax.servlet.http.HttpSession
- Passivation es el proceso a través del cual el
estado conversacional de un stateful session bean
es transferido a almacenamiento secundario - Activation es el proceso opuesto
- Un stateless session bean NO es específico a un
cliente - Son muy buenos para conseguir aplicaciones
escalables, se guardan en un pool y son
reutilizables por cualquier cliente
38Escribiendo un Session Bean
- Necesitamos las siguientes clases
- El home interface
- El remote interface
- La clase sesión bean
- La razón de existencia de los interfaces home y
remote es que el cliente no crea el bean
directamente, y tampoco invoca el método de un
sesión bean directamente.
39Interfaz javax.ejb.SessionBean
- Los cuatro métodos que provee son
- public void ejbActivate throws javax.ejb.EJBExcept
ion, java.rmi.RemoteException - El contenedor invoca este método cuando activa un
sessión bean que había sido pasivado - public void ejbPassivate() throws
javax.ejb.EJBException, java.rmi.RemoteException - El contenedor lo invoca cuando el bean se pasiva
- public void ejbRemove() throws javax.ejb.EJBExcept
ion, java.rmi.RemoteException - El contenedor invoca este método cuando el
cliente invoca en Remote remove() o un time-out
en el session object es alcanzado - public void setSessionContext(SessionContext
context) throws javax.ejb.EJBException,
java.rmi.RemoteException - El contenedor invoca este método después de que
una instancia del bean se crea. Suele ser
conveniente cachear este objeto en una variable
del bean
40El interfaz javax.ejb.SessionContext
- Provee algunos métodos útiles para obtener
información acerca de el cliente realizando una
invocación, el objeto home asociado, el entorno,
etc - getEJBHome(), getEJBLocalHome(), getPrimaryKey(),
isIdentical(), getEJBLocalObject(),
getEJBObject(), getMessageContext()
41Como guardar referencias a un stateful session
bean desde un JSP
- Usar objeto HttpSession
- HttpSession session request.getSession(true),
- Session.setAttribute(cart, cartBean)
-
- Cart cartBean (Cart)session.getAttribute(cart)
42El deployment descriptor de un session bean
- Toda aplicación EJB debe tener un deployment
descriptor, cuyo elemento raiz es ltejb-jargt y
contiene un nodo llamado ltenterprise-beansgt del
que cuelgan todos los beans declarados en un
aplicación - Cada session bean se registra debajo del elemento
ltsessiongt, pudiendo contener los siguientes
subelementos - description, display-name, small-icon, large-icon
- ejb-name ? nombre dado al EJB
- home/local-home ? el nombre completo del
home/local interfaz del bean - remote/local ? el nombre completo del home/local
interfaz del bean - ejb-class ? el nombre completo de la clase
implementando el bean - transaction-type, env-entry, etc.
43Deployment descriptor de la aplicación I
- lt?xml version"1.0" encoding"UTF-8"?gt
- lt!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems,
Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http//java.sun.com/dtd/ejb-jar_2_0.dtd"gt - ltejb-jargt
- ltdescriptiongtThe Search Bean for Tassie Online
Bookstorelt/descriptiongt - ltdisplay-namegtSearch Beanlt/display-namegt
- ltenterprise-beansgt
- ltsessiongt
- ltejb-namegtSearchlt/ejb-namegt
- lthomegtes.deusto.bookstore.ejb.SearchHomeRemo
telt/homegt - ltremotegtes.deusto.bookstore.ejb.SearchRemote
lt/remotegt - ltejb-classgtes.deusto.bookstore.ejb.SearchBea
nlt/ejb-classgt - ltsession-typegtStatelesslt/session-typegt
- lttransaction-typegtBeanlt/transaction-typegt
- lt/sessiongt
-
44Deployment descriptor de la aplicación II
- ltsessiongt
- ltejb-namegtBookDetailslt/ejb-namegt
- lthomegtes.deusto.bookstore.ejb.BookDetailsHom
eRemotelt/homegt - ltremotegtes.deusto.bookstore.ejb.BookDetailsR
emotelt/remotegt - ltejb-classgtes.deusto.bookstore.ejb.BookDetai
lsBeanlt/ejb-classgt - ltsession-typegtStatelesslt/session-typegt
- lttransaction-typegtBeanlt/transaction-typegt
- lt/sessiongt
- ltsessiongt
- ltejb-namegtCartlt/ejb-namegt
- lthomegtes.deusto.bookstore.ejb.CartHomeRemote
lt/homegt - ltremotegtes.deusto.bookstore.ejb.CartRemotelt/
remotegt - ltejb-classgtes.deusto.bookstore.ejb.CartBeanlt
/ejb-classgt - ltsession-typegtStatefullt/session-typegt
- lttransaction-typegtBeanlt/transaction-typegt
- lt/sessiongt
- lt/enterprise-beansgt
45Entity Beans I
- Es un componente de datos que persiste datos
permanentemente a almacenamiento secundario, e.j.
BD - Contiene campos y métodos
- Guarda datos en los campos
- Realiza operaciones sobre los campos con los
métodos - Vista de un registro en una tabla de una base de
datos - Aísla el desarrollo de aplicaciones del acceso a
BD
46Entity Beans II
- El contenedor de EJBs lleva a cabo la
sincronización y otras tareas para mantener los
datos - Provee servicios que hacen mucho más sencillo
manejar datos representados por entity beans - Mientras que un session mean modela un proceso de
negocio, un entity bean modela datos de negocio - Además un entity bean sobrevive una caída del
servidor - Dos tipos
- Bean-managed persistence (BMP)
- Container-managed persistence (CMP)
- Los ficheros necesarios para construir un entity
bean son - Interfaz Remote/Local
- Interfaz HomeRemote/HomeLocal
- La clase primaria
- La clase que implementa el entity bean
- El deployment descriptor
47La interfaz remota/local
- Esta interfaz permite a un cliente acceder a la
instancia de un bean de entidad - Debe extender
- javax.ejb.EJBObject para interfaces remotos
- javax.ejb.EJBLocalObject para interfaces locales
- El cliente puede usar esta interfaz para hacer
- Obtener la interfaz home para el bean de entidad
- Eliminar el bean de entidad
- Obtener su clave primaria
- Ejemplo
- public interface ProductRemote extends
javax.ejb.EJBObject - double getPrice(int productId)
- throws java.rmi.RemoteException
- int getCategory(int productId)
- throws java.rmi.RemoteException
-
48La interfaz home I
- Un cliente puede utilizar esta interfaz para
- Crear un bean de entidad
- Eliminarlo
- Buscar un bean de entidad
- Esta interfaz provee métodos de creación,
eliminación y búsqueda - Una interfaz home (javax.ejb.EJBHome o
javax.ejb.EJBHomeLocal) puede definir varios
métodos create - public interface ProductHomeRemote extends
javax.ejb.EJBHome - public ProductRemote create(int productId,
-
String productName, -
String description, -
double price) - throws java.rmi.RemoteException,
javax.ejb.CreateException -
49La interfaz home II
- Como un bean de entidad representa una pieza de
datos, una de las operaciones más frecuentes es
encontrar un bean de datos - Para eso se usan los métodos finder
- Al menos el método findByPrimaryKey debe
definirse - Otros métodos también pueden definirse
- El método findAll
- Si un método finder devuelve varios resultados el
tipo de datos devuelto deberá ser
java.util.Collection - public interface ProductHomeLocal extends
javax.ejb.EJBLocalHome - public ProductLocal findByPrimaryKey(Integer
productId) - throws javax.ejb.EJBException,
javax.ejb.FinderException - public Collection findByProductName(String
productName) - throws javax.ejb.EJBException,
javax.ejb.FinderException - public Collection findAll() throws
FinderException, EJBException -
- El método remove permite borrar una bean de
entidad - void remove(Object primaryKey) throws
jajvax.ejb.EJBException, javax.ejb.RemoveException
50El bean de entidad
- Debe implementar el interfaz javax.ejb.EntityBean
- Implementa los métodos de ciclo de vida definidos
en la interfaz home - Y métodos callback llamados por el contenedor
51La interfaz javax.ejb.EntityBean
- Los métodos a definir son
- public void ejbActivate() ? invocado por el
contenedor cuando la entidad es recuperada del
pool pasa a asociarse con un objeto entidad
específico - public void ejbPassivate() ? invocado por el
contenedor cuando la asociación entre una
instancia de un bean con su objeto entidad está a
punto de romperse - public void ejbLoad() ? invocado por el
contenedor para sincronizar el estado del bean de
los datos subyacentes - public void ejbStore() ? opuesto a ejbLoad
- public void ejbRemove() ? invocado por el
contenedor cuando una instancia de un bean está a
punto de borrarse - public void setEntityContext(EntityContext
context) ? invocado después de que la instancia
del bean haya sido creada - public void unsetEntityContext() ? opuesto a
setEntityContext - Los métodos ejbStore y ejbLoad permiten la
pasivación y activación del estado de un bean de
entidad a y desde una BD
52Métodos Create/Find/remove en un bean de entidad I
- Todo método create/find/remove en una interfaz
home es transformado en un método
ejbCreate/ejbFind/ejbRemove en la clase que
implementa el bean - Los métodos ejbCreate/ejbFind devuelven un valor
correspondiente a la clave primaria de un bean (o
colección con claves primarias en métodos find)
en vez de una referencia a la interfaz
remota/local del bean como en la interfaz home - Todos los métodos definidos en el interfaz remote
o local tienen los mismos tipos de datos de
retorno y listas de argumentos en la
implementación del bean
53Métodos Create/Find/remove en un bean de entidad
II
- public class ProductBean implements
javax.ejb.EntityBean - public ProductPK ejbCreate(int productId, String
productName, - String description,
double price) - throws javax.ejb.EJBException,
javax.ejb.CreateException - this.productId new Integer(productId)
- this.productName productName
- this.description description
- this.price price
- return this.productId
-
- public ProductPK ejbFindByPrimaryKey(ProductPK
primaryKey) - throws EJBException, FinderException
- ...
-
- public void ejbRemove()
- throws EJBException, RemoveExcepton
- ...
54La interfaz javax.ejb.EntityContext
- Define dos métodos
- javax.ejb.EJBObject getEJBObject() throws
IllegalStateException - Devuelve una refencia al objecto de empresa
asociado con una instancia del bean de entidad - Object getPrimaryKey() throws IllegalStateExceptio
n - Devuelve la clave primaria de un bean
55Dos tipos de bean de entidad
- Dependiendo del modo en que los datos son hechos
persistentes encontramos - Bean de entidad con bean-managed persistence
(BMP) - El programador tiene que escribir el código SQL
necesario para guardar/recuperar estado bean - Bean de entidad con container-managed persistence
(CMP) - La tarea de guardar/recuperar datos es llevada a
cabo por el contenedor de EJBs - Instrucciones sobre cómo llevar a cabo esa tarea
son dados al contenedor en el deployment
descriptor
56Escribiendo un bean de entidad BMP
- Crear un BMP que representa a un producto
- Pasos a seguir
- Crear una tabla de una base de datos, con los
campos ProductId (int), ProductName (string),
Description (string) y Price (string) ?
ProductsBD - Obtener un driver JDBC para tu base de datos.
- En nuestro caso usaremos el ODBC-JDBC bridge para
acceder a Access - Configurar JBoss para usar tu base de datos
preferida (lo haremos con el ejemplo en CMP) - Dado que usamos un driver que viene con la
distribución estándar de J2SE, no es necesario
ninguna configuración adicional - Preparar la estructura de directorio adecuada
para tu proyecto. - es.deusto.ejb en nuestro caso
57La interfaz remota ProductRemote
- package es.deusto.ejb
- import javax.ejb.EJBObject
- import java.rmi.RemoteException
- / this is the remote interface for Product /
- public interface ProductRemote
- extends EJBObject
- public Integer getProductId() throws
RemoteException - public void setProductId(Integer productId)
throws RemoteException - public double getPrice() throws
RemoteException - public void setPrice(double price) throws
RemoteException - public String getProductName() throws
RemoteException - public void setProductName(String
productName) throws RemoteException - public String getDescription() throws
RemoteException - public void setDescription(String desc)
throws RemoteException
58La interfaz home ProductHomeRemote
- package es.deusto.ejb
- import java.rmi.RemoteException
- import javax.ejb.FinderException
- import javax.ejb.CreateException
- import javax.ejb.EJBHome
- import java.util.Collection
- public interface ProductHomeRemote extends
EJBHome - public ProductRemote create(int productId,
String productName, - String
description, double price) - throws RemoteException, CreateException
- public ProductRemote findByPrimaryKey(Integer
key) - throws RemoteException, FinderException
- public Collection findByName(String name)
- throws RemoteException, FinderException
- public Collection findAll()
- throws RemoteException, FinderException
59El bean de entidad ProductBean I
- package es.deusto.ejb
- import java.sql.
- import java.util.Properties
- import java.util.Collection
- import java.util.Vector
- import java.rmi.RemoteException
- import javax.ejb.EntityBean
- import javax.ejb.EntityContext
- import javax.ejb.CreateException
- import javax.ejb.FinderException
- import javax.ejb.ObjectNotFoundException
- import javax.naming.InitialContext
- import javax.naming.Context
- import javax.naming.NamingException
- public class ProductBean implements EntityBean
- EntityContext context
- Integer productId
- String productName
60El bean de entidad ProductBean II
- public String getProductName()
- System.out.println("getProductName "
this.productName) - return this.productName
-
- public void setProductName(String
productName) - this.productName productName
-
- public String getDescription()
- System.out.println("getDescription "
this.description) - return this.description
-
- public void setDescription(String
description) - this.description description
-
- public double getPrice()
61El bean de entidad ProductBean III
- public Integer ejbCreate(int productId, String
productName, String description, double price) - throws RemoteException, CreateException
- System.out.println("ejbCreate")
- this.setProductId(new Integer(productId))
- this.setProductName(productName)
- this.setDescription(description)
- this.setPrice(price)
- Connection con null
- PreparedStatement ps null
- try
- String sql "INSERT INTO Products"
" (ProductId, ProductName, Description, Price)" - " VALUES" " (?, ?, ?, ?)"
- con getConnection()
- ps con.prepareStatement(sql)
- ps.setInt(1, this.getProductId().intVa
lue()) - ps.setString(2, this.getProductName())
- ps.setString(3, this.getDescription())
- ps.setDouble(4, this.getPrice())
- ps.executeUpdate()
62El bean de entidad ProductBean IV
- public void ejbPostCreate(int productId, String
productName, String description, double price)
throws RemoteException, CreateException
System.out.println("ejbPostCreate") - public Integer ejbFindByPrimaryKey(Integer
primaryKey) - throws RemoteException, FinderException
- System.out.println("ejbFindByPrimaryKey")
- Connection con null
- PreparedStatement ps null
- ResultSet rs null
- try
- String sql "SELECT ProductName" "
FROM Products" " WHERE ProductId?" - con getConnection() ps
con.prepareStatement(sql) - ps.setInt(1, primaryKey.intValue())
rs ps.executeQuery() - if (rs.next())
- rs.close() ps.close()
con.close() - return primaryKey
-
- catch (SQLException e)
e.printStackTrace() finally - try
- if (rs ! null) rs.close()
63El bean de entidad ProductBean V
- public Collection ejbFindByName(String name)
- throws RemoteException, FinderException
- System.out.println("ejbFindByName")
- Vector products new Vector()
- Connection con null
- PreparedStatement ps null
- ResultSet rs null
- try
- String sql "SELECT ProductId " "
FROM Products" " WHERE ProductName?" - con getConnection()
- ps con.prepareStatement(sql)
- ps.setString(1, name)
- rs ps.executeQuery()
- while (rs.next())
- int productId rs.getInt(1)
- System.out.println("Añadiendo
producto " productId) - products.addElement(new
Integer(productId))
64El bean de entidad ProductBean VI
- public Collection ejbFindAll()
- throws RemoteException, FinderException
- System.out.println("ejbFindAll")
- Vector products new Vector()
- Connection con null
- PreparedStatement ps null
- ResultSet rs null
- try
- String sql "SELECT " " FROM
Products" - con getConnection()
- ps con.prepareStatement(sql)
- rs ps.executeQuery()
- while (rs.next())
- int productId rs.getInt(1)
- System.out.println("Product
id retrieved " productId) - products.addElement(new
Integer(productId)) -
- catch (SQLException e)
65El bean de entidad ProductBean VII
- public void ejbRemove() throws
RemoteException - System.out.println("ejbRemove")
- Connection con null
- PreparedStatement ps null
- try
- String sql "DELETE FROM Products"
- " WHERE ProductId?"
- Integer key (Integer)
context.getPrimaryKey() - con getConnection()
- ps con.prepareStatement(sql)
- ps.setInt(1, key.intValue())
- ps.executeUpdate()
- catch (SQLException e)
- e.printStackTrace()
- finally
- try
- if (ps ! null)
- ps.close()
- if (con ! null)
66El bean de entidad ProductBean VIII
- public void ejbLoad()
- System.out.println("ejbLoad")
- Connection con null
- PreparedStatement ps null
- ResultSet rs null
- try
- String sql "SELECT ProductName,
Description, Price" " FROM Products" " WHERE
ProductId?" - con getConnection()
- ps con.prepareStatement(sql)
- Integer primaryKey
(Integer)context.getPrimaryKey () - ps.setInt(1, primaryKey.intValue())
- rs ps.executeQuery()
- if (rs.next())
- this.productName
rs.getString(1) - System.out.println("Product name
" this.productName) - this.description
rs.getString(2) - System.out.println("Description
" this.description) - this.price rs.getDouble(3)
- System.out.println("Price "
this.price)
67El bean de entidad ProductBean IX
- public void ejbStore()
- System.out.println("ejbStore")
- Connection con null
- PreparedStatement ps null
- try
- String sql "UPDATE Products" "
SET ProductName?, Description?, Price?" "
WHERE ProductId?" - Integer key (Integer)
context.getPrimaryKey() - con getConnection()
- ps con.prepareStatement(sql)
- ps.setString(1, this.productName)
- ps.setString(2, this.description)
- ps.setDouble(3, this.price)
- ps.setInt(4, key.intValue())
- ps.executeUpdate()
- catch (SQLException e)
e.printStackTrace() finally - try
- if (ps ! null) ps.close()
- if (con ! null) con.close()
- catch (SQLException e)
68El bean de entidad ProductBean X
- public Connection getConnection()
- String dbUrl null
- String userName null
- String password null
- Context initialContext
- Context environment
- Connection connection null
- try
- initialContext new
InitialContext() - environment (Context)
initialContext.lookup("javacomp/env") - dbUrl (String) environment.lookup("d
bUrl") - userName ((String)
environment.lookup("dbUserName")).trim() - password ((String)
environment.lookup("dbPassword")).trim() - catch (NamingException e)
e.printStackTrace() - try
- Class.forName("sun.jdbc.odbc.JdbcOdbcDriver")
- catch (ClassNotFoundException cnfe)
- System.out.println("ClassNotFoundExcep
tion " cnfe.getMessage()) - cnfe.printStackTrace(System.out)
69El bean de entidad ProductBean IX
- La url, nombre de usuario, contraseña usados para
conectarse a la base de datos son recuperados del
deployment descriptor - Para ello usamos JNDI, y recuperamos los valores
especificados en el fichero XML a través del
objeto InitialContext - initialContext new InitialContext()
- Environment (Context) initialContext.lookup(jav
acomp/env) - dbUrl (String)environment.lookup(dbUrl)
- Hay tres métodos de búsqueda findByPrimaryKey,
findByName y findAll - ejbFindByPrimaryKey devuelve el objeto
identificado por la clave primaria pasada o
javax.ejb.ObjectNotFoundException - ejbFindByName devuelve una colección de productos
donde el nombre contiene la clave dada - ejbFindAll devuelve una lista con todos los
productos
70Deployment Descriptor
- lt?xml version"1.0" encoding"UTF-8"?gt
- ltejb-jargt
- ltdescriptiongtYour first EJB application
lt/descriptiongt - ltdisplay-namegtProducts Applicationlt/display-name
gt - ltenterprise-beansgt
- ltentitygt
- ltejb-namegtBMPProductlt/ejb-namegt
- lthomegtes.deusto.ejb.ProductHomeRemotelt/homegt
- ltremotegtes.deusto.ejb.ProductRemotelt/remotegt
- ltejb-classgtes.deusto.ejb.ProductBeanlt/ejb-cl
assgt - ltpersistence-typegtBeanlt/persistence-typegt
- ltprim-key-classgtjava.lang.Integerlt/prim-key-
classgt - ltreentrantgtfalselt/reentrantgt
- ltenv-entrygt
- ltenv-entry-namegtdbUrllt/env-entry-namegt
- ltenv-entry-typegtjava.lang.Stringlt/env-entr
y-typegt - ltenv-entry-valuegtjdbcodbcProductsBDlt/env
-entry-valuegt - lt/env-entrygt
- ltenv-entrygt
71Aplicación cliente I
- package es.deusto.client
- import javax.naming.
- import javax.rmi.PortableRemoteObject
- import java.util.Properties
- import java.util.Collection
- import java.util.Iterator
- import es.deusto.ejb.ProductRemote
- import es.deusto.ejb.ProductHomeRemote
- public class BMPProductClient
- public static void main(String args)
- // preparing properties for constructing
an InitialContext object - Properties properties new Properties()
- properties.put(Context.INITIAL_CONTEXT_FAC
TORY, - "org.jnp.interfaces.NamingC
ontextFactory") - properties.put(Context.PROVIDER_URL,
"localhost1099")
72Aplicación cliente II
- // Get a reference from this to the
Bean's Home interface - ProductHomeRemote home
(ProductHomeRemote) - PortableRemoteObject.narrow(ref,
ProductHomeRemote.class) - // Create an Interest object from the
Home interface - home.create(11, "Franklin Spring
Water", "400ml", 2.25) - home.create(12, "Franklin Spring
Water", "600ml", 3.25) - home.create(13, "Choco Bar",
"Chocolate Bar 200g", 2.95) - home.create(14, "Timtim Biscuit",
"Biscuit w. mint flavor, 300g", 9.25) - ProductRemote product
home.create(15, "Supermie", "Instant Noodle",
1.05) - product.remove()
- Collection products
home.findByName("Franklin Spring Water") - //Collection products
home.findAll() - for (Iterator iterproducts.iterator()
iter.hasNext()) - product (ProductRemote)
iter.next() - System.out.println("Id "
product.getProductId()) - System.out.println("Product Name
" product.getProductName()) - System.out.println("Description
" product.getDescription())
73Compilación/ejecución de EJB Product
- Utilizar ant para generar un product.ear que se
copiará a JBOSS_HOME\server\default\deploy - Ejecutar cliente
- set CLASSPATHJBOSS_HOME\client\jbossall-client.
jarPRODUCT_APP_HOME\build\products-ejb.jar. - java es.deusto.client.BMPProductClient
- Resultado
- Got context
- Got reference
- Id 11
- Product Name Franklin Spring Water
- Description 400ml
- Price 2.25
- Id 12
- Product Name Franklin Spring Water
- Description 600ml
- Price 3.25
74Escribiendo un bean de entidad CMP
- Son más fáciles de escribir que BMPs
- Un bean de entidad CMP delega todas las tareas
relacionadas con el acceso a una BD al contenedor - No hay necesidad de implementar métodos ejbStore
y ejbLoad - Incluso los métodos finder son implementados por
el contenedor en base a los datos especificados
en el deployment descriptor - Menos trabajo de codificación pero más de
declaración - Es necesario configurar tu contenedor de EJBs con
tu base de datos de preferencia - En este caso vamos a usar hsqldb
75Hypersonic SQL (hsqldb) I
- Url http//hsqldb.sourceforge.net/
- La fuente de datos configurada por defecto con
Jboss es hsqldb - Ficheros de configuración de fuentes de datos en
JBoss - JBOSS_HOME\server\default\deploy\hsqldb-ds.xml
- JBOSS_HOME\server\default\conf\standardjbosscmp-
jdbc.xml - Para ver contenidos de DB ejecutar
- java -cp hsqldb.jar org.hsqldb.util.DatabaseManage
r - Conectarse como
- jdbchsqldbJBOSS_HOME/server/default/data/hyper
sonic/localDB - Type Database engine standalone
76Hypersonic SQL (hsqldb) II
77Pasos para desarrollar un CMP
- Declarar interfaz remota/local que define
contrato entre los clientes y el EJB - Declarar interfaz home remota o local para
acceder a los métodos de ciclo de vida del EJB - Implementar EJB
- Actualizar ejb-jar.xml with metadata para el EJB
creado
78CMPProductRemote
- package es.deusto.ejb
- import javax.ejb.EJBObject
- import java.rmi.RemoteException
- / this is the remote interface for Product /
- public interface CMPProductRemote
- extends EJBObject
- public void setProductId(Integer productId)
throws RemoteException - public Integer getProductId() throws
RemoteException - public void setPrice(double price) throws
RemoteException - public double getPrice() throws
RemoteException - public void setProductName(String
productName) throws RemoteException - public String getProductName() throws
RemoteException - public void setDescription(String
description) throws RemoteException
79CMPProductHomeRemote
- package es.deusto.ejb
- import java.rmi.RemoteException
- import javax.ejb.FinderException
- import javax.ejb.CreateException
- import javax.ejb.EJBHome
- import java.util.Collection
- public interface CMPProductHomeRemote
- extends EJBHome
- public CMPProductRemote create(int productId,
- String
productName, - String
description, - double price)
- throws RemoteException, CreateException
- public CMPProductRemote findByPrimaryKey(Integ
er productId) - throws RemoteException, FinderException
80CMPProductBean I
- package es.deusto.ejb
- import java.sql.
- import java.util.Properties
- import java.util.Enumeration
- import java.util.Vector
- import java.rmi.RemoteException
- import javax.ejb.EntityBean
- import javax.ejb.EntityContext
- import javax.ejb.CreateException
- import javax.ejb.FinderException
- import javax.ejb.ObjectNotFoundException
- import javax.naming.InitialContext
- import javax.naming.Context
- import javax.naming.NamingException
- public abstract class CMPProductBean implements
EntityBean - private EntityContext context
- public abstract void setProductId(Integer
productId) - public abstract Integer getProductId()
81CMPProductBean II
- public Integer ejbCreate(int productId, String
productName, - String description,
double price) throws - RemoteException, CreateException
- System.out.println("ejbCreate")
- this.setProductId(new Integer(productId))
- this.setProductName(productName)
- this.setDescription(description)
- this.setPrice(price)
- return null
-
- public void ejbPostCreate(int productId,
String productName, - String description,
double price) throws - RemoteException, CreateException
- System.out.println("ejbPostCreate")
-
- public void ejbRemove() throws
RemoteException
82CMPProductBean III
- public void ejbActivate()
- System.out.println("ejbActivate")
-
- public void ejbPassivate()
- System.out.println("ejbPassivate")
-
- public void ejbLoad()
- System.out.println("ejbLoad")
-
- public void ejbStore()
- System.out.println("ejbStore")
-
- public void setEntityContext(EntityContext
context) - System.out.println("setEntityContext")
- this.context context
83ejb-jar.xml
- lt?xml version"1.0"?gt
- lt!DOCTYPE ejb-jar PUBLIC"-//Sun Microsystems,
Inc.//DTD Enterprise JavaBeans 2.0//EN
"http//java.sun.com/dtd/ejb-jar_2_0.dtd"gt - ltejb-jargt
- ltenterprise-beansgt
- ltentitygt
- ltejb-namegtCMPProductEJBlt/ejb-namegt
- lthomegtes.deusto.ejb.CMPProductHomeRemotelt/ho
megt - ltremotegtes.deusto.ejb.CMPProductRemotelt/remo
tegt - ltejb-classgtes.deusto.ejb.CMPProductBeanlt/ejb
-classgt - ltpersistence-typegtContainerlt/persistence-typ
egt - ltprim-key-classgtjava.lang.Integerlt/prim-key-
classgt - ltreentrantgtFalselt/reentrantgt
- ltcmp-versiongt2.xlt/cmp-versiongt
- ltabstract-schema-namegtProductlt/abstract-sche
ma-namegt - ltcmp-fieldgtltfield-namegtproductIdlt/field-name
gtlt/cmp-fieldgt - ltcmp-fieldgtltfield-namegtproductNamelt/field-na
megtlt/cmp-fieldgt - ltcmp-fieldgtltfield-namegtpricelt/field-namegtlt/c
mp-fieldgt - ltcmp-fieldgtltfield-namegtdescriptionlt/field-na
megtlt/cmp-fieldgt - ltprimkey-fieldgtproductIdlt/primkey-fieldgt
84Ejb-jar.xml II
- ltquerygt
- ltquery-methodgt
- ltmethod-namegtfindByProductNamelt/method
-namegt - ltmethod-paramsgt
- ltmethod-paramgtjava.lang.Stringlt/met
hod-paramgt - lt/method-paramsgt
- lt/query-methodgt
- ltejb-qlgt
- SELECT OBJECT( p ) FROM Product AS p
- WHERE p.productName ?1
- lt/ejb-qlgt
- lt/querygt
- lt/entitygt
- lt/enterprise-beansgt
- Para definir consultas a bases de datos complejas
EJB 2.0 define Enterprise JavaBeans Query
Language (EJB QL), un lenguaje similar a SQL. -
85ejb-jar.xml III
- ltassembly-descriptorgt
- ltsecurity-rolegt
- ltdescriptiongt
- This role represents everyone who is
allowed full access to the beans. - lt/descriptiongt
- ltrole-namegteveryonelt/role-namegt
- lt/security-rolegt
- ltmethod-permissiongt
- ltrole-namegteveryonelt/role-namegt
- ltmethodgt
- ltejb-namegtCMPProductEJBlt/ejb-namegt
- ltmethod-namegtlt/method-namegt
- lt/methodgt
- lt/method-permissiongt
- ltcontainer-transactiongt
- ltmethodgt
- ltejb-namegtCMPProductEJBlt/ejb-namegt
- ltmethod-namegtlt/method-namegt
- lt/methodgt
86Configurando interfaces locales y remotos
- ltsessiongt
- ltejb-namegtSequenceSessionEJBlt/ejb-namegt
- lthomegtcom.pelikon.docman.util.ejb.keygenerator.S
equenceSessionHomeRemotelt/homegt - ltremotegtcom.pelikon.docman.util.ejb.keygenerator
.SequenceSessionRemotelt/remotegt - ltlocal-homegtcom.pelikon.docman.util.ejb.keygener
ator.SequenceSessionHomeLocallt/local-homegt - ltlocalgtcom.pelikon.docman.util.ejb.keygenerator.
SequenceSessionLocallt/localgt - ltejb-classgtcom.pelikon.docman.util.ejb.keygenera
tor.SequenceSessionBeanlt/ejb-classgt - ltsession-typegtStatelesslt/session-typegt
- lttransaction-typegtContainerlt/transaction-typegt
- ltenv-entrygt
- ltdescription/gt
- ltenv-entry-namegtretryCountlt/env-entry-namegt
- ltenv-entry-typegtjava.lang.Integerlt/env-entry
-typegt - ltenv-entry-valuegt5lt/env-entry-valuegt
- lt/env-entrygt
- ltsecurity-identitygt
- ltuse-caller-identity/gt
- lt/security-identitygt
- lt/sessiongt
87Buscando local/remote homes
- public static synchronized Object
getRemoteHome(String jndiName, Class narrowTo) - throws NamingException
-
- Object ref remoteHomes.get(jndiName)
- if(ref null)
-
- ref getContext().lookup(jndiName)
- ref PortableRemoteObject.narrow(ref,
narrowTo) - remoteHomes.put(jndiName, ref)
-
- return ref
-
- public static synchronized Object
getLocalHome(String jndiName) - throws NamingException
-
- Object ref localHomes.get(jndiName)
- if(ref null)
-
88Sintáxis EJB QL I
- Una query en EJB QL tiene la forma
- select_clause from_clause where_clause
- select_clause
- select DISTINCT single_valued_path_expression
OBJECT(identification_variable) - SELECT DISTINCT OBJECT(p) FROM Product AS p
89Sintáxis EJB QL II
- from_clause
- FROM identification_variable_declaration ,
identification_variable_declaration - identification_variable_declarationcollection_m
ember_declarationrange_variable_declaration - collection_member_declaration IN
(collection_valued_path_expression) AS
identifier - range_variab