Présentation de JNDI, Partie 3: JNDI avancé

J'ai besoin de couvrir beaucoup de terrain ce mois-ci, alors je vais laisser de côté les peluches et passer directement aux puces. Premièrement, l'interface de nommage et d'annuaire Java joue un rôle important dans plusieurs technologies Java. Nous allons examiner ce rôle pour mieux comprendre la position stratégique de JNDI dans l'image globale de Java. Ensuite, en reconnaissance de votre besoin d'un service JNDI fonctionnel avec lequel jouer, je vais vous présenter une implémentation LDAP portable et disponible gratuitement, et je vous apprendrai comment vous connecter et utiliser un fournisseur de services JNDI. Enfin, je vous présenterai de plus près la liaison d'objets aux entrées dans JNDI.

ZONE DE TEXTE:

TEXTBOX_HEAD: Aperçu JNDI: Lisez toute la série!

  • Partie 1. Une introduction aux services de dénomination

  • Partie 2. Utilisez les services d'annuaire JNDI pour mieux gérer vos applications distribuées

  • Partie 3. Utilisez JNDI pour stocker les objets de votre application distribuée

  • Partie 4. Rassemblez ce que vous avez appris avec une application compatible JNDI

: END_TEXTBOX

Avant de commencer, une petite double réflexion s'impose. Au cours des deux derniers mois, j'ai essayé de vous convaincre que les services de dénomination et d'annuaire sont à peu près l'équivalent électronique des catalogues sur fiches que l'on trouve dans les bibliothèques. Maintenant que nous commençons notre visite des fonctionnalités avancées de JNDI, je veux que vous oubliez complètement cette analogie - elle sous-illustre largement la puissance de JNDI.

Commençons par voir comment JNDI apparaît dans d'autres technologies Java.

JNDI partout

JNDI joue un rôle dans un certain nombre de technologies Java. Considérons trois d'entre eux: JDBC (le package Java Database Connectivity), JMS (le service de messagerie Java) et EJB (Enterprise JavaBeans).

JDBC est la technologie Java pour les bases de données relationnelles. JNDI est apparu pour la première fois dans le package optionnel JDBC 2.0 (voir Ressources) en conjonction avec l' DataSourceinterface. Une DataSourceinstance, comme son nom l'indique, représente une source de données - souvent à partir d'une base de données mais pas toujours. Une DataSourceinstance stocke des informations sur une source de données - telles que son nom, le pilote à charger et utiliser, ainsi que son emplacement - et permet à une application d'obtenir une connexion à la source de données sans tenir compte des détails sous-jacents. La spécification JDBC recommande d'utiliser JNDI pour stocker des DataSourceobjets.

JMS est la technologie Java pour la messagerie. La spécification JMS décrit les objets administrés - objets qui contiennent des informations de configuration JMS et sont utilisés par les clients JMS pour localiser des files d'attente de messages et des rubriques spécifiques. Comme c'est le cas avec JDBC, la spécification recommande de localiser les objets administrés par JMS via JNDI.

Enfin, considérez Enterprise JavaBeans. Tous les beans entreprise publient une interface d'accueil - l'emplacement unique par lequel les clients localisent un bean entreprise spécifique - via JNDI.

Qu'est-ce que JNDI apporte à la table qui fait qu'il soit si apprécié?

Premièrement, JNDI promeut la notion de source d'informations gérée de manière centralisée - une exigence clé pour les applications d'entreprise. Une source d'informations gérée de manière centralisée est plus facile à administrer qu'une collection distribuée de sources d'informations. Il est également plus simple pour les clients de localiser les informations dont ils ont besoin s'ils n'ont qu'à chercher dans un seul endroit.

Deuxièmement, comme vous le verrez, la capacité de JNDI à stocker directement des objets Java lui permet de s'intégrer de manière presque transparente dans les applications Java.

Le point du fournisseur

Pour utiliser JNDI, vous avez besoin d'un service de dénomination et d'annuaire et d'un fournisseur de services JNDI. Sun fournit plusieurs fournisseurs de services de noms et d'annuaires courants (noms COS, NIS, registre RMI, LDAP, etc.). J'ai choisi LDAP.

LDAP (Lightweight Directory Access Protocol) a le double avantage d'être largement implémenté (à la fois sous forme commerciale et gratuite) et d'être raisonnablement facile à utiliser. Ses fonctionnalités sont également bien prises en charge par le fournisseur de services LDAP de Sun et JNDI.

