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