| 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.
> - Terminal. Name resolution has reached the target naming system. Apply the operation to the name.
> - Terminal next naming system (terminal nns). Name resolution has reached the target naming system. Apply the operation to the nns pointer (next naming system pointer) of the name.
> - Intermediate. The current naming system is an intermediate naming system. Do the necessary name resolution to determine the nns to which to pass the operation.
> Here is a sample implementation of `bind()` 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` 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`. 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`, 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 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` 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 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 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;
> >         }
> >     }

| Adding Federation Support