JNDI-Übersicht, Teil 3: Erweiterte JNDI

Ich muss diesen Monat viel Boden abdecken, also werde ich den Flaum weglassen und bis zu den Aufzählungspunkten schneiden. Erstens spielt die Java-Namens- und Verzeichnisschnittstelle in mehreren Java-Technologien eine wichtige Rolle. Wir werden uns diese Rolle ansehen, um die strategische Position von JNDI im gesamten Java-Gesamtbild besser zu verstehen. In Anerkennung Ihrer Notwendigkeit, mit einem funktionierenden JNDI-Dienst zu spielen, werde ich Ihnen als Nächstes eine frei verfügbare, tragbare LDAP-Implementierung vorstellen und Ihnen zeigen, wie Sie eine Verbindung zu einem JNDI-Dienstanbieter herstellen und diesen verwenden. Abschließend möchte ich Ihnen die Bindung von Objekten an Einträge in JNDI näher erläutern.

TEXTFELD:

TEXTBOX_HEAD: JNDI-Übersicht: Lesen Sie die ganze Serie!

  • Teil 1. Eine Einführung in die Benennungsdienste

  • Teil 2. Verwenden Sie JNDI-Verzeichnisdienste, um Ihre verteilten Anwendungen besser zu verwalten

  • Teil 3. Verwenden Sie JNDI, um die Objekte Ihrer verteilten Anwendung zu speichern

  • Teil 4. Fassen Sie das Gelernte mit einer JNDI-fähigen Anwendung zusammen

: END_TEXTBOX

Bevor ich anfange, ist ein kleines Doppeldenken angebracht. In den letzten zwei Monaten habe ich versucht, Sie davon zu überzeugen, dass Namens- und Verzeichnisdienste in etwa dem elektronischen Äquivalent der in Bibliotheken enthaltenen Kartenkataloge entsprechen. Jetzt, da wir unsere Tour durch die erweiterten Funktionen von JNDI beginnen, möchte ich, dass Sie diese Analogie vollständig vergessen - sie zeigt die Leistungsfähigkeit von JNDI erheblich.

Beginnen wir mit einem Blick darauf, wie JNDI in anderen Java-Technologien erscheint.

JNDI überall

JNDI spielt eine Rolle in einer Reihe von Java-Technologien. Betrachten wir drei davon: JDBC (das Java Database Connectivity-Paket), JMS (der Java Messaging Service) und EJB (Enterprise JavaBeans).

JDBC ist die Java-Technologie für relationale Datenbanken. JNDI wurde erstmals im optionalen JDBC 2.0-Paket (siehe Ressourcen) in Verbindung mit der DataSourceSchnittstelle angezeigt. Eine DataSourceInstanz stellt, wie der Name schon sagt, eine Datenquelle dar - oft aus einer Datenbank, aber nicht immer. Eine DataSourceInstanz speichert Informationen zu einer Datenquelle - wie den Namen, den zu ladenden und zu verwendenden Treiber und ihren Speicherort - und ermöglicht einer Anwendung, eine Verbindung zur Datenquelle ohne Berücksichtigung der zugrunde liegenden Details herzustellen. In der JDBC-Spezifikation wird empfohlen, JNDI zum Speichern von DataSourceObjekten zu verwenden.

JMS ist die Java-Technologie für Messaging. Die JMS-Spezifikation beschreibt verwaltete Objekte - Objekte, die JMS-Konfigurationsinformationen enthalten und von JMS-Clients zum Auffinden bestimmter Nachrichtenwarteschlangen und -themen verwendet werden. Wie bei JDBC wird in der Spezifikation empfohlen, von JMS verwaltete Objekte über JNDI zu lokalisieren.

Betrachten Sie abschließend Enterprise JavaBeans. Alle Enterprise-Beans veröffentlichen über JNDI eine Home-Schnittstelle - den einzigen Speicherort, über den Clients eine bestimmte Enterprise-Bean finden.

Was bringt JNDI auf den Tisch, was dazu führt, dass es so hoch angesehen wird?

Erstens fördert JNDI die Idee einer zentral verwalteten Informationsquelle - eine wichtige Voraussetzung für Unternehmensanwendungen. Eine zentral verwaltete Informationsquelle ist einfacher zu verwalten als eine verteilte Sammlung von Informationsquellen. Für Kunden ist es auch einfacher, die benötigten Informationen zu finden, wenn sie nur an einem Ort suchen müssen.

Zweitens ermöglicht die Fähigkeit von JNDI, Java-Objekte direkt zu speichern, eine nahezu transparente Integration in Java-Anwendungen.

Der Punkt des Anbieters

Um JNDI verwenden zu können, benötigen Sie einen Namens- und Verzeichnisdienst sowie einen JNDI-Dienstanbieter. Sun bietet mehrere Anbieter allgemeiner Namens- und Verzeichnisdienste an (COS-Namen, NIS, RMI-Registrierung, LDAP und mehr). Ich habe mich für LDAP entschieden.

