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_HEAD: JNDI overview: Read the whole series!
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 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@example.com Email: firstname.lastname@example.org
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
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
The bind() method
void bind( String stringName, Object object, Attributes attributes )
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
object is an instance of the
DirContext class, the resulting binding will retain the attributes originally associated with
The rebind() method
void rebind( String stringName, Object object, Attributes attributes )
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 )
createSubcontext() method creates a new subcontext and binds a name to it, and then stores the specified attributes with that entry. If
null, this method works in exactly the same fashion as the like-named method on the
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 )
Attributes getAttributes( String stringName, String  rgstringAttributeNames )
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 )
void modifyAttributes( String stringName, ModificationItem  rgmodificationitem )
modifyAttributes methods modify the attributes associated with the specified entry. The permitted operations are
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
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 )
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 )
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 (
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 (
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
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.
Learn more about this topic
- All things JNDI
- JNDI documentation
- Service providers currently available for JNDI
- The original LDAP site at the University of Michigan
- RPC 1777 -- Lightweight Directory Access Protocol
- RFC 2254 -- A string representation of LDAP search filters