Sei sulla pagina 1di 46

rea de Formacin

EJB 3.0

Ref.Mamual EJB 3.0.

rea de Formacin

NDICE
1 Que haba antes? 2 Que ventaja nos ofrece ahora? 3 Aproximacin a la arquitectura. 4 Beans de sesin. 5 Seguridad 6 Transacciones en bean de sesin 7 Beans de Entidad. 7.1 7.2 7.3 7.4 Mapeando objetos Relaciones entre entidades Herencia entre entidades EJB QL

8 Beans de mensajera. 9 Temporizadores.

Ref.Mamual EJB 3.0.

rea de Formacin

1. Que haba antes?


Partimos de ejb 2.1, de sus engorrosos interfaces y sus ficheros xml de configuracin. Ejb 2.1 nos obligaba a utilizar un objeto home que controlaba la instanciacin y destruccin de los objetos remotos. Estos objetos remotos contenan la lgica de negocio. Estos dos interfaces (home y remote) estaban pensados para realizar conexiones remotas (a travs de socket) por lo que se volvan inefic ientes si el cliente y el objeto remoto estaban situados en la misma mquina virtual, por ello se duplicaron para poder ofrecer un par que se conecte a travs de socket y otro par que se conecte a travs de la propia memoria de la mquina virtual. Sun ofreca a travs de la especificacin un fichero de configuracin que no cubra la totalidad de las configuraciones necesarias, por lo que cada servidor de aplicaciones necesitaba de un fichero de configuracin propietario diferente al de los otros servidores. Sun consider que era necesario ofrecer a los programadores acceso directo a la base de datos de manera remota, por lo que aparecan problemas de rendimiento al tener acceso a base de datos de manera remota.

2. Que ventaja nos ofrece ahora?


Sobre todo, sencillez: Se han eliminado los interfaces home, slo disponemos de los remotos. Los bean de entidad son accesibles de manera local y no de manera remota, adems de utilizar una interfaz muy similar al concepto original de hibernate. Es decir, la persistencia es mucho ms sencilla de configurar. Seguimos disponiendo de envos de mensajes asncronos con los ejb de mensajera y podemos emplear servicios web de una manera mucho ms sencilla. Se emplean las anotaciones para modificar el comportamiento de los ejb sin necesidad de utilizar ficheros xml de configuracin. Esto se aplica a todos los tipos de ejb, clientes y a los servicios web. Adems emplea el nuevo sistema de inyeccin de valores, que permite declarar una variable, anotarla y conseguir que el servidor la asigne un valor (inyecte) automticamente desde el servicio de nombrado, ahorrndonos el uso del servicio de nombrado.

3. Aproximacin a la arquitectura
A pesar de la sencillez que nos ofrece es necesario conocer la arquitectura, para entender como utilizar a los ejb y a las anotaciones que nos permiten configurarlos. Beans de sesin Los beans de sesin son los objetos remotos clsicos, empleados como punto de entrada a la lgica de negocio de la aplicacin. No son objetos persistentes en la base de datos, pero puede ser de dos tipos: con estado y sin estado.

Ref.Mamual EJB 3.0.

rea de Formacin
Los que tienen estado permiten que entre llamada y llamada de los mtodos del bean, un cliente pueda almacenar informacin temporalmente dentro del bean (mientras dure la sesin del cliente con el bean), en realidad el cliente usar el bean como si fuese un objeto propio java en su mquina virtual. Los ejb de sesin sin estado son compartidos a la vez por varios clientes, por lo que no pueden guardar la informacin de ningn cliente, habitualmente se invocan sus mtodos de manera independiente y pasndoles todos los parmetros necesarios para su funcionamiento en el mismo momento de su llamada. Accederemos a ellos de manera remota o local. Al trabajar de manera remoto es obvio que es necesario utilizar sockets para comunicar el cliente y el servidor, pero esto es una penalizacin muy grande si tenemos al cliente y al servidor en la misma mquina virtual (por ejemplo: una aplicacin web que se encuentra en el mismo servidor que el ejb), por ello disponemos del accceso en local, es decir sin pasar por sockets, trabajando directamenten en memoria. Beans de entidad En los beans de entidad se ha adoptado la especificacin Java Persistence 1.0 en la que se trata a las entidades de base de datos como POJOS, esto implica que todo ejb de entidad estar formado por una clase mapeada a una tabla, en la que se define los atributos y su mapeo a columnas. Es obligatorio utilizar una clave primaria para poder diferenciar a las distintas instancias, o registros.

Al trabajar con POJOS, podemos crearlos, almacenarlos, serializarlos (para poder enviarlos entre cliente y el servido, hacer consultas, modificaciones, eliminarlos,etc... ). Los Beans de entidad son gestionados por el EntityManager y no son accesibles de manera remota, por lo que, o bien se usan desde la misma mquina virtual, o bien se usan dentro de un bean de sesin o de mensajera y de esta forma son accesibles de manera remota. Bean de mensajera Muchas aplicaciones necesitan un mecanismo de comunicacin asncrono, que no pueden ofrecer los bean de estado,debido a su comportamiento sncrono. Por ello los bean de mensajera ofrecen esa capacidad de recibir y procesar un mensaje de un cliente, mientras este se encuentra realizando otras tareas, en lugar de obligar al cliente a mantenerse bloqueado a la espera del fin de la invocacin de un mtodo. Para lograr este comportamiento, el servidor de aplicaciones permite crear un buzn de mensajes siguiendo el api JMS. Nuestros bean de mensajera sacarn (a medida que puedan) los mensajes de los clientes acumulados en dicho buzn, e irn procesndolos. Los clientes deben de usar las clases del api JMS para poder emplear dichos buzones, por tanto no se utilizan igual que los bean de sesin.

Ref.Mamual EJB 3.0.

rea de Formacin
Clases e interfaces A la hora de trabajar con los ejb 3.0 en realidad veremos que nos enfrentamos a una serie de interfaces (hablamos de interfaces planos de java) y las clases que los implementan: Interfaz Remoto: Define los mtodos de la lgica de negocio que haremos accesibles a travs de un bean de sesin de manera remota. Empleamos la anotacin javax.ejb.Remote para marcarlos. Interfaz Local: Define los mtodos de la lgica de negocio que haremos accesibles a travs de un bean de sesin de manera local. Empleamos la anotacin javax.ejb.Remote para marcarlos. Interfaz EndPoint: Define los mtodos que sern accesibles a travs de soap. Empleamos la anotacin javax.ejb.WebService para marcarlos. Interfaz de mensajes: Define los mtodos que permiten al ejb de mensajera recibir los mensajes enviados por los clientes. Clase del Bean: Es la clase que implementa alguno/s de los interfaces anteriores y por tanto donde programaremos el cdigo de dichos mtodos. Suele estar marcada con: javax.ejb.Stateless si es de sesin sin estado javax.ejb.StateFull si es de sesin con estado javax.ejb.MessageDriven si es de tipo mensajera El contenedor de ejb Los ejb no viven en el aire, de manera autnoma, sino que precisan de los servicios que les ofrece el contenedor de ejb para su correcto funcionamiento: Servicio de nombrado: Permite localizar al los ejb y otros recursos a partir de su nombre. Servicio de transacciones: Gestionan y controlan las transacciones en las que se involucran los ejb. Servicio de persistencia: Bsicamente el EntityManager que usaremos para la persistencia. Servicio de seguridad: Controla la invocacin de los mtodos de los ejb, si el cliente posee o no los permisos necesarios para llevarlo a cabo. Tambin se encarga de gestionar el canal seguro SSL. Concurrencia: Los ejb no pueden ser concurrentes, por lo que no es necesario sincronizar sus mtodos Servicio temporizador: notifica a un ejb de tipo timer que se ha disparado el evento de tiempo solicitado. Pool de objetos y servicio de pasivacin: permiten que con pocas instancias de ejb demos servicios a muchos ms clientes.

Ref.Mamual EJB 3.0.

rea de Formacin
Ficheros empleados Vamos a disponer de ficheros con las siguientes extensiones: war: contiene una aplicacin web. jar: contiene una aplicacin con ejb en su interior. ear: contie ne una aplicacin enterprise, dentro de la cul tendremos ficheros war y jar.

Como vemos, el fichero ear acta como un contenedor que permite subir varias aplicaciones juntas.

4. Beans de sesin
Son objetos remotos, accesibles de manera local o remota, ofreciendo la lgica de negocio. Es muy frecuente que en su interior se manejen las entidades asociadas a base de datos (beans de entidad). El bean de sesin se encuentra disponible a travs del servicio de nombrado ofrecido por el servidor , bajo un nombre que depende del servidor de aplicaciones en cuestin, en nuestro caso seguiremos la especificacin de sun en sus servidores, en concreto asumiremos el uso de glassfish que acompaa a netbeans. Pueden estar formados por el interfaz Remoto y por el Local, aunque no es obligatorio disponer de ambos:
CalculadoraRemote.java:

package ejb; import javax.ejb.Remote; @Remote public interface CalculadoraRemote { public double sumar(double operando1, double operando2); }

CalculadoraLocal.java:

package ejb; import javax.ejb.Local; @Local public interface CalculadoraLocal { public double sumar(double operando1, double operando2); }

y de la clase que los implementa:

Ref.Mamual EJB 3.0.

rea de Formacin
CalculadoraBean.java: package ejb; import javax.ejb.Stateless; @Stateless public class CalculadoraBean implements CalculadoraRemote, CalculadoraLocal { @Resource private SessionContext ctx; public double sumar(double operando1, double operando2) { return operando1+operando2; } }

