Building in Extensibility

If you followed the steps described in this lesson so far, then you should have a complete, functional context implementation. However, such a context implementation would be closed in the sense that the types of objects that can be read and stored by using the context implementation would be limited to what the context implementation was coded to accept. The JNDI provides utilities for making context implementations extensible. These utilities allow objects that are passed by the program to be transformed before they reach the context implementation, and allow objects that are read from the directory to be transformed before they reach the program.

 

 

Reading Objects

The Object Factories lesson describes how a service provider should use NamingManager.getObjectInstance() or DirectoryManager.getObjectInstance() before returning an object to the user program from one of the following methods: Following is how the hierarchical namespace example calls getObjectInstance() in its lookup() method. It uses the method in the NamingManager class because HierCtx implements only the Context interface. If a context implementation implements the DirContext interface, then it should use the one in the DirectoryManager class. See the Adding Directory Support lesson for details.
// Code that determined "inter" is the object bound to the
// atomic name "atom"
    ...

// Call getObjectInstance for using any object factories
try {
    return NamingManager.getObjectInstance(inter, 
        new CompositeName().add(atom), this, myEnv);
} catch (Exception e) {
    NamingException ne = new NamingException("getObjectInstance failed");
    ne.setRootCause(e);
    throw ne;
}
You should pass to getObjectInstance() the name of the object as a composite name and the context in which the name should be resolved. This need not be the deepest context (that is, the name need not be atomic). You should also pass in the context's environment properties in case the object factories need them.

Similarly, when returning the enumeration generated by Context.listBindings() , you should call getObjectInstance() for the object in each Binding in the enumeration. Here is the definition of the enumeration's next() method.

public Object next() throws NamingException {
    String name = (String)names.nextElement();
    Object obj = bindings.get(name);

    try {
	obj = NamingManager.getObjectInstance(obj, 
	    new CompositeName().add(name), HierCtx.this, 
	    HierCtx.this.myEnv);
    } catch (Exception e) {
	NamingException ne = new NamingException("getObjectInstance failed");
	ne.setRootCause(e);
	throw ne;
    }

    return new Binding(name, obj);
}
This example shows a static approach, in which getObjectInstance() is called as you create each Binding instance. Another approach is to define your own Binding subclass and override Binding.getObject() to call getObjectInstance(). (The result of getObjectInstance() could be cached to avoid repeated invocations.)

 

 

Storing Objects

The State Factories lesson describes how a service provider should use NamingManager.getStateToBind() or DirectoryManager.getStateToBind() before storing an object given by the user program to one of the following methods: Here is how the hierarchical namespace example calls getStateToBind() in its bind() and rebind() methods. It uses the method in the NamingManager class because HierCtx implements only the Context interface. If a context implementation implements the DirContext interface, then it should use the one in the DirectoryManager class. See the Adding Directory Support lesson for details.
// Code that determines that this is the context in which
// to bind the atomic name "atom" to the object "obj"
    ...

// Call getStateToBind for using any state factories
obj = NamingManager.getStateToBind(obj, 
    new CompositeName().add(atom), this, myEnv);

// Add the object to the internal data structure
bindings.put(atom, obj);
You should pass to getStateToBind() the name of the object as a composite name and the context in which the name will be resolved. This need not be the deepest context (that is, the name need not be atomic). You should also pass in the context's environment properties in case the state factories need them.

Note that this implementation is simplistic because the example can store any type of object. A more realistic implementation would check the result of getStateToBind() to ensure that the object is of a type that it can store. See the State Factories lesson for details.