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 
30 /**
31   * Clients: deal only with names for its own naming service
32   * and deals with single contexts that can be built up into
33   * hierarchical naming systems.
34   * Direct subclasses of AtomicContext must provide implementations for
35   * the abstract a_ Context methods, and c_parseComponent().
36   *
37   * If the subclass implements the notion of implicit nns,
38   * it must override the a_*_nns Context methods as well.
39   *
40   * @author Rosanna Lee
41   *
42   */
43 
44 public abstract class AtomicContext extends ComponentContext {
45     private static int debug = 0;
46 
AtomicContext()47     protected AtomicContext () {
48         _contextType = _ATOMIC;
49     }
50 
51 // ------ Abstract methods whose implementation are provided by subclasses
52 
53 
54     /* Equivalent to Context methods */
a_lookup(String name, Continuation cont)55     protected abstract Object a_lookup(String name, Continuation cont)
56         throws NamingException;
a_lookupLink(String name, Continuation cont)57     protected abstract Object a_lookupLink(String name, Continuation cont)
58         throws NamingException;
59 
a_list( Continuation cont)60     protected abstract NamingEnumeration<NameClassPair> a_list(
61         Continuation cont) throws NamingException;
a_listBindings( Continuation cont)62     protected abstract NamingEnumeration<Binding> a_listBindings(
63         Continuation cont) throws NamingException;
a_bind(String name, Object obj, Continuation cont)64     protected abstract void a_bind(String name, Object obj, Continuation cont)
65         throws NamingException;
a_rebind(String name, Object obj, Continuation cont)66     protected abstract void a_rebind(String name, Object obj, Continuation cont)
67         throws NamingException;
a_unbind(String name, Continuation cont)68     protected abstract void a_unbind(String name, Continuation cont)
69         throws NamingException;
a_destroySubcontext(String name, Continuation cont)70     protected abstract void a_destroySubcontext(String name, Continuation cont)
71         throws NamingException;
a_createSubcontext(String name, Continuation cont)72     protected abstract Context a_createSubcontext(String name,
73         Continuation cont) throws NamingException;
a_rename(String oldname, Name newname, Continuation cont)74     protected abstract void a_rename(String oldname, Name newname,
75         Continuation cont) throws NamingException;
a_getNameParser(Continuation cont)76     protected abstract NameParser a_getNameParser(Continuation cont)
77         throws NamingException;
78 
79     /* Parsing */
80     /**
81      * Parse 'inputName' into two parts:
82      * head: the first component in this name
83      * tail: the rest of the unused name.
84      *
85      * Subclasses should provide an implementation for this method
86      * which parses inputName using its own name syntax.
87      */
c_parseComponent(String inputName, Continuation cont)88     protected abstract StringHeadTail c_parseComponent(String inputName,
89         Continuation cont) throws NamingException;
90 
91 
92 // ------ Methods that need to be overridden by subclass
93 
94     /* Resolution method for supporting federation */
95     /**
96       * Resolves the nns for 'name' when the named context is acting
97       * as an intermediate context.
98       *
99       * For a system that supports junctions, this would be equivalent to
100       *         a_lookup(name, cont);
101       * because for junctions, an intermediate slash simply signifies
102       * a syntactic separator.
103       *
104       * For a system that supports implicit nns, this would be equivalent to
105       *         a_lookup_nns(name, cont);
106       * because for implicit nns, a slash always signifies the implicit nns,
107       * regardless of whether it is intermediate or trailing.
108       *
109       * By default this method supports junctions, and also allows for an
110       * implicit nns to be dynamically determined through the use of the
111       * "nns" reference (see a_processJunction_nns()).
112       * Contexts that implement implicit nns directly should provide an
113       * appropriate override.
114       */
a_resolveIntermediate_nns(String name, Continuation cont)115     protected Object a_resolveIntermediate_nns(String name, Continuation cont)
116         throws NamingException {
117             try {
118                 final Object obj = a_lookup(name, cont);
119 
120                 // Do not append "" to Continuation 'cont' even if set
121                 // because the intention is to ignore the nns
122 
123                 //
124                 if (obj != null && getClass().isInstance(obj)) {
125                     // If "obj" is in the same type as this object, it must
126                     // not be a junction. Continue the lookup with "/".
127 
128                     cont.setContinueNNS(obj, name, this);
129                     return null;
130 
131                 } else if (obj != null && !(obj instanceof Context)) {
132                     // obj is not even a context, so try to find its nns
133                     // dynamically by constructing a Reference containing obj.
134                     RefAddr addr = new RefAddr("nns") {
135                         public Object getContent() {
136                             return obj;
137                         }
138                         private static final long serialVersionUID =
139                             -3399518522645918499L;
140                     };
141                     Reference ref = new Reference("java.lang.Object", addr);
142 
143                     // Resolved name has trailing slash to indicate nns
144                     CompositeName resName = new CompositeName();
145                     resName.add(name);
146                     resName.add(""); // add trailing slash
147 
148                     // Set continuation leave it to
149                     // PartialCompositeContext.getPCContext() to throw CPE.
150                     // Do not use setContinueNNS() because we've already
151                     // consumed "/" (i.e., moved it to resName).
152 
153                     cont.setContinue(ref, resName, this);
154                     return null;
155 
156                 } else {
157                     return obj;
158                 }
159 
160             } catch (NamingException e) {
161                 e.appendRemainingComponent(""); // add nns back
162                 throw e;
163             }
164         }
165 
166     /* Equivalent of Context Methods for supporting nns */
167 
168     // The following methods are called when the DirContext methods
169     // are invoked with a name that has a trailing slash.
170     // For naming systems that support implicit nns,
171     // the trailing slash signifies the implicit nns.
172     // For such naming systems, override these a_*_nns methods.
173     //
174     // For naming systems that support junctions (explicit nns),
175     // the trailing slash is meaningless because a junction does not
176     // have an implicit nns.  The default implementation here
177     // throws a NameNotFoundException for such names.
178     // If a context wants to accept a trailing slash as having
179     // the same meaning as the same name without a trailing slash,
180     // then it should override these a_*_nns methods.
181 
182 
a_lookup_nns(String name, Continuation cont)183     protected Object a_lookup_nns(String name, Continuation cont)
184         throws NamingException {
185             a_processJunction_nns(name, cont);
186             return null;
187         }
188 
a_lookupLink_nns(String name, Continuation cont)189     protected Object a_lookupLink_nns(String name, Continuation cont)
190         throws NamingException {
191             a_processJunction_nns(name, cont);
192             return null;
193         }
194 
a_list_nns(Continuation cont)195     protected NamingEnumeration<NameClassPair> a_list_nns(Continuation cont)
196         throws NamingException {
197             a_processJunction_nns(cont);
198             return null;
199         }
a_listBindings_nns(Continuation cont)200     protected NamingEnumeration<Binding> a_listBindings_nns(Continuation cont)
201         throws NamingException {
202             a_processJunction_nns(cont);
203             return null;
204         }
205 
a_bind_nns(String name, Object obj, Continuation cont)206     protected void a_bind_nns(String name, Object obj, Continuation cont)
207         throws NamingException {
208             a_processJunction_nns(name, cont);
209         }
210 
a_rebind_nns(String name, Object obj, Continuation cont)211     protected void a_rebind_nns(String name, Object obj, Continuation cont)
212         throws NamingException {
213             a_processJunction_nns(name, cont);
214         }
215 
a_unbind_nns(String name, Continuation cont)216     protected void a_unbind_nns(String name, Continuation cont)
217         throws NamingException {
218             a_processJunction_nns(name, cont);
219         }
220 
a_createSubcontext_nns(String name, Continuation cont)221     protected Context a_createSubcontext_nns(String name, Continuation cont)
222         throws NamingException {
223             a_processJunction_nns(name, cont);
224             return null;
225         }
226 
a_destroySubcontext_nns(String name, Continuation cont)227     protected void a_destroySubcontext_nns(String name, Continuation cont)
228         throws NamingException {
229             a_processJunction_nns(name, cont);
230         }
231 
a_rename_nns(String oldname, Name newname, Continuation cont)232     protected void a_rename_nns(String oldname, Name newname, Continuation cont)
233         throws NamingException {
234             a_processJunction_nns(oldname, cont);
235         }
236 
a_getNameParser_nns(Continuation cont)237     protected NameParser a_getNameParser_nns(Continuation cont)
238         throws NamingException {
239             a_processJunction_nns(cont);
240             return null;
241         }
242 
243 
244 
isEmpty(String name)245     protected boolean isEmpty(String name) {
246         return name == null || name.equals("");
247     }
248 
249 // ------ implementations of c_  and c_*_nns methods using
250 // ------ the corresponding a_ and a_*_nns methods
251 
252     /* Equivalent to methods in  Context interface */
253 
c_lookup(Name name, Continuation cont)254     protected Object c_lookup(Name name, Continuation cont)
255         throws NamingException {
256             Object ret = null;
257             if (resolve_to_penultimate_context(name, cont)) {
258                 ret = a_lookup(name.toString(), cont);
259                 if (ret != null && ret instanceof LinkRef) {
260                     cont.setContinue(ret, name, this);
261                     ret = null;
262                 }
263             }
264             return ret;
265         }
266 
c_lookupLink(Name name, Continuation cont)267     protected Object c_lookupLink(Name name, Continuation cont)
268         throws NamingException {
269             if (resolve_to_penultimate_context(name, cont)) {
270                 return a_lookupLink(name.toString(), cont);
271             }
272             return null;
273         }
274 
c_list(Name name, Continuation cont)275     protected NamingEnumeration<NameClassPair> c_list(Name name,
276         Continuation cont) throws NamingException {
277             if (resolve_to_context(name, cont)) {
278                 return a_list(cont);
279             }
280             return null;
281         }
282 
c_listBindings(Name name, Continuation cont)283     protected NamingEnumeration<Binding> c_listBindings(Name name,
284         Continuation cont) throws NamingException {
285             if (resolve_to_context(name, cont)) {
286                 return a_listBindings(cont);
287             }
288             return null;
289         }
290 
c_bind(Name name, Object obj, Continuation cont)291     protected void c_bind(Name name, Object obj, Continuation cont)
292         throws NamingException {
293             if (resolve_to_penultimate_context(name, cont))
294                 a_bind(name.toString(), obj, cont);
295         }
296 
c_rebind(Name name, Object obj, Continuation cont)297     protected void c_rebind(Name name, Object obj, Continuation cont)
298         throws NamingException {
299             if (resolve_to_penultimate_context(name, cont))
300                 a_rebind(name.toString(), obj, cont);
301         }
302 
c_unbind(Name name, Continuation cont)303     protected void c_unbind(Name name, Continuation cont)
304         throws NamingException {
305             if (resolve_to_penultimate_context(name, cont))
306                 a_unbind(name.toString(), cont);
307         }
308 
c_destroySubcontext(Name name, Continuation cont)309     protected void c_destroySubcontext(Name name, Continuation cont)
310         throws NamingException {
311             if (resolve_to_penultimate_context(name, cont))
312                 a_destroySubcontext(name.toString(), cont);
313         }
314 
c_createSubcontext(Name name, Continuation cont)315     protected Context c_createSubcontext(Name name,
316         Continuation cont) throws NamingException {
317             if (resolve_to_penultimate_context(name, cont))
318                 return a_createSubcontext(name.toString(), cont);
319             else
320                 return null;
321         }
322 
c_rename(Name oldname, Name newname, Continuation cont)323     protected void c_rename(Name oldname, Name newname,
324         Continuation cont) throws NamingException {
325             if (resolve_to_penultimate_context(oldname, cont))
326                  a_rename(oldname.toString(), newname, cont);
327         }
328 
c_getNameParser(Name name, Continuation cont)329     protected NameParser c_getNameParser(Name name,
330         Continuation cont) throws NamingException {
331             if (resolve_to_context(name, cont))
332                 return a_getNameParser(cont);
333             return null;
334         }
335 
336     /* The following are overridden only for AtomicContexts.
337      * AtomicContext is used by PartialCompositeDirContext and ComponentDirContext
338      * in the inheritance tree to make use of methods in
339      * PartialCompositeContext and ComponentContext. We only want to use the
340      * atomic forms when we're actually an atomic context.
341      */
342 
343     /* From ComponentContext */
344 
c_resolveIntermediate_nns(Name name, Continuation cont)345     protected Object c_resolveIntermediate_nns(Name name, Continuation cont)
346         throws NamingException {
347             if (_contextType == _ATOMIC) {
348                 Object ret = null;
349                 if (resolve_to_penultimate_context_nns(name, cont)) {
350                     ret = a_resolveIntermediate_nns(name.toString(), cont);
351                     if (ret != null && ret instanceof LinkRef) {
352                         cont.setContinue(ret, name, this);
353                         ret = null;
354                     }
355                 }
356                 return ret;
357             } else {
358                 // use ComponentContext
359                 return super.c_resolveIntermediate_nns(name, cont);
360             }
361         }
362 
363     /* Equivalent to methods in Context interface for nns */
364 
c_lookup_nns(Name name, Continuation cont)365     protected Object c_lookup_nns(Name name, Continuation cont)
366         throws NamingException {
367             if (_contextType == _ATOMIC) {
368                 Object ret = null;
369                 if (resolve_to_penultimate_context_nns(name, cont)) {
370                     ret = a_lookup_nns(name.toString(), cont);
371                     if (ret != null && ret instanceof LinkRef) {
372                         cont.setContinue(ret, name, this);
373                         ret = null;
374                     }
375                 }
376                 return ret;
377             } else {
378                 return super.c_lookup_nns(name, cont);
379             }
380         }
381 
c_lookupLink_nns(Name name, Continuation cont)382     protected Object c_lookupLink_nns(Name name, Continuation cont)
383         throws NamingException {
384             if (_contextType == _ATOMIC) {
385                 // %%% check logic
386                 resolve_to_nns_and_continue(name, cont);
387                 return null;
388             } else {
389                 // use ComponentContext
390                 return super.c_lookupLink_nns(name, cont);
391             }
392         }
393 
c_list_nns(Name name, Continuation cont)394     protected NamingEnumeration<NameClassPair> c_list_nns(Name name,
395         Continuation cont) throws NamingException {
396             if (_contextType == _ATOMIC) {
397                 resolve_to_nns_and_continue(name, cont);
398                 return null;
399             } else {
400                 // use ComponentContext
401                 return super.c_list_nns(name, cont);
402             }
403         }
404 
c_listBindings_nns(Name name, Continuation cont)405     protected NamingEnumeration<Binding> c_listBindings_nns(Name name,
406         Continuation cont) throws NamingException {
407             if (_contextType == _ATOMIC) {
408                 resolve_to_nns_and_continue(name, cont);
409                 return null;
410             } else {
411                 // use ComponentContext
412                 return super.c_listBindings_nns(name, cont);
413             }
414         }
415 
c_bind_nns(Name name, Object obj, Continuation cont)416     protected void c_bind_nns(Name name, Object obj, Continuation cont)
417         throws NamingException {
418             if (_contextType == _ATOMIC) {
419                 if (resolve_to_penultimate_context_nns(name, cont))
420                     a_bind_nns(name.toString(), obj, cont);
421             } else {
422                 // use ComponentContext
423                 super.c_bind_nns(name, obj, cont);
424             }
425         }
426 
c_rebind_nns(Name name, Object obj, Continuation cont)427     protected void c_rebind_nns(Name name, Object obj, Continuation cont)
428         throws NamingException {
429             if (_contextType == _ATOMIC) {
430                 if (resolve_to_penultimate_context_nns(name, cont))
431                     a_rebind_nns(name.toString(), obj, cont);
432             } else {
433                 // use ComponentContext
434                 super.c_rebind_nns(name, obj, cont);
435             }
436         }
437 
c_unbind_nns(Name name, Continuation cont)438     protected void c_unbind_nns(Name name, Continuation cont)
439         throws NamingException {
440             if (_contextType == _ATOMIC) {
441                 if (resolve_to_penultimate_context_nns(name, cont))
442                     a_unbind_nns(name.toString(), cont);
443             } else {
444                 // use ComponentContext
445                 super.c_unbind_nns(name, cont);
446             }
447         }
448 
c_createSubcontext_nns(Name name, Continuation cont)449     protected Context c_createSubcontext_nns(Name name,
450         Continuation cont) throws NamingException {
451             if (_contextType == _ATOMIC) {
452                 if (resolve_to_penultimate_context_nns(name, cont))
453                     return a_createSubcontext_nns(name.toString(), cont);
454                 else
455                     return null;
456             } else {
457                 // use ComponentContext
458                 return super.c_createSubcontext_nns(name, cont);
459             }
460         }
461 
c_destroySubcontext_nns(Name name, Continuation cont)462     protected void c_destroySubcontext_nns(Name name, Continuation cont)
463         throws NamingException {
464             if (_contextType == _ATOMIC) {
465                 if (resolve_to_penultimate_context_nns(name, cont))
466                     a_destroySubcontext_nns(name.toString(), cont);
467             } else {
468                 // use ComponentContext
469                 super.c_destroySubcontext_nns(name, cont);
470             }
471         }
472 
c_rename_nns(Name oldname, Name newname, Continuation cont)473     protected void c_rename_nns(Name oldname, Name newname, Continuation cont)
474         throws NamingException {
475             if (_contextType == _ATOMIC) {
476                 if (resolve_to_penultimate_context_nns(oldname, cont))
477                     a_rename_nns(oldname.toString(), newname, cont);
478             } else {
479                 // use ComponentContext
480                 super.c_rename_nns(oldname, newname, cont);
481             }
482         }
483 
c_getNameParser_nns(Name name, Continuation cont)484     protected NameParser c_getNameParser_nns(Name name, Continuation cont)
485         throws NamingException {
486             if (_contextType == _ATOMIC) {
487                 resolve_to_nns_and_continue(name, cont);
488                 return null;
489             } else {
490                 // use ComponentContext
491                 return super.c_getNameParser_nns(name, cont);
492             }
493         }
494 
495 // --------------    internal methods used by this class
496 
497     /* Handles nns for junctions */
498     /**
499       * This function is used when implementing a naming system that
500       * supports junctions.  For example, when the a_bind_nns(name, newobj)
501       * method is invoked, that means the caller is attempting to bind the
502       * object 'newobj' to the nns of 'name'.  For context that supports
503       * junctions, 'name' names a junction and is pointing to the root
504       * of another naming system, which in turn might have an nns.
505       * This means that a_bind_nns() should first resolve 'name' and attempt to
506       * continue the operation in the context named by 'name'.  (i.e. bind
507       * to the nns of the context named by 'name').
508       * If name is already empty, then throw NameNotFoundException because
509       * this context by default does not have any nns.
510       */
a_processJunction_nns(String name, Continuation cont)511     protected void a_processJunction_nns(String name, Continuation cont)
512         throws NamingException {
513             if (name.equals("")) {
514                 NameNotFoundException e = new NameNotFoundException();
515                 cont.setErrorNNS(this, name);
516                 throw cont.fillInException(e);
517             }
518             try {
519                 // lookup name to continue operation in nns
520                 Object target = a_lookup(name, cont);
521                 if (cont.isContinue())
522                     cont.appendRemainingComponent("");  // add nns back
523                 else {
524                     cont.setContinueNNS(target, name, this);
525                 }
526             } catch (NamingException e) {
527                 e.appendRemainingComponent(""); // add nns back
528                 throw e;
529             }
530         }
531 
532     /**
533       * This function is used when implementing a naming system that
534       * supports junctions.  For example, when the a_list_nns(newobj)
535       * method is invoked, that means the caller is attempting to list the
536       * the nns context of this context.  For a context that supports
537       * junctions, it by default does not have any nns.  Consequently,
538       * a NameNotFoundException is thrown.
539       */
a_processJunction_nns(Continuation cont)540     protected void a_processJunction_nns(Continuation cont) throws NamingException {
541 
542         // Construct a new Reference that contains this context.
543         RefAddr addr = new RefAddr("nns") {
544             public Object getContent() {
545                 return AtomicContext.this;
546             }
547             private static final long serialVersionUID = 3449785852664978312L;
548         };
549         Reference ref = new Reference("java.lang.Object", addr);
550 
551         // Set continuation leave it to PartialCompositeContext.getPCContext()
552         // to throw the exception.
553         // Do not use setContinueNNS() because we've are
554         // setting relativeResolvedName to "/".
555         cont.setContinue(ref, _NNS_NAME, this);
556     }
557 
558     /* *********** core resolution routines ******************* */
559 
560     /** Resolve to context named by 'name'.
561       * Returns true if at named context (i.e. 'name' is empty name).
562       * Returns false otherwise, and sets Continuation on parts of 'name'
563       * not yet resolved.
564       */
resolve_to_context(Name name, Continuation cont)565     protected boolean resolve_to_context(Name name, Continuation cont)
566     throws NamingException {
567         String target = name.toString();
568 
569 
570         StringHeadTail ht = c_parseComponent(target, cont);
571         String tail = ht.getTail();
572         String head = ht.getHead();
573 
574         if (debug > 0)
575             System.out.println("RESOLVE TO CONTEXT(" + target + ") = {" +
576                                head + ", " + tail + "}");
577 
578         if (head == null) {
579             // something is wrong; no name at all
580             InvalidNameException e = new InvalidNameException();
581             throw cont.fillInException(e);
582         }
583         if (!isEmpty(head)) {
584             // if there is head is a non-empty name
585             // this means more resolution to be done
586             try {
587                 Object headCtx = a_lookup(head, cont);
588 //              System.out.println("answer " + headCtx);
589                 if (headCtx != null)
590                     cont.setContinue(headCtx, head, this, (tail == null ? "" : tail));
591                 else if (cont.isContinue())
592                     cont.appendRemainingComponent(tail);
593             } catch (NamingException e) {
594                 e.appendRemainingComponent(tail);
595                 throw e;
596             }
597         } else {
598             cont.setSuccess();  // clear
599             return true;
600         }
601         return false;
602     }
603 
604     /**
605       * Resolves to penultimate context named by 'name'.
606       * Returns true if penultimate context has been reached (i.e. name
607       * only has one atomic component left).
608       * Returns false otherwise, and sets Continuation to parts of name
609       * not yet resolved.
610       */
resolve_to_penultimate_context(Name name, Continuation cont)611     protected boolean resolve_to_penultimate_context(Name name, Continuation cont)
612     throws NamingException {
613         String target = name.toString();
614 
615         if (debug > 0)
616             System.out.println("RESOLVE TO PENULTIMATE" + target);
617 
618         StringHeadTail ht = c_parseComponent(target, cont);
619         String tail = ht.getTail();
620         String head = ht.getHead();
621         if (head == null) {
622             // something is wrong; no name at all
623             InvalidNameException e = new InvalidNameException();
624             throw cont.fillInException(e);
625         }
626 
627         if (!isEmpty(tail)) {
628             // more components; hence not at penultimate context yet
629             try {
630                 Object headCtx = a_lookup(head, cont);
631                 if (headCtx != null)
632                     cont.setContinue(headCtx, head, this, tail);
633                 else if (cont.isContinue())
634                     cont.appendRemainingComponent(tail);
635             } catch (NamingException e) {
636                 e.appendRemainingComponent(tail);
637                 throw e;
638             }
639         } else {
640             // already at penultimate context
641             cont.setSuccess();  // clear
642             return true;
643         }
644         return false;
645     }
646 
647     /**
648       * This function is similar to resolve_to_penultimate_context()
649       * except it should only be called by the nns() functions.
650       * This function fixes any exception or continuations so that
651       * it will have the proper nns name.
652       */
resolve_to_penultimate_context_nns(Name name, Continuation cont)653     protected boolean resolve_to_penultimate_context_nns(Name name,
654                                                          Continuation cont)
655         throws NamingException {
656             try {
657         if (debug > 0)
658             System.out.println("RESOLVE TO PENULTIMATE NNS" + name.toString());
659                 boolean answer = resolve_to_penultimate_context(name, cont);
660 
661                 // resolve_to_penultimate_context() only calls a_lookup().
662                 // Any continuation it sets is lacking the nns, so
663                 // we need to add it back
664                 if (cont.isContinue())
665                     cont.appendRemainingComponent("");
666 
667                 return answer;
668             } catch (NamingException e) {
669                 // resolve_to_penultimate_context() only calls a_lookup().
670                 // Any exceptions it throws is lacking the nns, so
671                 // we need to add it back.
672                 e.appendRemainingComponent("");
673                 throw e;
674             }
675         }
676 
677     /**
678       * Resolves to nns associated with 'name' and set Continuation
679       * to the result.
680       */
resolve_to_nns_and_continue(Name name, Continuation cont)681     protected void resolve_to_nns_and_continue(Name name, Continuation cont)
682         throws NamingException {
683         if (debug > 0)
684             System.out.println("RESOLVE TO NNS AND CONTINUE" + name.toString());
685 
686         if (resolve_to_penultimate_context_nns(name, cont)) {
687             Object nns = a_lookup_nns(name.toString(), cont);
688             if (nns != null)
689                 cont.setContinue(nns, name, this);
690         }
691     }
692 }
693