Java Naming and Directory Interface (JNDI) tutorial

Home arrow Java Tutorials arrow Core arrow Java Naming and Directory Interface (JNDI) tutorial
Java Naming and Directory Interface (JNDI) tutorial Print E-mail
User Rating: / 13
PoorBest 
Contributed by Howell   
Friday, 16 June 2006
Overview(Java Naming and Directory Interface (JNDI) tutorial)

Naming and directory services play a vital role in intranets and the Internet by providing network-wide sharing of a variety of information about users, machines, networks, services, and applications.

JNDI is an API specified in Java technology that provides naming and directory functionality to applications written in the Java programming language. It is designed especially for the Java platform using Java's object model. Using JNDI, applications based on Java technology can store and retrieve named Java objects of any type. In addition, JNDI provides methods for performing standard directory operations, such as associating attributes with objects and searching for objects using their attributes.

JNDI is also defined independent of any specific naming or directory service implementation. It enables applications to access different, possibly multiple, naming and directory services using a common API. Different naming and directory service providers can be plugged in seamlessly behind this common API. This enables Java technology-based applications to take advantage of information in a variety of existing naming and directory services, such as LDAP, NDS, DNS, and NIS(YP), as well as enabling the applications to coexist with legacy software and systems.

Using JNDI as a tool, you can build new powerful and portable applications that not only take advantage of Java's object model but are also well-integrated with the environment in which they are deployed.

A simple JNDI example (JNDI tutorial)

Storing and retrieving objects from a JNDI namespace is quite straightforward; you first obtain a JNDI naming context and then use the bind() and lookup() methods to store and retrieve objects, as Listing 1 shows:

 Store and retrieve objects from a JNDI namespace

  import javax.naming.*;

  public void createName() throws NamingException {
    Context context = new InitialContext();
    context.bind("/config/applicationName", "MyApp");
  }

  public String getName() throws NamingException {
    Context context = new InitialContext();
    return (String) context.lookup("/config/applicationName");
  } 

Creating an Initial Context to a Directory (JNDI tutorial)

This example uses the JNDI/LDAP service provider to connect to an LDAP server on the local machine.
    String url = "ldap://localhost/o=JNDITutorial";
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, url);
    try {
        DirContext ctx = new InitialDirContext(env);
    } catch (NamingException e) {
    }

 Creating a Directory Entry(JNDI tutorial)

This example creates an entry in the directory.
    try {
        // Create attributes to be associated with the new entry
        Attributes attrs = new BasicAttributes(true); // case-ignore
        Attribute objclass = new BasicAttribute("objectclass");
        objclass.add("top");
        objclass.add("extensibleObject");
        attrs.put(objclass);
   
        // Create the context
        Context entry = ctx.createSubcontext("cn=Sample", attrs);
    } catch (NamingException e) {
    }

Application configuration files using a custom JNDI object in resin  (JNDI tutorial)
The java code for a custom JNDI object


A custom JNDI object is implemented similar to a java-bean (see Bean-style initialization ). Setter methods like setFoo(String foo) are used to set values that are specified in the configuration.

In this case, a single setter is provided that matches the configuration parameter "config-files-location". The init() method is called by Resin after all of the setters have been called.

See it in: WEB-INF/classes/example/AppConfig.java  public class AppConfig {
  ConfigFilesLocation _cfl = null;

  /**
   * Set the base for subsequent call's to openConfigFileRead()
   * and openConfigFileWrite()
   *
   * @param location a file path or url
   */
  public void setConfigFilesLocation(String location)
    throws Exception
  {
    _cfl = new ConfigFilesLocation();
    _cfl.setLocation(location);
  }

  public void init()
    throws Exception
  {
    if (_cfl == null)
      throw new Exception("'config-files-location' must be set");
  }

  ...

 


Configuring the custom JNDI object


Configuration of the JNDI object is done with the <resource> tag.

The example here configures the location of the configuration files as WEB-INF/config (which means you need to make sure the directory exists for the example to work). It is good to hide the files somewhere under WEB-INF, because a browser will not be able to read the files, just the application.

The EL configuration variable app.docDir is used.

Configuring the AppConfig JNDI object
See it in: WEB-INF/web.xml    <resource name='config/Application'>
    <type>example.AppConfig</type>
    <init>
      <config-files-location>${'${'}app.docDir}/WEB-INF/config</config-files-location>
    </init>
  </resource>

 


Obtaining and using the object


An instance of the object is retrieved in the application using JNDI. Since the configuration will not change, it is best to store the results of the lookup.

In this example servlet, an instance of the object is retrieved in the init() method and stored in _appConfig.

