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