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