/*
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.jndi.toolkit.ctx;
import javax.naming.*;
import javax.naming.spi.ResolveResult;
/**
* Clients: deal only with names for its own naming service
* and deals with single contexts that can be built up into
* hierarchical naming systems.
* Direct subclasses of AtomicContext must provide implementations for
* the abstract a_ Context methods, and c_parseComponent().
*
* If the subclass implements the notion of implicit nns,
* it must override the a_*_nns Context methods as well.
*
* @author Rosanna Lee
*
*/
public abstract class AtomicContext extends ComponentContext {
private static int debug = 0;
protected AtomicContext () {
_contextType = _ATOMIC;
}
// ------ Abstract methods whose implementation are provided by subclasses
/* Equivalent to Context methods */
protected abstract Object a_lookup(String name, Continuation cont)
throws NamingException;
protected abstract Object a_lookupLink(String name, Continuation cont)
throws NamingException;
protected abstract NamingEnumeration a_list(
Continuation cont) throws NamingException;
protected abstract NamingEnumeration a_listBindings(
Continuation cont) throws NamingException;
protected abstract void a_bind(String name, Object obj, Continuation cont)
throws NamingException;
protected abstract void a_rebind(String name, Object obj, Continuation cont)
throws NamingException;
protected abstract void a_unbind(String name, Continuation cont)
throws NamingException;
protected abstract void a_destroySubcontext(String name, Continuation cont)
throws NamingException;
protected abstract Context a_createSubcontext(String name,
Continuation cont) throws NamingException;
protected abstract void a_rename(String oldname, Name newname,
Continuation cont) throws NamingException;
protected abstract NameParser a_getNameParser(Continuation cont)
throws NamingException;
/* Parsing */
/**
* Parse 'inputName' into two parts:
* head: the first component in this name
* tail: the rest of the unused name.
*
* Subclasses should provide an implementation for this method
* which parses inputName using its own name syntax.
*/
protected abstract StringHeadTail c_parseComponent(String inputName,
Continuation cont) throws NamingException;
// ------ Methods that need to be overridden by subclass
/* Resolution method for supporting federation */
/**
* Resolves the nns for 'name' when the named context is acting
* as an intermediate context.
*
* For a system that supports junctions, this would be equilvalent to
* a_lookup(name, cont);
* because for junctions, an intermediate slash simply signifies
* a syntactic separator.
*
* For a system that supports implicit nns, this would be equivalent to
* a_lookup_nns(name, cont);
* because for implicit nns, a slash always signifies the implicit nns,
* regardless of whether it is intermediate or trailing.
*
* By default this method supports junctions, and also allows for an
* implicit nns to be dynamically determined through the use of the
* "nns" reference (see a_processJunction_nns()).
* Contexts that implement implicit nns directly should provide an
* appropriate override.
*/
protected Object a_resolveIntermediate_nns(String name, Continuation cont)
throws NamingException {
try {
final Object obj = a_lookup(name, cont);
// Do not append "" to Continuation 'cont' even if set
// because the intention is to ignore the nns
//
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 "/".
cont.setContinueNNS(obj, name, this);
return null;
} else if (obj != null && !(obj instanceof Context)) {
// obj is not even a context, so try to find its nns
// dynamically by constructing a Reference containing obj.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return obj;
}
private static final long serialVersionUID =
-3399518522645918499L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Resolved name has trailing slash to indicate nns
CompositeName resName = new CompositeName();
resName.add(name);
resName.add(""); // add trailing slash
// Set continuation leave it to
// PartialCompositeContext.getPCContext() to throw CPE.
// Do not use setContinueNNS() because we've already
// consumed "/" (i.e., moved it to resName).
cont.setContinue(ref, resName, this);
return null;
} else {
return obj;
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
/* Equivalent of Context Methods for supporting nns */
// The following methods are called when the DirContext methods
// are invoked with a name that has a trailing slash.
// For naming systems that support implicit nns,
// the trailing slash signifies the implicit nns.
// For such naming systems, override these a_*_nns methods.
//
// For naming systems that support junctions (explicit nns),
// the trailing slash is meaningless because a junction does not
// have an implicit nns. The default implementation here
// throws a NameNotFoundException for such names.
// If a context wants to accept a trailing slash as having
// the same meaning as the same name without a trailing slash,
// then it should override these a_*_nns methods.
protected Object a_lookup_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected Object a_lookupLink_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected NamingEnumeration a_list_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected NamingEnumeration a_listBindings_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected void a_bind_nns(String name, Object obj, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_rebind_nns(String name, Object obj, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_unbind_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected Context a_createSubcontext_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
return null;
}
protected void a_destroySubcontext_nns(String name, Continuation cont)
throws NamingException {
a_processJunction_nns(name, cont);
}
protected void a_rename_nns(String oldname, Name newname, Continuation cont)
throws NamingException {
a_processJunction_nns(oldname, cont);
}
protected NameParser a_getNameParser_nns(Continuation cont)
throws NamingException {
a_processJunction_nns(cont);
return null;
}
protected boolean isEmpty(String name) {
return name == null || name.equals("");
}
// ------ implementations of c_ and c_*_nns methods using
// ------ the corresponding a_ and a_*_nns methods
/* Equivalent to methods in Context interface */
protected Object c_lookup(Name name, Continuation cont)
throws NamingException {
Object ret = null;
if (resolve_to_penultimate_context(name, cont)) {
ret = a_lookup(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
}
protected Object c_lookupLink(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont)) {
return a_lookupLink(name.toString(), cont);
}
return null;
}
protected NamingEnumeration c_list(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont)) {
return a_list(cont);
}
return null;
}
protected NamingEnumeration c_listBindings(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont)) {
return a_listBindings(cont);
}
return null;
}
protected void c_bind(Name name, Object obj, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_bind(name.toString(), obj, cont);
}
protected void c_rebind(Name name, Object obj, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_rebind(name.toString(), obj, cont);
}
protected void c_unbind(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_unbind(name.toString(), cont);
}
protected void c_destroySubcontext(Name name, Continuation cont)
throws NamingException {
if (resolve_to_penultimate_context(name, cont))
a_destroySubcontext(name.toString(), cont);
}
protected Context c_createSubcontext(Name name,
Continuation cont) throws NamingException {
if (resolve_to_penultimate_context(name, cont))
return a_createSubcontext(name.toString(), cont);
else
return null;
}
protected void c_rename(Name oldname, Name newname,
Continuation cont) throws NamingException {
if (resolve_to_penultimate_context(oldname, cont))
a_rename(oldname.toString(), newname, cont);
}
protected NameParser c_getNameParser(Name name,
Continuation cont) throws NamingException {
if (resolve_to_context(name, cont))
return a_getNameParser(cont);
return null;
}
/* The following are overridden only for AtomicContexts.
* AtomicContext is used by PartialCompositeDirContext and ComponentDirContext
* in the inheritance tree to make use of methods in
* PartialCompositeContext and ComponentContext. We only want to use the
* atomic forms when we're actually an atomic context.
*/
/* From ComponentContext */
protected Object c_resolveIntermediate_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
Object ret = null;
if (resolve_to_penultimate_context_nns(name, cont)) {
ret = a_resolveIntermediate_nns(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
} else {
// use ComponentContext
return super.c_resolveIntermediate_nns(name, cont);
}
}
/* Equivalent to methods in Context interface for nns */
protected Object c_lookup_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
Object ret = null;
if (resolve_to_penultimate_context_nns(name, cont)) {
ret = a_lookup_nns(name.toString(), cont);
if (ret != null && ret instanceof LinkRef) {
cont.setContinue(ret, name, this);
ret = null;
}
}
return ret;
} else {
return super.c_lookup_nns(name, cont);
}
}
protected Object c_lookupLink_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
// %%% check logic
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_lookupLink_nns(name, cont);
}
}
protected NamingEnumeration c_list_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_list_nns(name, cont);
}
}
protected NamingEnumeration c_listBindings_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use ComponentContext
return super.c_list_nns(name, cont);
}
}
protected void c_bind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_bind_nns(name.toString(), obj, cont);
} else {
// use ComponentContext
super.c_bind_nns(name, obj, cont);
}
}
protected void c_rebind_nns(Name name, Object obj, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_rebind_nns(name.toString(), obj, cont);
} else {
// use ComponentContext
super.c_rebind_nns(name, obj, cont);
}
}
protected void c_unbind_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_unbind_nns(name.toString(), cont);
} else {
// use ComponentContext
super.c_unbind_nns(name, cont);
}
}
protected Context c_createSubcontext_nns(Name name,
Continuation cont) throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
return a_createSubcontext_nns(name.toString(), cont);
else
return null;
} else {
// use ComponentContext
return super.c_createSubcontext_nns(name, cont);
}
}
protected void c_destroySubcontext_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(name, cont))
a_destroySubcontext_nns(name.toString(), cont);
} else {
// use ComponentContext
super.c_destroySubcontext_nns(name, cont);
}
}
protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
if (resolve_to_penultimate_context_nns(oldname, cont))
a_rename_nns(oldname.toString(), newname, cont);
} else {
// use ComponentContext
super.c_rename_nns(oldname, newname, cont);
}
}
protected NameParser c_getNameParser_nns(Name name, Continuation cont)
throws NamingException {
if (_contextType == _ATOMIC) {
resolve_to_nns_and_continue(name, cont);
return null;
} else {
// use COmponentContext
return super.c_getNameParser_nns(name, cont);
}
}
// -------------- internal methods used by this class
/* Handles nns for junctions */
/**
* This function is used when implementing a naming system that
* supports junctions. For example, when the a_bind_nns(name, newobj)
* method is invoked, that means the caller is attempting to bind the
* object 'newobj' to the nns of 'name'. For context that supports
* junctions, 'name' names a junction and is pointing to the root
* of another naming system, which in turn might have an nns.
* This means that a_bind_nns() should first resolve 'name' and attempt to
* continue the operation in the context named by 'name'. (i.e. bind
* to the nns of the context named by 'name').
* If name is already empty, then throw NameNotFoundException because
* this context by default does not have any nns.
*/
protected void a_processJunction_nns(String name, Continuation cont)
throws NamingException {
if (name.equals("")) {
NameNotFoundException e = new NameNotFoundException();
cont.setErrorNNS(this, name);
throw cont.fillInException(e);
}
try {
// lookup name to continue operation in nns
Object target = a_lookup(name, cont);
if (cont.isContinue())
cont.appendRemainingComponent(""); // add nns back
else {
cont.setContinueNNS(target, name, this);
}
} catch (NamingException e) {
e.appendRemainingComponent(""); // add nns back
throw e;
}
}
/**
* This function is used when implementing a naming system that
* supports junctions. For example, when the a_list_nns(newobj)
* method is invoked, that means the caller is attempting to list the
* the nns context of of this context. For a context that supports
* junctions, it by default does not have any nns. Consequently,
* a NameNotFoundException is thrown.
*/
protected void a_processJunction_nns(Continuation cont) throws NamingException {
// Construct a new Reference that contains this context.
RefAddr addr = new RefAddr("nns") {
public Object getContent() {
return AtomicContext.this;
}
private static final long serialVersionUID = 3449785852664978312L;
};
Reference ref = new Reference("java.lang.Object", addr);
// Set continuation leave it to PartialCompositeContext.getPCContext()
// to throw the exception.
// Do not use setContinueNNS() because we've are
// setting relativeResolvedName to "/".
cont.setContinue(ref, _NNS_NAME, this);
}
/* *********** core resolution routines ******************* */
/** Resolve to context named by 'name'.
* Returns true if at named context (i.e. 'name' is empty name).
* Returns false otherwise, and sets Continuation on parts of 'name'
* not yet resolved.
*/
protected boolean resolve_to_context(Name name, Continuation cont)
throws NamingException {
String target = name.toString();
StringHeadTail ht = c_parseComponent(target, cont);
String tail = ht.getTail();
String head = ht.getHead();
if (debug > 0)
System.out.println("RESOLVE TO CONTEXT(" + target + ") = {" +
head + ", " + tail + "}");
if (head == null) {
// something is wrong; no name at all
InvalidNameException e = new InvalidNameException();
throw cont.fillInException(e);
}
if (!isEmpty(head)) {
// if there is head is a non-empty name
// this means more resolution to be done
try {
Object headCtx = a_lookup(head, cont);
// System.out.println("answer " + headCtx);
if (headCtx != null)
cont.setContinue(headCtx, head, this, (tail == null ? "" : tail));
else if (cont.isContinue())
cont.appendRemainingComponent(tail);
} catch (NamingException e) {
e.appendRemainingComponent(tail);
throw e;
}
} else {
cont.setSuccess(); // clear
return true;
}
return false;
}
/**
* Resolves to penultimate context named by 'name'.
* Returns true if penultimate context has been reached (i.e. name
* only has one atomic component left).
* Returns false otherwise, and sets Continuation to parts of name
* not yet resolved.
*/
protected boolean resolve_to_penultimate_context(Name name, Continuation cont)
throws NamingException {
String target = name.toString();
if (debug > 0)
System.out.println("RESOLVE TO PENULTIMATE" + target);
StringHeadTail ht = c_parseComponent(target, cont);
String tail = ht.getTail();
String head = ht.getHead();
if (head == null) {
// something is wrong; no name at all
InvalidNameException e = new InvalidNameException();
throw cont.fillInException(e);
}
if (!isEmpty(tail)) {
// more components; hence not at penultimate context yet
try {
Object headCtx = a_lookup(head, cont);
if (headCtx != null)
cont.setContinue(headCtx, head, this, tail);
else if (cont.isContinue())
cont.appendRemainingComponent(tail);
} catch (NamingException e) {
e.appendRemainingComponent(tail);
throw e;
}
} else {
// already at penultimate context
cont.setSuccess(); // clear
return true;
}
return false;
}
/**
* This function is similar to resolve_to_penultimate_context()
* except it should only be called by the nns() functions.
* This function fixes any exception or continuations so that
* it will have the proper nns name.
*/
protected boolean resolve_to_penultimate_context_nns(Name name,
Continuation cont)
throws NamingException {
try {
if (debug > 0)
System.out.println("RESOLVE TO PENULTIMATE NNS" + name.toString());
boolean answer = resolve_to_penultimate_context(name, cont);
// resolve_to_penultimate_context() only calls a_lookup().
// Any continuation it sets is lacking the nns, so
// we need to add it back
if (cont.isContinue())
cont.appendRemainingComponent("");
return answer;
} catch (NamingException e) {
// resolve_to_penultimate_context() only calls a_lookup().
// Any exceptions it throws is lacking the nns, so
// we need to add it back.
e.appendRemainingComponent("");
throw e;
}
}
/**
* Resolves to nns associated with 'name' and set Continuation
* to the result.
*/
protected void resolve_to_nns_and_continue(Name name, Continuation cont)
throws NamingException {
if (debug > 0)
System.out.println("RESOLVE TO NNS AND CONTINUE" + name.toString());
if (resolve_to_penultimate_context_nns(name, cont)) {
Object nns = a_lookup_nns(name.toString(), cont);
if (nns != null)
cont.setContinue(nns, name, this);
}
}
}