Previous | Next | Trail Map | Building a Service Provider | Adding Federation Support

The Current Naming System

After extracting the name components that belong to your current naming system, you must decide how to process those components. You have three choices. Here is a sample implementation of bind()(in the API reference documentation) that implements these three choices.
public void bind(Name name, Object bindObj) throws NamingException {
    try {
	Name[] nm = parseComponents(name);
	Name mine = nm[0];
	Name rest = nm[1];

	if (rest == null || rest.isEmpty()) {
	    // Terminal; just use head
	    bind_internal(mine, bindObj);
	} else if (rest.get(0).equals("") && rest.size() == 1) {
	    // Terminal nns
	    bind_nns(mine, bindObj);
	} else if (mine.isEmpty() || isAllEmpty(rest)) {
	    // Intermediate; resolve current components as intermediate
	    Object obj = lookup_nns(mine);

	    // Skip the leading forward slash
	    throw fillInCPE(obj, mine, rest.getSuffix(1));
	} else {
	    // Intermediate; resolve current components as intermediate
	    Object obj = resolveIntermediate_nns(mine, rest);

	    throw fillInCPE(obj, mine, rest);
	}
    } catch (CannotProceedException e) {
	Context cctx = NamingManager.getContinuationContext(e);
	cctx.bind(e.getRemainingName(), bindObj);
    }
}
This example and the three alternatives are explained in more detail later in this lesson. Note that all other name-related methods in the Context(in the API reference documentation) interface should be implemented similarly.

Terminal

Once name resolution has reached the target naming system, you basically no longer need to worry about federation. In the example here, this case is handled by defining an xxx_internal method for each methods the Context(in the API reference documentation). This technique is useful for clearly delineating the portion of the code that is local or internal to this context implementation.

Here is the example for bind().

private void bind_internal(Name name, Object obj) throws NamingException {
    if (name.isEmpty()) {
        throw new InvalidNameException("Cannot bind empty name");
    }

    // Extract the components that belong to this namespace
    String atom = getInternalName(name);
    if (bindings.get(atom) != null) {
	throw new NameAlreadyBoundException("Use rebind to override");
    }

    // Call getStateToBind for using any state factories
    obj = NamingManager.getStateToBind(obj, name, this, myEnv);

    // Add the object to the internal data structure
    bindings.put(atom, obj);
}
If the context implementation supports dynamic weak separation (that is, it determines the naming system boundary dynamically), then the xxx_internal() methods will resolve the name to determine which parts belong to the current naming system. If the current naming system is determined not to be the terminal naming system, then the methods will throw a CannotProceedException(in the API reference documentation), with the remaining components as the remaining name.

Terminal Next Naming System

When name resolution has reached the target naming system with a remaining name that has a trailing forward slash character ("/"), the operation is to be applied to the nns pointer of the remaining name. Recall from the Federation (in the Beyond the Basics trail) lesson that context implementation may implement the nns pointer as explicit (also called a junction) or implicit. In the example, this case is handled by defining an xxx_nns methods for each of methods in the Context(in the API reference documentation) interface. As with the case of the xxx_internal naming technique, this technique is useful for delineating the part of the the code that handles the nns pointer.

The implementation of the xxx_nns methods depend on how the context implementation handles nns pointers. For example, a context implementation might support implicit nns by having a table that records the nns for each name bound in a context. In that case, its bind_nns() method might look as follows.

