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 
  47     protected AtomicContext () {
  48         _contextType = _ATOMIC;
  49     }
  50 
  51 // ------ Abstract methods whose implementation are provided by subclasses
  52 
  53 
  54     /* Equivalent to Context methods */
  55     protected abstract Object a_lookup(String name, Continuation cont)
  56         throws NamingException;
  57     protected abstract Object a_lookupLink(String name, Continuation cont)
  58         throws NamingException;
  59 
  60     protected abstract NamingEnumeration<NameClassPair> a_list(
  61         Continuation cont) throws NamingException;
  62     protected abstract NamingEnumeration<Binding> a_listBindings(
  63         Continuation cont) throws NamingException;
  64     protected abstract void a_bind(String name, Object obj, Continuation cont)
  65         throws NamingException;
  66     protected abstract void a_rebind(String name, Object obj, Continuation cont)
  67         throws NamingException;
  68     protected abstract void a_unbind(String name, Continuation cont)
  69         throws NamingException;
  70     protected abstract void a_destroySubcontext(String name, Continuation cont)
  71         throws NamingException;
  72     protected abstract Context a_createSubcontext(String name,
  73         Continuation cont) throws NamingException;
  74     protected abstract void a_rename(String oldname, Name newname,
  75         Continuation cont) throws NamingException;
  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      */
  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       */
 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 
 183     protected Object a_lookup_nns(String name, Continuation cont)
 184         throws NamingException {
 185             a_processJunction_nns(name, cont);
 186             return null;
 187         }
 188 
 189     protected Object a_lookupLink_nns(String name, Continuation cont)
 190         throws NamingException {
 191             a_processJunction_nns(name, cont);
 192             return null;
 193         }
 194 
 195     protected NamingEnumeration<NameClassPair> a_list_nns(Continuation cont)
 196         throws NamingException {
 197             a_processJunction_nns(cont);
 198             return null;
 199         }
 200     protected NamingEnumeration<Binding> a_listBindings_nns(Continuation cont)
 201         throws NamingException {
 202             a_processJunction_nns(cont);
 203             return null;
 204         }
 205 
 206     protected void a_bind_nns(String name, Object obj, Continuation cont)
 207         throws NamingException {
 208             a_processJunction_nns(name, cont);
 209         }
 210 
 211     protected void a_rebind_nns(String name, Object obj, Continuation cont)
 212         throws NamingException {
 213             a_processJunction_nns(name, cont);
 214         }
 215 
 216     protected void a_unbind_nns(String name, Continuation cont)
 217         throws NamingException {
 218             a_processJunction_nns(name, cont);
 219         }
 220 
 221     protected Context a_createSubcontext_nns(String name, Continuation cont)
 222         throws NamingException {
 223             a_processJunction_nns(name, cont);
 224             return null;
 225         }
 226 
 227     protected void a_destroySubcontext_nns(String name, Continuation cont)
 228         throws NamingException {
 229             a_processJunction_nns(name, cont);
 230         }
 231 
 232     protected void a_rename_nns(String oldname, Name newname, Continuation cont)
 233         throws NamingException {
 234             a_processJunction_nns(oldname, cont);
 235         }
 236 
 237     protected NameParser a_getNameParser_nns(Continuation cont)
 238         throws NamingException {
 239             a_processJunction_nns(cont);
 240             return null;
 241         }
 242 
 243 
 244 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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       */
 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       */
 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       */
 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       */
 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       */
 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       */
 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 }