Als Teil von Java EE kann JNDI (Java Naming and Directory Interface) heute in allen gängigen Application-Servern genutzt werden. Ein üblicher Verwendungszweck ist das Bereitstellen von DataSourcen für einzelne Webanwendung. Die Resourcen werden in diesem Szenario in der jeweiligen web.xml und context.xml definiert und sind dann im entsprechenden Application-Context verfügbar.
Unüblicher aber durchaus nützlich ist die Verwendung einer eigenen globalen Resource, die allen Applications gleichermaßen zur Verfügung steht. Im folgenden Beispiel wird eine kleine HalloWelt-Klasse als globale Resource abgelegt und genutzt.
Als erstes bearbeiten wir $CATALINA_BASE/conf/server.xml um die globale Resource anzulegen. Wir geben den Namen der Resource an, die Klasse und eine Factory zum Erstellen der Resource. Meist ist der Tag GlobalNamingResources bereits vorhanden, so dass wir unsere Resource dort lediglich hinzufügen müssen.
<GlobalNamingResources> <Resource auth="Container" factory="HelloWorldFactory" name="meine/services/HelloWorld" type="HelloWorld"/> </GlobalNamingResources>
Als nächstes fügen wir in die globale $CATALINA_BASE/conf/context.xml einen Resource-Link ein, der auf die erstellte globale Resource verweist. Da diese context.xml von allen Applications genutzt wird, ersparen wir uns hiermit, jede einzelne webapp/WEB-INF/context.xml anpassen zu müssen.
<Context> <ResourceLink global="meine/services/HelloWorld" name="meine/services/HelloWorld" type="HelloWorld"/> </Context>
Nun implementieren wir die globale Resource. Wir brauchen dazu lediglich drei Dateien, nämlich die HelloWorldFactory.java, das Interface HelloWorld.java und die konkrete Implementierung HelloWorldImpl.java. Alle Dateien exportieren wir als JAR-Datei und legen sie unter $CATALINA_BASE/lib/ext ab. Somit ist gewährleistet, dass alle Applications die HelloWorld Klassen durch den Common-ClassLoader im Classpath haben.
Die HelloWorldFactory erbt von ObjectFactory, welche die Standard Factory für Java Naming ist. Zurückgegeben wird die Singleton-Instanz unserer HelloWorldImpl.
public class HelloWorldFactory implements ObjectFactory {
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?, ?> environment) throws Exception {
return HelloWorldImpl.getInstance();
}
}
Zum Interface HelloWorld muss wenig gesagt werden. Es definiert lediglich alle Methoden, die die Resource zur Verfügung stellen soll und die die konkrete Klasse implementieren muss.
public interface HelloWorld {
String getHelloWorld();
}
Die Implementierung unserer Resource wird als Singleton ausgeführt, so dass die Factory immer nur eine Instanz der Resource zurückgibt.
public class HelloWorldImpl implements HelloWorld {
private static instance = new HelloWorldImpl();
public static HelloWorld getInstance() {
return instance;
}
@Override
public String getHelloWorld() {
return "Hello world!";
}
}
Sind die Vorbereitungen abgeschlossen, können wir in einer beliebigen Application per JNDI Lookup auf die Resource zugreifen, ohne dass die Application speziell konfiguriert werden muss oder Abhängigkeiten zu unseren Klassen enthalten muss. Der JNDI Lookup nutzt den InitialContext, den uns Tomcat zur Verfügung stellt. (Im Code nicht dargestellt ist ein entsprechender Try-Catch-Block, der um das Lookup gesetzt werden muss.)
@ManagedBean
@SessionScoped
public class SampleBean {
public String getGreetingMessage() {
Context serverContext = (Context) new InitialContext()
.lookup("java:/comp/env");
HelloWorld helloWorld = (HelloWorld) serverContext
.lookup("meine/services/HelloWorld");
return helloWorld.getHelloWorld();
}
}
Starten wir nun unseren Tomcat, wird durch den globalen Kontext gleich zu Begin die ObjectFactory aufgerufen und die Singleton-Instanz unserer Resource erstellt. Beim Zugriff auf die Resource durch die Applications, steht die Resource somit schon fertig initialisiert zur Verfügung. Dies kann besonders dann von Vorteil sein, wenn die Resource eine gewisse Zeit braucht um zur Verfügung zu stehen.