private void bind_nns(Name name, Object obj) throws NamingException {
    if (name.isEmpty()) {
	// Set your nns
	myNNS = NamingManager.getStateToBind(obj, 
	((Name)(name.clone())).add(""), this, myEnv);
	return;
    }
    // Extract the components that belong to this namespace
    String atom = getInternalName(name);
    if (nnsBindings.get(atom) != null) {
	throw new NameAlreadyBoundException("Use rebind to override");
    }

    // Call getStateToBind for using any state factories
    obj = NamingManager.getStateToBind(obj, 
	((Name)(name.clone())).add(""), this, myEnv);

    // Add the object to the internal nns data structure
    nnsBindings.put(atom, obj);
}
If the context implementation supports junctions, then it should look up the junction and apply the operation on the nns of the junction. This is illustrated by the example. Since this is a common pattern used by other context methods, an internal utility, processJunction_nns(), is defined for this purpose, as follows.
protected void processJunction_nns(Name name) throws NamingException {
    if (name.isEmpty()) {
	// Construct a new Reference that contains this context
	RefAddr addr = new RefAddr("nns") {
	    public Object getContent() {
		return FedCtx.this;
	    }
	};
	Reference ref = new Reference("java.lang.Object", addr);

	throw fillInCPE(ref, NNS_NAME, null);
    } else {
        // Look up the name to continue the operation in the nns
	Object target;
	try {
	    target = lookup_internal(name);
	} catch (NamingException e) {
	    e.appendRemainingComponent(""); // Add the nns back in
	    throw e;
	}

	throw fillInCPE(target, name, NNS_NAME);
    }
}
If the name is empty, then the user is requesting the nns of the current context. In that case, an nns reference (see the Federation (in the Beyond the Basics trail) lesson) is constructed by using the current context as the resolved object and the trailing forward slash character ("/") as the "alt" name. The "alt" name is the name of the resolved object resolved relative to the "alt" name context (which in this case is the current context). This information is used to create and throw a CannotProceedException. If the name is not empty, then you need to look up the named object from this current context and create a CannotProceedException that contains the trailing forward slash as the remaining name. The CannotProceedException is handled by the main bind() method, as discussed in the next section. bind_nns(), like other methods for handling the nns, simply uses the internal utility processJunction_nns().
private void bind_nns(Name name, Object obj) throws NamingException {
    processJunction_nns(name);
}
fillInCPE() is an internal utility that creates a CannotProceedException by using this context as the "alt" name context and this context's environment. Here is its definition.
protected CannotProceedException fillInCPE(Object resolvedObj, 
	Name altName, Name remainingName) {
    CannotProceedException cpe = new CannotProceedException();

    // Generic stuff
    cpe.setEnvironment(myEnv);
    cpe.setAltNameCtx(this);

    // Specific stuff
    cpe.setResolvedObj(resolvedObj);
    cpe.setAltName(altName);
    cpe.setRemainingName(remainingName);
    return cpe;
}

Intermediate

If the parseComponents() utility method returns results that indicate that resolution is currently at an intermediate context, then you must resolve the name components intended for the current naming system to obtain the reference to the nns. How the resolution occurs depends on whether the implicit nns has been requested. The implicit nns has been requested if the name contains a leading forward slash character ("/") or if the name components that belong to the nns (rest) are all empty (this is indicated by one or more trailing forward slashes). In this case, the context implementation should use the internal utility lookup_nns() to obtain the nns and then continue the operation on the rest of the name components.

If the implicit nns has not been requested, then the name components that belong to this current naming system (mine) might name a junction or an implicit nns. To process this case, a utility is defined that can be used by all context methods called resolveIntermediate_nns().

protected Object resolveIntermediate_nns(Name name, Name rest, 
    Name newName)
    throws NamingException {
    CannotProceedException cpe;
    try {
	final Object obj = lookup_internal(name);

	if (obj != null && getClass().isInstance(obj)) {
	    // If "obj" is in the same type as this object, it must
	    // not be a junction; continue the lookup with "/"

	    cpe = fillInCPE(obj, name,
		((Name)(NNS_NAME.clone())).addAll(rest));
	    cpe.setRemainingNewName(newName);
	} else if (obj != null && !(obj instanceof Context)) {
	    // obj is not even a context, so try to find its nns
	    // dynamically by constructing a Reference that
	    // contains obj
	    RefAddr addr = new RefAddr("nns") {
		public Object getContent() {
		    return obj;
		}
	    };
	    Reference ref = new Reference("java.lang.Object", addr);

	    // Resolved name has a trailing slash to indicate the nns
	    CompositeName resName = (CompositeName)name.clone();
	    resName.add(""); // Add the trailing forward slash

	    cpe = fillInCPE(ref, resName, rest);
	    cpe.setRemainingNewName(newName);

	} else {
	    // Consume "/" and continue
	    return obj;
	}
    } catch (NamingException e) {
	e.appendRemainingComponent(""); // Add the nns back in
	throw e;
    }
    throw cpe;
}
As defined in the example, this method supports junctions and dynamic implicit nns (see the Federation (in the Beyond the Basics trail) lesson). If your context implementation supports static implicit nns, then it would probably look as follows instead.
private void resolveIntermediate_nns(Name name, Name rest, Name newName)
    throws NamingException {
    Object nns;
    if (name.isEmpty()) {
	nns = myNNS;   // Return this context's nns
    } else {
        // Extract the components that belong to this namespace
        String atom = getInternalName(name);

        // Get the nns from the internal table
        nns  = nnsBindings.get(atom);
        if (nns == null) {
	    throw new NameNotFoundException(atom + "/");
        }
    }
    // Call getObjectInstance for using any object factories
    try {
	return NamingManager.getObjectInstance(nns,
	    ((Name)(name.clone())).add(""), this, myEnv);
    } catch (Exception e) {
	NamingException ne = new NamingException();
	ne.setRootCause(e);
	throw ne;
    }
}


Previous | Next | Trail Map | Building a Service Provider | Adding Federation Support