Descripción general de JNDI, Parte 3: JNDI avanzado

Necesito cubrir mucho terreno este mes, así que dejaré de lado la pelusa y iré directo a los puntos. En primer lugar, la interfaz de directorio y nombres de Java desempeña un papel importante en varias tecnologías Java. Vamos a echar un vistazo a este rol para comprender mejor la posición estratégica de JNDI en el panorama general de Java. A continuación, en reconocimiento de su necesidad de un servicio JNDI funcional con el que jugar, le presentaré una implementación LDAP portátil disponible de forma gratuita y le enseñaré cómo conectarse y utilizar un proveedor de servicios JNDI. Finalmente, lo llevaré a ver de cerca cómo vincular objetos a entradas en JNDI.

CAJA DE TEXTO:

TEXTBOX_HEAD: Descripción general de JNDI: ¡Lea la serie completa!

  • Parte 1. Introducción a los servicios de nombres

  • Parte 2. Utilice los servicios de directorio JNDI para administrar mejor sus aplicaciones distribuidas

  • Parte 3. Utilice JNDI para almacenar los objetos de su aplicación distribuida

  • Parte 4. Reúna lo que ha aprendido con una aplicación habilitada para JNDI

: END_TEXTBOX

Antes de empezar, conviene pensar dos veces. Durante los últimos dos meses, he intentado convencerlo de que los servicios de nombres y directorios son aproximadamente el equivalente electrónico de los catálogos de tarjetas que se encuentran en las bibliotecas. Ahora que comenzamos nuestro recorrido por las funciones avanzadas de JNDI, quiero que olvide esta analogía por completo, ya que ilustra muy poco el poder de JNDI.

Comencemos con un vistazo a cómo aparece JNDI en otras tecnologías Java.

JNDI en todas partes

JNDI juega un papel en una serie de tecnologías Java. Consideremos tres de ellos: JDBC (el paquete de conectividad de bases de datos de Java), JMS (el servicio de mensajería de Java) y EJB (Enterprise JavaBeans).

JDBC es la tecnología Java para bases de datos relacionales. JNDI apareció por primera vez en el paquete opcional JDBC 2.0 (ver Recursos) junto con la DataSourceinterfaz. Una DataSourceinstancia, como su nombre lo indica, representa una fuente de datos, a menudo de una base de datos, pero no siempre. Una DataSourceinstancia almacena información sobre una fuente de datos, como su nombre, el controlador a cargar y usar, y su ubicación, y permite que una aplicación obtenga una conexión a la fuente de datos sin tener en cuenta los detalles subyacentes. La especificación JDBC recomienda utilizar JNDI para almacenar DataSourceobjetos.

JMS es la tecnología Java para mensajería. La especificación JMS describe los objetos administrados: objetos que contienen información de configuración de JMS y que los clientes JMS utilizan para localizar colas de mensajes y temas específicos. Como es el caso de JDBC, la especificación recomienda ubicar los objetos administrados por JMS a través de JNDI.

Finalmente, considere Enterprise JavaBeans. Todos los beans empresariales publican una interfaz de inicio, la ubicación única a través de la cual los clientes ubican un bean empresarial específico, a través de JNDI.

¿Qué aporta JNDI a la mesa que hace que sea tan apreciado?

Primero, JNDI promueve la noción de una fuente de información administrada de forma centralizada, un requisito clave para las aplicaciones empresariales. Una fuente de información gestionada de forma centralizada es más fácil de administrar que una colección distribuida de fuentes de información. También es más sencillo para los clientes localizar la información necesaria si solo tienen que buscar en un lugar.

En segundo lugar, como verá, la capacidad de JNDI para almacenar directamente objetos Java le permite integrarse de forma casi transparente en aplicaciones Java.

El punto del proveedor

Para utilizar JNDI, necesita un servicio de directorio y nombres y un proveedor de servicios JNDI. Sun ofrece varios proveedores de servicios de directorio y nombres comunes (nombres COS, NIS, registro RMI, LDAP y más). Me decidí por LDAP.

LDAP (Lightweight Directory Access Protocol) tiene la doble ventaja de estar ampliamente implementado (tanto en forma comercial como gratuita) y ser razonablemente fácil de usar. Sus funciones también cuentan con el respaldo del proveedor de servicios LDAP de Sun y JNDI.

Dado que obtener y configurar un servidor LDAP no es realmente un tema de Java, solo lo guiaré en la dirección correcta y le proporcionaré referencias a los recursos de Internet.

Se encuentran disponibles numerosas implementaciones de LDAP. Muchos son productos comerciales como Netscape Directory Server y Secure Way Directory de IBM. Algunos están empaquetados como parte de ofertas más grandes (Active Directory de Microsoft es parte de Windows 2000). Si tiene acceso a dicha implementación, puede omitir la mayor parte de esta sección. De lo contrario, describiré OpenLDAP, una implementación de LDAP de libre acceso basada en la implementación de referencia de la Universidad de Michigan, así como su instalación y configuración.

OpenLDAP está disponible en OpenLDAP Foundation (ver Recursos). Su licencia se basa en la "licencia artística" de Perl, lo que significa que OpenLDAP es un software gratuito (o de código abierto). Los binarios preempaquetados están disponibles para varios tipos de Linux (Debian, Red Hat) y BSD Unix. Se está trabajando en un puerto para Windows NT.

Si planea instalar OpenLDAP, debe leer la Guía del administrador de SLAPD y SLURPD (slapd es el nombre del ejecutable del servidor LDAP y slurpd es el nombre del servidor de replicación LDAP; consulte Recursos para conocer la ubicación).

Tengo una última sugerencia para hacer que toda su experiencia más agradable: no importa qué implementación LDAP que utiliza, a su vez esquema de comprobación fuera . Un esquema LDAP, como un esquema de base de datos, define restricciones sobre la información almacenada. En uso normal, la verificación del esquema ayuda a garantizar que las entradas (piense en las entradas de la libreta de direcciones) se ajustan al formato correcto. Sin embargo, dado que probablemente jugará en lugar de construir algo de importancia duradera, la verificación del esquema se interpondrá en el camino. Confíe en mi palabra.

Conexión a un contexto JNDI

En artículos anteriores, traté de evitar explicar en detalle cómo interactuar con un proveedor de servicios JNDI como el proveedor de servicios LDAP. Mencioné que necesita un contexto inicial para hacer operaciones JNDI, pero no dediqué mucho tiempo a decirle cómo obtener uno. Déjame llenar los vacíos. (Para obtener más información sobre los contextos iniciales, consulte los dos primeros artículos de esta serie).

Antes de que pueda hacer algo con JNDI, necesita un contexto inicial. Todas las operaciones se realizan en relación con el contexto o uno de sus subcontextos.

Obtener un contexto inicial requiere tres pasos:

  1. Primero, seleccione un proveedor de servicios. Si va a utilizar OpenLDAP o alguna otra implementación de LDAP, Sun proporciona un proveedor de servicios LDAP de referencia (consulte Recursos). Agregue el nombre del proveedor de servicios al conjunto de propiedades del entorno (almacenadas en una Hashtableinstancia):

    Hashtable hashtableEnvironment = new Hashtable (); hashtableEnvironment.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
  2. Agregue cualquier información adicional que requiera el proveedor de servicios. Para LDAP, eso incluye la URL que identifica el servicio, el contexto raíz y el nombre y la contraseña para conectarse:

    // el servicio: ldap: // localhost: 389 / // el contexto raíz: dc = etcee, dc = com hashtableEnvironment.put (Context.PROVIDER_URL, "ldap: // localhost: 389 / dc = etcee, dc = com "); hashtableEnvironment.put (Context.SECURITY_PRINCIPAL, "nombre"); hashtableEnvironment.put (Context.SECURITY_CREDENTIALS, "contraseña");
  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.

El mes que viene veremos una aplicación basada en JNDI. Mientras tanto, debería intentar poner JNDI en funcionamiento en un servidor LDAP.

Más información sobre este tema

  • El paquete opcional JDBC 2.0

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

  • Vaya a OpenLDAP Foundation para descargar OpenLDAP

    //www.openldap.org/

  • Para descargar la Guía del administrador de SLAPD y SLURPD , vaya a

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

  • Información JNDI, proveedores de servicios, etc.

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

Esta historia, "Descripción general de JNDI, Parte 3: JNDI avanzado" fue publicada originalmente por JavaWorld.