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