logo de JavaActualmente está en proceso de definición las nuevas características que traerá Java Enterprise Edition 6. La versión anterior (Java EE 5) incorporó a EJB 3.0, que fue un enorme cambio para esta tecnología. EJB 3.0 buscó simplificar enormemente la utilización de estos componentes, haciéndolos más accesibles y simples, y a su vez brindando un servicio de inyección de dependencia.

Java EE 6 presentará a EJB 3.1, el cual sigue mejorando a pasos agigantados, y ahora presenta un set de funciones y característcias nuevas sumamenete interesante. Entre las novedades están la posiblidad de crear EJBs a partir de POJOs sin interfaz, simplificación en el empaquetado de los componentes, mejor integración con JSF y los WebBeans, y una nueva forma de realizar invocaciones asincrónicas sumamente interesante.

A continuación un resumen de lo que se viene próximamente.

Interfaces de EJB opcionales

Así como EJB 3.0 eliminó las interfaces "Home", en EJB 3.1 todas las interfaces serán opcionales. Así, se podrán crear servicios a partir de POJOs comunes, sumamente útil para aplicaciones chicas (o, veremos luego, al utilizar como WebBeans).

Crear entonces un EJB Stateless será tan simple como:

@Stateless 
public class PlaceBidBean {
@PersistenceContext
private EntityManager entityManager;

public void placeBid (Bid bid) {
entityManager.persist(bid);
}
}

Nuevos bean Singleton

Será posible crear Singletons de manera muy simple, e inyectarlos para su utilización. El container entonces garantiza la existencia de una única instancia del componente, el cual además contará con todos los servicios comunes de un EJB: transacciones, seguridad, callbacks del ciclo de vida, interceptores, inyección de dependencias, etc.

Como todos los EJB 3.1, los Singleton son POJOs anotados:

@Singleton
public class DiscountRateBean {
@PersistenceContext
private EntityManager entityManager;

private Rate rate;
@PostConstruct
private void init() {
rate = entityManager.find(Rate.class, 1);
}
@PreDestroy
private void destroy() {
entityManager.merge(rate);
}
public void setRate(Rate rate) {
this.rate = rate;
}
public Rate getRate() {
return rate;
}
}

Por omisión, todos los Singleton son thread-safe y transaccionales. Este comportamiento se puede cambiar con el uso las anotaciones correspondientes.

Nuevos servicios para Timer Service

El EJB Timer Service contiene varias mejoras para permitir realizar establecer eventos al estilo de cron, algo que venia faltando. Todo mediante anotaciones:

@Stateless
public class NewsLetterGeneratorBean implements NewsLetterGenerator {

@Schedule(second="0", minute="0", hour="0", dayOfMonth="1", month="*", year="*")
public void generateMonthlyNewsLetter() {
... Code to generate the monthly news letter goes here...
}
}

Empaquetado simplificado

Los EJB se empaquetan en archivos "ejb-jar" separados. Así, si una aplicación web tiene componentes de negocio en EJBs, suele resultar en la creación de un EAR con un WAR y un EJB-JAR adentro.

Esta separación es práctica cuando el EJB-JAR contiene componentes de negocio que pueden ser consumidos por terceros. Pero, para el caso del negocio propio de la aplicación web puede terminar siendo más molesto que otra cosa.

El nuevo esquema de paquetización permite incluir EJBs dentro de los WAR. Estos EJB pueden residir directamente en WEB-INF/classes, y su descriptor en WEB-INF/ejb-jar.xml

Lo que es más, estos EJB tienen acceso a los recursos declarados en el web.xml.

Invocación asincrónica de métodos

Hasta ahora la ejecución asincrónica se manejaba a través de mensajería, y el uso de MDBs para el consumo de los mensajes. Si bien funciona, obliga a la creación de colas y utilización de JMS. En EJB 3.1 existe una nueva forma de realizar invocaciones asincrónicas, que para muchos cosas puede resultar bastante más simple.

En EJB 3.1 los EJB de sesión pueden tener métodos anotado con @Asynchronous, y eso es todo. Al ejecutar ese método se devolverá el control inmediatamente, y la ejecución ocurrirá en diferido (seguramente implementado mediante mensajeria, pero todo por detrás de escena).

