Skip navigation

 

Un patrón muy utilizado dentro del mundo JEE es el conocido Service Locator, sobre todo para acceder a instancias de EJBs como vamos a ver en el ejemplo mas adelante.

Lamentablemente, aunque se detecta la necesidad de un componente que resuelva el problema de acceder ciertos servicios no siempre la solución implementada cumple con los requisitos o la manera de resolverlo tiene resultados no esperados, como por ejemplo hacer que dicho patrón sea estático o mezclarlo con un Singleton y sumar al caldo un cache _global_ de Stateful Session Bean (aka SFSB), aunque irónicamente se haga cache de Stateless Session Bean (aka SLSB) con el mismo fin. Está bien, en ciertas ocasiones un cache no vendría mal pero vale la pena analizarlo a fondo porque, como _toda_ solución de cache ( deberían anotarlo si no lo saben ), trae muchos efectos colaterales… muchos.

Primer problema, supongamos que decidimos hacer a la instancia del Service Locator (desde ahora SL) estática porque observamos que no importa el estado del SL, para un nombre de SB queremos que nos devuelva dicho SB sea SF o SL. Si la instancia del Service Locator es única los SFSB que quedan asociados van a ser los mismos para cada llamado dentro de la aplicación, haciendo a nuestro SFSB un servicio estático también.

Segundo problema, si la referencia que tenemos a cada SFSB se mantienen abierta durante mas tiempo de lo que necesitamos y tenemos un problema de conexión o cualquier otro imprevisto ya no hay manera de volver a usar dicho servicio si no renovamos la referencia, esto va sobretodo para aquellos que usan los SFSB con “métodos estáticos” o sin estados como por ejemplo “int sumarDos(int base)”. Para que se entienda, si tenemos un SFSB asociado a la sesión y el servidor de EJBs se reinicia entro dos llamados, el segundo llamado va a fallar porque el id de SFSB que tiene el cliente que consume dicho servicio no existe en el servidor de EJBs, tirando la siguiente excepción:

javax.ejb.NoSuchEJBException: Could not find stateful bean: <super_id_largo_y_horrible>

Los problemas, o mejor dicho las causas de perder la referencia a un SFSB pueden ser varias ( no siempre un problema ), las mas comunes:

  • Reinicio del servidor de EJBs, si tenemos el cliente y los ejbs en diferentes máquinas virtuales
  • Inactividad por un tiempo prolongado. Recuerden que los SFSB son uno por cliente, por lo que el contenedor de EJBs destruirá cualquier SFSB que esté inactivo por mas tiempo que por configuración se le indica.
  • Si llamamos a un método con la anotación @javax.ejb.Remove pero mantenemos la referencia al SFSB.
  • etc..

Solución: NO guardar ninguna instancia de Session Bean en un Service Locator, por mas tentadora que parezca la idea, por mas creamos que sea una buena optimización. En el único caso que vale la pena es cuando sabemos que vamos a consumir solo SLSB, pero como el cliente supuestamente no sabe nada sobre la implementación de los servicios esta solución nos puede traer mas dolores de cabeza mas tarde.

 

Dicho esto y como el titulo prometía hablar de JBoss Seam vamos a ver que les parece mi propuesta. Mi Service Locator, si bien van a ver que las clases tienen dependencias de runtime en Seam, la idea principal se puede usar sin este framework.

Empecemos por el principio, el punto de vista del usuario del patrón. ¿Cuál es el mejor Service Locator que conocen? Yo el @EJB, vamos a ver que tan parecido lo podemos hacer.

Hay una anotación de Seam muy parecida, @org.jboss.seam.annotations.In que nos permite inyectar dependencias, el problema es que no queremos hacer un componente diferente por cada implementación que valla a utilizar el cliente, a lo sumo llamaremos al SL con el nombre del EJB que queremos utilizar. Y como hacemos eso con Expression Language (EL) ? Un mapa de ejbs :D

Sería algo como esto:

    @org.jboss.seam.annotations.In("#{locator['myEJBImplBean']}")
    private MyEjbInterface mei;

Excelente, entonces _locator_ es nuestro componente encargado de encontrar los servicios, nuestro Service Locator. Pero como que es un Mapa? Veamos la implementacion

@Name("locator")
@Scope(ScopeType.APPLICATION)
public class EjbLocator implements Serializable {

    public Object locate(String name) throws RuntimeException {
        try {
            String jndi = Init.instance().getJndiPattern();
            return new InitialContext().lookup( jndi.replace("#{ejbName}", name) );
        } catch (NamingException ex) {
            log.error("Error inicializando el ejb " + name , ex);
        }
        return null;
    }

    @Unwrap
    public Map<string ,Object> getResource(){
        return new Map</string><string ,Object>(){

            public Object get(Object key) {
                return locate((String)key);
            }

            /* .... muchos metodos que no tiene sentido agregar ... */

            public Object put(String key, Object value) {
                throw new UnsupportedOperationException("Not supported yet.");
            }

        };
    }

}

Nota:

  • Todas las anotaciones están bajo el paquete org.jboss.seam.annotations
  • La instancia de InitialContext se podría generar menos seguido
  • Obviamente quite código q no venia al caso :)

Entonces, tenemos un componente Singleton que nos sirve como Service Locator que cuando hacemos referencia a él lo que obtenemos es un mapa. Cuando busquemos un objeto dentro del mapa con la key X, el SL intentará encontrar una referencia a un EJB con el nombre X.

Claramente, los métodos pueden ser estáticos pero la verdad en este caso no hace la diferencia, la magia está en como esto se mezcla con Dependency Injection y Expression Language. Sientanse libres de mandar sugerencias, ideas, correcciones o simples comentarios.

Y como decían en Nivel-X, bueeeno.. esto fue todo y espero q les haya gustado. ( espero que no tenga copyright =P )

Anuncios

4 Comments

  1. aguante el copyleft!

  2. esto porque seam es increíble -not-, pero si tuvieras una app común que consultara cosas de SLSB (aunque esta información es cierto que debiera ser transparente)? qué te queda? Se aceptan respuestas distintas a: 1) implementar un seam desde cero 2) usar seam 3) pedirle a un amigo que te convierta la app a seam 4) contratar a selenca.

  3. ¿Cuál es el sentido de un Service Locator con SEAM, siendo que tenemos biyección de dependencia?

  4. @diega:
    este ejemplo es para utilizar justamente la funcionalidad de inyección de Seam, sacar la constante Seam de la ecuación sería repensar el problema. Igualmente la solución no es menos elegante, yo usaría AOP ( JBoss AOP útil y fácil de usar ) para hacer algo parecido a la anotación de @javax.ejb.EJB. Había echo un ejemplo, si querés después lo subo.
    @abunaineko:
    fijate que no dije que los Session Beans tengan que cumplir con alguna condición, eso te permite hacer una separación y dejar los EJBs limpios de dependencias de Seam como a mi me gusta =D o utilizar esté tipo de inyección con EJBs legacy que no puedas modificar.

    Me dieron una idea, después veo si se puede hacer algo así con JSF/EJB

    Salutes


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: