JNDI overview, Part 2: An introduction to directory services

Use JNDI directory services to better manage your distributed applications

Return with me, for a moment, to last month’s point of departure. I introduced you (or reintroduced you, as the case may be) to that aged institution known as a library. I did so in order to draw an analogy between a physical tool known as a card catalog and a programming tool known as a naming service. The key to this analogy was the simple notion of looking something up by name in a centralized repository in order to more quickly determine its location. In a library, the card catalog maps the names of books to references to their locations on the shelves; in a distributed system, the naming service maps the names of objects to references to their locations in a network. Both tools are extremely useful in their respective domains.

TEXTBOX:

TEXTBOX_HEAD: JNDI overview: Read the whole series!

  • Part 1. An introduction to naming services

  • Part 2. Use JNDI directory services to better manage your distributed applications

  • Part 3. Use JNDI to store your distributed application’s objects

  • Part 4. Pull together what you’ve learned with a JNDI-enabled application

:END_TEXTBOX

It turns out that, with little effort, I can stretch this analogy even farther. You see, a card in a card catalog contains more than just a book’s location; it also contains the author’s name, the date the book was published, the book’s length, and many other useful bits of information. I can find out a lot about the book without actually having to go and get it.

In the domain of computer software, tools that provide this type of information are known as directories. It appears that, once again, a technique popularized long ago by librarians has turned out to be useful to software developers. (It makes me wonder what other little gems lie hidden within the infrastructure of the corner library.)

An introduction to directory services

A directory service provides a way to manage the storage and distribution of shared information. Such information can range from the email addresses and phone numbers of a company’s employees, to the IP addresses and print capabilities of a department’s printers, to the configuration information for a suite of application servers.

The figure below depicts a generic directory service.

A generic directory service

A directory service manages a directory of entries. A directory entry can refer to a person, place, service, or almost any other concrete object or abstract concept. An entry also has attributes associated with it; an attribute consists of a name or identifier and one or more values. These attributes describe the entry, and the exact set of attributes depends on the type of the entry. For example, the entry for an individual might have the following attributes (note the two email addresses):

Name: John Doe
Address: 123 Somewhere Street
Email: [email protected]
Email: [email protected]

Directory services are simple databases. Like their relational cousins, many common directory services provide search and filter functionality. Instead of locating an entry only by name, these directory services allow you to locate entries based on a set of search criteria.

Naming services and directory services are logical partners. In fact, most existing products provide both sets of functionality. Naming services provide name-to-object mapping, and directory services provide information about the objects and tools for searching for them.

There are a number of existing directory service products; LDAP (the Lightweight Directory Access Protocol) is the most common. LDAP provides both naming and directory functionality. Numerous commercial implementations exist, as well as some freely available implementations (OpenLDAP being the most common — see the Resources section below for more information).

Descriptions of various directory services are available in January’s How-To Java column.

A look at JNDI directory services

JNDI directory-service support is both comprehensive and powerful. It adds advanced functions, like storing and retrieving serialized class instances, to searching and other components of the basic suite of direct functions. This month, we will pass on the advanced features and focus on understanding basic JNDI directory functionality.

With this thought in mind, let’s examine the DirContext class — the heart of JNDI directory services.

Working with attributes

The DirContext class is a subclass of the Context class described last month. It provides all of the standard naming service functionality, and can also work with attributes and search for directory entries.

Let’s take a look at the methods of DirContext that extend those methods provided by the Context class.

The bind() method

void
bind(
   String stringName,
   Object object,
   Attributes attributes
)

The bind() method binds a name to an object and stores the specified attributes with that entry. This operation generally tries to preserve existing attributes in cases in which that makes sense. Specifically, if attributes is null and object is an instance of the DirContext class, the resulting binding will retain the attributes originally associated with object.

The rebind() method

void
rebind(
   String stringName,
   Object object,
   Attributes attributes
)

The rebind() method binds a name to an object and stores the specified attributes with that entry. The previous binding is replaced. As is the case with bind(), this operation tries to preserve existing attributes in cases in which that would make sense.

The createSubcontext() method

DirContext
createSubcontext(
   String stringName,
   Attributes attributes
)

The createSubcontext() method creates a new subcontext and binds a name to it, and then stores the specified attributes with that entry. If attributes is null, this method works in exactly the same fashion as the like-named method on the Context class.

Let’s next consider those of DirContext‘s methods that do not extend methods provided by the Context class, providing the tools for working with attributes instead.

The getAttributes() methods

The class provides two flavors of this method:

Attributes
getAttributes(
   String stringName
)

And:

Attributes
getAttributes(
   String stringName,
   String [] rgstringAttributeNames
)

The getAttributes methods return the attributes associated with the specified entry. The Attributes class represents a collection of attributes; it contains instances of the Attribute class, which by itself represents a single attribute. The first flavor of this method returns all attributes, and the second returns the attributes named in the supplied array of attribute names.

The modifyAttributes methods

modifyAttributes comes in two flavors as well:

void
modifyAttributes(
   String stringName,
   int nOperation,
   Attributes attributes
)

And:

void
modifyAttributes(
   String stringName,
   ModificationItem [] rgmodificationitem
)

The modifyAttributes methods modify the attributes associated with the specified entry. The permitted operations are ADD_ATTRIBUTE, REPLACE_ATTRIBUTE, and REMOVE_ATTRIBUTE. The first flavor of this method modifies several attributes in the same way, while the second performs a series of modifications on one or more attributes.

As with the Context class, each of the methods above also has a variant that takes a Name object rather than a String object.

Searching

In order to make use of directory service functionality, it is necessary to have some way to search the contents of a directory service. The DirContext class provides two general models by which searches may be conducted.

Searching by attribute name

There are two ways to conduct a search following this model:

NamingEnumeration
search(
  String stringName,
  Attributes attributesToMatch
)

And:

NamingEnumeration
search(
   String stringName,
   Attributes attributesToMatch,
   String [] rgstringAttributesToReturn
)

In this first model, the search occurs within a single context for entries that contain a specific set of attributes. For the entities that match, the search retrieves either the entire set of attributes (if the search is implemented using the first block of code above) or a select set of attributes (if the search is implemented using the second). Now, let’s look at the second model.

Searching by RFC 2254 filter

Again, there are two ways to implement this model:

NamingEnumeration
search(
   Name stringName,
   String stringRFC2254Filter,
   SearchControls searchcontrols
)

And:

NamingEnumeration
search(
   Name             stringName,
   String           stringRFC2254Filter,
   Object []        stringRFC2254FilterArgs,
   SearchControls   searchcontrols
)

In our second model, the search occurs within a context for entries that satisfy a search filter. RFC 2254 (which describes a string representation for LDAP search filters — see Resources for more information) defines the format of the filter.

An instance of the SearchControls class controls key aspects of the search:

SearchControls(
   int              nSearchScope,
   long             nEntryLimit,
   int              nTimeLimit,
   String []        rgstringAttributesToReturn,
   boolean          boolReturnObject,
   boolean          boolDereferenceLinks
)

The constructor above lists all of the aspects of a search that a SearchControls instance affects. Corresponding accessors (get and set methods) also exist. Below, I’ve listed each of these aspects and a short description of each:

  • nSearchScope: Sets the scope of the search to either the object (OBJECT_SCOPE), the object and the level immediately below it (ONELEVEL_SCOPE), or the object and its entire subtree (SUBTREE_SCOPE).

  • nEntryLimit: Sets the maximum number of entries that the search will return.

  • nTimeLimit: Sets the maximum number of milliseconds that the search will run.

  • rgstringAttributesToReturn: Determines which attributes should be returned along with the entries returned by the search.

  • boolReturnObject: Determines whether or not the objects bound to selected entries should to be returned along with the entries returned by the search.

  • boolDereferenceLinks: Determines whether or not links should be dereferenced links (or followed to their ultimate destination) during the search. A link references another directory entry and can span multiple naming systems. The underlying JNDI service provider may or may not provide support for links.

Once again, each of the methods above also has a variant that takes a Name object rather than a String.

Conclusion

If you’ve made it this far, you should now have a solid understanding of both naming and directory services, and a general understanding of JNDI. Next month, we’ll build a handful of JNDI-based tools to work with. Since JNDI requires an underlying service provider in order to function, we’ll also take a look at building and installing one of the freely available LDAP implementations.

Todd Sundsted has been writing programs since
computers became available in convenient desktop models. Though
originally interested in building distributed applications in C++,
Todd moved on to the Java programming language when it became the
obvious choice for that sort of thing. In addition to writing, Todd
also serves as a Java architect with ComFrame Software.

Source: www.infoworld.com