< Zurück | Inhalt | Weiter >

21.3.3 Putting a Face to a Name: JNDI

The Java Naming and Directory Interface package is designed to provide a common way to access all of these disparate naming and directory services.

The JNDI architecture consists of the JNDI API, which provides a consis- tent API, and a Service Provider Interface (SPI), which requires an instance to connect to each naming service (such as DNS, LDAP, the RMI registry, and so on).

Basic naming system functionality is obtained through the javax.naming package. Directory services are provided by the javax.naming.directory package.

Since JNDI can span multiple naming and directory systems, there are no absolute root contexts, so the InitialContext class exists to provide a base from which all other names and directories may be looked up.


21.3.3.1 A Sample JNDI Program

The next couple of sections describe a very simple JNDI application that uses the DNS Service Provider Interface to do directory operations on a DNS domain. The source code for the class is shown in Example 21.1.


image

Example 21.1 A sample JNDI application

import java.util.*; import javax.naming.*;

import javax.naming.directory.*;


5

public class GetDomain {

private Hashtable env = new Hashtable(); private DirContext dctx;

private String domainQuery;

10

public GetDomain(String dom2Query) throws NamingException { domainQuery = dom2Query;

env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); dctx = new InitialDirContext(env);

15 }


public NamingEnumeration getDomainMembers() throws NamingException { return dctx.list(domainQuery);

}

20

public static void main(String[] args) { GetDomain gd = null;

NamingEnumeration ne = null;


25 try {

gd = new GetDomain(args[0]); ne = gd.getDomainMembers();


while (ne.hasMore()) {

30 Object o = ne.next();


System.out.println("Object ["+o+"]");

}

} catch (Exception e) {

35 e.printStackTrace();

}

}

}


40


image


Example 21.2 is what we get when we run this program against one of the author’s DNS domains.7


image

Example 21.2 Running GetDomain against the multitool.net domain

[mschwarz@cassidy simpleApp]$ java GetDomain multitool.net Object [baroni: java.lang.Object]

Object [erik: java.lang.Object] Object [www: java.lang.Object] Object [class: java.lang.Object] Object [jboss: java.lang.Object] Object [penguin: java.lang.Object] Object [mail: java.lang.Object] Object [cvs: java.lang.Object] Object [stiletto: java.lang.Object] Object [penfold: java.lang.Object] Object [ns2: java.lang.Object] Object [ns1: java.lang.Object] Object [irc: java.lang.Object] [mschwarz@cassidy simpleApp]$


image


The GetDomain main() method. This is another “single class” program example. In this case, the main() method creates an instance of the class, passing the first command-line argument to the constructor. We’ll cover the constructor in the next section. By now, you will recognize that this is one of the purely pedagogical examples. Note the complete lack of input validation and error checking on the number and content of the command-line argu- ments.

Establishing an initial context. For both naming and directory services, it is necessary to establish an initial context. A context is a collected set of names. A directory system is a connected set of contexts. Our example is for DNS. We must set an initial context for DNS. The class constructor (lines 11–15) does that.


image

7. Note that directory operations in the JNDI DNS Service Provider Interface are done with DNS zone transfers. Many domains, especially large domains, disable zone transfers either for security reasons, or because they generate a lot of network traffic and are a popular tool for Denial of Service (DoS) attacks on name servers. To put it simply: This program won’t work on a lot of domains, especially from outside.


So what is going on here? This constructor is a bit unusual, isn’t it? The InitialDirContext is a “context factory.” It takes an “environment,” which is a Hashtable, that provides the information needed to make the context. And what is that information? At a minimum, the constant value associated with Context.INITIAL_CONTEXT_FACTORY must be associated with the class name of the real context factory for the directory system—in this case, com.sun.jndi.dns.DnsContextFactory. If you are from a C/C++ background, think of this as a function pointer.8

We now have an initial directory context, which we can use to search.

Going from the initial context to a DNS entry. Let’s now consider a use case for this little program. The program begins at main(), line 21. We create an instance of our class and an instance of NamingEnumeration (which we will discuss in a moment). We do some very lazy error handling by enclosing the entire process in a simple try/catch block9 and treating all exceptions the same. The first thing we do is construct an instance of our class, passing in the first command-line argument10 as the domain name to use for setting the initial context.

Next, we get an enumeration of all the names in that context. This is done through a method in our class that simply wraps the actual JNDI call that ob- tains this enumeration. The real event is on line 18. The list() method of the directory context returns a NamingEnumeration, which is an extension of the classic Enumeration Java class. With it, you can iterate over the contents of the context—which we do in lines 29–33. We rely on our old Object method, toString(), to make these names readable for us. Of course, each


image

8. Of course, it is not. What really happens here is that the code in InitialDirContext uses the Class class to load the specified class by name. All JNDI context factory classes imple- ment the Context interface, so InitialDirContext uses the ability of Class to load the class by its name as an instance of Context.

9. JNDI has a particularly rich collection of exceptions. When a naming or directory operation fails, it is usually possible to determine exactly how and why it failed from the type of Exception thrown. All JNDI Exceptions extend NamingException, so they also make it quite easy to handle them in a lazy manner. In a real production application, you should at least make some effort to differentiate between failures where the network is not working and failures where the network is working fine, but the named resource does not exist. Believe us, if you have to support your application in production you will care about the difference.

10. Again, very bad production coding. Note that no attempt is made to check the number of arguments passed or their contents.

image

21.4 Review 491

entry in the enumeration is actually a binding that binds the name to either a name object or to a context object.

If, when you encounter a context, you save the current context, set the current context to the new context, and make the method recursive, you would walk from the present context on down. In theory, you could set your initial context to “.” (which is the root of DNS) and this program would dump the whole domain name system to you.11

21.3.3.2 Learning More about JNDI

As with so much in this book, we have had time and space to cover only the basics. There is so much more to JNDI. For now we want to point you at Sun’s excellent JNDI Tutorial.12 JNDI is covered in more depth in many books, including JNDI API Tutorial and Reference: Building Directory-Enabled Java Applications by Rosanna Lee and Scott Seligman, ISBN 0201705028.