Étant donné que l'obtention et la configuration d'un serveur LDAP ne sont pas vraiment un sujet Java, je ne ferai que vous orienter dans la bonne direction et vous fournir des références aux ressources Internet.

De nombreuses implémentations LDAP sont disponibles. Beaucoup sont des produits commerciaux tels que Netscape Directory Server et IBM Secure Way Directory. Certains sont regroupés dans le cadre d'offres plus importantes (Active Directory de Microsoft fait partie de Windows 2000). Si vous avez accès à une telle implémentation, vous pouvez ignorer la majeure partie de cette section. Sinon, je vais décrire OpenLDAP - une implémentation disponible gratuitement de LDAP basée sur l'implémentation de référence de l'Université du Michigan - ainsi que son installation et sa configuration.

OpenLDAP est disponible auprès de la Fondation OpenLDAP (voir Ressources). Sa licence est basée sur la «licence artistique» de Perl, ce qui signifie qu'OpenLDAP est un logiciel libre (ou open source). Les binaires pré-emballés sont disponibles pour différentes versions de Linux (Debian, Red Hat) ainsi que BSD Unix. Des travaux sont en cours sur un port vers Windows NT.

Si vous prévoyez d'installer OpenLDAP, vous devez lire le Guide de l'administrateur SLAPD et SLURPD (slapd est le nom de l'exécutable du serveur LDAP et slurpd est le nom du serveur de réplication LDAP; voir Ressources pour l'emplacement).

J'ai une dernière suggestion pour rendre plus agréable votre expérience entière: quelle que soit la mise en œuvre LDAP que vous utilisez, le schéma de tour vérifier hors . Un schéma LDAP, comme un schéma de base de données, définit des contraintes sur les informations stockées. En utilisation normale, la vérification du schéma permet de s'assurer que les entrées (pensez aux entrées du carnet d'adresses) sont conformes au format correct. Cependant, comme vous jouerez probablement plutôt que de construire quelque chose d'une importance durable, la vérification du schéma ne fera que vous gêner. Croyez-moi sur parole.

Connexion à un contexte JNDI

Dans les articles précédents, j'ai essayé d'éviter d'expliquer en détail comment interagir avec un fournisseur de services JNDI tel que le fournisseur de services LDAP. J'ai mentionné que vous avez besoin d'un contexte initial pour faire des opérations JNDI, mais je n'ai pas passé beaucoup de temps à vous dire comment en obtenir un. Permettez-moi de combler les lacunes. (Pour en savoir plus sur les contextes initiaux, consultez les deux premiers articles de cette série.)

Avant de pouvoir faire quoi que ce soit avec JNDI, vous avez besoin d'un contexte initial. Toutes les opérations sont effectuées par rapport au contexte ou à l'un de ses sous-contextes.

L'obtention d'un contexte initial nécessite trois étapes:

  1. Tout d'abord, sélectionnez un fournisseur de services. Si vous allez utiliser OpenLDAP ou une autre implémentation LDAP, Sun fournit un fournisseur de services LDAP de référence (voir Ressources). Ajoutez le nom du fournisseur de services à l'ensemble des propriétés d'environnement (stockées dans une Hashtableinstance):

    Hashtable hashtableEnvironment = new Hashtable (); hashtableEnvironment.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  2. Ajoutez toute information supplémentaire requise par le fournisseur de services. Pour LDAP, cela inclut l'URL qui identifie le service, le contexte racine et le nom et le mot de passe avec lesquels se connecter:

    // le service: ldap: // localhost: 389 / // le contexte racine: dc = etcee, dc = com hashtableEnvironment.put (Context.PROVIDER_URL, "ldap: // localhost: 389 / dc = etcee, dc = com "); hashtableEnvironment.put (Context.SECURITY_PRINCIPAL, "nom"); hashtableEnvironment.put (Context.SECURITY_CREDENTIALS, "mot de passe");
  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.

Le mois prochain, nous examinerons une application basée sur JNDI. En attendant, vous devriez essayer de faire fonctionner JNDI sur un serveur LDAP.

En savoir plus sur ce sujet

  • Le package optionnel JDBC 2.0

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

  • Accédez à la Fondation OpenLDAP pour télécharger OpenLDAP

    //www.openldap.org/

  • Pour télécharger le guide de l'administrateur SLAPD et SLURPD , accédez à

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

  • Informations JNDI, fournisseurs de services, etc.

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

Cette histoire, "Vue d'ensemble de JNDI, Partie 3: JNDI avancé" a été initialement publiée par JavaWorld.