JNDI Tutorial
Naming Concepts
A fundamental facility in any computing system is the naming service--the means by which names are associated with objects and objects are found based on their names. When using almost any computer program or system, you are always naming one object or another. For example, when you use an electronic mail system, you must provide the name of the recipient to whom you want to send mail. To access a file in the computer, you must supply its name. A naming service allows you to look up an object given its name.
A naming service's primary function is to map people-friendly names to objects, such as addresses, identifiers, or objects typically used by computer programs. For example, the Internet Domain Name System (DNS) maps machine names (such as www.sun.com) to IP addresses (such as 192.9.48.5). A file system maps a filename (for example, c:\bin\autoexec.bat) to a file handle that a program can use to access the contents of the file. These two examples also illustrate the wide range of scale at which naming services exist--from naming an object on the Internet to naming a file on the local file system.
Names
To look up an object in a naming system, you supply it the name of the object. The naming system determines the syntax that the name must follow. This syntax is sometimes called the naming system's naming convention.
For example, the UNIXTM file system's naming convention is that a file is named from its path relative to the root of the file system, with each component in the path separated from left to right using the forward slash character ("/"). The UNIX pathname, /usr/hello, for example, names a file hello in the file directory usr, which is located in the root of the file system.
The DNS naming convention calls for components in the DNS name to be ordered from right to left and delimited by the dot character ("."). Thus the DNS namesales.Wiz.COM names a DNS entry with the name sales, relative to the DNS entry Wiz.COM. The DNS entry Wiz.COM, in turn, names an entry with the name Wiz in theCOM entry.
The Lightweight Directory Access Protocol (LDAP) naming convention orders components from right to left, delimited by the comma character (","). Thus the LDAP name cn=Rosanna Lee, o=Sun, c=US names an LDAP entry cn=Rosanna Lee, relative to the entry o=Sun, which in turn, is relative to c=us. The LDAP has the further rule that each component of the name must be a name/value pair with the name and value separated by an equals character ("=").
Bindings
The association of a name with an object is called a binding. For example, a file name is bound to a file.
The DNS contains bindings that map machine names to IP addresses. An LDAP name is bound to an LDAP entry.
References and Addresses
Directories and Directory Services
Many examples of directory services are possible. The Novell Directory Service (NDS) is a directory service from Novell that provides information about many networking services, such as the file and print services. Network Information Service (NIS) is a directory service available on the Solaris operating system for storing system-related information, such as that relating to machines, networks, printers, and users. The SunONE Directory Server is a general-purpose directory service based on the Internet standard LDAP.
Searches and Search Filters
You can look up a directory object by supplying its name to the directory service. Alternatively, many directories, such as those based on the LDAP, support the notion of searches. When you search, you can supply not a name but a query consisting of a logical expression in which you specify the attributes that the object or objects must have. The query is called a search filter. This style of searching is sometimes called reverse lookup or content-based searching. The directory service searches for and returns the objects that satisfy the search filter.
For example, you can query the directory service to find all users that have the attribute "age" greater than 40 years. Similarly, you can query it to find all machines whose IP address starts with "192.113.50".
Combining Naming and Directory Services
Directories often arrange their objects in a hierarchy. For example, the LDAP arranges all directory objects in a tree, called a directory information tree (DIT). Within the DIT, an organization object, for example, might contain group objects that might in turn contain person objects. When directory objects are arranged in this way, they play the role of naming contexts in addition to that of containers of attributes.
Directory-Enabled Java Applications
Directory service is a vital component of network computing. By using a directory service, you can simplify applications and their administration by centralizing the storage of shared information. As the use of the Java programming language to write practical applications in a network environment increases, the ability to access directory services will become essential.
Traditional Use of the Directory
A directory-enabled application is an application that uses a naming or directory service. Directory-enabled Java applications and applets, like any other program running on the network, can use the directory in the traditional way, that is, to store and retrieve attributes of directory objects. A Java mail client program, for example, can use the directory as an address book for retrieving the addresses of mail recipients. A Java mail transfer agent program can use it to retrieve mail routing information. And a Java calendar program can use it to retrieve user preference settings.
Applications can share the common infrastructure provided by the directory. This sharing makes applications that are deployed across the system, and even the network, more coherent and manageable. For example, printer configuration and mail routing information can be stored in the directory so that it can be replicated and distributed for use by all printer-related and mail-related applications and services.
The Directory as an Object Store
In addition to using the directory in the traditional way, Java applications can also use it as a repository for Java objects, that is to store and retrieve Java objects. For example, a Java print client program should be able to look up a printer object from the directory and send a data stream to the printer object for printing.
Glossary
The following glossary lists terms introduced in this lesson. It also contains some terms that will be introduced later in this tutorial; they are listed here for completeness.
Term | Definition |
address | A specification of a communication endpoint. |
An object that contains the name of another object. The use of aliases allows one object to be named using different names. | |
An optional properties file named jndi.properties found in the classpath of the application/applet using the JNDI. All of the properties contained in all application resource files in the classpath are collected and added into the environment of the initial context. | |
atomic name | An indivisible component of a name, as defined by the naming convention of the context in which the name is bound. |
Information associated with a directory object. An attribute consists of an attribute identifier and a set of attribute values. | |
The association of an atomic name with an object. | |
A name that spans multiple naming systems. | |
composite name resolution | The process of resolving a name that spans multiple naming systems. |
composite namespace | The arrangement of namespaces from autonomous naming systems to form one logical namespace. |
A name in the namespace of a single naming system. It is a sequence of zero or more atomic names composed according to the naming convention of that naming system. | |
context | An object whose state is a set of bindings that have distinct atomic names. |
A specialization of an object factory. It accepts information about how to create a context, such as a reference, and returns an instance of the context. | |
control | A modifier that accompanies an LDAP v3 request or an LDAP v3 response. A control that accompanies a request is called arequest control. A control that accompanies a response is called a response control. |
control factory | A class that narrows a control into one of a more specific type. |
directory | A connected set of directory objects. |
directory entry | Same as directory object. |
An object that is in the directory. Sometimes called a directory entry. | |
directory service | A service that provides operations for creating, adding, removing, and modifying the attributes associated with objects in a directory. |
An object that receives notification of events. | |
An object that fires (generates) events. | |
Properties used to specify various preferences and properties that define the environment in which naming and directory services are accessed. | |
A pair of "extended" operation request/response in LDAP. | |
federated namespace | Same as composite namespace. |
federated naming service | A service that provides operations on a federated naming system. |
An aggregation of autonomous naming systems that cooperate to support name resolution of composite names through a standard interface. Each member of the federation has autonomy in its choice of operations and naming conventions. | |
The starting point for resolution of names for naming and directory operations. | |
A binding in one naming system whose reference identifies a context in another naming system. | |
A reference that contains a composite name. It is a symbolic link that can span multiple naming systems. | |
A people-friendly identifier for identifying an object or a reference to an object. | |
name resolution | The process of resolving a name to the object to which it is bound. |
A set of all names in a naming system. | |
naming convention | The set of syntactic rules that govern how a name is generated. These rules determine whether a name is valid or invalid in the context in which the name is used. |
naming service | A service that provides the operations on a naming system. |
naming system | A connected set of contexts of the same type (they have the same naming convention). |
The subordinate naming system in a federation of naming systems. | |
A producer of objects that accepts some information about how to create an object, such as a reference, and then returns an instance of that object. | |
An attribute maintained and used for administrative purposes. It is not visible to clients unless explicitly requested. | |
An optional properties file named [prefix/]jndiprovider.properties, where prefix is the package name of the service provider class with each period character converted to a forward slash character ("/"). This file is used by the JNDI when determining the values of the following JNDI-defined properties:
| |
An object that contains the name(s) and location(s) of other object(s). It is a generalization of an alias. | |
Information for accessing an object. It contains one or more addresses for communicating or referring to an object. | |
A control that accompanies an LDAP v3 request sent by the client. The JNDI has two types of request controls: those that are associated with connection establishment, called connection request controls, and those that are associated with a context, called context request controls. | |
A control that accompanies an LDAP v3 response sent by the server. | |
A set or rules that specifies the types of objects that a directory may contain and the mandatory and optional attributes that directory objects of different types are to have. It may also specify the structure of the namespace and the relationship between different types of objects. | |
A logical expression specifying the attributes that the directory objects being requested should have. It is used by the directory to locate those objects. | |
An implementation of a context or initial context that can be plugged in dynamically to the JNDI architecture to be used by the JNDI client. | |
A factory that accepts an object and returns data representing the object to be stored in (and acceptable to) the underlying naming/directory service. | |
A context that is bound in another context of the same type (it has the same naming convention). | |
A notification sent by an LDAP v3 server not in response to any client request. |
Naming and Directory Concepts: End of Lesson
What's next? Now you can:
- Continue on in this trail to get an overview of the JNDI.
- Go to the Examples lesson to learn how to write some short programs for looking up an object and reading attributes from a directory service.
- Go to The Basics trail for more in-depth lessons on performing naming and directory operations using the JNDI.
JNDI Overview
The Java Naming and Directory InterfaceTM (JNDI) is an application programming interface (API) that provides naming and directory functionality to applications written using the JavaTM programming language. It is defined to be independent of any specific directory service implementation. Thus a variety of directories--new, emerging, and already deployed--can be accessed in a common way.
Architecture
The JNDI architecture consists of an API and a service provider interface (SPI). Java applications use the JNDI API to access a variety of naming and directory services. The SPI enables a variety of naming and directory services to be plugged in transparently, thereby allowing the Java application using the JNDI API to access their services. See the following figure.
Packaging
The JNDI is included in the Java 2 SDK, v1.3 and later releases. It is also available as a Java Standard Extension for use with the JDK 1.1 and the Java 2 SDK, v1.2. It extends the v1.1 and v1.2 platforms to provide naming and directory functionality.
To use the JNDI, you must have the JNDI classes and one or more service providers. The Java 2 SDK, v1.3 includes three service providers for the following naming/directory services:
- Lightweight Directory Access Protocol (LDAP)
- Common Object Request Broker Architecture (CORBA) Common Object Services (COS) name service
- Java Remote Method Invocation (RMI) Registry
Other service providers can be downloaded from the JNDI Web site or obtained from other vendors. When using the JNDI as a Standard Extension on the JDK 1.1 and Java 2 SDK, v1.2, you must first download the JNDI classes and one or more service providers. See the Preparations lesson for details on how to install the JNDI classes and service providers.
The JNDI is divided into five packages:
- javax.naming
- javax.naming.directory
- javax.naming.event
- javax.naming.ldap
- javax.naming.spi
- Naming Package
- The javax.naming package contains classes and interfaces for accessing naming services.
- Context
- The javax.naming package defines a Context interface, which is the core interface for looking up, binding/unbinding, renaming objects and creating and destroying subcontexts.
- The most commonly used operation is lookup(). You supply lookup() the name of the object you want to look up, and it returns the object bound to that name. For example, the following code fragment looks up a printer and sends a document to the printer object to be printed.
- Printer printer = (Printer)ctx.lookup("treekiller");
- printer.print(report);
- Names
- Every naming method in the Context interface has two overloads: one that accepts a Name argument and one that accepts a java.lang.String name. Name is an interface that represents a generic name--an ordered sequence of zero or more components. For the methods in the Context interface, a Name argument that is an instance of CompositeName represents a composite name , so you can name an object using a name that spans multiple namespaces. A Name argument of any other type represents a compound name. (Names are covered in the Beyond the Basics trail.) The overloads that accept Name are useful for applications that need to manipulate names, that is, composing them, comparing components, and so on.
- A java.lang.String name argument represents a composite name. The overloads that accept java.lang.String names are likely to be more useful for simple applications, such as those that simply read in a name and look up the corresponding object.
- Bindings
- listBindings() returns an enumeration of name-to-object bindings. Each binding is represented by an instance of the Binding class. A binding is a tuple containing the name of the bound object, the name of the object's class, and the object itself.
- list() is similar to listBindings(), except that it returns an enumeration of NameClassPair. NameClassPair contains an object's name and the name of the object's class. list() is useful for applications such as browsers that want to discover information about the objects bound within a context but that don't need all of the actual objects. Although listBindings() provides all of the same information, it is potentially a much more expensive operation.
- References
- Objects are stored in naming and directory services in different ways. A service that supports storing Java objects might support storing an object in its serialized form. However, some naming and directory services do not support the storing of Java objects. Furthermore, for some objects in the directory, Java programs are but one group of applications that access them. In this case, a serialized Java object might not be the most appropriate representation. A reference might be a very compact representation of an object, whereas its serialized form might contain a lot more state (see the Naming Concepts lesson).
- The JNDI defines the Reference class to represent a reference. A reference contains information on how to construct a copy of the object. The JNDI will attempt to turn references looked up from the directory into the Java objects that they represent so that JNDI clients have the illusion that what is stored in the directory are Java objects.
- The Initial Context
- In the JNDI, all naming and directory operations are performed relative to a context. There are no absolute roots. Therefore the JNDI defines an initial context, InitialContext, which provides a starting point for naming and directory operations. Once you have an initial context, you can use it to look up other contexts and objects.
- Exceptions
- The JNDI defines a class hierarchy for exceptions that can be thrown in the course of performing naming and directory operations. The root of this class hierarchy is NamingException. Programs interested in dealing with a particular exception can catch the corresponding subclass of the exception. Otherwise, they should catch NamingException.
Directory Package
The javax.naming.directory package extends the javax.naming package to provide functionality for accessing directory services in addition to naming services. This package allows applications to retrieve attributes associated with objects stored in the directory and to search for objects using specified attributes.
The Directory Context
The DirContext interface represents a directory context. It defines methods for examining and updating attributes associated with a directory object.
You use getAttributes() to retrieve the attributes associated with a directory object (for which you supply the name). Attributes are modified using modifyAttributes(). You can add, replace, or remove attributes and/or attribute values using this operation.
DirContext also behaves as a naming context by extending the Context interface. This means that any directory object can also provide a naming context. For example, a directory object for a person might contain attributes about that person as well as provide a context for naming objects, such as the person's printers and file system relative to that person directory object.
Searches
DirContext contains methods for performing content-based searching of the directory. In the simplest and most common form of usage, the application specifies a set of attributes--possibly with specific values--to match and submits this attribute set to the search() method. Other overloaded forms of search() support more sophisticated search filters.
Event Package
The javax.naming.event package contains classes and interfaces for supporting event notification in naming and directory services. Event notification is described in detail in theBeyond the Basics trail.
Events
A NamingEvent represents an event that is generated by a naming/directory service. The event contains a type that identifies the type of event. For example, event types are categorized into those that affect the namespace, such as "object added," and those that do not, such as "object changed." A NamingEvent also contains other information about the change, such as information about the object before and after the change.
Listeners
A NamingListener is an object that listens for NamingEvents. Each category of event type has a corresponding type of NamingListener. For example, a NamespaceChangeListener represents a listener interested in namespace change events and an ObjectChangeListener represents a listener interested in object change events.
To receive event notifications, a listener must be registered with either an EventContext or an EventDirContext. Once registered, the listener will receive event notifications when the corresponding changes occur in the naming/directory service.
LDAP Package
The javax.naming.ldap package contains classes and interfaces for using features that are specific to the LDAP v3 that are not already covered by the more genericjavax.naming.directory package. In fact, most JNDI applications that use the LDAP will find the javax.naming.directory package sufficient and will not need to use the javax.naming.ldappackage at all. This package is primarily for those applications that need to use "extended" operations, controls, or unsolicited notifications.
"Extended" Operation
In addition to specifying well-defined operations such as search and modify, the LDAP v3 (RFC 2251) specifies a way to transmit yet-to-be defined operations between the LDAP client and the server. These operations are called "extended" operations. An "extended" operation may be defined by a standards organization such as the Internet Engineering Task Force (IETF) or by a vendor. This package defines classes for the Start TLS extension.
Controls
The LDAP v3 allows any request or response to be augmented by yet-to-be defined modifiers, called controls . A control sent with a request is a request control and a control sent with a response is a response control . A control may be defined by a standards organization such as the IETF or by a vendor. Request controls and response controls are not necessarily paired, that is, there need not be a response control for each request control sent, and vice versa.
Unsolicited Notifications
In addition to the normal request/response style of interaction between the client and server, the LDAP v3 also specifies unsolicited notifications--messages that are sent from the server to the client asynchronously and not in response to any client request.
The LDAP Context
The LdapContext interface represents a context for performing "extended" operations, sending request controls, and receiving response controls. Examples of how to use these features are described in the Controls and Extensions lesson.
Service Provider Package
The javax.naming.spi package provides the means by which developers of different naming/directory service providers can develop and hook up their implementations so that the corresponding services are accessible from applications that use the JNDI.
Plug-In Architecture
The javax.naming.spi package allows different implementations to be plugged in dynamically. These implementations include those for the initial context and for contexts that can be reached from the initial context.
Java Object Support
The javax.naming.spi package supports implementors of Context.lookup() and related methods to return Java objects that are natural and intuitive for the Java programmer. For example, if you look up a printer name from the directory, then you likely would expect to get back a printer object on which to operate. This support is provided in the form of object factories.
This package also provides support for doing the reverse. That is, implementors of Context.bind() and related methods can accept Java objects and store the objects in a format acceptable to the underlying naming/directory service. This support is provided in the form of state factories.
Multiple Naming Systems (Federation)
JNDI operations allow applications to supply names that span multiple naming systems. In the process of completing an operation, one service provider might need to interact with another service provider, for example to pass on the operation to be continued in the next naming system. This package provides support for different providers to cooperate to complete JNDI operations.
JNDI Overview: End of Lesson
What's next? Now you can:
- Continue on in this trail to learn how to write some short programs for looking up an object and reading attributes from a directory service.
- Go to the The Basics trail for more in-depth lessons on performing naming and directory operations using the JNDI.
Examples
This lesson contains two examples. The first example shows you how to look up an object from a naming service, in this case the file system. The second example shows you how to read an attribute from a directory service, in this case an LDAP directory.
If you have problems compiling or running these examples, then see the Common Problems lesson. That lesson describes problems that you might encounter when trying to compile and run the examples or when using the JNDI in general and offers solutions that you can try.
Naming Example
This example shows you how to write a program that looks up an object whose name is passed in as a command-line argument. It uses aservice provider for the file system. Therefore the name that you supply to the program must be a filename. You do not need to understand details about the service provider at this point.
Importing the JNDI Classes
Using your favorite text editor, create a file named Lookup.java. You can import either the entire package or only individual classes and interfaces. The following code imports each class that is used from the javax.naming package.
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
Creating an Initial Context
In the main() method of the program, create an initial context. Indicate that you're using the file system service provider by setting theenvironment properties parameter (represented by a Hashtable class) to the InitialContext constructor, as follows.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
Context ctx = new InitialContext(env);
How to set up the parameters for this constructor is explained in more detail in The Basics trail.
Looking Up an Object
Next, use Context.lookup() to look up an object. The following code looks up the object bound to the name supplied in the command line.
Object obj = ctx.lookup(name);
Catching NamingException
The creation of the initial context and the lookup() method can throw a NamingException. For this reason, you need to enclose these calls inside a try/catch clause. Here's the code fragment repeated with the try/catch clause.
try {
// Create the initial context
Context ctx = new InitialContext(env);
// Look up an object
Object obj = ctx.lookup(name);
// Print it
System.out.println(name + " is bound to: " + obj);
} catch (NamingException e) {
System.err.println("Problem looking up " + name + ": " + e);
}
Compiling the Program
Next, you compile the source file using the Java compiler. To compile to program, you must have access to the JNDI classes. If you are using the Java 2 SDK, v1.3, then the JNDI classes are already included. Otherwise, you can include the classes either by setting theCLASSPATH variable to include the jndi.jar that you downloaded from the JNDI Web site or by installing jndi.jar as an installed extension. See the Preparations lesson for details on how to install the JNDI classes and service providers.
If the compilation succeeds, then the compiler will create a file named Lookup.class in the same directory (folder) as the Java source file (Lookup.java). If the compilation fails, then make sure that you typed in and named the program exactly as shown here, using the capitalization shown. If you are still having problems, then see the Common Problems lesson for help.
Running the Program
To run the program, you need access to the JNDI classes, the file system service provider, and your example class (Lookup.class). See the compilation step for instructions on including access to the JNDI classes. To include the file system service provider classes (fscontext.jarand providerutil.jar), either include them in your CLASSPATH variable or install them as extensions. Note that these archive files are notincluded with the Java 2 SDK, v1.3. See the Preparations lesson for details on how to install the JNDI classes and service providers. Finally, include the directory that contains your Lookup.class file in your the CLASSPATH variable.
To run the program, supply the name of a file in your file system, as follows:
# java Lookup /tmp
Or as follows:
# java Lookup \autoexec.bat
If you supply a file directory, then you will see something like the following.
# java Lookup /tmp
/tmp is bound to: com.sun.jndi.fscontext.RefFSContext@1dae083f
If the name that you supplied is a file, then you will see something like this:
/tmp/f is bound to: //tmp/f
If you have any trouble running this example, then see Common Problems .
Directory Example
This example shows you how to write a program that retrieves attributes from a directory object. It uses an LDAP service provider to access an LDAP service.
Importing the JNDI Directory Classes
Using your favorite text editor, create a file named Getattr.java. You can import either the entire package or only individual classes and interfaces. The following code imports each class that is used from the javax.naming and javax.naming.directory packages.
import javax.naming.Context;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.DirContext;
import javax.naming.directory.Attributes;
import javax.naming.NamingException;
Creating an Initial Directory Context
In the main() method of the program, create an initial directory context. This is similar to creating an initial context in the previous naming example, except that you use the constructor for InitialDirContext.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
DirContext ctx = new InitialDirContext(env);
Similar to the naming example, you indicate that you're using the LDAP service provider by setting the Hashtable parameter to the InitialDirContext constructor appropriately. Details on how to set up the parameters for this constructor are given in The Basics trail. For now, the only thing to understand is that the program by default identifies an LDAP server on the local machine. If your LDAP server is located on another machine or is using another port, then you need to edit the LDAP URL ("ldap://localhost:389/o=JNDITutorial") accordingly. Instructions for setting up a sample LDAP server for this tutorial are given in the Preparations lesson.
Getting a Directory Object's Attributes
Next, use getAttributes() to get an object's attributes. The following code retrieves all of the attributes associated with the object bound to the name"cn=Ted Geisel, ou=People":
Attributes attrs = ctx.getAttributes("cn = Ted Geisel, ou=People");
Extracting the Desired Attribute
From a set of attributes, Attributes, you can ask for a particular attribute by using Attributes.get() and then from that attribute get its value. The following line first gets the surname attribute "sn" and then invokes Attribute.get() on it to get its value:
attrs.get("sn").get();
Catching NamingException
The method calls shown so far can throw a NamingException. For this reason, you need to wrap these calls inside a try/catch clause. Here's the code fragment repeated with the try/catch clause.
try {
// Create the initial directory context
DirContext ctx = new InitialDirContext(env);
// Ask for all attributes of the object
Attributes attrs = ctx.getAttributes("cn=Ted Geisel, ou=People");
// Find the surname attribute ("sn") and print it
System.out.println("sn: " + attrs.get("sn").get());
} catch (NamingException e) {
System.err.println("Problem getting attribute:" + e);
}
Compiling the Program
Next, compile the source file using the Java compiler. As with the naming example, to do this you need access to the JNDI classes.
If the compilation succeeds, then the compiler creates a file named Getattr.class in the same directory (folder) as the Java source file (Getattr.java). If the compilation fails, then make sure that you typed in and named the program exactly as shown here, using the capitalization shown. If you are still having problems, then see the Common Problems lesson for help.
Running the Program
As with the naming example, you need access to both the JNDI classes and your example class, Getattr.class. You also need access to the LDAP service provider classes (ldap.jar and providerutil.jar). If you are using the Java 2 SDK, v1.3, then these classes are already included.
Here's an example of a command line for running Getattr and the output it generates.
# java Getattr
sn: Geisel
Recall that the program was configured with the following property.
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=JNDITutorial");
With this configuration, this command queries the LDAP server on machine localhost that is listening on port 389, serving the "o=JNDITutorial" namespace. (See the Preparations lesson for details on this configuration step.) It asks for the attributes of the entry "cn=Ted Geisel, ou=People". Once it has the attributes, it extracts the surname attribute ("sn"). If you have any trouble running this example, then see the Common Problems lesson.
Examples: End of Lesson
What's next? Now you can:
- Continue on in this trail to read about common problems that you might encounter when running or compiling JNDI programs.
- Go to the The Basics trail for more in-depth lessons on performing naming and directory operations using the JNDI.
Common Problems (and Their Solutions)
This lesson describes common problems that you might encounter when using the JNDI and gives their solutions. The problems are classified as follows:
Compilation Problems
Here are the most common problems that you might encounter when compiling a program that uses the JNDI classes.
Class or Package Not Found
Problem: You get "Package javax.naming not found" or a similar error complaining about missing classes.
Cause: You did not include the JNDI classes (jndi.jar) in your CLASSPATH when you compile your program, or you did not install the JNDI classes properly as an extension, or you mistyped the class or package name.
Solution: The Java 2 SDK, v1.3 includes the JNDI classes. If you are using this version and get a class or package not found error, then double-check the spelling of the package and class.
If you are not using the Java 2 SDK, v1.3, then you need to download the JNDI classes and include them in your development environment. The way that you include the JNDI classes depends on your development environment.
If you are using the Java 2 SDK, v1.2, make sure that jndi.jar is in the JAVA_HOME/jre/lib/ext directory, where JAVA_HOME is the directory that contains the SDK. If you are using the javac compiler from the JDK 1.1, then add jndi.jar either to your CLASSPATH environment variable or to the -classpath option on yourjavac command line. See the Preparations lesson for more details.
Incompatible Java Platform Versions
Problem: You get compilation failures complaining about missing java.* packages or classes.
Cause: You are using an old version of the Java platform.
Solution: You need to use the Java 1.1.2 or higher. See http://java.sun.com/products/jdk/.
Runtime Problems
Here are the most common problems that you might encounter when you try to run a successfully compiled program that uses the JNDI classes.
Class Not Found
Problem: You get a NoClassDefFoundError when running your program.
Cause: You did not include the JNDI classes (jndi.jar) in your classpath, or you did not install the JNDI classes properly.
Solution: The Java 2 SDK, v1.3 already include the JNDI classes so if you are using this version you should not get this error.
If you are not using the Java 2 SDK, v1.3, then the way you that include the JNDI classes your execution environment depends on the environment. If you are using the Java 2 SDK, v1.2, then make sure that jndi.jar is in theJAVA_HOME/jre/lib/ext directory, where JAVA_HOME is the directory that contains the Java Runtime Environment (JRE). Note that on some platforms, separate jre/lib/ext directories exist for the JRE and the SDK. Make sure that the JNDI JARs have been installed in both jre/lib/ext directories. If you are using the java interpreter from the JDK 1.1, then add the JARs either to your CLASSPATH environment variable or to the -classpath option in your java command line.
For an applet, you need to make the JNDI and provider classes available to that applet (for example, by adding them to thearchive option).
No Initial Context
Problem: You get a NoInitialContextException.
Cause: You did not specify which implementation to use for the initial context. Specifically, the Context.INITIAL_CONTEXT_FACTORY environment property was not set to the class name of the factory that will create the initial context. Or, you did not make available to the program the classes of the service provider named by Context.INITIAL_CONTEXT_FACTORY.
Solution: Set the Context.INITIAL_CONTEXT_FACTORY environment property to the class name of the initial context implementation that you are using. See The Basics trail for details.
If the property was set, then make sure that the class name was not mistyped, and that the class named is available to your program (either in its classpath or installed in the jre/lib/ext directory of the JRE). The Java 2 SDK, v1.3 includes service providers for LDAP, COS naming, and the RMI registry. All other service providers must be installed and added to the execution environment.
Connection Refused
Problem: You get a CommunicationException, indicating "connection refused."
Cause: The server and port identified by the Context.PROVIDER_URL environment property is not being served by the server. Perhaps someone has disabled or turned off the machine on which the server is running. Or, maybe you mistyped the server's name or port number.
Solution: Check that there is indeed a server running on that port, and restart the server if necessary. The way that you perform this check depends on the LDAP server that you are using. Usually, an administrative console or tool is available that you can use to administer the server. You may use that tool to verify the server's status.
Connection Fails
Problem: The LDAP server responds to other utilities (such as its administration console) but does not seem to respond to your program's requests.
Cause: The server does not respond to LDAP v3 connection requests. Some servers (especially public servers) do not respond correctly to the LDAP v3, ignoring the requests instead of rejecting them. Also, some LDAP v3 servers have problems handling a control that Sun's LDAP service provider automatically sends and often return a server-specific failure code.
Solution. Try setting the environment property "java.naming.ldap.version" to "2". The LDAP service provider by default attempts to connect to an LDAP server using the LDAP v3; if that fails, then it uses the LDAP v2. If the server silently ignores the v3 request, then the provider will assume that the request worked. To work around such servers, you must explicitly set the protocol version to ensure proper behavior by the server.
If the server is a v3 server, then try setting the following environment property before creating the initial context:
env.put(Context.REFERRAL, "throw");
This will turn off the control that the LDAP provider sends automatically. (See the Referrals lesson for details.)
Program Hangs
Problem: The program hangs.
Causes: Some servers (especially public ones) won't respond (not even with a negative answer) if you attempt to perform a search that would generate too many results or that would require the server to examine too many entries in order to generate the answer. Such servers are trying to limit the amount of resources that they expend on a per-request basis.
Or, you tried to use Secure Socket Layer (SSL) against a server/port that does not support it, and vice versa (that is, you tried to use a plain socket to talk to an SSL port).
Solution: If your program is hanging because the server is trying to restrict the use of its resources, then retry your request using a query that will return a single result or only a few results. This will help you to determine whether the server is alive. If it is, then you can broaden your initial query and resubmit it.
If your program is hanging because of SSL problems, then you need to find out whether the port is an SSL port and then set the Context.SECURITY_PROTOCOL environment property appropriately. If the port is an SSL port, then this property should be set to "ssl". If it is not an SSL port, then this property should not be set.
Name Not Found
Problem: You get a NameNotFoundException.
Causes: When you initialized the initial context for the LDAP, you supply a root-distinguished name. For example, if you set the Context.PROVIDER_URL environment property for the initial context to "ldap://ldapserver:389/o=JNDITutorial" and subsequently supplied a name such as "cn=Joe,c=us", then the full name that you passed to the LDAP service was "cn=Joe,c=us,o=JNDITutorial". If this was really the name that you intended, then you should check your server to make sure that it contains such an entry.
Also, the SunONE and Netscape Directory Servers return this error if you supply an incorrect distinguished name for authentication purposes. For example, the LDAP provider will throw a NameNotFoundException if you set theContext.SECURITY_PRINCIPAL environment property to "cn=Admin, o=Tutorial", and "cn=Admin, o=Tutorial" is not an entry on the LDAP server. The correct error for the SunONE and Netscape Directory Servers to return actually should be something related to authentication, rather than "name not found."
Solution: Verify the name that you supplied is that of an entry existing on the server. You can do this by listing the entry's parent context or using some other tool such as the directory server's administration console.
Web Browser Problems
Here are some problems that you might encounter when trying to deploy an applet that uses the JNDI classes.
Cannot Authenticate by Using CRAM-MD5
Problem: You get an AppletSecurityException when an applet running inside Netscape Communicator attempts to authenticate using CRAM-MD5 to the LDAP server.
Cause: Netscape Communicator disables access to the java.security packages. The LDAP provider used the message digest functionality provided byjava.security.MessageDigest for implementing CRAM-MD5.
Solution: Use the Java Plug-in.
Cannot Connect to Arbitrary Hosts
Problem: You get an AppletSecurityException when your applet attempts to communicate with a directory server that is running on a machine different from the one from which the applet was loaded.
Cause: Your applet was not signed, so it can connect only to the machine from which it was loaded. Or, if the applet was signed, the browser has not granted the applet permission to connect to the directory server machine.
Solution: If you want to allow the applet to connect to directory servers running on arbitrary machines, then you need to sign both your applet and all of the JNDI JARs that your applet will be using. For information on signing jars, see http://java.sun.com/products/jdk/1.1/docs/guide/security/index.html.
Cannot Access System Properties for Configuration
Problem: You get an AppletSecurityException when your applet attempts to set up the environment properties using system properties.
Cause: Web browsers limit access to system properties and throw a SecurityException if you attempt to read them.
Solution: If you need to obtain input for your applet, then try using applet params instead.