@Stateless
public class OrderBillingServiceBean implements OrderBillingService {

@Asynchronous
public void billOrder(Order order) {
try {
// Attempt to charge the order.
bill(order);
// Send email notification of billing success.
notifyBillingSuccess(order);
order.setStatus(OrderStatus.COMPLETE);
} catch (BillingException be) {
// Send email notification of billing failure.
notifyBillingFailure(be, order);
order.setStatus(OrderStatus.BILLING_FAILED);
} finally {
update(order);
}
}
}

Como se ve, el método billOrder() devuelve void, ya que la ejecución será en diferido. Sin embargo, es posible devolver una instancia de java.util.concurrent.Future. Esta interfaz permite cancelar una ejecución asincrónica, verificar si surgieron excepciones u obtener un valor de resultado.

El mismo ejemplo anterior pero devolviendo el estado de la orden sería:

@Stateless
public class OrderBillingServiceBean implements OrderBillingService {

@Asynchronous
public Future<OrderStatus> billOrder(Order order) {
try {
// Attempt to charge the order.
bill(order);
// Send email notification of billing success.
notifyBillingSuccess(order);
return new AsyncResult<OrderStatus>(OrderStatus.COMPLETE);
} catch (BillingException be) {
// Send email notification of billing failure.
notifyBillingFailure(be, order);
return new AsyncResult<OrderStatus>(OrderStatus.BILLING_FAILED);
}
}
}

WebBeans y EJB

En JSF se utilizan backing-beans como una capa muy fina que accede al negocio de la aplicación. En estos backing-beans luego era posible inyectar a los EJB para resolver la lógica necesaria.

En EJB 3.1 es posible utilizar directamente EJBs como un backing-bean. Todo el soporte para WebBeans fue pensado luego de la experiencia de JBoss Seam, y esta mejora a WebBeans cuenta con el liderazgo de Gavin King.

Los EJB se anotan con @Component, lo que los registra automáticamente al entorno de WebBeans. Así, son directamente accesibles luego via JSF utilizando EL, tal como si fueran backing-beans tradicionales. Estos backing-beans cuentan, como ya es habitual, con inyección de dependencias y otros servicios.

Supongamos entonces un bean se sesión y una entidad:

@Component
@Stateless
@Named("placeBid")

public class PlaceBidBean {
@PersistenceContext
private EntityManager entityManager;

@In
private Bid bid;

public void addBid() {
entityManager.persist(bid);
}
}

@Component
@Entity
@Named("bid")

public class Bid {
private Long bidId;
private String bidder;
private String item;
private Double bidPrice;

@Id
@GeneratedValue
public Long getBidId() {
return bidId;
}

public void setBidId(Long bidId) {
this.bidId = bidId;
}

public String getBidder() {
return bidder;
}

public void setBidder(String bidder) {
this.bidder = bidder;
}

public String getItem() {
return item;
}

public void setItem(String item) {
this.item = item;
}

public Double getBidPrice() {
return bidPrice;
}

public void setBidPrice(Double bidPrice) {
this.bidPrice = bidPrice;
}
}

La anotación @In inyecta al bean Bid correspondiente. La anotación @Named indca el nombre que tendrán para su utilización. La anotación @Component los registra con el entorno de WebBeans, y ahora son simplementa accesibles desde una página JSF:

<html>
...
<body>
<f:view>
...
<h:form>
<table>
<tr>
<td>Bidder</td>
<td><h:inputText value="#{bid.bidder}"/></td>
</tr>
<tr>
<td>Item</td>
<td><h:inputText value="#{bid.item}"/></td>
</tr>
<tr>
<td>Bid Amount</td>
<td><h:inputText value="#{bid.bidPrice}"/></td>
</tr>
</table>
...
<h:commandButton type="submit" value="Add Bid"
action="#{placeBid.addBid}"/>
...
</h:form>
...
</f:view>
</body>
</html>

WebBeans y EJB tienen varias mejoras más, como interceptores y la posiblidad de crear e inyectar componentes que no sean EJBs .

Leer más

Pueden leer todos estos ejemplos y novedades (y más!) en las siguientes excelentes series de notas:

Inspiración.

"Si tú tienes una manzana y yo tengo una manzana e intercambiamos las manzanas, entonces tanto tú como yo seguiremos teniendo una manzana cada uno. Pero si tú tienes una idea y yo tengo una idea, e intercambiamos las ideas, entonces ambos tendremos dos ideas"

Bernard Shaw