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