| /* |
| * 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); |
| } |
| } |
| } |