Obtaining the AppConfig JNDI object
See it in: WEB-INF/classes/example/TestServlet.java 
  final static String JNDI_NAME = "java:comp/env/config/Application";

  public void init()
    throws ServletException
  {
    try {
      _appConfig = (AppConfig) new InitialContext().lookup(JNDI_NAME);

      if (_appConfig == null)
        throw new ServletException("`" + JNDI_NAME + "' is an unknown JNDI resource");
    } catch (NamingException e) {
      throw new ServletException(e);
    }

 


_appConfig is used to open the configuration files for reading and writing.

Using the AppConfig JNDI object
See it in: WEB-INF/classes/example/TestServlet.java  ...

    InputStream is = _appConfig.openConfigFileRead(inputFile);

...

    OutputStream os = _appConfig.openConfigFileWrite(outputFile);

...

 


Variation - Hiding the configuration file with getters


The example in this tutorial is easily modified to allow the hiding of the configuration file behind get methods of the bean. Implementing getters on the confugration bean abstracts the configuration information, protecting code which uses the configuration information from implementation details of how the configuration information is read and stored.

Hiding the configuration file with getters  package example;

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

public class AppConfig {
  public final static String APPCONFIG_JNDINAME = "java:comp/env/config/Application";
  private final static String DEFAULT_PROPERTIES = "example/AppConfig.properties";

  private String _configFile;
  private Properties _properties;


  /**
   * A convenience method that emulates the singleton pattern.
   * It is not a good idea to use static member variables to implement the
   * singleton pattern in an app server because of ClassLoader problems.
   * In this case, JNDI is used to store the object in a safe manner.
   *
   * The AppConfig object has already been instantiated by Resin, the JNDI
   * lookup is used to get a reference to an object that already exists. 
   */
  static public AppConfig getInstance()
    throws NamingException
  {
    AppConfig r = (AppConfig) new InitialContext().lookup(APPCONFIG_JNDINAME);
    if (r == null)
      throw new NamingException("no object found with jndi name `" + APPCONFIG_JNDINAME + "'");
    return r;
  }

  /**
   * Optionally set the name of a file that provides properties that override
   * the defaults.  The defaults are obtained from a file in the classpath
   * named 'example/AppConfig.properties'
   *
   * For example, the file containing default properties might be in
   * WEB-INF/classes/example/AppConfig.properties,
   * or if AppConfig.class is in a jar, the AppConfig.properties
   * could be in the jar file alongside the AppConfig.class file.
   *
   * AppConfig.properties contains values placed there by the developer.
   * The <config-file> is used to indicate a file that specifies properties
   * that override the defaults, perhaps properties that change depending
   * on the deployment environment.
   */
  public void setConfigFile(String configFile)
    throws Exception
  {
    _configFile = configFile;
  }

  public void init()
    throws Exception
  {
    InputStream is = null;
    Properties defaults;

    // try to find a default configuration file in the classpath
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    is = loader.getResourceAsStream(DEFAULT_PROPERTIES);

    if (is != null)
      defaults = new Properties();
      defaults.load(is);
    }
    else {
      // throw an exception here to make the defaults required
      throw new FileNotFoundException(DEFAULT_PROPERTIES);
    }

    if (_configFile == null) {
      // just use the defaults
      _properties = defaults;
    }
    else {
      // the properties in _configFile override the defaults
      is = new FileInputStream(_configFile);
      _properties = new Properties(defaults);
      _properties.load(is);
    }
  }

  public String getFoo()
  {
    return _properties.getProperty("foo");
  }

  public String getBar()
  {
    return _properties.getProperty("bar");
  }
}

 


<web-app>
 <resource name='config/Application'>
    <type>example.AppConfig</type>
 </resource>
</web-app>

or

<web-app>
 <resource name='config/Application'>
    <type>example.AppConfig</type>
    <init>
      <config-file>${'${'}app.docDir}/WEB-INF/AppConfig-override.properties</config-file>
    </init>
 </resource>
</web-app>

 


package example;

import javax.servlet.*;
import javax.servlet.http.*;

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

public class TestServlet extends HttpServlet {
  /**
   * _appConfig is stored locally, for efficiency.
   */
  AppConfig _appConfig;

  public void init()
    throws ServletException
  {
    try {
      _appConfig = AppConfig.getInstance();
    } catch (NamingException e) {
      throw new ServletException(e);
    }
  }

  ...

  String foo = _appConfig.getFoo();
  String bar = _appConfig.getBar();

  ...

}

 


Availability of AppConfig from different web-apps


The availability of AppConfig to different web-apps depends upon the context that the <resource ...> configuration is placed within.

If the configuration is placed as a child of <web-app>, then that instance of AppConfig is available only to that web-app.

<web-app>
 <resource name='config/Application'>
    <type>example.AppConfig</type>
 </resource>
</web-app>

 


If it is placed as a child of <host>, that instance of AppConfig is available to all web-app's within the host.

<host>
  ...
 <resource name='config/Application'>
    <type>example.AppConfig</type>
 </resource>
  ...
</host>

 


If it is placed as a child of <server>, that instance of AppConfig is available to all web-app's within all host's within that server.

<server>
  ...
 <resource name='config/Application'>
    <type>example.AppConfig</type>
 </resource>
  ...
</server>

 


In the case of <server> or <host>, the example.AppConfig class needs to be available in the classpath. The easiest way to accomplish that is to place a jar with that class in $RESIN_HOME/lib, or you can use an explicit <class-loader> .

Compatibility


Although the <resource> tag is Resin specific the pattern shown in this tutorial is good for portability. If your application needs to work in another app-server, you can use a startup facility such as a <load-on-startup> servlet to manually configure the bean, call the init() method, and stuff the instance into JNDI.

 

 

Last Updated ( Friday, 16 June 2006 )

  home              contact us

 

©2006-2012 DeveloperZone.biz   All rights reserved     powered by Mambo Designed by Siteground