LDAP (Lightweight Directory Access Protocol) bietet den doppelten Vorteil, dass es umfassend implementiert ist (sowohl in kommerzieller als auch in freier Form) und relativ einfach zu verwenden ist. Die Funktionen werden auch von Suns LDAP-Dienstanbieter und JNDI gut unterstützt.

Da das Abrufen und Konfigurieren eines LDAP-Servers nicht wirklich ein Java-Thema ist, werde ich Sie nur in die richtige Richtung führen und Ihnen Verweise auf Internetressourcen liefern.

Es stehen zahlreiche LDAP-Implementierungen zur Verfügung. Bei vielen handelt es sich um kommerzielle Produkte wie den Netscape Directory Server und das Secure Way Directory von IBM. Einige sind Teil größerer Angebote (Microsoft Active Directory ist Teil von Windows 2000). Wenn Sie Zugriff auf eine solche Implementierung haben, können Sie den größten Teil dieses Abschnitts überspringen. Ansonsten werde ich OpenLDAP - eine frei verfügbare Implementierung von LDAP basierend auf der Referenzimplementierung der University of Michigan - sowie deren Installation und Konfiguration beschreiben.

OpenLDAP ist bei der OpenLDAP Foundation erhältlich (siehe Ressourcen). Die Lizenz basiert auf Perls "künstlerischer Lizenz", was bedeutet, dass OpenLDAP freie (oder Open Source) Software ist. Vorgefertigte Binärdateien sind für verschiedene Linux-Varianten (Debian, Red Hat) sowie BSD Unix verfügbar. An einem Port für Windows NT wird derzeit gearbeitet.

Wenn Sie OpenLDAP installieren möchten, lesen Sie das SLAPD- und SLURPD-Administratorhandbuch (slapd ist der Name der ausführbaren Datei des LDAP-Servers und slurpd ist der Name des LDAP-Replikationsservers; den Speicherort finden Sie unter Ressourcen).

Ich habe einen letzten Vorschlag Ihre gesamte Erfahrung angenehmer zu machen: egal , welche LDAP - Implementierung Sie verwenden, wiederum Schema Überprüfung aus . Ein LDAP-Schema definiert wie ein Datenbankschema Einschränkungen für die gespeicherten Informationen. Bei normaler Verwendung stellt die Schemaüberprüfung sicher, dass Einträge (denken Sie an Adressbucheinträge) dem richtigen Format entsprechen. Da Sie jedoch wahrscheinlich spielen, anstatt etwas von bleibender Bedeutung aufzubauen, wird die Schemaüberprüfung nur stören. Verlass dich drauf.

Verbindung zu einem JNDI-Kontext herstellen

In früheren Artikeln habe ich versucht zu vermeiden, ausführlich zu erklären, wie mit einem JNDI-Dienstanbieter wie dem LDAP-Dienstanbieter interagiert wird. Ich erwähnte, dass Sie einen anfänglichen Kontext benötigen, um JNDI-Operationen auszuführen, aber ich habe nicht viel Zeit damit verbracht, Ihnen zu erklären, wie Sie einen bekommen. Lassen Sie mich die Lücken füllen. (Weitere Informationen zu anfänglichen Kontexten finden Sie in den ersten beiden Artikeln dieser Reihe.)

Bevor Sie etwas mit JNDI tun können, benötigen Sie einen ersten Kontext. Alle Operationen werden relativ zum Kontext oder einem seiner Unterkontexte ausgeführt.

Das Erhalten eines anfänglichen Kontexts erfordert drei Schritte:

  1. Wählen Sie zunächst einen Dienstanbieter aus. Wenn Sie OpenLDAP oder eine andere LDAP-Implementierung verwenden, stellt Sun einen Referenz-LDAP-Dienstanbieter bereit (siehe Ressourcen). Fügen Sie den Namen des Dienstanbieters zu den Umgebungseigenschaften hinzu (in einer HashtableInstanz gespeichert ):

    Hashtable hashtableEnvironment = new Hashtable (); hashtableEnvironment.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  2. Fügen Sie alle zusätzlichen Informationen hinzu, die der Dienstanbieter benötigt. Bei LDAP umfasst dies die URL, die den Dienst, den Stammkontext sowie den Namen und das Kennwort für die Verbindung angibt:

    // der Dienst: ldap: // localhost: 389 / // der Stammkontext: dc = etcee, dc = com hashtableEnvironment.put (Context.PROVIDER_URL, "ldap: // localhost: 389 / dc = etcee, dc = com "); hashtableEnvironment.put (Context.SECURITY_PRINCIPAL, "name"); hashtableEnvironment.put (Context.SECURITY_CREDENTIALS, "Passwort");
  3. Finally, get the initial context. If you just intend to perform naming operations, you'll only need a Context instance. If you intend to perform a directory operation as well, you'll need a DirContext instance instead. Not all providers supply both:

     Context context = new InitialContext(hashtableEnvironment); 

    Or:

     DirContext dircontext = new InitialDirContext(hashtableEnvironment); 

