blogger templates blogger widgets
This is part of a list of blog posts.
To browse the contents go to

The IntialContext

But firstly, the Context.

JNDI represents a context in a naming system using the javax.naming.Context interface. This is the key interface for interacting with naming services. A Context knows about its set of bindings in the naming system, but little else. It contains methods for examining and updating these bindings.

A Context instance is not guaranteed to be synchronized against concurrent access by multiple threads. Threads that need to access a single Context instance concurrently should synchronize amongst themselves and provide the necessary locking.

JNDI applications need a way to communicate various preferences and properties that define the environment in which naming and directory services are accessed. For example, a context might require specification of security credentials in order to access the service. Another context might require that server configuration information be supplied. These are referred to as the environment of a context. The Context interface provides methods for retrieving and updating this environment.

These could be specified through
  • Application Resource Files
  • System Properties
  • Applet Parameters

More about these here

InitialContext

The javax.naming.InitialContext class implements the Context interface and serves as our entry point to a naming system.

The initial context implementation is determined at runtime.

The default policy uses the environment property "java.naming.factory.initial", which contains the class name of the initial context factory. An exception to this policy is made when resolving URL strings, as described here.

What happens when we do not supply a factory class name for InitialContext constructor?
Context initctx = new InitialContext();
InitialContext object is created using the default implementation found in the JDK itself.
Note that without specifying the mandatory INITIAL_CONTEXT_FACTORY environment property for this context it's useless.

For eg:
try {
    Context initCxt = new InitialContext();
    } catch (NamingException e) {
        e.printStackTrace();
    }

Works fine. No errors. But

try {
    Context initCxt = new InitialContext();
    Object obj = initCxt.lookup(""); //or any operation
    } catch (NamingException e) {
        e.printStackTrace();
    }

Throws,
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
When a factory class is specified as we saw in the examples before, the initialContext object is created by calling getInitialContext() on the factory class instance.

Here is a short sneak peek into the JNDI/JDK source code,

//javax.naming.spi.NamingManager
public static Context getInitialContext(Hashtable env)
 throws NamingException {
 InitialContextFactory factory;

 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
 if (builder == null) {
  // No factory installed, use property
  // Get initial context factory class name

  String className = env != null ?
   (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
  if (className == null) {
   NoInitialContextException ne = new NoInitialContextException(
    "Need to specify class name in environment or system " +
    "property, or as an applet parameter, or in an " +
    "application resource file:  " +
    Context.INITIAL_CONTEXT_FACTORY);
   throw ne;
  }

  try {
   factory = (InitialContextFactory)
    helper.loadClass(className).newInstance();
  } catch(Exception e) {
   .....
  }
 } else {
  factory = builder.createInitialContextFactory(env);
 }
 return factory.getInitialContext(env);
}

This now explains why we got an exception.

What happens when we run

Context initctx = new InitialContext();
in a container like tomcat?

Tomcat provides a JNDI InitialContext implementation instance for each web application running under it.

You might be wondering what is the default environment settings used by this context. Well, let's try to printout from within a servlet.

Context initCxt = new InitialContext();
Hashtable<?, ?> enviProps = initCxt.getEnvironment();
Enumeration enumKey = enviProps.keys();
while(enumKey.hasMoreElements()) {
 String key = (String) enumKey.nextElement();
 String val = (String) enviProps.get(key);
 System.out.println(key+" ::: "+val);
}

Output:
java.naming.factory.initial ::: org.apache.naming.java.javaURLContextFactory
java.naming.factory.url.pkgs ::: org.apache.naming

Note that java.naming.factory.initial is INITIAL_CONTEXT_FACTORY and java.naming.factory.url.pkgs is URL_PKG_PREFIXES.

Who supplied these jndi properties?

Well, tomcat specified these as system properties when it started the JRE.
Let's print the system properties.

Properties sysProps = System.getProperties();
Enumeration keys = sysProps.keys();
while (keys.hasMoreElements()) {
 String key = (String) keys.nextElement();
 String value = (String) sysProps.get(key);
 System.out.println(key + ": " + value);
}

You will find these,
java.naming.factory.url.pkgs: org.apache.naming
java.naming.factory.initial: org.apache.naming.java.javaURLContextFactory

Note that javaURLContextFactory is the Context factory for the "java:" namespace.
To my knowledge tomcat doesn't provide any other namespaces whereas application servers like websphere does. Checkout this for websphere

Here is a short sneak peek into tomcat source code,

/**
 * Context factory for the "java:" namespace.
 **/
public class javaURLContextFactory
    implements ObjectFactory, InitialContextFactory {
 /**
     * Initial context.
     */
    protected static volatile Context initialContext = null;
 public static final String MAIN = "initialContext";
 /**
     * Get a new (writable) initial context.
     */
    @Override
    public Context getInitialContext(Hashtable environment)
        throws NamingException {
        if (initialContext == null) {
            synchronized(javaURLContextFactory.class) {
                if (initialContext == null) {
                    initialContext = new NamingContext(
                            (environment, MAIN);
                }
            }
        }
        return initialContext;
    }
}

/**
 * Catalina JNDI Context implementation.
 *
 * @author Remy Maucherat
 */
public class NamingContext implements Context {

    /**
     * Bindings in this Context.
     */
    protected HashMap bindings;
    /**
     * Name of the associated Catalina Context.
     */
    protected String name;
    /**
     * Environment.
     */
    protected Hashtable env;
 
    /**
     * Builds a naming context using the given environment.
     */
    public NamingContext(Hashtable env, String name) 
        throws NamingException {
        this.bindings = new HashMap();
        this.env = new Hashtable();
        this.name = name;
        // Populating the environment hashtable
        if (env != null ) {
            Enumeration envEntries = env.keys();
            while (envEntries.hasMoreElements()) {
                String entryName = envEntries.nextElement();
                addToEnvironment(entryName, env.get(entryName));
            }
        }
    }
}

Continue reading: How JNDI works in tomcat

No comments:

Post a Comment