Download J2ee
Document related concepts
no text concepts found
Transcript
Los Enterprise Java Beans son como los Servlets • Son trozos de código que extienden un servidor • “Viven” en un contenedor apropiado • El contenedor decide cuándo se crean y se destruyen • No son contactados directamente por el cliente Existen 3 Clases principales • Session Beans: – Implementan procesos, orientados a acciones (cálculo de un valor) • Entity Beans: – Están asociados a datos persistentes. Representan una instancia de un dato almacenado • Message Driven Beans: – Parecidos a Session beans pero son “despertados” o contactados por mensajes que pueden incluso ser asínctonos Refinando la clasificación • Session Beans: – Sin estado: son contactados una vez por los clientes, ejecutan una acción y no queda traza de lo que se hizo – Con estado: en una “sesión” pueden ser contactados varias veces por el mismo cliente para desarrollar una “conversación”. Será necesario mantener algún tipo de información para recordar lo que va haciendo el cliente • Entity Beans: – Persistencia controlada por el Bean: el programador debe incluir código de modo de asegurarse que el enttity bean represente a un dato en una tabla – Persistencia controlada por el container: el container se preocupa de asociar el bean a un dato de una tabla Qué se necesita escribir para implementar un bean • Los Archivos Java (programados por el desarrollador de la aplicación) – La interfaz EJBObject: en esta interfaz se especifican los business methods que implementa el bean, es decir, todos aquellos métodos que no tienen que ver con crear, recuperar, destruir o localizar un bean. Típicamente los que diseña el programador – La interfaz EJBHome: aquí están los métodos para para crear, destruir y localizar un bean – El EJBean: este archivo implementa todos los métodos del bean. Estos incluyen (de alguna manera) los declarados por los dos archivos anteriores y otros métodos propios de la interfaz bean (obligación de escribirlos, aunque no hagan nada) – En la última versión hay tembién EJBLocalObject y EJBLocalHome, para hacer más eficientes las invocaciones entre beans de un mismo container Qué se necesita escribir para implementar un bean • Los Archivos NO Java (generalmente generados con ayuda de herramientas del aplication server) – El Deployment descriptor: un archivo declarativo donde se especifican algunas cualidades del bean, • Bean management and lifecicle requirements: si es un session, entity o message-driven bean • Persistencia (para entity beans) si será CMP o BMP • Transacciones: cómo se manejan las transacciones • Seguridad: control de accesos – Archivos propios de requeridos por la implementación del aplication server: serán para sacar provecho de algunas características específicas de este – Todo esto se debe combinar en un archivo jar, que se instala en el aplication server en un lugar específico (estilo servlets) Cómo administra el container el cliclo de vida de los beans • Los beans son creados y destruidos por el container. Cuando un bean se levanta con el container (el bean debe estar ahí cuando se echa a andar el server) se crean instancias del bean (bean pool) las cuales son “asignadas” a los clientes. Qué bean es entregado a qué cliente lo decide el container • Si se necesitan más beans estos son creados por el container (create) • Si hay demasiados estos son destruidos (Remove) • El container puede decidir además hacer “dormir” o “despertar” a los beans según las necesidades (activate, passivate) para El papel de cada uno de las 3 clases de objetos • Cuando un cliente desea contactar a un bean localiza un un ejbHome Object que correspoda al de un bean deseado. • Este proceso es bien dependiente de las “condiciones locales” pero normalmente requiere hacer un lookup a un servidor de nombres (normalmente provisto por el servidor de aplicaciones también) por medio de la API JNDI • Una vez que tiene una referencia a este lo usa para fabricar un objeto EJB, al cual le aplica los métodos • El EJBObjet se contactará con un bean adecuado para que dé el servicio (esto lo hace el contenedor) El papel de cada uno de las 3 clases de objetos Bean Pool 3 contacta home ejbHome cliente 5- retorna referencia 4 crea ejbObject 6 invoca método 1-ubicar 2 retorna referencia Naming ejbObject 7 contacta bean El Hello World EJB • Haremos un EJB y un cliente que lo contacte e invoque el método String hello() que devorverá el string “Hello World” • Este será un Session Bean sin estado (obvio) • El primer archivo es el Hello.java que es la interfaz que EJBObject que declara los “buisness methods” import javax.ejb.*; import java.rmi.*; public interface Hello extends EJBObject { public string hello() throws RemoteException; } La interfaz EJBObject • Extiende java.rmi.Remote • tiene los siguientes métodos – – – – – EJBhome getEJBHome() Object getPrimaryKey() //para entity beans void remove() Handle getHandle() boolean isIdentical() El Hello World EJB • El archivo HelloHome.java declara la interfaz con el home object. En este caso sólo necesitamos declarar un método para la creación (no necesita parámetros, es sin estado) import javax.ejb.*; import java.rmi.*; public interface HelloHome extends EJBHome { Hello create() throws RemoteException, CreateException; } • Notar que el método create retorna un objeto del tipo Hello (EJBObject) que es el que se usará para invocar los métodos La interfaz EJBHome • Extiende java.rmi.Remote • tiene los siguientes métodos – – – – EJBMetaData getEJBMetaData() HomeHandle getHomeHandle() void remove(Handle handle) void remove(Object primaryKey) El Hello World EJB • El archivo HelloBean.java implementa los métodos necesarios: por cada create declarado en Home debe implementar un ejbCreate con los mismos parámetros. Además debe implementar los business methods (hello no más en este caso) y los métodos propios de los session beans import javax.ejb.*; public class HelloBean extends SessionBean { private SessionContext ctx; public void ejbCreate() {} public String hello() { return(“hello world!”); } public ejbRemove() {} //llamado antes de eliminar el bean public ejbActivate(){} //llamado al despertar un bean public ejbPassivate(){} //llamado al poner a dormir el bean //en este caso no nos sirve pero en otros puede servir //especialmente en los BMP entity bean public setSessionContext(SessionContext ctx) { this.ctx = ctx; } } El Deployment descriptor • Es un archivo xml donde se le dan declarativamente algunas propiedades al bean, generado por los tools del aplication developer <!DOCTIPE ejb-jar PUBLIC ..... <ejb-jar> <enterprise-beans> <session> <ejb-name>Hello</ejb-name> <home>HelloHome</home> <remote>Hello</remote> <ejb-class>HelloBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar> El cliente import javax.naming.*; import java.util.*; import javax.rmi.*; public class HelloClient { public static void main(String args[) throws Exception { Properties props = System.getproperties(); Context ctx = new InitialContext(props); Object obj = ctx.lookup(“HelloHome”); HelloHome home = (HelloHome)PortableRemoteObject.narrow (obj,HelloHome.class); Hello hello = home.create(); System.out.println(hello.hello()); hello.remove(); } } • El lookup se realiza en el recurso de naming (provisto por el container) que se le da al cliente cuando se lo echa a andar • Cuando el EJB se sube al contenedor, este registra al Home object (bind) con el seudónimo “HelloHome” (nombre de clase) Un Session Servlet con Estado • Cuando un cliente contacta a un stateful servlet no es tan conveniente que el container los destruya cuando estime conveniente ya que el mismo servlet tiene que estar al servicio del mismo cliente, y el container no puede saber cuando termina el cliente de contactar al servlet sino hasta que lo destruye explicitamente. • Tampoco puede mantenerlos indefinidamente en el container ya que consumen recursos • La solución pasa por “pasivarlos” y “activarlos” • Pasivarlos: pasan de emoria principal a secundaria • Activarlos: pasan de memoria secundaria a principal (swapping) Un Session Servlet con Estado • El container implementa una “política” de pasivacionactivación por ejemplo, Least Used reciently • Un bean involucrado en una transaccón o sirviendo a un cliente no puede ser pasivado • Se usa serialización • el método ejbPassivate es llamado antes de copiar el bean al disco • el método ejbActivate es llamado cuando se activa • En cada método se liberan/recuperan recursos que no se pueden serializar por ej. conexiones a bases de datos, archivos abiertos (que pasa si esta leyendo en medio del archivo), conexiones a sockets El Count Bean • Tendrá un método count() que incrementa una variable llamada val • Esta será la variable que determinará que es un bean de estado //interfaz remota import javax.ejb.*; import java.rmi.*; public interface Count extends EJBObject { public int count() throws RemoteException; } //el home interface import javax.ejb.*; import java.rmi.*; public interface CountHome extends EJBHome { Count create(int val) throws RemoteException, CreateException; } El Count Bean import javax.ejb.*; public class CountBean extends SessionBean { public int val; private SessionContext ctx; public int count() { return ++val; } public void ejbCreate(int val) { this.val = val; } public public public public } } ejbRemove() {} //llamado antes de eliminar el bean ejbActivate(){} //llamado al despertar un bean ejbPassivate(){} //llamado al poner a dormir el bean setSessionContext(SessionContext ctx) { this.ctx = ctx; El Count Bean <!DOCTIPE ejb-jar PUBLIC ..... <ejb-jar> <enterprise-beans> <session> <ejb-name>Count</ejb-name> <home>CountHome</home> <remote>Count</remote> <ejb-class>CountBean</ejb-class> <session-type>Stateful</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> </ejb-jar> Estados de un Bean Cliente invoca create en un home Interface Cliente llama a remove() en el ejbObject o se le da un timeout al cliente No existe El container llega a un límite de su capacidad: swapping 1- Class.newInstance() 2- setSessionContext() 3- ejbCreate(...) ejbRemove() Timeout del cleinte ejbActivate() Activo Pasivo ejbPassivate() Liente llama a un método del Bean pasivado Los Entity beans • Un bean representa a un dato (fila) en una base de datos • Hay que pensar en ellos como si fueran uno solo con el dato en memoria secundaria • Debe existir un mecanismo para automáticamente transferir los datos de la memoria secundaria al EJB y vice-versa • Esto se hace a través de llamadas a los métodos ejbLoad() y ejbStore() • Estos métodos son llamados por el container cuando estima que es necesario • distintos beans pueden representar al mismo dato en disco • ejbActivate() y ejbPassivate() se llaman cuando un entity bean es puesto/sacado de un pool de beans, por lo que hay que programas la adquisición y liberación de reucursos • Como además se debe guardar el estado del bean en memoria secundaria, por lo cual se llama siempre a ejbStore abtes de pasivar y a ejbLoad antes de activar Las 2 maneras de lograr persistencia de los beans • En un bean-manajed persistence entity bean el programador debe escribir las instrucciones para que las variables del entity bean sean las correspondientes a un dato en una base de datos (saving, loading, and finding) • Estas instrucciones van en los métodos de creación (ejbCreate(...)), destrucción (ejbRemove()), localización (ejbFind(...)), carga (ejbload()) y almacenamiento (ejbStore()) • Esto generalmente se hace via instrucciones JDBC • En los container-managed persistence beans de esto se encarga el container, sólo basta dar algunas directrices para la localización de los datos en un archivo especial (según yo, esto sería una de las gracias más grandes de j2ee) Creación y destrucción de Beans • Cuando un entity bean es creado por una llamada al método ejbCreate se debe crear también este dato en la base de datos, si se trata de un bean-managed persistence bean, aquí se deben programar las instruccónes SQL para insertar una fila en una tabla • De la misma manera, cuando un entity bean es removido, se llama a ejbRemove y aquí se debe programas la instrucción SQL que borre la fila correspondiente • A cada clase de entity bean que se crea hay que asociarle un objeto que represente la clave primaria de ese tipo de objeto (por ejemplo un string. Por convención se usa el nombre del bean terminado en PK (por ejemplo CuentaPK) • El método ejbCreate de un entity bean debe devolver un siempre un objeto de este tipo luego de haber creado el dato Esquema de creación de un entity bean 1- create() 2- ejbCreate() cliente Home 4- retorna una referencia al EJB object 5- creación del objeto EJB 4- retorna un objeto que representa la clave primaria del ejb creado EJB Object CONTAINER Bean 3- se crea el dato en la base de datos Base de Datos Creación y destrucción de Beans • Si, por ejemplo, tenemos un Bean que se llamará Account, el home object será de la clase AccountHome, el EJB Object se llamará Account y el EJBean se llamará AccountBean y el objeto que representa a la clave primaria se llamará AccountPK • Para un un método de creación en el AccountHome de la siguiente forma: – public Account create(String id, String nomb)... • le corresponderá un método en el AccountBean de las siguiente forma: – public AccountPK ejbCreate(String id, String nomb).. • El método remove() se puede aplicar tanto al EJB object como al home object, en ambos casos se terminará llamando a ejbRemove() que debe hacerse cargo de borrar el dato de la base de datos Encontrando Beans (en BMP) • Como sucede en el manejo directo de bases de datos, muchas veces vamos a querer encontrar beans, es decir, tener referencia a uno o mas beans que reflejen datos que ya se encuantran en la base de datos • Estas se hacen por medio de los métodos findXXX en el home y su correspondiente ejbFindXXX en el Bean • Ejemplo para uno: home retorna un EJBobject y el bean un PrimaryKey – public Account findAnAccountFor(String name) en el home – public AccountPK ejbFindAnAccountFor(String name) en el Bean • Ejemplo para varios: home retorna una colección de EJB y el Bean de keys – public Collection findAllAccountsFor(String name) en el home – public Collection ejbFindAllAccountsFor(String name) en el Bean • SIEMPRE debe implementarse al menos el siguiente – public Account findByPrimaryKey(AccountPK key) – public AccountPK ejbFindByPrimaryKey(AccountPK key) El Contexto • El objeto Context es pasado al bean por el container cuando llama a setSessionContext o setEntityContext según corresponda. Este contiene información acerca del contexto del bean • Si el bean lo necesita, debería mantener una referencia (como se hizo en el primer ejemplo) • Los métodos que se pueden llamar son: – getEJBObject() retorna el EJBObject asociado al bean – getPrimaryKey() sólo para entity beans (obvio), retorna el key del dato asociado a esta instancia. Esto es necesario porque un bean no sabe en principio a que dato está asociado (el EJBObject si) • Es muy útil en los bean managed persistence entity beans cuando se programa EjbLoad() para saber qué dato hay que recuperar de la base de datos (con un select) y asociarlo al bean. También para ejbRemove() para saber qué fila de la tabla se debe borrar en la base de datos La Interfaz entity bean • Cuando se programa un Entity bean hay que programar los siguientes métodos, (aparte de los “business methods) – – – – – – – – – – setEntityContext(EntityContext ctx) unsetEntityContext() se llama antes de destruirse el bean ejbFindXXX(...) para encontrar datos según lo especificado en el home ejbHomeXXX(...) para business methods no asociados a datos (como session) ejbCreate(...) según lo especificado en el home ejbRemove() ejbActivate() ejbPassivate() ejbLoad() ejbStore() El EJBObject para cuentas Account import javax.ejb.*; import java.rmi.*; public interface Account extends EJBObject { public void depositar(int monto) throws RemoteException; public boolean girar(int monto) throws RemoteException; public int getSaldo() throws RemoteException; public String getOwner() throws RemoteException; public void setOwner(String name) throws RemoteException; public String getAccountID() throws RemoteException; public void setAccountID(String ID) throws RemoteException; } El Home Interface AccountHome import import import public } java.util.Collection; javax.ejb.*; java.rmi.*; interface AccountHome extends EJBHome { Account create(String ID, String name) throws RemoteException, CreateException; public Account findByPrimaryKey(AccountPK ac) throws RemoteException, FinderException; public Collection findByOwnerName(String name) throws RemoteException, FinderException; public double getTotelBankValue() throws RemoteException; El Primary Key AccountPK import java.io.Serializable; public class AccountPK implements Serializable { public String accountID; public AccountPK(String id) { accountID = id; } public AccountPK() {} public toString() { //requerido !!! return accountID; } public hashCode() { // requerido !!! return accountID.hashCode(); } public equals(Object account) { // requerido !!! return ((AccountPK)account).accountID.equals(accountID); } } El Bean AccountBean (1) import import import import java.sql.*; java.naming.*; javax.ejb.*; javax.util.*; public class AccountBean implements EntityBean { EntityContext ctx; String accountID; String owner; int saldo; public void depositar(int monto) { saldo = saldo + monto; } public boolean girar(int monto) { if (monto >= saldo) { saldo = saldo - monto; return true; } return false; } .... El Bean AccountBean (2) ... public int getSaldo() { return saldo; } public String getOwner() { return owner; } public void setOwner(String name) { owner = name; } public String getAccountID() { return accountID; } public void setAccountID(String id) { sccountID = id } ... El Bean AccountBean (3) ... public Connection getConnection() throws Exception { Class.forName(“com.informix.jdbc.IfxDriver”); String url = “jdbc:informix-sqli://”+ “hostname/CGE_HOLD:INFORMIXSERVER=servername”; Connection con = DriverManager.getConnection(url,”nbaloian”,”123”); return con; } public int ejbHomeGetTotalBankValue() { try { Connection conn = getConnection(); PreparedStatement psmt = conn.prepareStatement( “select sum(saldo) as total from accaounts”); ResultSet rs = psmt.executeQuery(); psmt.close(); conn.close(); return rs.getInt(“total”); } catch (Exception e) { //arreglar el pastel } } El Bean AccountBean (4) ... public void ejbActivate() { public void ejbPassivate() { } // es necesario escribirla } // igual public void ejbRemove() { AccountPK pk = (AccountPk) ctx.getPrimaryKey(); String id = pk.acountID; try { Connection conn = getconnection(); PreparedStatement psmt = conn.prepareStatement( “delete from accounts where id = ?”); psmt.setString(1,id); if(psmt.executeUpdate() == 0) System.out.println(“problemas”); psmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace()} } ... El Bean AccountBean (5) ... public void ejbLoad() { AccountPK pk = (AccountPk) ctx.getPrimaryKey(); String id = pk.acountID; try { Connection conn = getconnection(); PreparedStatement psmt = conn.prepareStatement( “select ownerName, balance from accounts where id = ?”); psmt.setString(1,id); ResultSet rs = psmt.executeQuery(); rs.next(); ownerName = rs.getString(“ownername”); saldo = rs.getInt(“saledo”); psmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace()} } ... El Bean AccountBean (6) ... public void ejbStore() { try { Connection conn = getconnection(); PreparedStatement psmt = conn.prepareStatement( “update accounts set ownerName = ?, saldo = ?”+ “where id = ?”); psmt.setString(1,owner); psmt.setString(2,saldo); psmt.setString(3,accountID); psmt.executeUpdate(); psmt.close(); conn.close(); } catch (Exception e) { e.printStackTrace()} } public setEntityContext(EntityContext ctx) { this.ctx = ctx; } public } ... unsetEntityCOntext() { this.ctx = null; El Bean AccountBean (7) ... public AccountPK ejbCreate(String id, String name) throws CreateException { accountID = id; ownerName = name; saldo = 0; try { Connection conn = getconnection(); PreparedStatement psmt = conn.prepareStatement( “insert into accounts (id, ownerName, saldo) values (?,?,?)”); psmt.setString(1,accountID); psmt.setString(2,owner); psmt.setString(3,saldo); psmt.executeUpdate(); psmt.close(); conn.close(); return new AccountPK(accountID); } catch (Exception e) { e.printStackTrace()} } ... El Bean AccountBean (8) ... public AccountPK ejbPostCreate(String id, String name) throws CreateException { } // por cada create hay que escribir un PostCreate que se llama // justo después de la creación public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException { try { Connection conn = getConnection(); PreparedStatement psmt = conn.prepareStatement( “select id from account where id = ?”); psmt.setString(1,key.toString()); ResultSet rs = psmt.executeQuery(); rs.next(); psmt.close(); conn.close(); return key(); catch (Exception e) {....} } ... ... El Bean AccountBean (9) public AccountPK ejbFindByOwnerName(String n) throws FinderException { try { Connection conn = getConnection(); PreparedStatement psmt = conn.prepareStatement( “select id from account where ownerName = ?”); psmt.setString(1,n); ResultSet rs = psmt.executeQuery(); Vector v = new Vector(); while (rs.next()) { String id = rs.getString(“id”); v.addElement(new AccountPK(id)); } psmt.close(); conn.close(); return v; catch (Exception e) {....} } } //por fin !!! ... El Deployment descriptor <!DOCTIPE ejb-jar PUBLIC ..... <ejb-jar> <enterprise-beans> <entity> <ejb-name>Account</ejb-name> <home>AccountHome</home> <remote>Account</remote> <ejb-class>AccountBean</ejb-class> <persistence-type>Bean</persistence-type> <primary-key-class>AccountPK</ primary-key-class > <reentrant>false</reentrant> <resource-ref> <res-ref-name>jdbc/ejPool</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </entity> </enterprise-beans> <assembly-descriptor> ....para transacciones... </assembly-descriptor>l </ejb-jar> Los CMP Entity Beans • La idea principal es no tener que escribir ningun código de persistencia con la base de datos • Mucho del código migra del Bean al Deployment descriptor (pero muy simplificado) • Juega un papel importante el EJB-QL, que es un lenguaje estilo SQL orientado a objetos con el cual se especifican muchas cosas. Principalen diferencias con BMP • Lo que uno escribe es una superclase del bean, que será extendida automáticamente por el sistema para añadirle el código de persistencia • Por esto, la declaración de un CMP es abstract !!! • No se declaran Campos del bean (variables). Estas van especificadas en el Deployment descriptor y aparecen en la clase extendida • Por eso mismo, tampoco se escriben los métodos set/get finales, sólo se declaran en forma abstracta (como en una interfaz) • los métodos find también se declaran en horma abstracta. La forma de cómo localizan los beans se da por medio del EJB-QL en el deployment descriptor • también se pueden definir métodos abstractos ejbSelectXXX que serán usados al interior del bean. Estos no sólo pueden ubicar beans sino que campos de ellos (por ejemplo, el saldo de todas las cuentas que pertenecen a un owner dado) Métodos a declarar en el Bean • setEntityContext() igual que en los BMP • ejbFindXXX(...) se declaran en forma abstracta, la forma cómo deben trabajar se especifica en el deployment descriptor con el EJB-QL • ejbSelectXXX(...) igual que para el punto anterior, pero estos no son visibles desde el EJBObject, son par auso interno del bean • ejbHomeXXX(...) para declaración de métodos “estáticos” • ejbCreate(...) no se debe escribir código que inserta datos en la base de datos. Sólo se usan los métodos setXXX para poner el valor a los campos según lo pasado por los parámetros (o no) • ejbPostCreate(...) igual que en BMP • ejbActivate() igual que en BMP • ejbLoad() no hacer cosas que tengan que ver con cargar el dato, esto lo implementa el container. (pero adquirir recursos) • ejbStore() idem anterior (pero liberar recursos) • ejbRemove() idem anterior • ejbUnsetEntityContent() igual que para BMP El EJBObject para Product import javax.ejb.*; import java.rmi.*; public interface Product extends EJBObject { public String getName() throws RemoteException; public void setName(String name) throws RemoteException; public String getDescription() throws RemoteException; public void setDescription(String desc) throws RemoteException; public double getBasePrice() throws RemoteException; public void setBasePrice(double price) throws RemoteException; public String getProductID() throws RemoteException; public void setProductID(String id) throws RemoteException; } El Home Interface ProductHome import import import public } java.util.Collection; javax.ejb.*; java.rmi.*; interface ProductHome extends EJBHome { Product create(String ProductID, String name, String description, double price) throws RemoteException, CreateException; poublic Product findByPrimaryKey(ProductPK key) throws RemoteException, FinderException; public Collection findByName(String name) throws RemoteException, FinderException; public Collection findByDescription(String desc) throws RemoteException, FinderException; public Collection findByBasePrice(double price) throws RemoteException, FinderException; public Collection findExpensiveProducts(double price) throws RemoteException, FinderException; public Collection findCheapProducts(double price) throws RemoteException, FinderException; public Collection findAll(String name) throws RemoteException, FinderException; El Primary Key ProductPK import java.io.Serializable; public class ProductPK implements Serializable { public String productID; public ProductPK(String id) { productID = id; } public productID() {} public toString() { //requerido !!! return productID; } public hashCode() { // requerido !!! return productID.hashCode(); } public equals(Object prod) { // requerido !!! return ((AccountPK)prod). productID.equals(productID); } } El Bean ProductBean (1) import java.sql.*; public abstract class ProducttBean implements EntityBean { EntityContext ctx; public public public public public public public public abstract abstract abstract abstract abstract abstract abstract abstract public public public public public .... void void void void void String getName(); void setName(String name); String getDescription(); void setDescription(String desc); double getBasePrice(); void setBasePrice(double price); String getProductID(); void setProductID(String id); ejbActivate() {} ejbPasivate() {} ejbRemove() {} ejbLoad() {} ejbStore() {} El Bean ProductBean (2) ... public void setEntityContext(EntityContext ctx) { this.ctx = ctx; } public void unsetEntityContext() {this.ctx = null;} public void ejbPostCreate(String id, String name String desc, double price) {} public String Create(String id, String name String desc, double price) { setProductID(id); setName(name); setDescription(desc); setBasePrice(price); return id; //sorry esta en el libro } } El Deployment descriptor es bastante grande, claro <!DOCTIPE ejb-jar PUBLIC ..... <ejb-jar> <enterprise-beans> <entity> <ejb-name>Product</ejb-name> <home>ProductHome</home> <remote>Product</remote> <ejb-class>ProductBean</ejb-class> <persistence-type>Container</persistence-type> <primary-key-class>ProductPK</ primary-key-class > <reentrant>false</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>ProductBean</abstract-schema-name> <cmp-field> <field-name>productID</field-name> </cmp-field> <cmp-field> <field-name>name</field-name> </cmp-field> <cmp-field> <field-name>description</field-name> </cmp-field> <cmp-field> <field-name>basePrice</field-name> </cmp-field> El Deployment descriptor es bastante grande, claro <query> <query-method> <method-name>findByName</method-name> <method-params> <method-param>java.lang.String</method-param> <method-params> <query-method> <ejb-sql> <![CDATA[SELECT OBJECT (a) FROM ProducBean AS a WHERE name = ?1> </ejb-sql> </query> <query> <query-method> <method-name>findExpensiveProducts</method-name> <method-params> <method-param>double</method-param> <method-params> <query-method> <ejb-sql> <![CDATA[SELECT OBJECT (a) FROM ProducBean AS a WHERE basePrice > ?1> </ejb-sql> </query> </entity> </enterprise-beans> El Deployment descriptor es bastante grande, claro <assembly-descriptor> ....para transacciones... </assembly-descriptor>l </ejb-jar>