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 
ComponentContext()46     protected ComponentContext() {
47         _contextType = _COMPONENT;
48     }
49 
50 // ------ Abstract methods whose implementation are provided by subclass
51 
52     /* Equivalent methods in Context interface */
c_lookup(Name name, Continuation cont)53     protected abstract Object c_lookup(Name name, Continuation cont)
54         throws NamingException;
c_lookupLink(Name name, Continuation cont)55     protected abstract Object c_lookupLink(Name name, Continuation cont)
56         throws NamingException;
57 
c_list(Name name, Continuation cont)58     protected abstract NamingEnumeration<NameClassPair> c_list(Name name,
59         Continuation cont) throws NamingException;
c_listBindings(Name name, Continuation cont)60     protected abstract NamingEnumeration<Binding> c_listBindings(Name name,
61         Continuation cont) throws NamingException;
c_bind(Name name, Object obj, Continuation cont)62     protected abstract void c_bind(Name name, Object obj, Continuation cont)
63         throws NamingException;
c_rebind(Name name, Object obj, Continuation cont)64     protected abstract void c_rebind(Name name, Object obj, Continuation cont)
65         throws NamingException;
c_unbind(Name name, Continuation cont)66     protected abstract void c_unbind(Name name, Continuation cont)
67         throws NamingException;
c_destroySubcontext(Name name, Continuation cont)68     protected abstract void c_destroySubcontext(Name name, Continuation cont)
69         throws NamingException;
c_createSubcontext(Name name, Continuation cont)70     protected abstract Context c_createSubcontext(Name name,
71         Continuation cont) throws NamingException;
c_rename(Name oldname, Name newname, Continuation cont)72     protected abstract void c_rename(Name oldname, Name newname,
73         Continuation cont) throws NamingException;
c_getNameParser(Name name, Continuation cont)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       */
p_parseComponent(Name name, Continuation cont)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       * equilvalent 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       */
c_resolveIntermediate_nns(Name name, Continuation cont)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 
c_lookup_nns(Name name, Continuation cont)226     protected Object c_lookup_nns(Name name, Continuation cont)
227         throws NamingException {
228             c_processJunction_nns(name, cont);
229             return null;
230         }
231 
c_lookupLink_nns(Name name, Continuation cont)232     protected Object c_lookupLink_nns(Name name, Continuation cont)
233         throws NamingException {
234             c_processJunction_nns(name, cont);
235             return null;
236         }
237 
c_list_nns(Name name, Continuation cont)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 
c_listBindings_nns(Name name, Continuation cont)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 
c_bind_nns(Name name, Object obj, Continuation cont)250     protected void c_bind_nns(Name name, Object obj, Continuation cont)
251         throws NamingException {
252             c_processJunction_nns(name, cont);
253         }
254 
c_rebind_nns(Name name, Object obj, Continuation cont)255     protected void c_rebind_nns(Name name, Object obj, Continuation cont)
256         throws NamingException {
257             c_processJunction_nns(name, cont);
258         }
259 
c_unbind_nns(Name name, Continuation cont)260     protected void c_unbind_nns(Name name, Continuation cont)
261         throws NamingException {
262             c_processJunction_nns(name, cont);
263         }
264 
c_createSubcontext_nns(Name name, Continuation cont)265     protected Context c_createSubcontext_nns(Name name,
266         Continuation cont) throws NamingException {
267             c_processJunction_nns(name, cont);
268             return null;
269         }
270 
c_destroySubcontext_nns(Name name, Continuation cont)271     protected void c_destroySubcontext_nns(Name name, Continuation cont)
272         throws NamingException {
273             c_processJunction_nns(name, cont);
274         }
275 
276 
c_rename_nns(Name oldname, Name newname, Continuation cont)277     protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
278         throws NamingException {
279             c_processJunction_nns(oldname, cont);
280         }
281 
c_getNameParser_nns(Name name, Continuation cont)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      */
c_processJunction_nns(Name name, Continuation cont)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 
p_resolveIntermediate(Name name, Continuation cont)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).
checkAndAdjustRemainingName(Name rname)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
isAllEmpty(Name n)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 
p_resolveToClass(Name name, Class<?> contextType, Continuation cont)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 
p_lookup(Name name, Continuation cont)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 
p_list(Name name, Continuation cont)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 
p_listBindings(Name name, Continuation cont)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 
p_bind(Name name, Object obj, Continuation cont)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 
p_rebind(Name name, Object obj, Continuation cont)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 
p_unbind(Name name, Continuation cont)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 
p_destroySubcontext(Name name, Continuation cont)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 
p_createSubcontext(Name name, Continuation cont)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 
p_rename(Name oldName, Name newName, Continuation cont)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 
p_getNameParser(Name name, Continuation cont)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 
p_lookupLink(Name name, Continuation cont)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  */
806