That's all there is to it. Now let's look at how applications store objects to and retrieve objects from JNDI.

Work with objects

The ability to store Java objects is useful: object storage provides persistence and allows objects to be shared between applications or between different executions of the same application.

From the standpoint of the code involved, object storage is surprisingly easy:

 context.bind("name", object) 

The bind() operation binds a name to a Java object. The syntax of the command is reminiscent of RMI, but the semantics are not as clearly defined. It's permissible for the bind() operation to store either a snapshot of the object or a reference to a "live" object, for example.

Be aware that the bind() operation throws a NamingException if an exception occurs during the execution of the operation.

Now let's take a look at the bind() operation's complement -- lookup():

 Object object = context.lookup("name") 

The lookup() operation retrieves the object bound to the specified name. Once again, the syntax is reminiscent of RMI, but the method's semantics are not as clearly defined.

Just as with bind(), the lookup() operation throws a NamingException if an exception occurs during the execution of the operation.

Object storage

What does it mean to store an object in a JNDI naming and directory service? We've already mentioned that the exact semantics of the bind() and lookup() operations aren't tightly defined; it's up to the JNDI service provider to define their semantics.

According to the JNDI specification, service providers are encouraged (but not required) to support object storage in one of the following formats:

  • Serialized data
  • Reference
  • Attributes in a directory context

If all JNDI service providers support these standard mechanisms, Java programmers are free to develop generic solutions that work even when the underlying service provider layer changes.

Each of the methods above has advantages and disadvantages. The best method will depend on the requirements of the application under development.

Let's consider each in turn.

As serialized data

The most obvious approach to storing an object in a directory is to store the serialized representation of an object. The only requirement is that the object's class implement the Serializable interface.

When an object is serialized, its state becomes transformed into a stream of bytes. The service provider takes the stream of bytes and stores it in the directory. When a client looks up the object, the service provider reconstructs it from the stored data.

The following code demonstrates how to bind a LinkedList to an entry in an JNDI service:

 // create linked list LinkedList linkedlist = new LinkedList(); . . . // bind context.bind("cn=foo", linkedlist); . . . // lookup linkedlist = (LinkedList)context.lookup("cn=foo"); 

It's that easy!

Unfortunately, the other two methods are more complicated. I will describe them briefly but reserve a detailed discussion for a later date.

As a reference

Sometimes it's not appropriate (or possible) to serialize an object. If the object provides a service on a network, for example, it doesn't make sense to store the state of the object itself. We're interested in the information necessary to find and communicate with the object.

An example is a connection to an external resource (one outside the scope of the Java Virtual Machine) such as a database or file. It clearly doesn't make sense to try to store the database or the file itself in the JNDI service. Instead, we want to store the information necessary to reconstruct the connection.

In this case the programmer should either bind a Reference instance that corresponds to the object or have the object's class implement the Referenceable interface (in which the object generates and provides a Reference instance when requested by the service provider).

The Reference instance contains enough information to recreate the reference. If a reference to a file was stored, the reference contains enough information to create a File object that points to the correct file.

As attributes

If you're using a service provider that provides directory functionality instead of only naming functionality, you can also store an object as a collection of attributes on a DirContext object (a DirContext instance differs from a Context instance in that it may have attributes).

To use this method, you must create objects that implement the DirContext interface and contain the code necessary to write their internal state as an Attributes object. You must also create an object factory to reconstitute the object.

This approach is useful when the object must be accessible by non-Java applications.

Conclusion

If you've read the series, you should understand and appreciate the power and importance of JNDI -- you don't hear much about it, but it's there under the covers.

Nächsten Monat werfen wir einen Blick auf eine JNDI-basierte Anwendung. In der Zwischenzeit sollten Sie versuchen, JNDI auf einem LDAP-Server zum Laufen zu bringen.

Erfahren Sie mehr über dieses Thema

  • Das optionale JDBC 2.0-Paket

    //java.sun.com/products/jdbc/articles/package2.html

  • Gehen Sie zur OpenLDAP Foundation, um OpenLDAP herunterzuladen

    //www.openldap.org/

  • Um das SLAPD- und SLURPD-Administratorhandbuch herunterzuladen , gehen Sie zu

    //www.umich.edu/~dirsvcs/ldap/doc/guides/

  • JNDI-Informationen, Dienstanbieter usw.

    //java.sun.com/products/jndi/

Diese Geschichte, "JNDI-Übersicht, Teil 3: Advanced JNDI", wurde ursprünglich von JavaWorld veröffentlicht.