A todo esto le agregamos el cdigo de los dos posibles tipos de cliente:


Main.java: package proyectoejb3; import ejb.CalculadoraRemote; import java.rmi.RemoteException; import javax.ejb.EJB; public class Main { @EJB private static CalculadoraRemote cr; public static void main(String[] args) throws RemoteException { System.out.println("2+3="+cr.suma(2.0, 3.0)); } }

Main2.java: package clienteclasico; import ejb.CalculadoraRemote; import javax.naming.InitialContext; import javax.naming.NamingException; public class Main { public static void main(String[] args) throws NamingException { InitialContext ctx = new InitialContext(); CalculadoraRemote cr = (CalculadoraRemote) ctx.lookup(CalculadoraRemote.class.getName()); System.out.println("2+3="+cr.sumar(2.0, 3.0));
Ref.Mamual EJB 3.0.

rea de Formacin
} }

y un cliente local en un servlet:


ClienteLocal.java:

package servlet; import ejb.CalculadoraLocal; import java.io.*; import javax.ejb.EJB; import javax.servlet.*; import javax.servlet.http.*; public class ClienteLocal extends HttpServlet { @EJB private CalculadoraLocal cl; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { out.println("2+3="+cl.sumar(2.0, 3.0)); } finally { out.close(); } } }

y ahora analicemos todo lo anterior: Los interfaces local y remoto mantienen los mtodos accesib les de manera local o remota, entendiendo que un cliente remoto es aquel que se encuentra en otra mquina virtual de java diferente y que debe de usar obligatoriamente sockets para conectar con el ejb. Un cliente local es aquel que se ejecuta en la misma mquina virtual que el ejb, pero esto slo es posible si el cliente se encuentra dentro de una aplicacin web, o de ejb, que est dentro del mismo ear en el que se encuentra situado el ejb. Estos interfaces no tienen porque compartir los mtodos, e incluso se recomienda que no compartan ningn mtodo. Se diferencian simplemente en el uso de la anotacin @Local y @Remote y no es obligatorio disponer de ambos.

Ref.Mamual EJB 3.0.

rea de Formacin
La clase del bean debe de implementar los mtodos de los interfaces Local y Remote si estos existen. Tambin es necesario utilizar las anotaciones @Stateless y @Statefull para indicar si se trata de un bean sin estado o con estado, respectivamente. Tambin vemos el uso de la inyeccin de valores en la declaracin de la variable ctx (no es obligatoria ):
@Resource private SessionContext ctx;

Esta variable es el nexo de unin del ejb con el servidor de aplicaciones, ofreciendo diversos servicios, entre ellos seguridad, transacciones, etc... La especificacin de ejb 3.0 permite el uso de clientes remotos clsicos (similares a ejb 2.1):
InitialContext ctx = new InitialContext(); CalculadoraRemote cr = (CalculadoraRemote) ctx.lookup(CalculadoraRemote.class.getName()); System.out.println("2+3="+cr.sumar(2.0, 3.0));

en el cul vemos que obtenemos el InitialContext que representa al servicio de nombrado (hay que agregar ciertos jar al classpath del proyecto para que conecte correctamente, dependen de cada servidor de aplicaciones). Despus empleamos el mtodo lookup para buscar al ejb por nombre, en este caso, usando glassfish, a ejb.CalculadoraRemote que lo obtenemos de CalculadoraRemote.class.getName(). El criterio de nombrado usado por sun dice que el bean se publica usando el nombre del interfaz. Y tambin podemos usar un cliente que utiliza el nuevo sistema de inyeccin de referencias:
@EJB private static CalculadoraRemote cr; public static void main(String[] args) throws RemoteException { System.out.println("2+3="+cr.suma(2.0, 3.0)); }

en el que vemos el uso de la anotacin @EJB para inyectar en la referencia cr una referencia al objeto CalculadoraRemote, es decir se encarga automticamente de realizar el lookup en el servicio de nombrado y de guardar esa referencia obtenida en cr. Lo malo es que no funciona en un cliente java normal, precisa de un cliente lanzado con webstart, por ello se suele crear un cliente webstart que se sube dentro del propio ear, de esta manera se puede acceder a l desde un navegador que tenga soporte java habilitado y permita la ejecucin de clientes webstart. Es muy tpico ejecutar el cdigo desde una aplicacin java, que no sea webstart, se puede usar un enfoque mixto:

Ref.Mamual EJB 3.0.

rea de Formacin
@EJB private static CalculadoraRemote cr; public static void main(String[] args) throws RemoteException { if(cr==null){ Context ctx = new InitialContext(); cr=(CalculadoraRemote) ctx.lookup(CalculadoraRemote.class.getName()); } System.out.println("2+3="+cr.suma(2.0, 3.0)); }

de esta manera, si no funciona la inyeccin, utilizar el sistema clsico de acceso al servicio de nombrado. En el servlet mostrado anteriormente tambin se usa la inyeccin para crear la referencia al ejb. Cuando un cliente localiza en el servicio de nombrado a un bean de sesin (no afecta si es cliente local o remoto), detrs de las bambalinas el servidor de aplicaciones es el encargado de detectar si el ejb es con estado o sin l, para retornar un nuevo objeto para el cliente, o el mismo objeto que retorna al resto de clientes, respectivamente. Es posible usar en los beans de sesin un constructor y un destructor, generalmente para obtener y liberar los recursos necesarios para el funcionamiento del bean. En caso de emplearlos, bastar con anotar dos mtodos con @PostConstruct y @PreDestroy dentro de la clase del bean.
@PostConstruct public void constructor(){ System.out.println("Obtencin de recursos"); } @PreDestroy public void destructor(){ System.out.println("Liberacin de recursos"); }

El ciclo de vida de un bean de sesin sin estado es el siguiente: No existe Class.newInstance() Inyecciones @PostConstruct

@PreDestroy

Listo para atender llamadas Mtodos de la lgica de negocio 10

Ref.Mamual EJB 3.0.

rea de Formacin
Podemos ver que se crea una nueva instancia al ser necesario por primera vez, justo en ese momento se realizan las inyecciones en las variables dentro del bean y se invoca a @PostConstruct para notificarnos que ya est construido y que podemos obtener los recursos necesarios para el funcionamiento del bean. Mientras que se encuentra dentro del estado Listo para atender llamadas responder a las llamadas a los mtodos de la lgica de negocio. Cuando se libere al objeto, por no ser necesario, o al detenerse la aplicacin, se invocar a @PreDestroy. Si trabajamos con un bean de sesin con estado su ciclo de vida es: No existe

timeout timeout

@PreDestroy

Class.newInstance() Inyecciones @PostConstruct

Listo para atender llamadas @PostActivate Mtodos de la lgica de negocio

Pasivado @PrePassivate

Como vemos, es el mismo que para un bean de sesin sin estado, pero aparece el concepto de pasivacin. Para poder atender a todos los clientes de un bean de sesin con estado necesitamos un objeto por cada cliente, pero no siempre es posible contar con la memoria necesaria para tener todos esos objetos. Los servidores recurren al uso de un pool de objetos, donde un objeto puede ser usado para atender varios clientes y un cliente puede usar varios objetos durante su trabajo, es muy importante tener claro que de cara al cliente es como si slo hubiese un objeto que le atiende en exclusiva, aunque detrs del teln existan intercambios de objetos entre clientes. La manera de conseguirlo es asignar al cliente un objeto, que almacena los atributos correspondientes a ese cliente. Mientras se ejecuta la invocacin de un mtodo de la lgica de negocio por parte del cliente el objeto permanece asignado a dicho cliente. Cuando no se est ejecutando un mtodo sobre el objeto, se pueden copiar a disco los valores de los atributos del cliente, dejando de esta manera el objeto libre para ser asignado a otro cliente. En un futuro, cuando el cliente reclame su objeto para invocar a un mtodo lo que se hace es asignarle un objeto (el mismo u otro libre) y copiar en l los valores almacenados en disco.

Ref.Mamual EJB 3.0.

11

rea de Formacin
El servidor decide si es necesario o no realizar ese mecanismo de intercambios, en funcin del tamao del pool de objetos y del nmero de clientes que quieren utilizarlos. Es decir se realiza un mecanismo de swap, para simular con pocos objetos que existen muchos ms y poder atender de esta manera un mayor nmero de clientes. @PrePassivate y @PostActivate son las anotaciones empleadas para indicar los mtodos, no es obligatorio que existan, que se invocarn antes de entrar en la pasivacin y al regresar al estadio de listo. Su misin es permitirnos liberar los recursos antes de pasivar y obtenerlos a la vuelta, para que el bean se encuentre con los valores adecuados para su funcionamiento. Como se aprecia en el diagrama del ciclo de vida, existe tambin el concepto de timeout, que nos indica que transcurrido un periodo de tiempo sin que el cliente interaccione con el objeto, este debe de ser liberado para poder atender a otros clientes, perdindose los valores de los atributos del cliente.

5. Seguridad
Para el apartado de seguridad, asumiremos que en el servidor de aplicaciones se han definido los usuarios y los grupos a los que pertenecen, al igual que se asume que en el fichero xml de configuracin especfico a nuestro servidor, que se encuentra dentro del proyecto de ejb, hemos mapeado los nombres de rol que usaremos a dichos grupos. Por una parte tenemos la autenticacin, que es la forma en la que especificamos el usuario y la clave desde la parte del cliente. La forma de hacerlo, compatible con ejb 2.1, es pasar esos dos datos al contexto del servicio de nombrado, para que l lo propague al servidor cuando usemos el servicio de nombrado para localizar a un recurso:
Properties props = new Properties(); props.put(Context.SECURITY_PRINCIPAL,usuario); props.put(Context.SECURITY_CREDENTIALS,clave); Context ctx = new InitialContext(props);

