This blog has moved to
http://blog.matthias-reining.com

Die bestehenden Artikel bleiben vorerst alle bei blogspot. Neue Artikel veröffentliche ich allerdings nur noch auf http://blog.matthias-reining.com

Donnerstag, 30. Oktober 2008

EJB3 und ServiceLocator

Leider benötige ich, anders als hier im Web oft beschreiben, im Zusammenspiel zwischen Stateless SessionBeans (SLSB) und meinem Web Frontend das ServiceLocator Pattern (Plattform JBoss5). Aus einem Servlet (managed container) kann man zwar ganz komfortable die Annotation @EJB aufrufen, aus einem einfachen POJO allerdings leider nicht… (wäre mal ein ganz nettes Feature für die nächste Generation ;-) )

Problem: Aufruf meiner SLSB aus meiner Struts2 Action.

Nachdem die Action nicht vom Webcontainer verwaltet wird kann mit @EJB auch die SLSB nicht injiziert werden. Also muss doch das gute alte ServiceLocator Pattern her. Seit EJB2 hat sich hier allerdings einiges getan (Generics, HomeInterface, …), so dass ein einfaches C&P von der Pattern Page nicht wirklich toll passt (http://java.sun.com/blueprints/corej2eepatterns/Patterns/ServiceLocator.html).

Klar, jetzt kommt eigentlich Spring zum Einsatz. Aber… ich will in diesem Projekt einfach kein Spring benutzen ;-)

Mit folgendem Code komme ich ganz gut zu recht:

ServiceLocator Klasse:

import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ServiceLocator {

    private static ServiceLocator instance;
    InitialContext context;
    private ServiceLocator() {
        try {
            Properties p = new Properties();
            p.put(Context.INITIAL_CONTEXT_FACTORY,
                    "org.jnp.interfaces.NamingContextFactory");
            p.put(Context.URL_PKG_PREFIXES,
                    "org.jboss.naming:org.jnp.interfaces");
            p.put(Context.PROVIDER_URL, "jnp://localhost:1099");
            context = new InitialContext(p);
        } catch (NamingException e) {
            throw new ServiceLocatorException(e);
        }
    }

    public static ServiceLocator getInstance() {
        if (instance == null)
            instance = new ServiceLocator();
        return instance;
    }

    @SuppressWarnings("unchecked")
    public <T> T getService(Class<T> clazz) {
        try {
            // TODO Name des ear-Files (MrBlue) zur Laufzeit ermitteln
            String lookupName = "MrBlue/" + clazz.getSimpleName()
                    + "Bean/local";
            T lookup = (T) context.lookup(lookupName);
            return lookup;
        } catch (ClassCastException e) {
            throw new ServiceLocatorException(e);
        } catch (NamingException e) {
            throw new ServiceLocatorException(e);
        }
    }

}

Aufruf aus der Struts Action:

public String execute() {        
        AccountService accountService = ServiceLocator.getInstance()
                .getService(AccountService.class);
        accountService.ping();

        return SUCCESS;
    }

Caching wird hier Clientseitig nicht verwendet. Übernimmt hier ja quasi der EJB-Container.

Der ServiceLocator hier geht davon aus, dass bei der Klassenbezeichnung der SessionBeans eine Konvention eingehalten wird (wie eigentlich üblich…)

Local Interface: <name>

Remote Interface: <name>Remote ß hier im ServiceLocator noch nicht implementiert (geht ja bei einer Webapplikation hier im ersten Schritt ja auch nur um local Calls).

Session Bean: <name>Bean


 

Keine Kommentare:

Kommentar veröffentlichen