1 /*
   2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.toolkit.ctx;
  27 
  28 import javax.naming.*;
  29 import javax.naming.spi.ResolveResult;
  30 
  31 /**
  32   * Provides implementation of p_* operations using
  33   * c_* operations provided by subclasses.
  34   *
  35   * Clients: deal only with names for its own naming service.  Must
  36   * provide implementations for c_* methods, and for p_parseComponent()
  37   * and the c_*_nns methods if the defaults are not appropriate.
  38   *
  39   * @author Rosanna Lee
  40   * @author Scott Seligman
  41   */
  42 
  43 public abstract class ComponentContext extends PartialCompositeContext {
  44     private static int debug = 0;
  45 
  46     protected ComponentContext() {
  47         _contextType = _COMPONENT;
  48     }
  49 
  50 // ------ Abstract methods whose implementation are provided by subclass
  51 
  52     /* Equivalent methods in Context interface */
  53     protected abstract Object c_lookup(Name name, Continuation cont)
  54         throws NamingException;
  55     protected abstract Object c_lookupLink(Name name, Continuation cont)
  56         throws NamingException;
  57 
  58     protected abstract NamingEnumeration<NameClassPair> c_list(Name name,
  59         Continuation cont) throws NamingException;
  60     protected abstract NamingEnumeration<Binding> c_listBindings(Name name,
  61         Continuation cont) throws NamingException;
  62     protected abstract void c_bind(Name name, Object obj, Continuation cont)
  63         throws NamingException;
  64     protected abstract void c_rebind(Name name, Object obj, Continuation cont)
  65         throws NamingException;
  66     protected abstract void c_unbind(Name name, Continuation cont)
  67         throws NamingException;
  68     protected abstract void c_destroySubcontext(Name name, Continuation cont)
  69         throws NamingException;
  70     protected abstract Context c_createSubcontext(Name name,
  71         Continuation cont) throws NamingException;
  72     protected abstract void c_rename(Name oldname, Name newname,
  73         Continuation cont) throws NamingException;
  74     protected abstract NameParser c_getNameParser(Name name, Continuation cont)
  75         throws NamingException;
  76 
  77 // ------ Methods that may need to be overridden by subclass
  78 
  79     /* Parsing method */
  80     /**
  81       * Determines which of the first components of 'name' belong
  82       * to this naming system.
  83       * If no components belong to this naming system, return
  84       * the empty name (new CompositeName()) as the head,
  85       * and the entire name as the tail.
  86       *
  87       * The default implementation supports strong separation.
  88       * If the name is empty or if the first component is empty,
  89       * head is the empty name and tail is the entire name.
  90       * (This means that this context does not have any name to work with).
  91       * Otherwise, it returns the first component as head, and the rest of
  92       * the components as tail.
  93       *
  94       * Subclass should override this method according its own policies.
  95       *
  96       * For example, a weakly separated system with dynamic boundary
  97       * determination would simply return as head 'name'.
  98       * A weakly separated with static boundary
  99       * determination would select the components in the front of 'name'
 100       * that conform to some syntax rules.  (e.g. in X.500 syntax, perhaps
 101       * select front components that have a equal sign).
 102       * If none conforms, return an empty name.
 103       */
 104     protected HeadTail p_parseComponent(Name name, Continuation cont)
 105         throws NamingException {
 106         int separator;
 107         // if no name to parse, or if we're already at boundary
 108         if (name.isEmpty() ||  name.get(0).equals("")) {
 109             separator = 0;
 110         } else {
 111             separator = 1;
 112         }
 113         Name head, tail;
 114 
 115         if (name instanceof CompositeName) {
 116             head = name.getPrefix(separator);
 117             tail = name.getSuffix(separator);
 118         } else {
 119             // treat like compound name
 120             head = new CompositeName().add(name.toString());
 121             tail = null;
 122         }
 123 
 124         if (debug > 2) {
 125             System.err.println("ORIG: " + name);
 126             System.err.println("PREFIX: " + name);
 127             System.err.println("SUFFIX: " + null);
 128         }
 129         return new HeadTail(head, tail);
 130     }
 131 
 132 
 133     /* Resolution method for supporting federation */
 134 
 135     /**
 136       * Resolves the nns for 'name' when the named context is acting
 137       * as an intermediate context.
 138       *
 139       * For a system that supports only junctions, this would be
 140       * equivalent to
 141       *         c_lookup(name, cont);
 142       * because for junctions, an intermediate slash simply signifies
 143       * a syntactic separator.
 144       *
 145       * For a system that supports only implicit nns, this would be
 146       * equivalent to
 147       *         c_lookup_nns(name, cont);
 148       * because for implicit nns, a slash always signifies the implicit nns,
 149       * regardless of whether it is intermediate or trailing.
 150       *
 151       * By default this method supports junctions, and also allows for an
 152       * implicit nns to be dynamically determined through the use of the
 153       * "nns" reference (see c_processJunction_nns()).
 154       * Contexts that implement implicit nns directly should provide an
 155       * appropriate override.
 156       *
 157       * A junction, by definition, is a binding of a name in one
 158       * namespace to an object in another.  The default implementation
 159       * of this method detects the crossover into another namespace
 160       * using the following heuristic:  there is a junction when "name"
 161       * resolves to a context that is not an instance of
 162       * this.getClass().  Contexts supporting junctions for which this
 163       * heuristic is inappropriate should override this method.
 164       */
 165     protected Object c_resolveIntermediate_nns(Name name, Continuation cont)
 166         throws NamingException {
 167             try {
 168                 final Object obj = c_lookup(name, cont);
 169 
 170                 // Do not append "" to Continuation 'cont' even if set
 171                 // because the intention is to ignore the nns
 172 
 173                 if (obj != null && getClass().isInstance(obj)) {
 174                     // If "obj" is in the same type as this object, it must
 175                     // not be a junction. Continue the lookup with "/".
 176 
 177                     cont.setContinueNNS(obj, name, this);
 178                     return null;
 179 
 180                 } else if (obj != null && !(obj instanceof Context)) {
 181                     // obj is not even a context, so try to find its nns
 182                     // dynamically by constructing a Reference containing obj.
 183                     RefAddr addr = new RefAddr("nns") {
 184                         public Object getContent() {
 185                             return obj;
 186                         }
 187                         private static final long serialVersionUID =
 188                             -8831204798861786362L;
 189                     };
 190                     Reference ref = new Reference("java.lang.Object", addr);
 191 
 192                     // Resolved name has trailing slash to indicate nns
 193                     CompositeName resName = (CompositeName)name.clone();
 194                     resName.add(""); // add trailing slash
 195 
 196                     // Set continuation leave it to
 197                     // PartialCompositeContext.getPCContext() to throw CPE.
 198                     // Do not use setContinueNNS() because we've already
 199                     // consumed "/" (i.e., moved it to resName).
 200 
 201                     cont.setContinue(ref, resName, this);
 202                     return null;
 203                 } else {
 204                     // Consume "/" and continue
 205                     return obj;
 206                 }
 207 
 208             } catch (NamingException e) {
 209                 e.appendRemainingComponent(""); // add nns back
 210                 throw e;
 211             }
 212         }
 213 
 214     /* Equivalent of Context Methods for supporting nns */
 215 
 216     // The following methods are called when the Context methods
 217     // are invoked with a name that has a trailing slash.
 218     // For naming systems that support implicit nns,
 219     // the trailing slash signifies the implicit nns.
 220     // For such naming systems, override these c_*_nns methods.
 221     //
 222     // For naming systems that do not support implicit nns, the
 223     // default implementations here throw an exception.  See
 224     // c_processJunction_nns() for details.
 225 
 226     protected Object c_lookup_nns(Name name, Continuation cont)
 227         throws NamingException {
 228             c_processJunction_nns(name, cont);
 229             return null;
 230         }
 231 
 232     protected Object c_lookupLink_nns(Name name, Continuation cont)
 233         throws NamingException {
 234             c_processJunction_nns(name, cont);
 235             return null;
 236         }
 237 
 238     protected NamingEnumeration<NameClassPair> c_list_nns(Name name,
 239         Continuation cont) throws NamingException {
 240             c_processJunction_nns(name, cont);
 241             return null;
 242         }
 243 
 244     protected NamingEnumeration<Binding> c_listBindings_nns(Name name,
 245         Continuation cont) throws NamingException {
 246             c_processJunction_nns(name, cont);
 247             return null;
 248         }
 249 
 250     protected void c_bind_nns(Name name, Object obj, Continuation cont)
 251         throws NamingException {
 252             c_processJunction_nns(name, cont);
 253         }
 254 
 255     protected void c_rebind_nns(Name name, Object obj, Continuation cont)
 256         throws NamingException {
 257             c_processJunction_nns(name, cont);
 258         }
 259 
 260     protected void c_unbind_nns(Name name, Continuation cont)
 261         throws NamingException {
 262             c_processJunction_nns(name, cont);
 263         }
 264 
 265     protected Context c_createSubcontext_nns(Name name,
 266         Continuation cont) throws NamingException {
 267             c_processJunction_nns(name, cont);
 268             return null;
 269         }
 270 
 271     protected void c_destroySubcontext_nns(Name name, Continuation cont)
 272         throws NamingException {
 273             c_processJunction_nns(name, cont);
 274         }
 275 
 276 
 277     protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
 278         throws NamingException {
 279             c_processJunction_nns(oldname, cont);
 280         }
 281 
 282     protected NameParser c_getNameParser_nns(Name name, Continuation cont)
 283         throws NamingException {
 284             c_processJunction_nns(name, cont);
 285             return null;
 286         }
 287 
 288 // ------ internal method used by ComponentContext
 289 
 290     /**
 291      * Locates the nns using the default policy.  This policy fully
 292      * handles junctions, but otherwise throws an exception when an
 293      * attempt is made to resolve an implicit nns.
 294      *
 295      * The default policy is as follows:  If there is a junction in
 296      * the namespace, then resolve to the junction and continue the
 297      * operation there (thus deferring to that context to find its own
 298      * nns).  Otherwise, resolve as far as possible and then throw
 299      * CannotProceedException with the resolved object being a reference:
 300      * the address type is "nns", and the address contents is this
 301      * context.
 302      *
 303      * For example, when c_bind_nns(name, obj, ...) is invoked, the
 304      * caller is attempting to bind the object "obj" to the nns of
 305      * "name".  If "name" is a junction, it names an object in another
 306      * naming system that (presumably) has an nns.  c_bind_nns() will
 307      * first resolve "name" to a context and then attempt to continue
 308      * the bind operation there, (thus binding to the nns of the
 309      * context named by "name").  If "name" is empty then throw an
 310      * exception, since this context does not by default support an
 311      * implicit nns.
 312      *
 313      * To implement a context that does support an implicit nns, it is
 314      * necessary to override this default policy.  This is done by
 315      * overriding the c_*_nns() methods (which each call this method
 316      * by default).
 317      */
 318     protected void c_processJunction_nns(Name name, Continuation cont)
 319             throws NamingException
 320     {
 321         if (name.isEmpty()) {
 322             // Construct a new Reference that contains this context.
 323             RefAddr addr = new RefAddr("nns") {
 324                 public Object getContent() {
 325                     return ComponentContext.this;
 326                 }
 327                 private static final long serialVersionUID =
 328                     -1389472957988053402L;
 329             };
 330             Reference ref = new Reference("java.lang.Object", addr);
 331 
 332             // Set continuation leave it to PartialCompositeContext.getPCContext()
 333             // to throw the exception.
 334             // Do not use setContinueNNS() because we've are
 335             // setting relativeResolvedName to "/".
 336             cont.setContinue(ref, _NNS_NAME, this);
 337             return;
 338         }
 339 
 340         try {
 341             // lookup name to continue operation in nns
 342             Object target = c_lookup(name, cont);
 343             if (cont.isContinue())
 344                 cont.appendRemainingComponent("");
 345             else {
 346                 cont.setContinueNNS(target, name, this);
 347             }
 348         } catch (NamingException e) {
 349             e.appendRemainingComponent(""); // add nns back
 350             throw e;
 351         }
 352     }
 353 
 354     protected static final byte USE_CONTINUATION = 1;
 355     protected static final byte TERMINAL_COMPONENT = 2;
 356     protected static final byte TERMINAL_NNS_COMPONENT = 3;
 357 
 358     /**
 359       * Determine whether 'name' is a terminal component in
 360       * this naming system.
 361       * If so, return status indicating so, so that caller
 362       * can perform context operation on this name.
 363       *
 364       * If not, then the first component(s) of 'name' names
 365       * an intermediate context.  In that case, resolve these components
 366       * and set Continuation to be the object named.
 367       *
 368       * see test cases at bottom of file.
 369       */
 370 
 371     protected HeadTail p_resolveIntermediate(Name name, Continuation cont)
 372         throws NamingException {
 373         int ret = USE_CONTINUATION;
 374         cont.setSuccess();      // initialize
 375         HeadTail p = p_parseComponent(name, cont);
 376         Name tail = p.getTail();
 377         Name head = p.getHead();
 378 
 379         if (tail == null || tail.isEmpty()) {
 380 //System.out.println("terminal : " + head);
 381             ret = TERMINAL_COMPONENT;
 382         } else if (!tail.get(0).equals("")) {
 383             // tail does not begin with "/"
 384 /*
 385             if (head.isEmpty()) {
 386                 // Context could not find name that it can use
 387                 // illegal syntax error or name not found
 388 //System.out.println("nnf exception : " + head);
 389                 NamingException e = new NameNotFoundException();
 390                 cont.setError(this, name);
 391                 throw cont.fillInException(e);
 392             } else  {
 393 */
 394                 // head is being used as intermediate context,
 395                 // resolve head and set Continuation with tail
 396                 try {
 397                     Object obj = c_resolveIntermediate_nns(head, cont);
 398 //System.out.println("resInter : " + head + "=" + obj);
 399                     if (obj != null)
 400                         cont.setContinue(obj, head, this, tail);
 401                     else if (cont.isContinue()) {
 402                         checkAndAdjustRemainingName(cont.getRemainingName());
 403                         cont.appendRemainingName(tail);
 404                     }
 405                 } catch (NamingException e) {
 406                     checkAndAdjustRemainingName(e.getRemainingName());
 407                     e.appendRemainingName(tail);
 408                     throw e;
 409                 }
 410 /*
 411             }
 412 */
 413         } else {
 414             // tail begins with "/"
 415             if (tail.size() == 1) {
 416                 ret = TERMINAL_NNS_COMPONENT;
 417 //System.out.println("terminal_nns : " + head);
 418             } else if (head.isEmpty() || isAllEmpty(tail)) {
 419                 // resolve nns of head and continue with tail.getSuffix(1)
 420                 Name newTail = tail.getSuffix(1);
 421                 try {
 422                     Object obj = c_lookup_nns(head, cont);
 423 //System.out.println("lookup_nns : " + head + "=" + obj);
 424                     if (obj != null)
 425                         cont.setContinue(obj, head, this, newTail);
 426                     else if (cont.isContinue()) {
 427                         cont.appendRemainingName(newTail);
 428 //                      Name rname = cont.getRemainingName();
 429 //System.out.println("cont.rname" + rname);
 430                     }
 431                 } catch (NamingException e) {
 432                     e.appendRemainingName(newTail);
 433                     throw e;
 434                 }
 435             } else {
 436                 // head is being used as intermediate context
 437                 // resolve and set continuation to tail
 438                 try {
 439                     Object obj = c_resolveIntermediate_nns(head, cont);
 440 //System.out.println("resInter2 : " + head + "=" + obj);
 441                     if (obj != null)
 442                         cont.setContinue(obj, head, this, tail);
 443                     else if (cont.isContinue()) {
 444                         checkAndAdjustRemainingName(cont.getRemainingName());
 445                         cont.appendRemainingName(tail);
 446                     }
 447                 } catch (NamingException e) {
 448                     checkAndAdjustRemainingName(e.getRemainingName());
 449                     e.appendRemainingName(tail);
 450                     throw e;
 451                 }
 452             }
 453         }
 454 
 455         p.setStatus(ret);
 456         return p;
 457     }
 458 
 459     // When c_resolveIntermediate_nns() or c_lookup_nns() sets up
 460     // its continuation, to indicate "nns", it appends an empty
 461     // component to the remaining name (e.g. "eng/"). If last
 462     // component of remaining name is empty; delete empty component
 463     // before appending tail so that composition of the names work
 464     // correctly. For example, when merging "eng/" and "c.b.a", we want
 465     // the result to be "eng/c.b.a" because the trailing slash in eng
 466     // is extraneous.  When merging "" and "c.b.a", we want the result
 467     // to be "/c.b.a" and so must keep the trailing slash (empty name).
 468     void checkAndAdjustRemainingName(Name rname) throws InvalidNameException {
 469         int count;
 470         if (rname != null && (count=rname.size()) > 1 &&
 471             rname.get(count-1).equals("")) {
 472             rname.remove(count-1);
 473         }
 474     }
 475 
 476     // Returns true if n contains only empty components
 477     protected boolean isAllEmpty(Name n) {
 478         int count = n.size();
 479         for (int i =0; i < count; i++ ) {
 480             if (!n.get(i).equals("")) {
 481                 return false;
 482             }
 483         }
 484         return true;
 485     }
 486 
 487 
 488 
 489 // ------ implementations of p_ Resolver and Context methods using
 490 // ------ corresponding c_ and c_*_nns methods
 491 
 492 
 493     /* implementation for Resolver method */
 494 
 495     protected ResolveResult p_resolveToClass(Name name,
 496                                              Class<?> contextType,
 497                                              Continuation cont)
 498             throws NamingException {
 499 
 500         if (contextType.isInstance(this)) {
 501             cont.setSuccess();
 502             return (new ResolveResult(this, name));
 503         }
 504 
 505         ResolveResult ret = null;
 506         HeadTail res = p_resolveIntermediate(name, cont);
 507         switch (res.getStatus()) {
 508         case TERMINAL_NNS_COMPONENT:
 509             Object obj = p_lookup(name, cont);
 510             if (!cont.isContinue() && contextType.isInstance(obj)) {
 511                 ret = new ResolveResult(obj, _EMPTY_NAME);
 512             }
 513             break;
 514 
 515         case TERMINAL_COMPONENT:
 516             cont.setSuccess();  // no contextType found; return null
 517             break;
 518 
 519         default:
 520             /* USE_CONTINUATION */
 521             /* pcont already set or exception thrown */
 522             break;
 523         }
 524         return ret;
 525     }
 526 
 527     /* implementations of p_ Context methods */
 528 
 529     protected Object p_lookup(Name name, Continuation cont) throws NamingException {
 530         Object ret = null;
 531         HeadTail res = p_resolveIntermediate(name, cont);
 532         switch (res.getStatus()) {
 533             case TERMINAL_NNS_COMPONENT:
 534                 ret = c_lookup_nns(res.getHead(), cont);
 535                 if (ret instanceof LinkRef) {
 536                     cont.setContinue(ret, res.getHead(), this);
 537                     ret = null;
 538                 }
 539                 break;
 540 
 541             case TERMINAL_COMPONENT:
 542                 ret = c_lookup(res.getHead(), cont);
 543                 if (ret instanceof LinkRef) {
 544                     cont.setContinue(ret, res.getHead(), this);
 545                     ret = null;
 546                 }
 547                 break;
 548 
 549             default:
 550                 /* USE_CONTINUATION */
 551                 /* pcont already set or exception thrown */
 552                 break;
 553         }
 554         return ret;
 555     }
 556 
 557     protected NamingEnumeration<NameClassPair> p_list(Name name, Continuation cont)
 558         throws NamingException {
 559         NamingEnumeration<NameClassPair> ret = null;
 560         HeadTail res = p_resolveIntermediate(name, cont);
 561         switch (res.getStatus()) {
 562             case TERMINAL_NNS_COMPONENT:
 563                 if (debug > 0)
 564                     System.out.println("c_list_nns(" + res.getHead() + ")");
 565                 ret = c_list_nns(res.getHead(), cont);
 566                 break;
 567 
 568             case TERMINAL_COMPONENT:
 569                 if (debug > 0)
 570                     System.out.println("c_list(" + res.getHead() + ")");
 571                 ret = c_list(res.getHead(), cont);
 572                 break;
 573 
 574             default:
 575                 /* USE_CONTINUATION */
 576                 /* cont already set or exception thrown */
 577                 break;
 578         }
 579         return ret;
 580     }
 581 
 582     protected NamingEnumeration<Binding> p_listBindings(Name name, Continuation cont) throws
 583         NamingException {
 584         NamingEnumeration<Binding> ret = null;
 585         HeadTail res = p_resolveIntermediate(name, cont);
 586         switch (res.getStatus()) {
 587             case TERMINAL_NNS_COMPONENT:
 588                 ret = c_listBindings_nns(res.getHead(), cont);
 589                 break;
 590 
 591             case TERMINAL_COMPONENT:
 592                 ret = c_listBindings(res.getHead(), cont);
 593                 break;
 594 
 595             default:
 596                 /* USE_CONTINUATION */
 597                 /* cont already set or exception thrown */
 598                 break;
 599         }
 600         return ret;
 601     }
 602 
 603     protected void p_bind(Name name, Object obj, Continuation cont) throws
 604         NamingException {
 605         HeadTail res = p_resolveIntermediate(name, cont);
 606         switch (res.getStatus()) {
 607             case TERMINAL_NNS_COMPONENT:
 608                 c_bind_nns(res.getHead(), obj, cont);
 609                 break;
 610 
 611             case TERMINAL_COMPONENT:
 612                 c_bind(res.getHead(), obj, cont);
 613                 break;
 614 
 615             default:
 616                 /* USE_CONTINUATION */
 617                 /* cont already set or exception thrown */
 618                 break;
 619         }
 620     }
 621 
 622     protected void p_rebind(Name name, Object obj, Continuation cont) throws
 623         NamingException {
 624         HeadTail res = p_resolveIntermediate(name, cont);
 625         switch (res.getStatus()) {
 626             case TERMINAL_NNS_COMPONENT:
 627                 c_rebind_nns(res.getHead(), obj, cont);
 628                 break;
 629 
 630             case TERMINAL_COMPONENT:
 631                 c_rebind(res.getHead(), obj, cont);
 632                 break;
 633 
 634             default:
 635                 /* USE_CONTINUATION */
 636                 /* cont already set or exception thrown */
 637                 break;
 638         }
 639     }
 640 
 641     protected void p_unbind(Name name, Continuation cont) throws
 642         NamingException {
 643         HeadTail res = p_resolveIntermediate(name, cont);
 644         switch (res.getStatus()) {
 645             case TERMINAL_NNS_COMPONENT:
 646                 c_unbind_nns(res.getHead(), cont);
 647                 break;
 648 
 649             case TERMINAL_COMPONENT:
 650                 c_unbind(res.getHead(), cont);
 651                 break;
 652 
 653             default:
 654                 /* USE_CONTINUATION */
 655                 /* cont already set or exception thrown */
 656                 break;
 657         }
 658     }
 659 
 660     protected void p_destroySubcontext(Name name, Continuation cont) throws
 661         NamingException {
 662         HeadTail res = p_resolveIntermediate(name, cont);
 663         switch (res.getStatus()) {
 664             case TERMINAL_NNS_COMPONENT:
 665                 c_destroySubcontext_nns(res.getHead(), cont);
 666                 break;
 667 
 668             case TERMINAL_COMPONENT:
 669                 c_destroySubcontext(res.getHead(), cont);
 670                 break;
 671 
 672             default:
 673                 /* USE_CONTINUATION */
 674                 /* cont already set or exception thrown */
 675                 break;
 676         }
 677     }
 678 
 679     protected Context p_createSubcontext(Name name, Continuation cont) throws
 680         NamingException {
 681             Context ret = null;
 682         HeadTail res = p_resolveIntermediate(name, cont);
 683         switch (res.getStatus()) {
 684             case TERMINAL_NNS_COMPONENT:
 685                 ret = c_createSubcontext_nns(res.getHead(), cont);
 686                 break;
 687 
 688             case TERMINAL_COMPONENT:
 689                 ret = c_createSubcontext(res.getHead(), cont);
 690                 break;
 691 
 692             default:
 693                 /* USE_CONTINUATION */
 694                 /* cont already set or exception thrown */
 695                 break;
 696         }
 697         return ret;
 698     }
 699 
 700     protected void p_rename(Name oldName, Name newName, Continuation cont) throws
 701         NamingException {
 702         HeadTail res = p_resolveIntermediate(oldName, cont);
 703         switch (res.getStatus()) {
 704             case TERMINAL_NNS_COMPONENT:
 705                 c_rename_nns(res.getHead(), newName, cont);
 706                 break;
 707 
 708             case TERMINAL_COMPONENT:
 709                 c_rename(res.getHead(), newName, cont);
 710                 break;
 711 
 712             default:
 713                 /* USE_CONTINUATION */
 714                 /* cont already set or exception thrown */
 715                 break;
 716         }
 717     }
 718 
 719     protected NameParser p_getNameParser(Name name, Continuation cont) throws
 720         NamingException {
 721         NameParser ret = null;
 722         HeadTail res = p_resolveIntermediate(name, cont);
 723         switch (res.getStatus()) {
 724             case TERMINAL_NNS_COMPONENT:
 725                 ret = c_getNameParser_nns(res.getHead(), cont);
 726                 break;
 727 
 728             case TERMINAL_COMPONENT:
 729                 ret = c_getNameParser(res.getHead(), cont);
 730                 break;
 731 
 732             default:
 733                 /* USE_CONTINUATION */
 734                 /* cont already set or exception thrown */
 735                 break;
 736         }
 737         return ret;
 738     }
 739 
 740     protected Object p_lookupLink(Name name, Continuation cont)
 741         throws NamingException {
 742         Object ret = null;
 743         HeadTail res = p_resolveIntermediate(name, cont);
 744         switch (res.getStatus()) {
 745             case TERMINAL_NNS_COMPONENT:
 746                 ret = c_lookupLink_nns(res.getHead(), cont);
 747                 break;
 748 
 749             case TERMINAL_COMPONENT:
 750                 ret = c_lookupLink(res.getHead(), cont);
 751                 break;
 752 
 753             default:
 754                 /* USE_CONTINUATION */
 755                 /* cont already set or exception thrown */
 756                 break;
 757         }
 758         return ret;
 759     }
 760 }
 761 
 762 /*
 763  *      How p_resolveIntermediate() should behave for various test cases
 764 
 765 a.b/x   {a.b, x}
 766         c_resolveIntermediate_nns(a.b)
 767         continue(x)
 768         {x,}
 769         terminal(x)
 770 
 771 a.b/    {a.b, ""}
 772         terminal_nns(a.b);
 773 
 774 a.b//
 775         {a.b, ("", "")}
 776         c_lookup_nns(a.b)
 777         continue({""})
 778         {,""}
 779         terminal_nns({})
 780 
 781 /x      {{}, {"", x}}
 782         c_lookup_nns({})
 783         continue(x)
 784         {x,}
 785         terminal(x)
 786 
 787 //y     {{}, {"", "", y}}
 788         c_lookup_nns({})
 789         continue({"", y})
 790         {{}, {"", y}}
 791         c_lookup_nns({})
 792         continue(y)
 793         {y,}
 794         terminal(y)
 795 
 796 a.b//y  {a.b, {"", y}}
 797         c_resolveIntermediate_nns(a.b)
 798         continue({"", y})
 799         {{}, {"",y}}
 800         c_lookup_nns({});
 801         continue(y)
 802         {y,}
 803         terminal(y);
 804  *
 805  */