La otra opcin al usar un cliente de la versin 3.0, es que nos aparecer una ventana para introducir usuario y clave. Si no queremos que aparezca la ventana, podemos usar una clase (consultar documentacin del servidor para comprobar cual es) que permita especificar usuario y clave mediante cdigo:
public class Main { @EJB private static sinestado.CalculadoraSinEstadoRemote calculadoraBeanSinEstado;

public static void main(String[] args) throws NamingException, Exception { ProgrammaticLogin programmaticLogin = new ProgrammaticLogin();
Ref.Mamual EJB 3.0.

12

rea de Formacin
programmaticLogin.login("bueno", "bueno","file", false); if(calculadoraBeanSinEstado==null){ InitialContext ctx = new InitialContext(); calculadoraBeanSinEstado=(sinestado.CalculadoraSinEstadoRemote)ctx.lookup(sinestado.CalculadoraS inEstadoRemote.class.getName()); } System.out.println("Suma sin estado: "+calculadoraBeanSinEstado.suma(1.1f, 2.2f)); } }

Por otro lado debemos de asignar los permisos a nuestro cdigo, siempre teniendo en cuenta que se lleva a cabo a nivel de rol, para ello contaremos con algunas anotaciones (paquete javax.annotation.security): @RolesAllowed: Declara una lista de roles que pueden ejecutar. @PermitAll: Permite acceso libre, es valor por defecto si no se pone nada. @DenyAll: Deniega el acceso a todos los usuarios, independiente de su rol. Estas anotaciones se pueden emplear a nivel de clase, afectando a todos los mtodos, o a nivel de mtodo. Siempre tiene prioridad la anotacin de un mtodo frente a la de la clase. Veamos un ejemplo:
@Stateless @RolesAllowed("rolMantenimiento") public class CalculadoraSinEstadoBean implements CalculadoraSinEstadoRemote, CalculadoraSinEstadoLocal { @RolesAllowed("rolUsuario") public float suma(float operando1, float operando2) { return operando1+operando2; } @RolesAllowed({"rolProducto",rolAdmin}) public float resta(float operando1, float operando2) { return operando1-operando2; } @DenyAll public float producto(float operando1, float operando2) { return operando1*operando2; } @PermitAll public float division(float operando1, float operando2) {
Ref.Mamual EJB 3.0.

13

rea de Formacin
return operando1/operando2; }

Cuando un ejb/servlet se convierte en un cliente que accede a otro ejb, pueden darse dos casos, que propague su identidad al ejb accedido (comportamiento por defecto) o que pase una identidad constante, diferente de la del cliente que le invoca a l mismo. Lo lograremos usando la anotacin @RunAs.
@Stateless @RunAs("miRol") public class CalculadoraSinEstadoBean implements CalculadoraSinEstadoRemote, CalculadoraSinEstadoLocal {

Tambin, es posible comprobar en el cdigo de los mtodos del ejb/servlet si el usuario est dentro de un determinado rol, para ejecutar cdigo java distinto en funcin del rol del usuario:
@RolesAllowed({"rolBueno","rolMalo"}) public float resta(float operando1, float operando2) { Principal llamante = ctx.getCallerPrincipal(); if(ctx.isCallerInRole("rolMalo")){ if(llamante.getName().equals("tecnico01")){ throw new EJBException("No se permite al usuario: tecnico01"); } } return operando1-operando2; }

para que funcione isCallerInRole, es necesario anotar la clase del ejb con @DeclareRoles que indica:
@Stateless @DeclareRoles("rolMalo") public class CalculadoraSinEstadoBean implements CalculadoraSinEstadoRemote, CalculadoraSinEstadoLocal {

que indica sobre que roles vamos a emplear la funcin isCallerInRole.

Ref.Mamual EJB 3.0.

14

rea de Formacin

6. Transacciones en beans de sesin


El mecanismo de transacciones que ofrece ejb 3.0 es el mismo que en ejb 2.1, pero utilizando anotaciones en lugar de emplear configuracin en fichero xml. El mecanismo configura a nivel de mtodo si este precisa, o no, de una transaccin para ser ejecutado dentro de ella. Si el mtodo lanza excepcin y estaba dentro de una transaccin se producir un rollback de ella. Para configurar un mtodo usaremos la anotacin @TransactionAttribute, en la que indicaremos el tipo de atributo de entre los siguientes: MANDATORY: Es obligatorio que el mtodo se invoque desde un llamante que proporcione una transaccin abierta, si no es as lanzar una excepcin. REQUIRED: Es obligatorio que el mtodo se invoque dentro de una transaccin, si el llamante no la proporciona se crea una nueva para ejecutar el mtodo en su interior. Adems es el valor predeterminado si no se indica nada en contra. REQUIRES_NEW: Siempre crea una transaccin para ejecutar el mtodo, si el llamante proporciona una transaccin se pondr en pausa hasta acabar la ejecucin de este mtodo. SUPPORTS: Si el llamante proporciona una transaccin ser usada por el mtodo, pero si no la proporciona no pasa nada. NOT_SUPPORTED: Aunque el llamante proporcione la transaccin, no ser utilizada. NEVER: Es obligatorio que el mtodo se invoque desde un llamante que no proporcione una transaccin abierta, si no es as lanzar una excepcin. Veamos un ejemplo:
@TransactionAttribute(TransactionAttributeType.NEVER) public float division(float operando1, float operando2) { return operando1+operando2; }

en el que obligamos a que no se llame al mtodo dentro de una transaccin. Cuando un fragmento de cdigo java invoca a un mtodo de un ejb de manera remota el servidor de aplicaciones comprueba que atributo de transaccin tiene el mtodo. Si es necesario (si es REQUIRED o REQUIRES_NEW) crea una transaccin y hace el begin, despus invoca al mtodo dentro de un try/catch. Si no se producen errores realiza un commit() de la transaccin, pero si hay excepciones lanzadas por el mtodo, invoca al rollback(). Esto es importante, dado que si usamos bean de entidad dentro del mtodo, llevar implcita un commit o rollback de la base de datos. Si el mtodo invoca a otro mtodo del mismo bean directamente, no se tiene en cuenta el atributo de transaccin de este segundo mtodo, y se invoca como un mtodo java normal. En cambio, si se invoca a otro mtodo de otro ejb del mismo proyecto, se propagar la transaccin (si existe) y este segundo mtodo se ejecutar dentro de ella. Por supuesto se tendr en cuenta el atributo de transaccin de este segundo mtodo.

Ref.Mamual EJB 3.0.

15

rea de Formacin

7. Beans de entidad
Los beans de entidad son la solucin al problema ms tpico de la programacin en java, permiten guardar los objetos java en una base de datos relacional, con soporte incluso de consultas. En las versiones anteriores de ejb, se trataban de objetos iguales a los bean de sesin pero con la caracterstica que lo que le ocurra al bean(borrado, modificacin,etc...) le ocurra al registro asociado. En la versin actual de ejb, se ha optado por que no sean objetos similares a los de sesin, es decir, no se pueden invocar de menera remota ni local. En parte es lgico, esto permite usar a los bean de sesin como fachada que acceda a los bean de entidad, as se evitan los problemas de seguridad por permitir a los clientes remotos acceso libre a la base de datos a travs de los bean de entidad. El mecanismo por el que se ha optado es idntico al usado por hibernate, objetos POJO que mediante cdigo auxiliar se transforman en registros en base de datos. POJO (Plain Old Java Objects) simplemente indica que son bean, pero no enterprise java bean. Hibernate empleaba ficheros xml para configurar el mapeo de objeto a registro, despus permiti el uso de anotaciones para configurarlo y esa es la forma que ha adoptado ejb 3.0. Se ha construido el api JPA (Java Persistence API, paquete javax.persistence) en el que se define la existencia del EntityManager, responsable de llevar a cabo los mapeos de objeto a registro y viceversa. El api JPA adems permite el uso de los bean de entidad fuera de un servidor de aplicaciones, de esta manera podemos utilizar los bean de entidad con jsf, por ejemplo, o en una aplicacin swing. Un entity bean podra ser similar a este:
@Entity @Table(name = "cliente") public class Cliente implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY)

@Column(name = "id", nullable = false) private Integer id;

@Column(name = "nombre", length = 255) private String nombre;

@Column(name = "activo") private Boolean activo;

Ref.Mamual EJB 3.0.

16

rea de Formacin
public Cliente() { } public Cliente(Integer id) { this.id = id; } public Integer getId() { return id; }

public void setId(Integer id) { this.id = id; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public Boolean getActivo() { return activo;} public void setActivo(Boolean activo) { this.activo = activo; } }

Podemos ver el uso de la anotacin @Entity que declara que esta es una clase de tipo entidad, el uso de @Table para declarar el nombre de la tabla relacionada en la base de datos. El bean tiene propiedades, y en las que nos interesa mapearlas a base de datos hemos colocado la anotacin @Column que declara el nombre del campo relacionado y sus caractersticas(admite nulos, precisiones, tipo de la columna). Un inciso, se puede generar la estructura de la base de datos a partir de toda esta informacin, util al desplegar la aplicacin por primera vez, Tambin aparece @Id para marcar los atributos que forman parte de la clave primaria, y @GeneratedValue para indicar como se generar el valor de la clave primaria. Si ejecutamos este cdigo:
Cliente c = new Cliente(12);

no hemos creado ningn registro, tan slo tenemos un objeto java, es necesario pasarle este objeto al EntityManager para que este lo tenga en cuenta:
EntityManager em = em.persist(c);

esto nos lleva a tener en cuenta que un objeto java puede estar en dos estados: gestionado o sin gestionar por el EntityManager. Para obtener el EntityManager es necesario disponer de una unidad de persistencia, es un fichero persistence.xml que describe a que base de datos nos conectaremos y ms informacin necesaria:

<?xml version="1.0" encoding="UTF-8"?> <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> <persistence-unit name="EJB3-ejbPU" transaction-type="JTA"> <jta-data-source>jdbc/mensajeria</jta-data-source> <class>entidad.Campaa</class> <class>entidad.Cliente</class> <class>entidad.GrupoUsuario</class>
Ref.Mamual EJB 3.0.

17

rea de Formacin
<class>entidad.Mensaje</class> <class>entidad.Receptor</class> <class>entidad.Usuario</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="toplink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>

podemos ver que describe el nombre de la unidad de persistencia EJB3-ejbPU necesario para poder usarla. Declara que jdbc/mensajeria es el nombre jndi del pool de conexiones que empler y mediante la etiqueta class declara que clases de tipo entidad gestionar. Dentro de properties declara propiedades que utilizar el proveedor de persistencia utilizado (no es sun quien proporciona el cdigo, slo proporciona la especificacin del api), en este caso declara que al ejecutar el cdigo, el EntityManager debe de hacer drop de las tablas y volver a crearlas. Para obtener el EntityManager hay que tener en cuenta desde donde ejecutamos, una aplicacin J2SE o J2EE. Si es J2SE el cdigo ser similar a este:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("EJB3-ejbPU"); EntityManager em = emf.createEntityManager();

y si es J2EE bastar con usar inyeccin:


@PersistenceContext(unitName=EJB3-ejbPU) EntityManager em;

Veamos las operaciones que podemos realizar con un EntityManager: persist() es el hecho de guardar en bases de datos una entidad (objeto java) que no haba sido guardada previamente:
Cliente c = new Cliente(); c.setNombre(Exes); em.persist(c);

cuando es invocado, se almacena en la lista de operaciones pendientes y el objeto c se convierte en gestionado por el EntityManager. Si es invocada dentro de una transaccin puede ser realizado el insert into inmediatamente, o esperar al fin de la transaccin, dependiendo del modo flush empleado
Ref.Mamual EJB 3.0.

18

rea de Formacin
(ya hablaremos de ello ms adelante). Se puede forzar a que sea inmediato llamando a flush(). find() y getReference() permiten buscar un objeto a travs de su clave primaria:
Cliente c = em.find(Cliente.class,12); Cliente c2 = em.getReference(Cliente.class,12);

ambas reciben la clase del bean a encontrar en la base de datos y la clave primaria buscada. La diferencia es que find retorna null si no encuentra el registro y getReference lanza EntityNotFoundException si no lo encuentra. El objeto retornado se encuentra gestionado por el EntityManager. Consultas podemos llevar a cabo consultas:
Query consulta = em.createQuery(select c from Cliente where id=2); Cliente hallado = (Cliente)consulta.getSingleResult();

o declaralas con anotaciones en la clase del bean:


@NamedQueries( { @NamedQuery(name = "Cliente.findAll", query = "SELECT c FROM Cliente c"), @NamedQuery(name = "Cliente.findById", query = "SELECT c FROM Cliente c WHERE c.id = :id"), @NamedQuery(name = "Cliente.findByNombre", query = "SELECT c FROM Cliente c WHERE c.nombre = :nombre"), @NamedQuery(name = "Cliente.findByActivo", query = "SELECT c FROM Cliente c WHERE c.activo = :activo")}) public class Cliente implements Serializable { ...

y usarlas:
Cliente hallado = (Cliente) em.createNamedQuery("Cliente.findByNombre").setParameter("nombre", "Jose").getSingleResult();

Actualizando entidades cuando disponemos de una entidad gestionada por el EntityManager, podemos modificar sus valores simplemente usando sus mtodos set. Cuando el EntityManager considere (depende del modo flush) que hay que sincronizar la base de datos con el objeto realizar el update en la bd. Se puede forzar invocando al mtodo flush(). Si el EntityManager no gestiona al bean, no tendr en cuenta los cambios realizados sobre l, en ese caso si queremos guardarlos en la bd debemos de usar merge(), ver el punto siguiente.

Ref.Mamual EJB 3.0.

19

rea de Formacin
Mezclando entidades si disponemos de un objeto del tipo entidad, pero que no se encuentre gestionado por el EntityManager, sus cambios no se reflejarn en la base de datos, para conseguirlo disponemos de merge():
public void guardar(Cliente c){ Cliente gestionado = em.merge(c); }

este mtodo merge busca en el EntityManager si ya tienen una entidad con el mismo id gestionada por si mismo. Si la encuentra copiar los datos del parmetro sobre la entidad gestionada y la retornar, si no la encuentra crear una nueva entidad gestionada, la copiar los valores y la retornar. Eliminando entidades podemos emplear remove para eliminar entidades gestionadas por el EntityManager:
public void guardar(Cliente c){ Cliente gestionado = em.merge(c); em.remove(gestionado); // Slo podemos eliminar entidades gestionadas }

cuando se invoca remove, la entidad deja de estar gestionada y se programa para ser eliminada en la lista de operaciones pendientes, recordemos que cuando el Ent ityManager considere oportuno, o forcemos llamando a flush() se ejecutar el borrado. Hay que tener en cuenta que si se han definido las reglas de integridad referencial, puede conllevar el borrado de otras entidades asociadas. Refrescando entidades hay veces que interesa recargar los datos desde la bd, para ello podemos utilizar refresh:
Cliente gestionado = gestionado.setNombre(Paco); em.refresh(gestionado);

contains() y clear() podemos emplear contains, pasandole como parmetro una entidad para saber si se encuentra gestionada por el EntityManager o no. Tambin podemos usar clear() para conseguir que el EntityManager no tenga a ninguna entidad gestionada, pero hay que tener claro que si hay cambios pendientes de volcarse a base de datos se perdern, por eso se suele llamar a flush() antes que a clear(). Flush() y FlushModeType Al invocar a persist(), merge() o remove() los cambios se llevan a cabo cuando el EntityManager lo considere oportuno, a menos que invoquemos a flush() expresamente.

Ref.Mamual EJB 3.0.

20

rea de Formacin
El EntityManager considera que es oportuno llevar a cabo los cambios cuando se realiza un comit de la transaccin, o bien cuando se ejecuta una consulta que trabaje sobre las entidades pendientes de llevar a cabo sus acciones. Podemos alterar este comportamiento invocando setFlushMode() sobre el EntityManager, hay dos valores AUTO y COMMIT definidos en javax.persistence.FlushModeType, auto es el comportamiento comentado, y COMMIT fuerza a que slo se actualice justo antes del commit de la transaccin. Acceso a la transaccin Si trabajamos con J2EE es el servidor de aplicaciones el responsable de gestionar las transacciones, de realizar el commit o rollback, pero si trabajamos con J2SE seremos nosotros quienes lo gestionemos:
Cliente c = ... EntityTransaction et = em.getTransaction(); et.begin(); //Hay que iniciarla explcitamente try{ em.persist(c); et.commit(); }catch(Exception ex){ et.rollback(); }

7.1. Mapeando objetos


Con ejb 3.0 ya no se utiliza ficheros xml para declarar el mapeo de de las entidades a base de datos, sino que usaremos anotaciones (paquete javax.persistence ) sobre la propia clase java. Todos los beans deben de marcar su clase con @Entity, para que sea reconocido como tal por el EntityManager. Tambin es habitual utilizar @Table para declarar el nombre de la tabla asociada:
@Entity @Table(name = "cliente") public class Cliente implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false)

private Integer id;

@Column(name = "nombre", length = 255) private String nombre;

Ref.Mamual EJB 3.0.

21

rea de Formacin
@Column(name = "activo") private Boolean activo;

public Cliente() { } public Cliente(Integer id) { this.id = id; } public Integer getId() { return id; }

public void setId(Integer id) { this.id = id; } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public Boolean getActivo() { return activo;} public void setActivo(Boolean activo) { this.activo = activo; } }

si no se usa el nombre de la tabla sera el nombre de la clase, Cliente en este caso. Cada campo que queramos mapear debemos de indicarlo mediante @Column que se define como:
public @interface Column { String name() defaults ""; int length() defaults 255; String table() defaults ""; int scale() defaults 0; String columnDefinition() defaults ""; boolean insertable() defaults true; boolean nullable() defaults true; int precision() defaults 0; boolean unique() defaults false; boolean updatable() defaults true; }

vemos que ofrece la posibilidad de configurar cualquier detalle relativo a propiedades de una columna del modelo relacional,por ejemplo:
@Column(name=fechaNacimiento,nullable=false,updateble=false,columDefinition=DATE)

Adems las columnas que formen parte de la clave primaria (siempre existe clave primaria, de otra forma la tabla no puede ser gestionada por el EntityManager) sern marcadas por @Id. Generadores de claves Podemos tener claves primarias gestionadas por nosotros mismos asignando los valores en el bean, pero en muchas ocasiones es preferible contar con un generador de claves primarias, para ello agregaremos @GeneratedValue en los campos marcados con @Id. Existen (segn el gestor de bases

Ref.Mamual EJB 3.0.

22

rea de Formacin
de datos) tres tipos de generadores, basados en tabla, en secuencias o en campos autonumricos, nosotros podemos elegir con alguna de las siguientes cuatro variantes:
@GeneratedValue(strategy=GenerationTable.AUTO) ---------@GeneratedValue(strategy=GenerationTable.IDENTITY) ---------@TableGenerator(name=miGenerador , table=GENERATOR_TABLE, pkColumnName=PRIMARY_KEY_COLUMN, valueColumnName=VALUE_COLUMN , pkColumnValue=CUST_ID , allocationSize=10) @GeneratedValue(strategy=GenerationTable.TABLE,generator=miGenerador) ---------@SecuenceGenerator(name=MI_SECUENCIA , sequenceName=CUST_SEQ) @GeneratedValue(strategy=GenerationTable.SECUENCE,generator=MI_SECUENCIA)

auto deja en manos del sistema gestor de bases de datos la generacin del valor. Identity indica que utilice un campo especial, el autonumrico. En el caso de usar TABLE, hay que disponer de la tabla indicada por table:
create table GENERATOR_TABLE( PRIMARY_KEY_COLUMN VARCHAR not NULL, VALUE_COLUMN long not null );

table, pkColumnName y valueColumnName hacen alusin a esta tabla y sus campos, pkColumnValue indica el nombre del campo que es la clave primaria en la entidad para la que estamos generando los valores de la clave. Y allocationSize es el valor en el que se incrementa la clave. En el caso de las secuencias, hay que indicar en sequenceName el nombre de la secuencia que se crear en la base de datos y name es un nombre lgico usado para asociarla con el @GeneratedValue correspondiente. Claves compuestas Es posible que la clave primaria no sea un nico campo, sino que est formado por varios, en ese caso debemos de marcar la clase con la anotacin @IdClass:
@IdClass(UsuarioPK.class) public class Usuario{

@Id private String codigoA; @Id private String codigoB; ...


Ref.Mamual EJB 3.0.

23

rea de Formacin
apuntado a la clase que almacenar los valores de las distintas columnas que forman la clave primaria:
public class UsuarioPK implements java.io.Serializable{ //No mostramos los get y set de codigoA y codigoB, pero son obligatorios. private String codigoA; private String codigoB; //Tampoco mostramos la sobreescritura de equals, hashCode y toString, pero son necesarios. ... }

estas columnas estn marcadas en la entidad con @Id. La clase que almacena la clave primaria debe de ser Serializable, tener un constructor publico sin argumentos e implementar equals y hashCode. No se permiten campos autogenerados en claves compuestas. Para utilizarla en busquedas, hay que trabajar con la clave compuesta:
UsuarioPK clave = new UsuarioPK(); clave.setCodigoA(12); clave.setCodigoB(34); Usuario hallado = entityManager.find(Usuario.class,clave);

Mapeo de las propiedades Podemos alterar la manera en la que se mapean las propiedades usando las siguientes anotaciones: @Transient : Al preceder un atributo indica que no ser persistido en bases de datos, la norma es que todos los atributos lo sern, excepto si usamos @Transient. @Basic: es la anotacin por defecto para los atributos basicos de tipo: String, byte[], Byte[], char[], Char[], Character[], java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, jav.sql.Time y java.sql.Timestamp. Slo se suele poner para alterar el atributo fetch:
... @Basic(fetch=FetchType.LAZY, optional=false) private String nombre;

fetch permite que el motor optimice las consultas trayendo menos datos en la consulta de la entidad, y trayendo posteriormente los datos que le falten en el momento de usar la entidad.

FetchType.EAGER indica que se traiga el valor en la consula y FetchType.LAZY indica que no se lo traiga hasta que realmente sea accedido el campo. El atributo optional se usa en la generacin de tabla a partir de la entidad, indica si el campo es admite nulos o no. @Temporal: se usa para indicar como se mapea el campo de tipo fecha, si como Time, Date o Timestamp:
Ref.Mamual EJB 3.0.

24

rea de Formacin
@Temporal(TemporalType.DATE) private Date fechaNacimiento;

los valores permitidos son:


TemporalType.DATE, TemporalType.TIME o TemporalType.TIMESTAMP

@Lob: Indica que el campo se mapear como un campo de tipo BLOB o CLOB, el tipo final ser: - Blob: si es de tipo byte[], Byte[] o java.io.Serializable - Clob: si es de tipo char[], Char[], Character[] o String Es muy tpico que se use junto con @Basic(FetchType.LAZY) por el ahorro en el acceso. @Enumerated: Indica que tenemos una enumeracin java, por ejemplo:
public enum Estatura{ ALTO,BAJO } public class Persona{ @Enumerated(EnumType.STRING) private Estatura altura; ...

Se puede almacenar en la base de datos el valor numrico de la constante o su representacin en String, mediante EnumType.ORDINAL (valor por defecto) o con EnumType.STRING, respectivamente. Entidades en varias tablas Es frecuente tener entidades divididas en dos, o ms, tablas, por ejemplo un estudiante puede tener sus datos personales en la tabla persona y sus datos de estudiante en la tabla estudiante. Existir un registro de persona relacionado con un registro de estudiante:
TABLA Persona: create table Persona( id_persona integer, NIF varchar(255) primary key, nombre varchar(255), ... );

TABLA Estudiante: create table Estudiante( id_estudiante integer, CodigoEstudiante varchar(255) primary key, aoEntrada integer, ...
Ref.Mamual EJB 3.0.

25

rea de Formacin
);

Clase Estudiante: @Table(name=Estudiante) @SecondaryTable( name=Persona, pkJoinColumns={ @PrimaryKeyJoinColumn(name=id_persona) } ) public class Estudiante{ @Column(name=CodigoEstudiante) private String codigoEstudiante; @Column(name=NIF,table=Persona) private String nif; ...

@SecondaryTable declara mediante name cul es la tabla relacionada, Persona en este caso. pkJoinColumns declara cules son las columnas que establecen las relaciones entre ambas tablas, vemos que id_persona es la clave ajena en Persona y que apunta a la clave primaria de estudiante. Se puede apuntar a otro campo usando referencedColumnName:
@SecondaryTable( name=Persona, pkJoinColumns={ @PrimaryKeyJoinColumn(name=id_persona, referencedColumnName=id_estudiante) } )

Este tipo de relacin implica una relacin uno a uno entre ambas tablas. Es posible tener varias tablas relacionadas:
@SecondaryTables({ @SecondaryTable( name=tabla1, pkJoinColumns={ @PrimaryKeyJoinColumn(name=id_tabla1)

} ) , @SecondaryTable( name=tabla2, pkJoinColumns={ @PrimaryKeyJoinColumn(name=id_tabla2)


Ref.Mamual EJB 3.0.

26

rea de Formacin
} ) } )

7.2. Relaciones entre entidades


Al igual que en el modelo relacional, las entidades java (o simplemente entre objetos java), existen relaciones de tres tipos: 1:1, 1:N o N:M. En cada una de ellas podemos hablar de si son unidireccionales o bidireccionales (si a partir de un objeto podemos localizar al/los otro/s objeto/s relacionados o no). Aqu tenemos algunos casos para entender las posteriores explicaciones:

Aqu tenemos las posibles relaciones y como mapearlas: Relacin 1:1 Una relacin como la de Pedido con Factura, en la que un Pedido genera una nica Factura, y una Factura es generada desde un nico Pedido. Se suele implementar con una clave ajena en una de las entidades que apunta a la clave primaria de la otra entidad. Generalmente en programacin orientada a objetos, y por tanto para java y entidades se representa mediante una propiedad del tipo contrario, es decir en Factura habr una propiedad de tipo Pedido y en Pedido una Propiedad de tipo Factura. Esto sera una relacin de uno a uno bidireccional, si la queremos unidireccional basta con eliminar la propiedad no necesaria.

Ref.Mamual EJB 3.0.

27

rea de Formacin
Veamos como lo representamos en entidades:
En entidad Pedido: @OneToOne(cascade={CascadeType.ALL}) @JoinColumn(name=ID_FACTURA) private Factura factura; public Factura getFactura(){ return Factura;} public void setFactura(Factura f){ factura=f;} En entidad Factura: @OneToOne(mappedBy=factura) private Pedido pedido; public Pedido getPedido(){ return Pedido;} public void setPedido(Pedido p){ pedido=p;} Y un ejemplo de uso: Pedido p = new Pedido(); entityManager.persist(p); Factura f= new Factura(); entityManager.persist(f); p.setFactura(f);

La anotacin @OneToOne declara que hay una relacin de 1:1 de pedido a factura y que pedido es la propietaria (inicio) de la relacin. @JoinColumn declara cual es la columna de la tabla de Pedido que es la clave ajena que apunta a la clave primaria de Factura. Veamos algo acerca de @JoinColumn:
public @interface JoinColumn { String name() defaults ""; String table() defaults ""; String columnDefinition() defaults ""; boolean insertable() defaults true; boolean nullable() defaults true; String referencedColumnName() defaults ""; boolean unique() defaults false; boolean updatable() defaults true; }

Ref.Mamual EJB 3.0.

28

rea de Formacin
name declara la columna, table declara en que tabla se encuentra. referencedColumnName indica el nombre de la columna de la entidad relacionada que es la clave primaria. Si la clave primaria es compuesta, necesitaremos usar @JoinColumns que permite emplear un array de @JoinColumn. Hablemos un poco acerca de @OneToOne
public @interface OneToOne { CascadeType[] cascade() defaults {}; FetchType fetch() defaults EAGER; String mappedBy() defaults ""; boolean optional() defaults true; Class targetEntity() defaults void; }

targetEntity contiene la clase de la entidad relacio nada, no se suele asignar porque automticamente toma el valor del tipo de la propiedad a la que acompaa. fetch indica si la carga de los objetos relacionados ser temporana EAGER o tarda LAZY. En el caso de factura vemos el uso de mappedBy, indica que la propiedad a la que acompaa forma parte de una relacin bidireccional, y que sus caractersticas se sacaran a partir de la propiedad de la otra entidad indicada por mappedBy. Relacin 1:N Una relacin de 1 a N como la que existe entre Cliente y Pedido, es una relacin que en modelo relacional se construye colocando una clave ajena en la entidad de multiplicidad N para apuntar a la clave primaria de la entidad de multiplicidad 1. Veamos en entidades como sera:
En entidad Cliente: @OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name=ID_CLIENTE) private Set<Pedido> pedidos; public Set<Pedido> getPedidos(){ return pedidos;} public void setPedidos(Set<Pedido> p){ pedidos=p;} En entidad Pedido: @ManyToOne(mappedBy=pedidos) private Cliente cliente; public Cliente getCliente(){ return cliente;} public void setCliente(Cliente c){ cliente=c;} Y un ejemplo de uso: Pedido p = new Pedido();

Ref.Mamual EJB 3.0.

29

rea de Formacin
entityManager.persist(p); Cliente c = new Cliente(); entityManager.persist(c); c.getPedidos().add(p);

Vemos el uso de @OneToMany en Cliente para indicar que es el lado de multiplicidad 1 en la relacin, al igual que el @ManyToOne indica que Pedido es el de la multiplicidad N. @JoinColumn lo estamos empleando para indicar que la clave primaria de Cliente ser apuntada po r la clave ajena de Pedido, que es ID_CLIENTE. En modelo relacional tambin se puede implementar esta relacin con una tabla intermedia en la que cada registro contenga las claves primarias de las entidades relacionadas, esa es justo la solucin usada para las relaciones N:M (1:N es un caso particular de N:M), en nuestro caso podra ser as:
En entidad Cliente: @OneToMany(cascade={CascadeType.ALL}) @JoinTable(name=CLIENTE_PEDIDO, joinColumns={ @JoinColumn(ID_CLIENTE) } , inverseJoinColumns={ @JoinColumn(ID_PEDIDO) } ) private Set<Pedido> pedidos; public Set<Pedido> getPedidos(){ return pedidos;} public void setPedidos(Set<Pedido> p){ pedidos=p;} En entidad Pedido: @ManyToOne(mappedBy=pedidos) private Cliente cliente; public Cliente getCliente(){ return cliente;} public void setCliente(Cliente c){ cliente=c;} Y un ejemplo de uso: Pedido p = new Pedido(); entityManager.persist(p); Cliente c = new Cliente(); entityManager.persist(c); c.getPedidos().add(p);

La diferencia es el uso de @JoinTable para declarar el nombre de la tabla intermedia (CLIENTE_PEDIDO) y que joinColumns declara el campo (ID_CLIENTE), que ser la clave ajena que apunte a Cliente, en la tabla intermedia. inverseJoinColumns declara el campo (ID_PEDIDO), que ser la clave ajena que apunte a Pedido, en la tabla intermedia.

Ref.Mamual EJB 3.0.

30

rea de Formacin
En ambos casos, si queremos una relacin unidireccional bastar con eliminar la propiedad de Pedido junto con el @ManyToOne. Otro detalle a tener en cuenta es que la eliminacin de la relacin debe de realizarse desde la entidad propietaria de la relacin, es decir:
Pedido p = entityManager.find(Pedido.class,11); Cliente c = entityManager.find(Cliente.class,14); c.getPedidos().remove(p); // Correcto //p.setCliente(null); ERROR

Relacin N:M Una relacin de N a M, como la de Cliente y los Actos en los que interviene, se implementa en el modelo relacional con una tabla intermedia en la que cada registro contenga las claves primarias de las entidades relacionadas. En el caso de la s entidades podra ser similar a esto:
En entidad Cliente: @ManyToMany(cascade={CascadeType.ALL}) @JoinTable(name=CLIENTE_ACTO, joinColumns={ @JoinColumn(ID_CLIENTE) } , inverseJoinColumns={ @JoinColumn(ID_ACTO) } ) private Set<Acto> actos; public Set<Acto> getActos(){ return actos;} public void setActos(Set<Actos> a){ actos=a;} En entidad Acto: @ManyToMany(mappedBy=actos) private Set<Cliente> clientes; public Set<Cliente> getClientes(){ return clientes;} public void setClientes(Set<Cliente> c){ clientes=c;} Y un ejemplo de uso: Acto a = new Acto(); entityManager.persist(a); Cliente c = new Cliente(); entityManager.persist(c); c.getActos().add(a);

Como podemos ver la diferencia con respecto a la relacin de 1:N anterior es el uso de @ManyToMany en ambos lados de la relacin.

Ref.Mamual EJB 3.0.

31

rea de Formacin
Al igual que en la relacin 1:N hay que tener en cuenta que la eliminacin de la relacin debe de realizarse desde la entidad propietaria de la relacin, es decir:
Acto a = entityManager.find(Acto.class,11); Cliente c = entityManager.find(Cliente.class,14); c.getPedidos().remove(a); // Correcto //a.getClientes().remove(c); ERROR

Al igual que en los casos anteriores para tener una relacin unidireccional basta con eliminar la propiedad de relacin que hay en Acto. En las relaciones podemos emplear java.util.Set o java.util.Collection, pero tambin podemos emplea java.util.List (sobre todo si queremos ordenar) y java.util.Map (si queremos acceder a datos con estructura clave->Objeto). Veamos un ejemplo con List:
En entidad Cliente: @ManyToMany(cascade={CascadeType.ALL}) @OrderBy(fechaacto DESC) @JoinTable(name=CLIENTE_ACTO, joinColumns={ @JoinColumn(ID_CLIENTE) } , inverseJoinColumns={ @JoinColumn(ID_ACTO) } ) private List<Acto> actos; public List<Acto> getActos(){ return actos;} public void setActos(List<Actos> a){ actos=a;}

Es el mismo ejemplo de relacin N:M en el que hemos empleado List, para acceder a los elementos ordenados, y hemos anotado con @OrderBy para indicar los campos de Acto por los que ordenaremos. Se puede poner varios separados por coma y utilizar ASC o DESC para indicar el orden. Si no indicamos ningn campo, ordenar por la clave primaria. Veamos un ejemplo con Map:
En entidad Cliente: @ManyToMany(cascade={CascadeType.ALL}) @MapKey(name=titulo) @JoinTable(name=CLIENTE_ACTO, joinColumns={ @JoinColumn(ID_CLIENTE) } , inverseJoinColumns={ @JoinColumn(ID_ACTO) } ) private Map<String,Acto> actos;

public Map<String,Acto> getActos(){ return actos;}


Ref.Mamual EJB 3.0.

32

rea de Formacin
public void setActos(Map<String,Acto> a){ actos=a;}

lo que conseguimos es que se trabajar con un Map que contiene como clave el valor de la propiedad de la entidad no propietaria (en este caso Acto) indicada por @MapKey (titulo) y como valor el propio objeto Acto. Propagacin en cascada En las anotaciones @OneToOne, @OneToMany, @ManyToOne y @ManyToMany se puede usar cascade para indicar el tipo de propagacin en cascada, vamos a comentar sus posibilidades, por ello no lo hicimos anteriormente. Cascada se refiere a que sucede con las entidades relacionadas cuando realizamos una operacin sobre la entidad principal, para ello especificaremos en cascade uno o varios valores separados por coma: PERSIST: indica que al crear una entidad (funcin persist() del entity manager) se crearan en cascada las relacionadas MERGE: indica que al agrega una entidad no gestionada (funcin merge() del entity manager) al entity manager se actualizarn en cascada las relacionadas. REMOVE: indica que al eliminar una entidad (funcin remove() del entity manager) se borrarn en cascada las relacionadas REFRESH:indica que al refrescar una entidad (funcin refresh() del entity manager) se refrescaran en cascada las relacionadas. ALL: Es la suma de los anteriores valores. Podemos usar estos valores, para evitar por ejemplo que al borrar la entidad se borren las entidades relacionadas. Herencia entre entidades Al igual que existe la herencia entre clases java, tambin existe herencia entre las entidades persistidas. El api de persistencia nos permite tres posibilidades: Una tabla: Esta tabla contiene la unin de los campos de todas las clases relacionadas por herencia. Una tabla por cada clase: Cada clase derivada tendr una tabla propia con la unin de sus propiedades y las de la clase base. Una tabla por cada subclase: Cada clase derivada tendr una tabla propia nicamente con sus propiedades. Supongamos esta relacin de clases:

Ref.Mamual EJB 3.0.

33

rea de Formacin

y veamos las diferentes posibilidades: Una tabla Esta tabla est formada por la unin de los campos de las distintas clases ms un campo discriminador, que indica a que clase pertenece el registro. Veamos un ejemplo:
CLASE PERSONA: @Entity @Table(name=Persona_herencia) @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name=discriminador, discriminatorType=DiscriminatorType.STRING) @DiscriminatorValue(PERSONA) public class Persona{ @Id @GeneratedValue private int id; ... } CLASE POLICIA: @ENTITY @DiscriminatorValue(POLICIA) public class Policia extends Persona{ // No existe campo id, ya que est definido en persona. ... }

Ref.Mamual EJB 3.0.

34

rea de Formacin
@Inheritance define cul de las tres estrategias se va a usar, de entre los valores de @InheritanceType (SINGLE_TABLE, JOINED o TABLE_PER_CLASS). @DiscriminatorColumn declara el nombre de la columna que acta como discriminador entre clases, tambin indica el tipo de dicha columna mediante los valores de DiscriminatorType ( STRING, CHAR o INTEGER). Por ltimo vemos el valor usado para representar la clase Persona mediante el valor indicado por @DiscriminatorValue. En las clases derivadas como Policia vemos que no tiene atributo clave, dado que lo hereda de la clase base. Tambin vemos que tiene otro valor (POLICIA) indicado por @DiscriminatorValue. Este sistema tiene la ventaja de ser muy rpido en las consultas, pero exige que todas las columnas de las subclases admitan valores nulos y no es una tabla normalizada segn el modelo relacional. Una tabla por cada clase Existe una tabla por cada clase que tengamos, conteniendo las propiedades de la entidad, mas las propiedades que hereda de su clase base. Es ms sencillo de anotar como vemos a continuacin:
CLASE PERSONA: @Entity @Table(name=Persona) @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Persona{ @Id @GeneratedValue private int id; ... } CLASE POLICIA: @ENTITY @Table(name=Policia) public class Policia extends Persona{ // No existe campo id, ya que est definido en persona. ... }

tan slo hemos indicado con @Inheritance el tipo de estrategia, y al igual que antes las clases derivadas no deben de tener campo id dado que lo heredan. Las tablas generadas tampoco son normalizadas.

Ref.Mamual EJB 3.0.

35

rea de Formacin
Una tabla por cada subclase En esta estrategia tendremos una tabla principal, la de la clase base y una tabla por cada subclase. Veamos la anotacin:
CLASE PERSONA: @Entity @Table(name=Persona) @Inheritance(strategy=InheritanceType.JOIN) public class Persona{ @Id @GeneratedValue private int id; ... } CLASE POLICIA: @ENTITY @Table(name=Policia) @PrimaryKeyJoinColumn(name=ID_PERSONA) public class Policia extends Persona{ // No existe campo id, ya que est definido en persona. ... }

Vemos el uso de @Inheritance para indicar el tipo de strategia, JOIN en este caso. Mediante @PrimaryKeyJoinColumn indicamos el campo de la tabla Policia que apuntar a la clave primaria de la tabla Persona. Las tablas generadas sern tablas normalizadas.

7.4. EJB QL
Las entidades nos ofrecen el lenguaje de consulta EJB QL, basado en el sql, pero diseado para trabajar sobre objetos, en lugar de registros, por tanto asumimos el conocimiento del lenguaje sql. El interfaz que nos ofrece acceso a las consultas es java.persistence.Query:
public interface Query { int executeUpdate(); List getResultList(); Object getSingleResult();

Ref.Mamual EJB 3.0.

36

rea de Formacin
Query setFirstResult(int posicionInicio); Query setFlushMode(FlushModeType tipo); Query setHint(String hintNombre,Object valor); Query setMaxResults(int maximo); Query setParameter(String nombre,Object valor); Query setParameter(String nombre ,Date fecha,TemporalType tipoFecha); Query setParameter(String nombre,Calendar calendario,TemporalType tipoFecha); Query setParameter(int posicion,Object valor); Query setParameter(int posicion,Date fecha,TemporalType tipo Fecha); Query setParameter(int posicion,Calendar calendario,TemporalType tipoFecha); }

Las consultas las podemos crear a partir del entity manager:


public interface EntityManager { Query createNamedQuery(String); Query createNativeQuery(String); Query createNativeQuery(String,Class); Query createNativeQuery(String,String); Query createQuery(String); ... }

Podemos usar createQuery para obtener una consulta dinmica:


Un nico resultado: Query consulta = entityManager.createQuery(select from persona p where p.nombre='Paco'); Persona p = (Persona)consulta.getSingleResult(); Varios resultados: Query consulta = entityManager.createQuery(select from persona p where p.nombre='Paco'); List resultados = consulta.getResultList();

Tambin podemos pasar parmetros a la consulta:


Query consulta = entityManager.createQuery(select from persona p where p.nombre=:nombre); consulta.setParameter(nombre,Jose); Persona p = (Persona)consulta.getSingleResult();

como vemos el parmetro tiene nombre y le asignamos valor usando el nombre para referenciarlo. Tambin es posible usar parmetros posicionales:
Ref.Mamual EJB 3.0.

37

rea de Formacin
Query consulta = entityManager.createQuery(select from persona p where p.nombre=?1); consulta.setParameter(1,Jose); Persona p = (Persona)consulta.getSingleResult();

Si el parmetro es de tipo fecha hay que indicarlo expresamente usando DATE,TIME o TIMESTAMP:
Query consulta = entityManager.createQuery(select from persona p where p.fechanacimiento=:fecha); consulta.setParameter(fecha,new Date(),TemporalType.DATE); Persona p = (Persona)consulta.getSingleResult();

Otra caracterstica muy importante, sobre todo para listados es la paginacin, para ello podemos usar setMaxResults y setFirstResult:
Query consulta = entityManager.createQuery(select from persona p); consulta.setMaxResults(10); consulta.setFirstResult(1); Persona p = (Persona)consulta.getSingleResult();

Una vez que hemos visto las funciones bsicas para trabajar con consultas, vamos a ver el propio lenguaje EJB QL. Nombres abstractos de esquema Es el nombre lgico que hace alusin a la entidad, por defecto es el nombre de la clase, pero se puede cambiar usando @Entity.name para indicarlo. Consultas simples La consulta ms simple es similar a esta:
SELECT OBJECT(c) FROM Cliente AS c

en la que buscaremos dentro de Cliente los registros, y los llamaremos c a cada uno de ellos, retornando el registro c, pero transformado como objeto (entidad). Se puede simplificar:
SELECT c FROM Cliente c

Como vemos OBJECT es opcional, simplemente se mantiene por herencia de la versin 2.1 de EJB. En las consultas podemos utilizar el nombre de las propiedades java, no el de los mtodos get:
SELECT c FROM Cliente c where c.nombre LIKE 'J%'

No slo es posible retornar entidades, sino tambin valores:


Query consulta = entityManager.createQuery(select c.nombre,c.direccion); List resultados = consulta.getResultList(); Iterator it = resultados.iterator(); while(it.hasNext()){ Object[] valores = (Object[]) it.next();

Ref.Mamual EJB 3.0.

38

rea de Formacin
String nombre = (String) valores[0]; String direccion = (String) valores[1]; }

Y es posible navegar entre entidades:


SELECT c.direccion.calle FROM Cliente c

que retorna la propiedad calle de las entidades direccion, que esten relacionadas con entidades cliente, es decir si tenemos direcciones que no estn relacionadas con clientes, no saldrn en los resultados. Disponemos del operador IN que nos permite asignar un alias a las entidades a las que llegamos a ellas a travs de una relacin:
SELECT c FROM Cliente c, IN (c.direccion) d WHERE d.ciudad='Madrid'

es decir, a cada direccin asociada con un cliente se le asigna el alias d, para luego poder usarlo en la condicin. Es importante tener claro que si no tiene direccin relacionado, un cliente no estar en el conjunto de resultados. Tambin se puede usar para retornar un valor:
SELECT d.calle FROM Cliente c, IN (c.direccion) d WHERE d.ciudad='Madrid'

Supongamos esta consulta:


SELECT l FROM Cliente c, IN (c.pedidos) p, IN (p.lineaPedido) l

en la que desde el cliente tomamos sus pedidos y retornamos las lneas de los pedido. Se podra escribir con INNER JOIN al estilo relacional:
SELECT l FROM Cliente c INNER JOIN c.pedidos p INNER JOIN p.lineaPedido l;

Si es necesario una consulta en la que no existan entidades relacionadas podemos emplear LEFT JOIN:
SELECT c.nombre,d.ciudad FROM Cliente c LEFT JOIN c.direccion d

en la que un Cliente tenga o no direccin aparecer en el resultado final, y d.ciudad tomar un valor null. Supongamos que tenemos este cdigo:
Query consulta = entityManager.createQuery(SELECT c FROM Cliente); List resultados = consulta.getResultList(); Iterator it = resultados.iterator(); while(it.hasNext()){ Cliente c =(Cliente) it.next(); for(Pedido p : c.getPedidos()){ System.out.println(c.getFecha()); } }

y que pedidos se defini como:

Ref.Mamual EJB 3.0.

39

rea de Formacin
@OneToMany(fetch=FetchType.LAZY) private Collection<Pedido> pedidos;

esto significa un gran problema de rendimiento, debido a que se realiza la consulta qu retorna los clientes, y despus, por cada cliente se realiza otra consulta para obtener sus pedidos (recordemos que, al ser de tipo LAZY la relacin, no se obtendrn sus pedidos al acceder al cliente, sino cuando accedamos a la propiedad pedidos). La solucin pasa por conseguir que en la primera consulta, la del cliente, se precarguen los datos de los pedidos:
SELECT c FROM Cliente c LEFT JOIN FETCH c.pedidos

Tambin es posible usar DISTINCT para evitar duplicados:


SELECT DISTINCT c FROM Pedido p, IN (p.cliente) c

La instruccin BETWEEN tambin est disponible para valores reales y enteros:


SELECT c FROM Cliente WHERE c.edad BETWEEN 15 AND 25

Para comprobar una lista de valores podemos usar IN o NOT IN:


SELECT c FROM Cliente WHERE c.nombre IN ('Jose' , 'Luis')

IS NULL o IS NOT NULL comprueba si es nulo o no un determinado valor:


SELECT c FROM Cliente c WHERE c.segundoTelefono IS NOT NULL

Podemos comprobar si una entidad (cliente) tiene o no tiene entidades relacionadas (pedido) dentro de una relacin:
SELECT c FROM Cliente c WHERE IS EMPTY c.pedidos

Es posible comprobar si una entidad forma parte de una coleccin:


SELECT c FROM Cliente c WHERE :pedido MEMBER OF c.pedidos

Las funciones de agregado tambin estn disponibles: COUNT,MAX,MIN,AVG y SUM. La instruccin ORDER BY slo se puede aplicar para ordenar por campos pertenecientes a la entidad que se retorna:
SELECT c FROM Cliente c ORDER BY c.fechaNacimiento DESC

Group by y having tambin se encuentran disponibles:


SELECT c.nombre,COUNT(c.pedidos) cuantos FROM Cliente c GROUP BY c.nombre HAVING cuantos > 100

Otra caracterstica soportada es el uso de subconsultas:


SELECT c.nombre FROM Cliente c WHERE c.direccion.ciudad IN (SELECT ci.nombre FROM Ciudad ci WHERE ci.numeroHabitantes>100)

Una de las caractersticas que ofrece el uso de EJB QL es que podemos agrupar las consultas en el propio codigo fuente de la entidad mediante anotaciones, por ejemplo:
Clase Cliente: @Entity @NamedQueries({ @NamedQuery(name=Cliente.todos,query=SELECT c FROM Cliente c)

Ref.Mamual EJB 3.0.

40

rea de Formacin
}) ...

para luego utilizarla:


Query consulta = entityManager.createNamedQuery(Cliente.todos);

8. Beans de mensajera
Si necesitamos un mecanismo que permita trabajar de manera asncrona al invocar a un ejb de sesin, veremos que la nica alternativa es trabajar con el api de mensajera asncrona JMS. Para ayudarnos, en ejb 3.0, disponemos de los bean de mensajera que simplificando mucho, nos ofrecen un mtodo que se ejecuta al recibir un mensaje que envi un cliente a travs de JMS. Un bean de mensajera podra ser similar a este:
@MessageDriven( mappedName = "jms/QueueReceptor", activationConfig = {

@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Autoacknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") }) public class ReceptorMensajeBean implements MessageListener { public void onMessage(Message message) { try { ObjectMessage mensaje = (ObjectMessage) message; System.out.println(mensaje.getObject()); } catch (JMSException ex) { Logger.getLogger(ReceptorMensajeBean.class.getName()).log(Level.SEVERE, null, ex); } } }

Se puede ver la funcin onMessage, obligatoria por implementar MessageListener, en la que se recibe el mensaje y se procesa. Vemos el uso de @MessageDriven, donde declaramos a que buzn disponible en el servidor,se conecta el ejb de mensajera mediante mappedName. En activationConfig declaramos una array de @ActivationConfigProperty, cada @ActivationConfigProperty representa una propiedad (nombre y valor). En concreto se declaran el modo de acknowledge y el tipo de conexin JMS (javax.jms.Topic o javax.jms.Queue) de que se est usando.

Ref.Mamual EJB 3.0.

41

rea de Formacin
No es nuestro cometido explicar el api JMS, as que simplemente vamos a utilizar un ejb de sesin que enve un mensaje para comprobar el funcionamiento:
@Stateless public class ClienteReceptorMensajeriaBean implements ClienteReceptorMensajeriaRemote { @Resource(name = "jms/QueueReceptor") private Queue queueReceptor; @Resource(name = "jms/QueueReceptorFactory") private ConnectionFactory queueReceptorFactory;

public void enviarMensaje(Serializable objeto) { Connection connection = null; Session session = null; try { connection = queueReceptorFactory.createConnection(); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer messageProducer = session.createProducer(queueReceptor); messageProducer.send(createJMSMessageForjmsQueueReceptor(session, objeto)); } catch (JMSException ex) { Logger.getLogger(ClienteReceptorMensajeriaBean.class.getName()).log(Level.SEVERE, null, ex); } finally { if (session != null) { try { session.close(); } catch (JMSException e) { Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e); } } if (connection != null) { try { connection.close(); } catch (JMSException ex) { Logger.getLogger(ClienteReceptorMensajeriaBean.class.getName()).log(Level.SEVERE, null, ex); }

Ref.Mamual EJB 3.0.

42

rea de Formacin
} }

private Message createJMSMessageForjmsQueueReceptor(Session session, Serializable messageData) throws JMSException { // TODO create and populate message to send ObjectMessage tm = session.createObjectMessage(); tm.setObject(messageData); return tm; }

// Add business logic below. (Right-click in editor and choose // "Insert Code > Add Business Method" or "Web Service > Add Operation")

Vemos el uso de la inyeccin de referencias:


@Resource(name = "jms/QueueReceptor") private Queue queueReceptor; @Resource(name = "jms/QueueReceptorFactory") private ConnectionFactory queueReceptorFactory;

para acceder al buzn y a la fabrica necesarias para el envo del mensaje. No entramos en la explicacin de la funcin enviarMensaje, dado que requiere el conocimiento del api JMS y queda fuera del mbito de este manual. Simplemente nos quedamos con que enviarMensaje podemos invocarlo desde cualquier cliente remoto:
public class Main { @EJB private static ClienteReceptorMensajeriaRemote clienteReceptorMensajeriaBean; public static void main(String[] args) throws NamingException, Exception { if(clienteReceptorMensajeriaBean==null){ InitialContext ctx = new InitialContext(); clienteReceptorMensajeriaBean=(ClienteReceptorMensajeriaRemote) ctx.lookup(mensajeria.ClienteReceptorMensajeriaRemote.class.getName());

Ref.Mamual EJB 3.0.

43

rea de Formacin
} clienteReceptorMensajeriaBean.enviarMensaje("Probando"); } }

El ciclo de vida de un bean de mensajera es bastante simple:

No existe Class.newInstance() Inyecciones @PostConstruct

@PreDestroy

Listo para recibir mensajes Es igual que el ciclo de vida de un bean de sesin sin estado, cuando es creado por primera vez pasa al estado Listo tras haber realizado las inyecciones de referencia s y haber notificado con @PostConstruct que el bean est listo para empezar a recibir los mensajes de los clientes. Al finalizar la aplicacin, el bean ser eliminado, pero previamente se notifica con @PreDestroy que est a punto de desaparecer.

9. Temporizadores
Es muy probable que necesitemos realizar tareas programadas, para lo cul necesitamos usar el servicio de temporizacin que ofrecen los ejb 3.0. Partimos de un ejb de sesin sin estado:
@Stateless public class TemporizadoBean implements TemporizadoRemote { @Resource TimerService servicioTiempo; Timer temporizador;

@Timeout public void tarea(Timer temporizador){ System.out.println("Ejecutando"); }

Ref.Mamual EJB 3.0.

44

rea de Formacin
public void iniciar() { Calendar cuando = Calendar.getInstance(); cuando.add(Calendar.SECOND, 15); temporizador = servicioTiempo.createTimer(cuando.getTime(),null); }

public void parar() { if(temporizador!=null){ temporizador.cancel(); } } }

vemos el uso de:


@Resource TimerService servicioTiempo;

para acceder al servicio de temporizacin. Usamos:


Timer temporizador;

simplemente para poder acceder al temporizador que construiremos para ejecutar nuestra tarea:
@Timeout public void tarea(Timer temporizador){ ... }

que como vemos est anotada con @Timeout. Hemos agregado a este ejb de sesin dos mtodos remotos:
public void iniciar() { Calendar cuando = Calendar.getInstance(); cuando.add(Calendar.SECOND, 15); temporizador = servicioTiempo.createTimer(cuando.getTime(),null); }

public void parar() { if(temporizador!=null){ temporizador.cancel(); temporizador=null; } }

Ref.Mamual EJB 3.0.

45

rea de Formacin
para poder lanzar y parar la temporizacin. TimerService nos ofrece diversas funciones createTimer para poder lanzar tareas peridicas o que se ejecuten un sola vez como la nuestra. Es importante tener en cuenta que el timer se crea dentro de una funcin que se invoca desde un cliente, por tanto se crea dentro de la transaccin de dicho mtodo, es decir si la transaccin es cancelada el timer ser eliminado. El interfaz remoto ser:
@Remote public interface TemporizadoRemote { void iniciar(); void parar(); }

Ciclo de vida: Listo para No llamadas atenderexiste Class.newInstance() Inyecciones @PostConstruct

@PreDestroy

Listo para atender llamadas @Timeout Mtodos de la lgica de negocio

El ciclo de vida es igual que el de los bean de sesin sin estado(puesto que es uno de ellos) pero teniendo en cuenta la ejecucin del @Timeout cuando se dispare el evento del temporizador.

Ref.Mamual EJB 3.0.

46