1. Enterprise Java Beans 3.0
Introducción
El objetivo de Enterprise JavaBeans (EJB) 3.0 es simplificar el desarrollo de
aplicaciones Java y estandarizar el API de persistencia para la plataforma Java.
EJB 3.0 está cambiando drásticamente el modelo de programación de EJBs.
Algunas de las nuevas características clave son:
Cambios generales:
• EJB 3.0 elimina la necesidad de las interfaces home y de componente, y el
requisito de que las clases bean implementen la interfaz
javax.ejb.EnterpriseBean. Los EJBs pasan a ser ahora POJOs.
• Simplificación de la configuración a través de valores por defecto y del uso de
anotaciones de metadatos en lugar de descriptores de despliegue.
• Se soporta la inyección de dependencias para utilizar EJBs, recursos y variables
de entorno.
• Soporte métodos de ciclo de vida mejorados, y de clases listener para callbacks.
• Soporte de métodos de intercepción.
• Búsqueda e invocación de métodos simplificada.
API de persistencia / Beans de entidad:
1. Los beans de entidad CMP son ahora POJOs y pueden ser probados o usados
fuera del contenedor.
2. Se introduce el API EntityManager para la ejecución de operaciones CRUD
sobre entidades.
3. Se estandariza un mecanismo de mapeo objeto-relacional a través de anotaciones
de metadatos. Versiones futuras de la especificación soportarán XML para este
mapeo objeto-relacional.
4. Mejora enormemente EJB-QL y añade soporte para la ejecución de SQL nativo.
EJB 3.0 hace más fácil el desarrollo de aplicaciones por que:
• Elimina la necesidad de construir interfaces EJB y descriptores de despliegue
innecesarios, y en lugar de esto, permite que los desarrolladores los generen
especificando anotaciones (similar a XDoclet). Esta aproximación libera a los
desarrolladores de crear descriptores de despliegue y de crear interfaces para los
componentes
• Simplifica los EJBs para asemejarse a los POJOs o Java Beans.
• Elimina la necesidad de tener interfaces de componentes para los EJBs.
• Los beans de entidad no requieren ninguna interfaz de componente.
• Los beans de entidad utilizarán ahora una interfaz POJO.
• Elimina la necesidad de implementar métodos callback de ciclo de vida
innecesarios.
2. Inyección de dependencias en EJB 3.0
Es difícil llegar a una definición simple para el concepto de inyección de dependencias.
En términos simples, la inyección de dependencias hace más fácil el uso de recursos
como DataSources, EJBs, contextos, etc.
En J2EE 1.4, el utilizar recursos u otro EJB desde aplicaciones EJB es complejo y
propenso a errores. Tienes que definir dependencias utilizando resource-ref o ejb-ref y
hacer una búsqueda JNDI.
En contraste, con EJB 3.0, puedes simplemente definir la dependencia en el EJB o
recurso.
Ejemplo:
@EJB AdminService bean;
public void privilegedTask() {
bean.adminTask();
}
Compatibilidad con EJB 2.x
EJB 3.0 requiere compatibilidad e interoperabilidad con EJB 2.x; las aplicaciones EJB
2.x funcionan en contenedores compatibles con EJB 3.0. El modelo de programación
para los EJB ha cambiado drásticamente entre EJB 2.x y EJB 3.0, por lo que migrar una
aplicación a la nueva especificación no resulta trivial.
Los vendedores de herramientas y de servidores de aplicaciones proporcionarán
herramientas y utilidades para hacer la migración más fácil.
Por ejemplo, la implementación previa de Oracle de EJB 3.0 soporta el concepto de
migración incremental.
3. Que se puede Hacer Con EJB3
EJB es el único estándar Java que se ocupa de la lógica de negocio del lado del servidor,
y esto es fundamental para J2EE. El comité de especificación de EJB reconoce que EJB
se quedó corto en alcanzar algunas de sus ambiciosas metas, y necesitó de una
modernización. Esta modernización está muy enfocada en la facilidad de uso,
principalmente mediante la simplificación de los requerimientos para los
desarrolladores.
Sin embargo, el comité de especificación también ha identificado un número de mejoras
funcionales críticas que facilitan el uso y la eliminación de ciertos anti-patrones J2EE.
Afortunadamente, la comunidad Java conoce ahora mucho más los problemas
relacionados a la construcción de aplicaciones web y empresariales que hace cinco años.
El comité de especificación pensó mucho como simplificar ciertos casos de usos
generales extremadamente comunes, como por ejemplo:
Actualizando datos
1. recuperar un dato
2. mostrarlo en pantalla
3. aceptar la entrada del usuario
4. actualizar el dato
5. comunicar el éxito al usuario
Ingresando nuevos datos
1. recuperar un dato
2. mostrarlo en pantalla
3. aceptar la entrada del usuario
4. crear un nuevo dato, con una asociación al primer dato
5. comunicar el éxito al usuario
Cada uno de estos casos involucra dos ciclos request/response de aplicación completos.
Ambos demuestran que el bloqueo optimista es esencial en una aplicación que requiere
alta concurrencia (ambos casos necesitarían ser implementados como una sola
comunicación atravesando dos transacciones ACID de base de datos distintas).
Un caso de uso adicional muy común, que es especialmente difícil de hacer en EJB 2.1,
dadas las limitaciones del lenguaje de consultas (EJB-QL) es el siguiente:
Listando datos
1. recuperar una lista de datos sumarizada o agrupada
2. mostrarla al usuario
4. Uso de anotaciones
Lo mas llamativo, inicialmente, son las anotaciones. No se necesita ningún deployment
descriptor. EJB 3.0 permite elegir entre el uso de anotaciones y descriptores de
despliegue en XML, pero lo esperado es que las anotaciones serán el caso mas común.
@Entity
public class Item {
private Long id;
private User seller;
private Collection<Bid> bids = new ArrayList<Bid>();
private String description;
private String shortDescription;
private Date auctionEnd;
private int version;
public Item(User seller, String desc, String shortDesc, Date end) {
this.seller = seller;
this.description = desc;
this.shortDescription = shortDesc;
this.auctionEnd = end;
}
protected Item() {}
@Id(generate=AUTO)
public Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
@Column(length=500)
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getAuctionEnd() {
return auctionEnd;
}
protected void setAuctionEnd(Date end) {
this.auctionEnd = end;
}
@Column(length=100)
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
5. this.shortDescription = shortDescription;
}
@JoinColumn(nullable=false, updatable=false)
public User getSeller() {
return seller;
}
protected void setSeller(User seller) {
this.seller = seller;
}
@OneToMany(cascade=ALL)
protected Collection<Bid> getBids() {
return bids;
}
protected void setBids(Collection<Bid> bids) {
this.bids = bids;
}
@Version
public int getVersion() {
return version;
}
protected void setVersion(int version) {
this.version = version;
}
public Bid bid(BigDecimal amount, User bidder) {
Bid newBid = new Bid(this, amount, bidder);
bids.add(newBid);
return bid;
}
}
La anotación @Entity le dice al contenedor que una clase es un CPM entity bean.
Las anotaciones opcionales @Column definen los mappings de las columnas para las
propiedades persistentes (si estuviéramos con los mappings de datos antiguos,
podríamos definir los nombres de las columnas en estas anotaciones).
Las anotaciones @Id seleccionan la propiedad de clave primaria del entity bean.
Las anotaciones opcionales @OneToMany definen asociaciones de uno a muchos, y
especifican un estilo de cascada de ALL.
La anotación opcional @JoinColumn define un mapping de columna para una
asociación. En este caso, obliga a la asociación a ser obligatoria e inmutable.
La anotación @Version define la propiedad utilizada por el contenedor para su bloqueo.
Quizás lo más importante a tener en cuenta aquí es que casi todas las anotaciones son
opcionales. EJB3 utiliza una configuración por excepciones, es decir que la
6. especificación define valores por defecto útiles y lógicos y así no es necesario
especificar anotaciones para el caso normal. Por ejemplo, no hemos incluido ninguna
anotación en una de las propiedades persistentes.
También llamativo es que, además de las anotaciones, Item no depende de clases o
interfaces en javax.ejb. Esto fue una meta prioritaria de EJB3, y ayuda
significativamente a reducir el "ruido".
Los entity beans no necesitan una interface local o remota, lo que también reduce el
ruido.
Ahora nuestras clases del modelo de dominio son simples JavaBeans. Esto significa que
son testeables fuera del contenedor EJB.
Ahora, miremos nuestro primer caso de uso, actualizando un Item. Asumiremos una
arquitectura co-localizada, e implementaremos nuestra lógica de negocio en un stateless
session bean con una interface de negocio local.
Una interface de negocio define operaciones visibles al cliente (vuestros session beans
pueden tener tantas interfaces de negocio como quieran). Definiremos la interface local
Auction (Subasta) asi:
public interface Auction {
public Item getItemById(Long itemId);
public void updateItem(Item item);
}
Las interfaces de negocio son locales por defecto, por lo tanto no es necesaria ninguna
anotación @Local.
Dado que nuestro entity bean Item es también un JavaBean, podemos pasarlo
directamente a una JSP (por ejemplo).
La clase bean AuctionImpl implementa esta interface:
@Stateless
public class AuctionImpl implements Auction {
@Inject public EntityManager em;
public Item getItemById(Long itemId) {
return em.find(Item.class, itemId);
}
public void updateItem(Item item) {
em.merge(item);
}
}
La anotación @Inject se utiliza para indicar que un campo de un session bean es
actualizado por el contenedor. En EJB3.0, los session beans no necesitan utilizar JNDI
para obtener referencias a recursos u otros EJBs. En este caso, el contenedor inyecta una
7. referencia al EntityManager, la interface para operaciones relacionadas con la
persistencia en entity beans.
El contenedor se encarga del bloqueo optimista en forma transparente.
Supongamos que nuestro Cliente es un servlet. El código para mostrar un Item sería
algo como esto:
Long itemId = new Long( request.getParameter("itemId") );
Auction auction = (Auction) new InitialContext().lookup("Auction");
Item item = auction.getItemById(itemId);
session.setAttribute("item", item);
Dado que el entity bean es solo un simple JavaBean, la JSP puede utilizarlo
directamente. El segundo request, que actualiza el Item, podría ser algo asi:
Item item = (Item) session.getAttribute("item");
item.setDescription( request.getParameter("description") );
item.setShortDescription( request.getParameter("shortDescription") );
Auction auction = (Auction) new InitialContext().lookup("Auction");
auction.updateItem(item);
Por lo tanto, un resumen de las simplificaciones sería:
• Las anotaciones reemplazan a los complejos descriptores de despliege en XML
• Eliminación de las home interfaces
• Eliminación de dependencias a clases e interfaces en javax.ejb
• Los entity beans son ahora simples JavaBeans, sin interfaces locales o remotas
• La inyección de dependencia reemplaza a las búsquedas JNDI