Java Naming and Directory Interface (JNDI) is a set of APIs for accessing the name and directory service from the Java application. Naming Services will be associated with an object in order to access these objects through the corresponding name. The directory service is a naming service of its objects with attributes and names.
Naming or Directory Services allows you to centrally manage storage of shared information, which is important in web applications because it allows such applications more consistent and easy to manage. For example, you can store the printer in a directory service so that all applications related to the printer can use it.
This article is a code-intensive quick entry guide that lets you start understanding and using JNDI. it:
Provide a review of JNDI. Describe the characteristics of JNDI. Provide experiences in the process of developing applications using JNDI. Explain how to use JNDI to access the LDAP server, such as Sun One Directory Server. Explain how to use JNDI to access J2EE services. Provide sample code, you can modify it for your own application.
JNDI review
All of us use naming services every day in unbearable. For example, when you enter url http://java.sun.com in your browser, the domain name system (DNS) converts this URL represented by symbol to a communication identifier (IP address). In the naming system, the range of objects can be changed from the name in the DNS record to the Enterprise JavaBeans Components, EJBS, and can also go to the Lightweight Directory Access Protocol, LDAP User profile in.
Directory services are nature expansion of naming services. The key difference between the two is that the directory service allows attributes (such as the user's email address), and the naming service is not. This way, when using a directory service, you can search them based on object's properties. JNDI allows you to access files in the file system, locate objects in the remote RMI registry, access directory services such as LDAP, and locate EJB on the network.
Many applications choose to use JNDI to receive good results, such as LDAP clients, application initiators, class browsers, network management utilities, or even address books.
JNDI architecture
The JNDI architecture provides a standard, an API-independent API that is unrelated to the name system, which is built on top of the name-specific-specific driver. This layer helps isolate the application and the actual data source, so it doesn't matter whether the application is accessing LDAP, RMI, DNS or other directory services. In other words, JNDI has indeed correlated with any specific directory service, you can use any directory, as long as you have the corresponding service provider interface (or driver), as shown in Figure 1.
Figure 1: JNDI architecture
Note that about JNDI is important, it also provides an application programming interface (API) and service provider interface (Service Provider Interface, SPI). The actual significance of this is that for applications with name or directory service, there must be a JNDI service provider for the service, which is a stage where JNDI SPI functions. A service provider is basically a set of classes that implement various JNDI interfaces for a specific naming and directory service - this is extremely similar to the JDBC driver to implement various JDBC interfaces for specific data systems. As an application developer, you don't need to worry about JNDI SPI .. You only need to make sure you provide a service provider for each name or directory service you want to use. J2SE and JNDI
JNDI is included in Java 2 SDK 1.3 and its updated version. It can also be used as a standard extension of JDK 1.1 and 1.2. The latest version of Java 2 SDK 1.4.x is improved, including the following named / directory service provider, incoming:
Lightweight Directory Access Protocol, LDAP service provider. Public Object Request Agent Architecture (CORBA) Public Object Services (COS) Name Service Provider. REMOTE METHOD INVOCATION, RMI Registry Service Provider. Domain Name System, DNS service provider.
More content related to service providers
Here you can download a series of service providers. Windows Registry JNDI Provider (from CoGentLogic.com) may cause you particularly interest because it allows you to access registry on Windows XP / 2000 / NT / ME / 9X.
Also, you can download JNDI / LDAP BOOTSTER PACK. This enhanced patch contains support for popular LDAP controls and extensions. It replaces the enhanced patch that is bundled with the LDAP 1.2.1 service provider. See Controls and Extensions for more information.
Another interesting service provider to be examined is Sun's Directory Services Markup Language (DSML) V2.0 provider. The DSML goal is to connect the directory service with XML.
JNDI API
JNDI API includes 5 packages:
Javax.naming: Contains classes and interfaces used to access naming services. For example, it defines the Context interface that is the entry point of the name of the service when performing a lookup. Javax.naming.directory: Extended Name Package to provide classes and interfaces for accessing directory services. For example, it adds a new attribute class that provides a DirContext interface representing a directory context and defines a method for checking and updating attributes related to a directory object. Javax.naming.Event: When accessing naming and directory services, support event notifications. For example, it defines a Namingevent class that represents events generated by named / directory services, as well as a NamingListener interface for monitoring Namingevents classes. Javax.naming.ldap: This package provides specific support for LDAP version 3 extension operations and space, while the normal javax.naming.directory package does not provide these support. Javax.naming.spi: This package provides a way to dynamically insert support to access naming and directory services via javax.naming and its related package. Only developers who have a strong interest in creating a service provider should be interested in this package. JNDI context
The name service is associated with an object before the name of the name. This association is called binding. A set of such bindings is called context, which provides an decomposition or lookup operation of the return object. Other operations may also include binding and release binding names, and listing the bounded names. Note that the names in a context object can be bound to another context object having the same name convention. This is called sub context. For example, if UNIX Directory / Home is a context, then the name of the name is the sub-context. For example, / home / guests. The guests here is a child of HOME.
In JNDI, the context is represented using a javax.naming.context interface, and this interface is also a primary interface that interacts with the naming service. Context (or later DirContext) Each name method in the interface is in the form of two overload:
Lookup (String Name): Accept a string name. Lookup (javax.naming.name): Accept a structured name, such as Compositename (a name spanning multiple named systems) or CompondName (a name in a single naming system); both implements the Name interface. Here is an example of a composite name: CN = mydir, cn = q mahmoud, ou = people, there is an example of a combination name: CN = mydir, cn = q mahmoud, ou = people / myfiles / max.txt (here MyFiles / Max.txt is a file name representing the second part).
Javax.naming.initialContext is a class that implements the Context interface. Use this class as the entry point for your naming service. To create an initialcontext object, the constructor needs to use a set of properties, the form is one of Java.util.HashTable or one of its subclasses, such as Properties .. Below is an example:
Hashtable env = new Hashtable (); // select a service provider factory env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContext"); // create the initial context Context contxt = new InitialContext (env) Initial_Context_Factory Specifies the name of the factory class in the JNDI service provider. The plant is responsible for creating a suitable initialcontext object for its services. In the above code snippet, a factory class for the file system service provider is specified. Table 1 lists factory classes for the service provider supported. Note that factory classes for file system service providers need to download separate from Sun Microsystems, which is not issued with J2SE 1.4.x.
Table 1: Context.INITIAL_CONTEXT_FACTORY value name service provider factory file system com.sun.jndi.fscontext.RefFSContextFactory LDAP com.sun.jndi.ldap.LdapCtxFactory RMI com.sun.jndi.rmi.registry.RegistryContextFactory CORBA com.sun .jndi.cosnaming.cnctxfactory dns com.sun.jndi.dns.dnscontextFactory
To retrieve or resolve (find) an object from a name or directory service, use the lookup method for the context: object obj = contxt.look (name). The Lookup method returns an object that represents the sub-context of the context you want to find.
A naming example
Now let's take a look at an example of using a naming service. In this example, we have written a simple program that is used to find an object whose name is used as the command line parameter. Here, we will use a service provider for a file system, and therefore, we provide names as a parameter must be a file name. The corresponding code is given in the sample code 1.
Sample Code 1: Resolve.Java
import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.util.Hashtable; public class Resolve {public static void main (String argv []) {// The user should provide a File to lookup if (argv.Length! = 1) {system.err.println ("usage: java resolve"); system.exit (-1);} String name = argv [0]; // Here We use the the file system service provider Hashtable env = new Hashtable (); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); try {// Create the initial context context ctx = new InitialContext (env); // Look Up An Object Object Obj = CTX.lookup (Name); // Print It Out System.out.Println (Name "is Bound To:" Obj); // Close The Context CTX.Close (); } catch (namingexception e) {system.err.println ("Problem Looking Up" Name ":" E); }} Here, I assume that you are using Java 2SDK 1.4.x, which comes with several service providers (above already listed). This app is to use the file system service provider, and the file system service provider is not installed by default. Therefore, you need to download and install it. On the other hand, if you run this program, the service provider has not been installed, you will get a NOInitialContextexception, which means that the service provider factory class cannot be found, so this class cannot be initialized. Next, you need to include fscontext.jar and providerutil.jar in your classpath, or like me, you can simply copy these two files to java_home / jre / lib / ext, here's Java_Home refers to you. Java 2SDK installed root directory.
To test this app:
1. Make sure you have downloaded and installed the file system service provider (as mentioned above), because this service provider is not provided with J2SE 1.4.x.
2. Copy code and paste it into the file and name the file to resolve.java.
3. Compile Resolve.java using Javac.
4. Run the application using the Java interpreter. Below is a demonstration operation:
Prompt> java resolve / class / classes is bound to: com.sun.jndi.fscontext.fscontext@f62373
If you provide the name is a file name, you will see the following results:
Prompt> java resolve /classes/resolve.java
/classes/resolve.java is bound to: c: /classes/resolve.java
List the contents of the file directory
Now let's take a look at how to list the contents of a file directory using another JNDI API. We assume that you want users to use file: /// such a URL to specify command line parameters. In this case, you have to set a new property provider_url, as shown in the sample code 2. Context's listbindings method returns a NAMINGENUMERATION object, which can be used to iterate this object by using a While loop, as shown in Sample Code 2.
Sample Code 2 Resolve2.java
import javax.naming.Binding; import javax.naming.NamingEnumeration; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.util.Hashtable; public class Resolve2 {public static void main (String Argv []) {// The user surnted provide a file to lookup if (argv.Length! = 1) {system.err.println ("usage: java resolve2"); system.exit (-1);} // Here we use the file system service provider Hashtable env = new Hashtable (); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.FSContextFactory"); env.put (Context.PROVIDER_URL, argv [0 ]); Try {// Create The Initial Context CText CTX = New InitialContext (ENV); Namingenumeration Ne = CTX.ListBindings (""); While (ne.hasmore ()) {binding b = (binding) ne.next ( ); System.out.println (B.GetName () " B.GetObject ());} // close the context Ctx.close ();} catch (namingexception e) {system.err.println ("Problem Looking Up" Argv [0] ":" E);}}} To test this application, follow the previous one Examples of the same editing and running steps. Below is a demonstration operation:
Prompt>: java resolve2 file: /// uddi fig1.gif c: /uddi/fig1.gif fig2.gif c: /uddi/fig2.gif fig3.gif c: /uddi/fig3.gif fig4.gif C: / UDDI / FIG4.GIF FIG5.GIF C: /UDDI /FIG5.GIF IMPL.TXT C: /UDDI/Impl.txt
Directory service
The directory service is a naming service with an object and name of its object. Objects with properties and names are called directory portals. The application can store and retrieve the properties of the directory object using the directory service. It can even be used for object storage.
LDAP
Lightweight Directory Access Protocol (LDAP) is derived from the X.500 protocol (developed by the University of ANN Arbor), is an agreement for accessing and managing directory services; it defines how clients should access storage on the server Data, but no definition should store data. The LDAP directory consists of an entry with descriptive information, which describes people (eg, name, phone number, email address, etc.) or network resources (such as printers, fax machines). Such descriptive information is stored in the properties of an entry, each attribute of the inlet describes a particular type of information. One will be given below, the content is used to describe the properties of a person: CN: Qusay H. Mahmoud Mail: qmahmoud@javacourses.com TelephonEnumber: 123-4567
The LDAP directory service can be used to find a personal phone number or email address based on attributes. Table 2 lists some common LDAP properties:
Table 2: Some common LDAP attribute properties significance O organization CN common name SN name UID User ID Mail Email Address C
The LDAP name is a sequence of a (name, value), such as name, organization, and country.
CN = qusay mahmoud, o = javacourses.com, c =
Canada
Javax.naming.directory.dircontext is a JNDI directory service interface that extends javax.naming.context. It provides methods:
Search: Search for the directory of the directory entry and compare a directory portal and a set of properties. Bind and CreateSubContext: Add a new directory entry. ModifyAttributes: Modify the specific properties of a directory entry. The Rename method can be used to modify the entry name itself. Unbind and DestroysubContext: Delete a specific directory entry. Close: End the session with an LDAP server.
LDAP programming using JNDI
To operate an object in a LDAP server (such as Sun One Directory Server), you must first connect to the server; you may also need to make yourself authenticate through the server. To connect to the server, you can get a reference to an object from the Dircontext interface. This can do this with the initialdircontext class, and this class requires a HashTable.
The following code snippet can use the user through an LDAP server authentication and connect to the server. Note that simplicity authentication is used here. Simple authentication includes sending the fully qualified DN of the user to the LDAP server. To avoid exposure of the express text, use the SSL mechanism with an encrypted channel if your LDAP server supports this mechanism. For more information on authentication mode, see JNDI TUTORIAL.
Hashtable env = new Hashtable (); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); // specify where the ldap server is running env.put (Context.PROVIDER_URL, "ldap: / /GH308C-N-MAHMOUD.HUMBER.ORG: 61596 "); env.put (Context.Security_Authentication," Simple "); env.Put (Context.security_principal," cn = directory manager); env.put (Context). Security_credentials, "password"); // Create The Initial Directory Context DirContext CTX = New InitialDirContext (ENV); After connecting to the LDAP server, you can add a new entry on the LDAP server, or modify, delete, search for an entry. The following code snippet illustrates how to add or store a new entry. Note: To store an object, you need to load it with Java Schema, while Java Schema is not pre-configured on the directory server. For more information on this, see the Java Objects and the Directory section in the JNDI guide.
SomeObject obj = new homeobjct ("param1", "param2", "param3"); ctx.bind ("cn = myObject", obj);
You can use the Lookup method to find an object as follows:
SomeObject obj = (someobject) CTX.lookup ("cn = myObject");
The sample code 3 gives an example of how to retrieve the properties of the named object. As you can see, the code used to select the factory class is the same as before. We use the InitialDirContext class to create a directory context DirContext, the GetAttributes method is used to return the properties of the object, and finally, the GET method finds the surname and print it. Quite intuitive, is it?
Sample Code 3: GetAttrib. Java
import javax.naming.Context; import javax.naming.directory.InitialDirContext; import javax.naming.directory.DirContext; import javax.naming.directory.Attributes; import javax.naming.NamingException; import java.util.Hashtable; class GetAttrib {public static void main (String [] argv) {Hashtable env = new Hashtable (); env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); // specify where the ldap server is running Env.put (Context.Provider_url, "LDAP: // localhost: 389 / o = javacourses.com, c = canada
"); // use simple authenticate to authenticate the user env.put (Context.SECURITY_AUTHENTICATION," simple "); env.put (Context.SECURITY_PRINCIPAL," cn = Directory Manager "); env.put (Context.SECURITY_CREDENTIALS," password "); try {// Create the initial directory context DirContext ctx = new InitialDirContext (env); // Ask for all attributes of the object Attributes attrs = ctx.getAttributes (" cn = Qusay Mahmoud "); // Find the Surname ("SN") Attribute of this Object and print it system.out.println ("Last Name:" Attrs.get ("sn"). get ()); // close the context ctx.close (); } catch (namingexception e) {system.err.println ("Problem getting attribute: e);}}}
JNDI provides an API for performing basic and advanced (using filters). For example, using a set of entrances must have an attribute, and a simple search can be performed with a target context to perform a search. The following code snippet illustrates how to search for an entry with a UID = QmahMoud property in a sub-tree. Advanced search using filters is not within the discussion scope of this article.
// ignore attribute name case Attributes matchattribs = new BasicAttributes (true); matchattribs.put (new BasicAttribute ( "uid", "qmahmoud")); // search for objects with those matching attributes NamingEnumeration answer = ctx.search ( "ou = People, o = javacourses.com ", matchattribs); while (answer.hasmore ()) {searchResult sr = (SearchResult) answer.next (); //print the resultS you need} I want to know about using JNDI to write LDAP customers For more information, see Tips for LDAP Uses.
JNDI's CORBA COS Name Service Provider
CORBA Public Object Services (COS) Name Server is used to store CORBA object references. You can use the COS named package (org.omg.corba.cosnaming) to access it in the CORBA application.
The JNDI COS Name Service Provider implements the javax.naming.context interface based on the COS name package, so the CORBA application can access the COS name server using JNDI. Therefore, the CORBA application using JNDI has an interface for accessing all names and directory services. This allows the CORBA application to store object references using distributed enterprise services such as LDAP.
To select a COS naming service provider, use:
Env.put (Context.initial_Context_Factory, "com.sun.jndi.cosnaming.cnctxfactory);
To convert your CORBA application to consider addserver.java and AddClient.java, they have more detailed description in another article.
1. Use javax.naming in the client and server, will:
Import org.omg.cosnaming. *; import org.omg.cosnaming.namingContextPackage. *;
Replace with:
Import javax.naming. *;
2. Use INITIALCONTEXT in the client and server instead of NAMESERVICE:
will:
Org.omg.corba.object objref = orb.resolve_initial_references ("Nameservice"); NamingContexText ncref = NamingContextextHelper.narrow (Objref);
Replace with:
Hashtable env = new hashtable (); env.put ("java.naming.corba.orb", orb); context ctx = new initialContext (ENV);
3. Use lookup instead of Resolve:
will:
String name = "add"; add href = addHelper.narrow (ncref.resolve_str (name));
Replace with:
Add href = addhelper.narrow ((org.omg.corba.object) CTX.lookup ("add")); JNDI's RMI Registry Service Provider
The RMI Registry Service Provider allows JNDI applications to access remote objects registered using the RMI registry. After the location where the registry is located, the provider uses the bind to register the object in the registry to create a name context. Next, this context can be bound to another JNDI accessible namespace, such as LDAP. This new feature contains the functions provided by java.rmi.naming classes.
The main advantage of this using RMI is that the client no longer needs to know the host name and port number of the RMI registry operation; it is independent of location.
The following code snippet shows how to use JNDI with RMI:
// select the registry service provider as the initial context env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); // specify where the registry is running env.put (Context.PROVIDER_URL, "rmi: // server: 1099"); // create an initial context that accesses the registry context ctx = new InitialContext (env); // now, the names stored in registry can be listed NamingEnumeration enum = ctx.list ( " "); // bind The registry consto ldap directory context ldapctX = (context) CTX.lookup (" ldap: // server: port / o = comp, c = ca "); ldapctx.bind (" cn = rmi " , CTX);
JNDI DNS service provider
The DNS service provider allows JNDI-based applications to access information stored in DNS. The DNS service provider presents DNS namespace as a tree in the JNDI directory context, and rendering DNS resource records as JNDI properties.
Sample Code 4 demonstrates how to use the DNS service provider to retrieve the information of the environment and IP address (A record).
Sample Code 4: Testdns.java
Import javax.naming. *; import com.sun.jndi.dns. *; import java.util.hashtable; public class testdns {public static void main (string [] argv) {name cn = null; string name = argv [String name = argv [String name = argv 0]; havehtable env = new hashtable (); env.put (context.initial_context_factory, "com.sun.jndi.dns.dnscontextfactory); env.put (Context.Provider_URL," DNS: // ip for DNS Server / "); Try {// create the initial context CText CTX = New InitialContext (ENV); //print the full qualified name (" name in namespace: " ctx.getnameinnamespace ());" Name In Namespace: " CTX.GetNameInnamespace ()); // retrieve the parser associated with the named context NameParser np = ctx.getNameParser (ctx.getNameInNamespace ()); if (argv.length = 1!) {System.out.println ( "Usage: java TestDNS"); System. EXIT (-1);} // parse the name ing its components and print them cn = np.parse (name); SYS Tem.out.println ("Name is:" cn.tostring ()); System.out.Println ("TH PARSED NAME HAS" CN.Size () "Components:"); for (INT i = 0 i System.out.println (Domain.Tostring () "IS Bound to:" Obj); // Retrieve and Print The Environment In Effect System.Println ("Domain Properties:" (Context) OBJ). GetENVIRONMENT ()); // Retrieve and Print The IP Address (The DNS A Records) System.out.Println ("IP for:" CN "IS: ((DNSContext) Obj) .getattributes (Host, New String [] {"A"})); // We're Done So Close The Context CTX.Close ();} catch (namingexception e) {system.err.println ("Problem Looking Up" CN ":" E);}}} Make sure you specify the IP address of the DNS server before you run this application. Below is a demonstration operation: Prompt> java testdns prep.ai.mit.edu name in name:. name is: prep.ai.mit.edu the pased name HAS 4 Components: EDU MIT AI Prep Trying to lookup dns host: preip domain: ai.mit. Edu ai.mit.edu is bound to: com.sun.jndi.dns.dnscontext@b89838 Domain Properties: {java.naming.provider.URL = DNS: // IP for DNS Server /, java.namin g.factory. Initial = com.sun.jndi.dns.dnscontextFactory} ip for: prep.ai.mit.edu IS: {a = a: 199.232.41.9} JNDI and J2EE JNDI is one of the standard service APIs of the J2EE platform. The purpose of it is to provide a standard API for application components for reference resources and other application components. J2EE also defines a standard naming policy (logical and real name), uses JNDI, which can be written in a way that is not related to the deployment environment. You can quote J2EE service, and the specific method is to find them in the directory based on its logical name. In order to achieve this, each system that meets the J2EE specification provides a JNDI service called the environment, which includes: Environment variable EJB reference resource factory reference Note: Here, I only discuss environment variables. For more information on EJB reference and resource factory reference, see this article. Environment variable The name environment of the application component allows you to customize the application component without having to access or modify the source code of the component. Each application component defines a collection of its own environments. In the same container, all instances of an application component share the same entry. Note that the application component instance is not allowed to modify the environment at runtime. Disclaimer environment variable The application component provider must declare all environment portions accessed from the application's component code. They are declared in deployment descriptors (such as Web.xml in Tomcat) by using the The example in Example Code 5 gives a declaration of two environmental portions. To specify a statement for a new environment, you just want to add it to your web application descriptor (web.xml). Sample code 5: Declaration environment variable Each Now, the application component instance can use the JNDI to locate the environments. It creates a javax.naming.initialContext object using a constructor without parameters. Then, it looks for a naming environment via the initialcontext, which is the JNDI URL headed with Java: Comp / ENV. Sample Code 6 illustrates how an application component accesses its environment inlet. Sample Code 6: Access Environment Portal // obtain the application component's ctx = new javax.naming.InitialContext environment // naming context javax.naming.Context (); javax.naming.Context env = ctx.lookup ( "java: comp / env"); // obtain the greetings message // configured by the deployer String str = (String) env.lookup ( "greetings"); // use the greetings message System.out.println (greetings); // obtain the maximum number of products // configured By The Deployer Integer Maximum = (Integer) ENV.LOOKUP ("Inventory / Max"); // Use the entry to Customize Business Logic Note that the application component can also use the following full path name to find the environment portal: Javax.naming.context ctx = new javax.naming.initialcontext (); string str = (string) CTX.lookup ("java: comp / env / greetings); This code snippet can be used in a JSP page, as shown by sample code: Sample Code 7: Access Environment Portal from a JSP page inventory system h2> <% javax.naming.context CTX = New Javax.naming.initialContext (); javax.naming.context myenv = (javax.naming.context) T.LOOKUP ("Java: Comp / ENV"); java.lang.string s = (java.lang.string) Myenv .lookup ("Greetings"); Out.println ("The value is:" greetings);%> center> body> html>
Conclude
JNDI is a set of APIs enhance your web application using Named / Directory Services. The example given by this article demonstrates that it is a simple thing to start using JNDI development-based applications. These examples also demonstrate how to access different named / directory services using the same API. Developers don't have to learn different APIs. In some cases, such as in the RMI and CORBA applications, JNDI allows you to extend the selection of the naming service to the deployment phase.
For the future of JNDI: combined with standard Java SASL API (JSR-28), support international domain names, and supports secure DNS.
To start learning and using JNDI and LDAP, download the SUN ONE Directory Server trial version, which can be used in a variety of platforms and various languages.
More information
LDAP V3 JNDI THE JNDI TUTORIAL JNDI Service Provider Sun One Directory Server JNDI-INTEREST MAILING LIST (for Discussing JNDI) Acknowledgment
Special thanks to Sun Microsystems Jaya Hangal and Rosanna Lee, their feedback helps me improve this article.