807 lines · 28.4 KB · Java
RawDownload
/* * Copyright (c) 1999, 2004, 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 java.util.Hashtable; import javax.naming.*;import javax.naming.spi.ResolveResult; /**  * Provides implementation of p_* operations using  * c_* operations provided by subclasses.  *  * Clients: deal only with names for its own naming service.  Must  * provide implementations for c_* methods, and for p_parseComponent()  * and the c_*_nns methods if the defaults are not appropriate.  *  * @author Rosanna Lee  * @author Scott Seligman  */ public abstract class ComponentContext extends PartialCompositeContext {    private static int debug = 0;     protected ComponentContext() {        _contextType = _COMPONENT;    } // ------ Abstract methods whose implementation are provided by subclass     /* Equivalent methods in Context interface */    protected abstract Object c_lookup(Name name, Continuation cont)        throws NamingException;    protected abstract Object c_lookupLink(Name name, Continuation cont)        throws NamingException;     protected abstract NamingEnumeration c_list(Name name,        Continuation cont) throws NamingException;    protected abstract NamingEnumeration c_listBindings(Name name,        Continuation cont) throws NamingException;    protected abstract void c_bind(Name name, Object obj, Continuation cont)        throws NamingException;    protected abstract void c_rebind(Name name, Object obj, Continuation cont)        throws NamingException;    protected abstract void c_unbind(Name name, Continuation cont)        throws NamingException;    protected abstract void c_destroySubcontext(Name name, Continuation cont)        throws NamingException;    protected abstract Context c_createSubcontext(Name name,        Continuation cont) throws NamingException;    protected abstract void c_rename(Name oldname, Name newname,        Continuation cont) throws NamingException;    protected abstract NameParser c_getNameParser(Name name, Continuation cont)        throws NamingException; // ------ Methods that may need to be overridden by subclass     /* Parsing method */    /**      * Determines which of the first components of 'name' belong      * to this naming system.      * If no components belong to this naming system, return      * the empty name (new CompositeName()) as the head,      * and the entire name as the tail.      *      * The default implementation supports strong separation.      * If the name is empty or if the first component is empty,      * head is the empty name and tail is the entire name.      * (This means that this context does not have any name to work with).      * Otherwise, it returns the first component as head, and the rest of      * the components as tail.      *      * Subclass should override this method according its own policies.      *      * For example, a weakly separated system with dynamic boundary      * determination would simply return as head 'name'.      * A weakly separated with static boundary      * determination would select the components in the front of 'name'      * that conform to some syntax rules.  (e.g. in X.500 syntax, perhaps      * select front components that have a equal sign).      * If none conforms, return an empty name.      */    protected HeadTail p_parseComponent(Name name, Continuation cont)        throws NamingException {        int separator;        // if no name to parse, or if we're already at boundary        if (name.isEmpty() ||  name.get(0).equals("")) {            separator = 0;        } else {            separator = 1;        }        Name head, tail;         if (name instanceof CompositeName) {            head = name.getPrefix(separator);            tail = name.getSuffix(separator);        } else {            // treat like compound name            head = new CompositeName().add(name.toString());            tail = null;        }         if (debug > 2) {            System.err.println("ORIG: " + name);            System.err.println("PREFIX: " + name);            System.err.println("SUFFIX: " + null);        }        return new HeadTail(head, tail);    }      /* 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 only junctions, this would be      * equilvalent to      *         c_lookup(name, cont);      * because for junctions, an intermediate slash simply signifies      * a syntactic separator.      *      * For a system that supports only implicit nns, this would be      * equivalent to      *         c_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 c_processJunction_nns()).      * Contexts that implement implicit nns directly should provide an      * appropriate override.      *      * A junction, by definition, is a binding of a name in one      * namespace to an object in another.  The default implementation      * of this method detects the crossover into another namespace      * using the following heuristic:  there is a junction when "name"      * resolves to a context that is not an instance of      * this.getClass().  Contexts supporting junctions for which this      * heuristic is inappropriate should override this method.      */    protected Object c_resolveIntermediate_nns(Name name, Continuation cont)        throws NamingException {            try {                final Object obj = c_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 =                            -8831204798861786362L;                    };                    Reference ref = new Reference("java.lang.Object", addr);                     // Resolved name has trailing slash to indicate nns                    CompositeName resName = (CompositeName)name.clone();                    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 {                    // Consume "/" and continue                    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 Context 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 c_*_nns methods.    //    // For naming systems that do not support implicit nns, the    // default implementations here throw an exception.  See    // c_processJunction_nns() for details.     protected Object c_lookup_nns(Name name, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);            return null;        }     protected Object c_lookupLink_nns(Name name, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);            return null;        }     protected NamingEnumeration c_list_nns(Name name,        Continuation cont) throws NamingException {            c_processJunction_nns(name, cont);            return null;        }     protected NamingEnumeration c_listBindings_nns(Name name,        Continuation cont) throws NamingException {            c_processJunction_nns(name, cont);            return null;        }     protected void c_bind_nns(Name name, Object obj, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);        }     protected void c_rebind_nns(Name name, Object obj, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);        }     protected void c_unbind_nns(Name name, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);        }     protected Context c_createSubcontext_nns(Name name,        Continuation cont) throws NamingException {            c_processJunction_nns(name, cont);            return null;        }     protected void c_destroySubcontext_nns(Name name, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);        }      protected void c_rename_nns(Name oldname, Name newname, Continuation cont)        throws NamingException {            c_processJunction_nns(oldname, cont);        }     protected NameParser c_getNameParser_nns(Name name, Continuation cont)        throws NamingException {            c_processJunction_nns(name, cont);            return null;        } // ------ internal method used by ComponentContext     /**     * Locates the nns using the default policy.  This policy fully     * handles junctions, but otherwise throws an exception when an     * attempt is made to resolve an implicit nns.     *     * The default policy is as follows:  If there is a junction in     * the namespace, then resolve to the junction and continue the     * operation there (thus deferring to that context to find its own     * nns).  Otherwise, resolve as far as possible and then throw     * CannotProceedException with the resolved object being a reference:     * the address type is "nns", and the address contents is this     * context.     *     * For example, when c_bind_nns(name, obj, ...) is invoked, the     * caller is attempting to bind the object "obj" to the nns of     * "name".  If "name" is a junction, it names an object in another     * naming system that (presumably) has an nns.  c_bind_nns() will     * first resolve "name" to a context and then attempt to continue     * the bind operation there, (thus binding to the nns of the     * context named by "name").  If "name" is empty then throw an     * exception, since this context does not by default support an     * implicit nns.     *     * To implement a context that does support an implicit nns, it is     * necessary to override this default policy.  This is done by     * overriding the c_*_nns() methods (which each call this method     * by default).     */    protected void c_processJunction_nns(Name name, Continuation cont)            throws NamingException    {        if (name.isEmpty()) {            // Construct a new Reference that contains this context.            RefAddr addr = new RefAddr("nns") {                public Object getContent() {                    return ComponentContext.this;                }                private static final long serialVersionUID =                    -1389472957988053402L;            };            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);            return;        }         try {            // lookup name to continue operation in nns            Object target = c_lookup(name, cont);            if (cont.isContinue())                cont.appendRemainingComponent("");            else {                cont.setContinueNNS(target, name, this);            }        } catch (NamingException e) {            e.appendRemainingComponent(""); // add nns back            throw e;        }    }     protected static final byte USE_CONTINUATION = 1;    protected static final byte TERMINAL_COMPONENT = 2;    protected static final byte TERMINAL_NNS_COMPONENT = 3;     /**      * Determine whether 'name' is a terminal component in      * this naming system.      * If so, return status indicating so, so that caller      * can perform context operation on this name.      *      * If not, then the first component(s) of 'name' names      * an intermediate context.  In that case, resolve these components      * and set Continuation to be the object named.      *      * see test cases at bottom of file.      */     protected HeadTail p_resolveIntermediate(Name name, Continuation cont)        throws NamingException {        int ret = USE_CONTINUATION;        cont.setSuccess();      // initialize        HeadTail p = p_parseComponent(name, cont);        Name tail = p.getTail();        Name head = p.getHead();         if (tail == null || tail.isEmpty()) {//System.out.println("terminal : " + head);            ret = TERMINAL_COMPONENT;        } else if (!tail.get(0).equals("")) {            // tail does not begin with "/"/*            if (head.isEmpty()) {                // Context could not find name that it can use                // illegal syntax error or name not found//System.out.println("nnf exception : " + head);                NamingException e = new NameNotFoundException();                cont.setError(this, name);                throw cont.fillInException(e);            } else  {*/                // head is being used as intermediate context,                // resolve head and set Continuation with tail                try {                    Object obj = c_resolveIntermediate_nns(head, cont);//System.out.println("resInter : " + head + "=" + obj);                    if (obj != null)                        cont.setContinue(obj, head, this, tail);                    else if (cont.isContinue()) {                        checkAndAdjustRemainingName(cont.getRemainingName());                        cont.appendRemainingName(tail);                    }                } catch (NamingException e) {                    checkAndAdjustRemainingName(e.getRemainingName());                    e.appendRemainingName(tail);                    throw e;                }/*            }*/        } else {            // tail begins with "/"            if (tail.size() == 1) {                ret = TERMINAL_NNS_COMPONENT;//System.out.println("terminal_nns : " + head);            } else if (head.isEmpty() || isAllEmpty(tail)) {                // resolve nns of head and continue with tail.getSuffix(1)                Name newTail = tail.getSuffix(1);                try {                    Object obj = c_lookup_nns(head, cont);//System.out.println("lookup_nns : " + head + "=" + obj);                    if (obj != null)                        cont.setContinue(obj, head, this, newTail);                    else if (cont.isContinue()) {                        cont.appendRemainingName(newTail);//                      Name rname = cont.getRemainingName();//System.out.println("cont.rname" + rname);                    }                } catch (NamingException e) {                    e.appendRemainingName(newTail);                    throw e;                }            } else {                // head is being used as intermediate context                // resolve and set continuation to tail                try {                    Object obj = c_resolveIntermediate_nns(head, cont);//System.out.println("resInter2 : " + head + "=" + obj);                    if (obj != null)                        cont.setContinue(obj, head, this, tail);                    else if (cont.isContinue()) {                        checkAndAdjustRemainingName(cont.getRemainingName());                        cont.appendRemainingName(tail);                    }                } catch (NamingException e) {                    checkAndAdjustRemainingName(e.getRemainingName());                    e.appendRemainingName(tail);                    throw e;                }            }        }         p.setStatus(ret);        return p;    }     // When c_resolveIntermediate_nns() or c_lookup_nns() sets up    // its continuation, to indicate "nns", it appends an empty    // component to the remaining name (e.g. "eng/"). If last    // component of remaining name is empty; delete empty component    // before appending tail so that composition of the names work    // correctly. For example, when merging "eng/" and "c.b.a", we want    // the result to be "eng/c.b.a" because the trailing slash in eng    // is extraneous.  When merging "" and "c.b.a", we want the result    // to be "/c.b.a" and so must keep the trailing slash (empty name).    void checkAndAdjustRemainingName(Name rname) throws InvalidNameException {        int count;        if (rname != null && (count=rname.size()) > 1 &&            rname.get(count-1).equals("")) {            rname.remove(count-1);        }    }     // Returns true if n contains only empty components    protected boolean isAllEmpty(Name n) {        int count = n.size();        for (int i =0; i < count; i++ ) {            if (!n.get(i).equals("")) {                return false;            }        }        return true;    }   // ------ implementations of p_ Resolver and Context methods using// ------ corresponding c_ and c_*_nns methods      /* implementation for Resolver method */     protected ResolveResult p_resolveToClass(Name name,                                             Class contextType,                                             Continuation cont)            throws NamingException {

Lines 1–500 of 807.