001: /*
002: * Copyright 1999-2002 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: package com.sun.jndi.toolkit.dir;
026:
027: import javax.naming.*;
028: import javax.naming.directory.*;
029: import javax.naming.spi.*;
030: import java.util.*;
031:
032: /**
033: * A sample service provider that implements a hierarchical directory in memory.
034: * Every operation begins by doing a lookup on the name passed to it and then
035: * calls a corresponding "do<OperationName>" on the result of the lookup. The
036: * "do<OperationName>" does the work without any further resolution (it assumes
037: * that it is the target context).
038: */
039:
040: public class HierMemDirCtx implements DirContext {
041:
042: static private final boolean debug = false;
043: private static final NameParser defaultParser = new HierarchicalNameParser();
044:
045: protected Hashtable myEnv;
046: protected Hashtable bindings;
047: protected Attributes attrs;
048: protected boolean ignoreCase = false;
049: protected NamingException readOnlyEx = null;
050: protected NameParser myParser = defaultParser;
051:
052: private boolean alwaysUseFactory;
053:
054: public void close() throws NamingException {
055: myEnv = null;
056: bindings = null;
057: attrs = null;
058: }
059:
060: public String getNameInNamespace() throws NamingException {
061: throw new OperationNotSupportedException(
062: "Cannot determine full name");
063: }
064:
065: public HierMemDirCtx() {
066: this (null, false, false);
067: }
068:
069: public HierMemDirCtx(boolean ignoreCase) {
070: this (null, ignoreCase, false);
071: }
072:
073: public HierMemDirCtx(Hashtable environment, boolean ignoreCase) {
074: this (environment, ignoreCase, false);
075: }
076:
077: protected HierMemDirCtx(Hashtable environment, boolean ignoreCase,
078: boolean useFac) {
079: myEnv = environment;
080: this .ignoreCase = ignoreCase;
081: init();
082: this .alwaysUseFactory = useFac;
083: }
084:
085: private void init() {
086: attrs = new BasicAttributes(ignoreCase);
087: bindings = new Hashtable(11, 0.75f);
088: }
089:
090: public Object lookup(String name) throws NamingException {
091: return lookup(myParser.parse(name));
092: }
093:
094: public Object lookup(Name name) throws NamingException {
095: return doLookup(name, alwaysUseFactory);
096: }
097:
098: public Object doLookup(Name name, boolean useFactory)
099: throws NamingException {
100:
101: Object target = null;
102: name = canonizeName(name);
103:
104: switch (name.size()) {
105: case 0:
106: // name is empty, caller wants this object
107: target = this ;
108: break;
109:
110: case 1:
111: // name is atomic, caller wants one of this object's bindings
112: target = bindings.get(name);
113: break;
114:
115: default:
116: // name is compound, delegate to child context
117: HierMemDirCtx ctx = (HierMemDirCtx) bindings.get(name
118: .getPrefix(1));
119: if (ctx == null) {
120: target = null;
121: } else {
122: target = ctx.doLookup(name.getSuffix(1), false);
123: }
124: break;
125: }
126:
127: if (target == null) {
128: throw new NameNotFoundException(name.toString());
129: }
130:
131: if (useFactory) {
132: try {
133: return DirectoryManager
134: .getObjectInstance(
135: target,
136: name,
137: this ,
138: myEnv,
139: (target instanceof HierMemDirCtx) ? ((HierMemDirCtx) target).attrs
140: : null);
141: } catch (NamingException e) {
142: throw e;
143: } catch (Exception e) {
144: NamingException e2 = new NamingException(
145: "Problem calling getObjectInstance");
146: e2.setRootCause(e);
147: throw e2;
148: }
149: } else {
150: return target;
151: }
152: }
153:
154: public void bind(String name, Object obj) throws NamingException {
155: bind(myParser.parse(name), obj);
156: }
157:
158: public void bind(Name name, Object obj) throws NamingException {
159: doBind(name, obj, null, alwaysUseFactory);
160: }
161:
162: public void bind(String name, Object obj, Attributes attrs)
163: throws NamingException {
164: bind(myParser.parse(name), obj, attrs);
165: }
166:
167: public void bind(Name name, Object obj, Attributes attrs)
168: throws NamingException {
169: doBind(name, obj, attrs, alwaysUseFactory);
170: }
171:
172: protected void doBind(Name name, Object obj, Attributes attrs,
173: boolean useFactory) throws NamingException {
174: if (name.isEmpty()) {
175: throw new InvalidNameException("Cannot bind empty name");
176: }
177:
178: if (useFactory) {
179: DirStateFactory.Result res = DirectoryManager
180: .getStateToBind(obj, name, this , myEnv, attrs);
181: obj = res.getObject();
182: attrs = res.getAttributes();
183: }
184:
185: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
186: getInternalName(name), false);
187: ctx.doBindAux(getLeafName(name), obj);
188:
189: if (attrs != null && attrs.size() > 0) {
190: modifyAttributes(name, ADD_ATTRIBUTE, attrs);
191: }
192: }
193:
194: protected void doBindAux(Name name, Object obj)
195: throws NamingException {
196: if (readOnlyEx != null) {
197: throw (NamingException) readOnlyEx.fillInStackTrace();
198: }
199:
200: if (bindings.get(name) != null) {
201: throw new NameAlreadyBoundException(name.toString());
202: }
203: if (obj instanceof HierMemDirCtx) {
204: bindings.put(name, obj);
205: } else {
206: throw new SchemaViolationException(
207: "This context only supports binding objects of it's own kind");
208: }
209: }
210:
211: public void rebind(String name, Object obj) throws NamingException {
212: rebind(myParser.parse(name), obj);
213: }
214:
215: public void rebind(Name name, Object obj) throws NamingException {
216: doRebind(name, obj, null, alwaysUseFactory);
217: }
218:
219: public void rebind(String name, Object obj, Attributes attrs)
220: throws NamingException {
221: rebind(myParser.parse(name), obj, attrs);
222: }
223:
224: public void rebind(Name name, Object obj, Attributes attrs)
225: throws NamingException {
226: doRebind(name, obj, attrs, alwaysUseFactory);
227: }
228:
229: protected void doRebind(Name name, Object obj, Attributes attrs,
230: boolean useFactory) throws NamingException {
231: if (name.isEmpty()) {
232: throw new InvalidNameException("Cannot rebind empty name");
233: }
234:
235: if (useFactory) {
236: DirStateFactory.Result res = DirectoryManager
237: .getStateToBind(obj, name, this , myEnv, attrs);
238: obj = res.getObject();
239: attrs = res.getAttributes();
240: }
241:
242: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
243: getInternalName(name), false);
244: ctx.doRebindAux(getLeafName(name), obj);
245:
246: //
247: // attrs == null -> use attrs from obj
248: // attrs != null -> use attrs
249: //
250: // %%% Strictly speaking, when attrs is non-null, we should
251: // take the explicit step of removing obj's attrs.
252: // We don't do that currently.
253:
254: if (attrs != null && attrs.size() > 0) {
255: modifyAttributes(name, ADD_ATTRIBUTE, attrs);
256: }
257: }
258:
259: protected void doRebindAux(Name name, Object obj)
260: throws NamingException {
261: if (readOnlyEx != null) {
262: throw (NamingException) readOnlyEx.fillInStackTrace();
263: }
264: if (obj instanceof HierMemDirCtx) {
265: bindings.put(name, obj);
266:
267: } else {
268: throw new SchemaViolationException(
269: "This context only supports binding objects of it's own kind");
270: }
271: }
272:
273: public void unbind(String name) throws NamingException {
274: unbind(myParser.parse(name));
275: }
276:
277: public void unbind(Name name) throws NamingException {
278: if (name.isEmpty()) {
279: throw new InvalidNameException("Cannot unbind empty name");
280: } else {
281: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
282: getInternalName(name), false);
283: ctx.doUnbind(getLeafName(name));
284: }
285: }
286:
287: protected void doUnbind(Name name) throws NamingException {
288: if (readOnlyEx != null) {
289: throw (NamingException) readOnlyEx.fillInStackTrace();
290: }
291:
292: bindings.remove(name); // attrs will also be removed along with ctx
293: }
294:
295: public void rename(String oldname, String newname)
296: throws NamingException {
297: rename(myParser.parse(oldname), myParser.parse(newname));
298: }
299:
300: public void rename(Name oldname, Name newname)
301: throws NamingException {
302:
303: if (newname.isEmpty() || oldname.isEmpty()) {
304: throw new InvalidNameException("Cannot rename empty name");
305: }
306:
307: if (!getInternalName(newname).equals(getInternalName(oldname))) {
308: throw new InvalidNameException(
309: "Cannot rename across contexts");
310: }
311:
312: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
313: getInternalName(newname), false);
314: ctx.doRename(getLeafName(oldname), getLeafName(newname));
315: }
316:
317: protected void doRename(Name oldname, Name newname)
318: throws NamingException {
319: if (readOnlyEx != null) {
320: throw (NamingException) readOnlyEx.fillInStackTrace();
321: }
322:
323: oldname = canonizeName(oldname);
324: newname = canonizeName(newname);
325:
326: // Check if new name exists
327: if (bindings.get(newname) != null) {
328: throw new NameAlreadyBoundException(newname.toString());
329: }
330:
331: // Check if old name is bound
332: Object oldBinding = bindings.remove(oldname);
333: if (oldBinding == null) {
334: throw new NameNotFoundException(oldname.toString());
335: }
336:
337: bindings.put(newname, oldBinding);
338: }
339:
340: public NamingEnumeration list(String name) throws NamingException {
341: return list(myParser.parse(name));
342: }
343:
344: public NamingEnumeration list(Name name) throws NamingException {
345: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
346: return ctx.doList();
347: }
348:
349: protected NamingEnumeration doList() throws NamingException {
350: return new FlatNames(bindings.keys());
351: }
352:
353: public NamingEnumeration listBindings(String name)
354: throws NamingException {
355: return listBindings(myParser.parse(name));
356: }
357:
358: public NamingEnumeration listBindings(Name name)
359: throws NamingException {
360: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
361: return ctx.doListBindings(alwaysUseFactory);
362: }
363:
364: protected NamingEnumeration doListBindings(boolean useFactory)
365: throws NamingException {
366: return new FlatBindings(bindings, myEnv, useFactory);
367: }
368:
369: public void destroySubcontext(String name) throws NamingException {
370: destroySubcontext(myParser.parse(name));
371: }
372:
373: public void destroySubcontext(Name name) throws NamingException {
374: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
375: getInternalName(name), false);
376: ctx.doDestroySubcontext(getLeafName(name));
377: }
378:
379: protected void doDestroySubcontext(Name name)
380: throws NamingException {
381:
382: if (readOnlyEx != null) {
383: throw (NamingException) readOnlyEx.fillInStackTrace();
384: }
385: name = canonizeName(name);
386: bindings.remove(name);
387: }
388:
389: public Context createSubcontext(String name) throws NamingException {
390: return createSubcontext(myParser.parse(name));
391: }
392:
393: public Context createSubcontext(Name name) throws NamingException {
394: return createSubcontext(name, null);
395: }
396:
397: public DirContext createSubcontext(String name, Attributes attrs)
398: throws NamingException {
399: return createSubcontext(myParser.parse(name), attrs);
400: }
401:
402: public DirContext createSubcontext(Name name, Attributes attrs)
403: throws NamingException {
404: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(
405: getInternalName(name), false);
406: return ctx.doCreateSubcontext(getLeafName(name), attrs);
407: }
408:
409: protected DirContext doCreateSubcontext(Name name, Attributes attrs)
410: throws NamingException {
411: if (readOnlyEx != null) {
412: throw (NamingException) readOnlyEx.fillInStackTrace();
413: }
414:
415: name = canonizeName(name);
416:
417: if (bindings.get(name) != null) {
418: throw new NameAlreadyBoundException(name.toString());
419: }
420: HierMemDirCtx newCtx = createNewCtx();
421: bindings.put(name, newCtx);
422: if (attrs != null) {
423: newCtx.modifyAttributes("", ADD_ATTRIBUTE, attrs);
424: }
425: return newCtx;
426: }
427:
428: public Object lookupLink(String name) throws NamingException {
429: // This context does not treat links specially
430: return lookupLink(myParser.parse(name));
431: }
432:
433: public Object lookupLink(Name name) throws NamingException {
434: // Flat namespace; no federation; just call string version
435: return lookup(name);
436: }
437:
438: public NameParser getNameParser(String name) throws NamingException {
439: return myParser;
440: }
441:
442: public NameParser getNameParser(Name name) throws NamingException {
443: return myParser;
444: }
445:
446: public String composeName(String name, String prefix)
447: throws NamingException {
448: Name result = composeName(new CompositeName(name),
449: new CompositeName(prefix));
450: return result.toString();
451: }
452:
453: public Name composeName(Name name, Name prefix)
454: throws NamingException {
455: name = canonizeName(name);
456: prefix = canonizeName(prefix);
457: Name result = (Name) (prefix.clone());
458: result.addAll(name);
459: return result;
460: }
461:
462: public Object addToEnvironment(String propName, Object propVal)
463: throws NamingException {
464: myEnv = (myEnv == null) ? new Hashtable(11, 0.75f)
465: : (Hashtable) myEnv.clone();
466:
467: return myEnv.put(propName, propVal);
468: }
469:
470: public Object removeFromEnvironment(String propName)
471: throws NamingException {
472: if (myEnv == null)
473: return null;
474:
475: myEnv = (Hashtable) myEnv.clone();
476: return myEnv.remove(propName);
477: }
478:
479: public Hashtable getEnvironment() throws NamingException {
480: if (myEnv == null) {
481: return new Hashtable(5, 0.75f);
482: } else {
483: return (Hashtable) myEnv.clone();
484: }
485: }
486:
487: public Attributes getAttributes(String name) throws NamingException {
488: return getAttributes(myParser.parse(name));
489: }
490:
491: public Attributes getAttributes(Name name) throws NamingException {
492: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
493: return ctx.doGetAttributes();
494: }
495:
496: protected Attributes doGetAttributes() throws NamingException {
497: return (Attributes) attrs.clone();
498: }
499:
500: public Attributes getAttributes(String name, String[] attrIds)
501: throws NamingException {
502: return getAttributes(myParser.parse(name), attrIds);
503: }
504:
505: public Attributes getAttributes(Name name, String[] attrIds)
506: throws NamingException {
507: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
508: return ctx.doGetAttributes(attrIds);
509: }
510:
511: protected Attributes doGetAttributes(String[] attrIds)
512: throws NamingException {
513:
514: if (attrIds == null) {
515: return doGetAttributes();
516: }
517: Attributes attrs = new BasicAttributes(ignoreCase);
518: Attribute attr = null;
519: for (int i = 0; i < attrIds.length; i++) {
520: attr = this .attrs.get(attrIds[i]);
521: if (attr != null) {
522: attrs.put(attr);
523: }
524: }
525: return attrs;
526: }
527:
528: public void modifyAttributes(String name, int mod_op,
529: Attributes attrs) throws NamingException {
530: modifyAttributes(myParser.parse(name), mod_op, attrs);
531: }
532:
533: public void modifyAttributes(Name name, int mod_op, Attributes attrs)
534: throws NamingException {
535:
536: if (attrs == null || attrs.size() == 0) {
537: throw new IllegalArgumentException(
538: "Cannot modify without an attribute");
539: }
540:
541: // turn it into a modification Enumeration and pass it on
542: NamingEnumeration attrEnum = attrs.getAll();
543: ModificationItem[] mods = new ModificationItem[attrs.size()];
544: for (int i = 0; i < mods.length && attrEnum.hasMoreElements(); i++) {
545: mods[i] = new ModificationItem(mod_op, (Attribute) attrEnum
546: .next());
547: }
548:
549: modifyAttributes(name, mods);
550: }
551:
552: public void modifyAttributes(String name, ModificationItem[] mods)
553: throws NamingException {
554: modifyAttributes(myParser.parse(name), mods);
555: }
556:
557: public void modifyAttributes(Name name, ModificationItem[] mods)
558: throws NamingException {
559: HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false);
560: ctx.doModifyAttributes(mods);
561: }
562:
563: protected void doModifyAttributes(ModificationItem[] mods)
564: throws NamingException {
565:
566: if (readOnlyEx != null) {
567: throw (NamingException) readOnlyEx.fillInStackTrace();
568: }
569:
570: applyMods(mods, attrs);
571: }
572:
573: protected static Attributes applyMods(ModificationItem[] mods,
574: Attributes orig) throws NamingException {
575:
576: ModificationItem mod;
577: Attribute existingAttr, modAttr;
578: NamingEnumeration modVals;
579:
580: for (int i = 0; i < mods.length; i++) {
581: mod = mods[i];
582: modAttr = mod.getAttribute();
583:
584: switch (mod.getModificationOp()) {
585: case ADD_ATTRIBUTE:
586: if (debug) {
587: System.out.println("HierMemDSCtx: adding "
588: + mod.getAttribute().toString());
589: }
590: existingAttr = orig.get(modAttr.getID());
591: if (existingAttr == null) {
592: orig.put((Attribute) modAttr.clone());
593: } else {
594: // Add new attribute values to existing attribute
595: modVals = modAttr.getAll();
596: while (modVals.hasMore()) {
597: existingAttr.add(modVals.next());
598: }
599: }
600: break;
601: case REPLACE_ATTRIBUTE:
602: if (modAttr.size() == 0) {
603: orig.remove(modAttr.getID());
604: } else {
605: orig.put((Attribute) modAttr.clone());
606: }
607: break;
608: case REMOVE_ATTRIBUTE:
609: existingAttr = orig.get(modAttr.getID());
610: if (existingAttr != null) {
611: if (modAttr.size() == 0) {
612: orig.remove(modAttr.getID());
613: } else {
614: // Remove attribute values from existing attribute
615: modVals = modAttr.getAll();
616: while (modVals.hasMore()) {
617: existingAttr.remove(modVals.next());
618: }
619: if (existingAttr.size() == 0) {
620: orig.remove(modAttr.getID());
621: }
622: }
623: }
624: break;
625: default:
626: throw new AttributeModificationException(
627: "Unknown mod_op");
628: }
629: }
630:
631: return orig;
632: }
633:
634: public NamingEnumeration search(String name,
635: Attributes matchingAttributes) throws NamingException {
636: return search(name, matchingAttributes, null);
637: }
638:
639: public NamingEnumeration search(Name name,
640: Attributes matchingAttributes) throws NamingException {
641: return search(name, matchingAttributes, null);
642: }
643:
644: public NamingEnumeration search(String name,
645: Attributes matchingAttributes, String[] attributesToReturn)
646: throws NamingException {
647: return search(myParser.parse(name), matchingAttributes,
648: attributesToReturn);
649: }
650:
651: public NamingEnumeration search(Name name,
652: Attributes matchingAttributes, String[] attributesToReturn)
653: throws NamingException {
654:
655: HierMemDirCtx target = (HierMemDirCtx) doLookup(name, false);
656:
657: SearchControls cons = new SearchControls();
658: cons.setReturningAttributes(attributesToReturn);
659:
660: return new LazySearchEnumerationImpl(target
661: .doListBindings(false), new ContainmentFilter(
662: matchingAttributes), cons, this , myEnv, false); // alwaysUseFactory ignored because objReturnFlag == false
663: }
664:
665: public NamingEnumeration search(Name name, String filter,
666: SearchControls cons) throws NamingException {
667: DirContext target = (DirContext) doLookup(name, false);
668:
669: SearchFilter stringfilter = new SearchFilter(filter);
670: return new LazySearchEnumerationImpl(new HierContextEnumerator(
671: target, (cons != null) ? cons.getSearchScope()
672: : SearchControls.ONELEVEL_SCOPE), stringfilter,
673: cons, this , myEnv, alwaysUseFactory);
674: }
675:
676: public NamingEnumeration search(Name name, String filterExpr,
677: Object[] filterArgs, SearchControls cons)
678: throws NamingException {
679:
680: String strfilter = SearchFilter.format(filterExpr, filterArgs);
681: return search(name, strfilter, cons);
682: }
683:
684: public NamingEnumeration search(String name, String filter,
685: SearchControls cons) throws NamingException {
686: return search(myParser.parse(name), filter, cons);
687: }
688:
689: public NamingEnumeration search(String name, String filterExpr,
690: Object[] filterArgs, SearchControls cons)
691: throws NamingException {
692: return search(myParser.parse(name), filterExpr, filterArgs,
693: cons);
694: }
695:
696: // This function is called whenever a new object needs to be created.
697: // this is used so that if anyone subclasses us, they can override this
698: // and return object of their own kind.
699: protected HierMemDirCtx createNewCtx() throws NamingException {
700: return new HierMemDirCtx(myEnv, ignoreCase);
701: }
702:
703: // If the supplied name is a composite name, return the name that
704: // is its first component.
705: protected Name canonizeName(Name name) throws NamingException {
706: Name canonicalName = name;
707:
708: if (!(name instanceof HierarchicalName)) {
709: // If name is not of the correct type, make copy
710: canonicalName = new HierarchicalName();
711: int n = name.size();
712: for (int i = 0; i < n; i++) {
713: canonicalName.add(i, name.get(i));
714: }
715: }
716:
717: return canonicalName;
718: }
719:
720: protected Name getInternalName(Name name) throws NamingException {
721: return (name.getPrefix(name.size() - 1));
722: }
723:
724: protected Name getLeafName(Name name) throws NamingException {
725: return (name.getSuffix(name.size() - 1));
726: }
727:
728: public DirContext getSchema(String name) throws NamingException {
729: throw new OperationNotSupportedException();
730: }
731:
732: public DirContext getSchema(Name name) throws NamingException {
733: throw new OperationNotSupportedException();
734: }
735:
736: public DirContext getSchemaClassDefinition(String name)
737: throws NamingException {
738: throw new OperationNotSupportedException();
739: }
740:
741: public DirContext getSchemaClassDefinition(Name name)
742: throws NamingException {
743: throw new OperationNotSupportedException();
744: }
745:
746: // Set context in readonly mode; throw e when update operation attempted.
747: public void setReadOnly(NamingException e) {
748: readOnlyEx = e;
749: }
750:
751: // Set context to support case-insensitive names
752: public void setIgnoreCase(boolean ignoreCase) {
753: this .ignoreCase = ignoreCase;
754: }
755:
756: public void setNameParser(NameParser parser) {
757: myParser = parser;
758: }
759:
760: // Class for enumerating name/class pairs
761: private class FlatNames implements NamingEnumeration {
762: Enumeration names;
763:
764: FlatNames(Enumeration names) {
765: this .names = names;
766: }
767:
768: public boolean hasMoreElements() {
769: try {
770: return hasMore();
771: } catch (NamingException e) {
772: return false;
773: }
774: }
775:
776: public boolean hasMore() throws NamingException {
777: return names.hasMoreElements();
778: }
779:
780: public Object nextElement() {
781: try {
782: return next();
783: } catch (NamingException e) {
784: throw new NoSuchElementException(e.toString());
785: }
786: }
787:
788: public Object next() throws NamingException {
789: Name name = (Name) names.nextElement();
790: String className = bindings.get(name).getClass().getName();
791: return new NameClassPair(name.toString(), className);
792: }
793:
794: public void close() {
795: names = null;
796: }
797: }
798:
799: // Class for enumerating bindings
800: private final class FlatBindings extends FlatNames {
801: private Hashtable bds;
802: private Hashtable env;
803: private boolean useFactory;
804:
805: FlatBindings(Hashtable bindings, Hashtable env,
806: boolean useFactory) {
807: super (bindings.keys());
808: this .env = env;
809: this .bds = bindings;
810: this .useFactory = useFactory;
811: }
812:
813: public Object next() throws NamingException {
814: Name name = (Name) names.nextElement();
815:
816: HierMemDirCtx obj = (HierMemDirCtx) bds.get(name);
817:
818: Object answer = obj;
819: if (useFactory) {
820: Attributes attrs = obj.getAttributes(""); // only method available
821: try {
822: answer = DirectoryManager.getObjectInstance(obj,
823: name, HierMemDirCtx.this , env, attrs);
824: } catch (NamingException e) {
825: throw e;
826: } catch (Exception e) {
827: NamingException e2 = new NamingException(
828: "Problem calling getObjectInstance");
829: e2.setRootCause(e);
830: throw e2;
831: }
832: }
833:
834: return new Binding(name.toString(), answer);
835: }
836: }
837:
838: public class HierContextEnumerator extends ContextEnumerator {
839: public HierContextEnumerator(Context context, int scope)
840: throws NamingException {
841: super (context, scope);
842: }
843:
844: protected HierContextEnumerator(Context context, int scope,
845: String contextName, boolean returnSelf)
846: throws NamingException {
847: super (context, scope, contextName, returnSelf);
848: }
849:
850: protected NamingEnumeration getImmediateChildren(Context ctx)
851: throws NamingException {
852: return ((HierMemDirCtx) ctx).doListBindings(false);
853: }
854:
855: protected ContextEnumerator newEnumerator(Context ctx,
856: int scope, String contextName, boolean returnSelf)
857: throws NamingException {
858: return new HierContextEnumerator(ctx, scope, contextName,
859: returnSelf);
860: }
861: }
862: }
863:
864: // CompundNames's HashCode() method isn't good enough for many string.
865: // The only prupose of this subclass is to have a more discerning
866: // hash function. We'll make up for the performance hit by caching
867: // the hash value.
868:
869: final class HierarchicalName extends CompoundName {
870: private int hashValue = -1;
871:
872: // Creates an empty name
873: HierarchicalName() {
874: super (new Enumeration() {
875: public boolean hasMoreElements() {
876: return false;
877: }
878:
879: public Object nextElement() {
880: throw new NoSuchElementException();
881: }
882: }, HierarchicalNameParser.mySyntax);
883: }
884:
885: HierarchicalName(Enumeration comps, Properties syntax) {
886: super (comps, syntax);
887: }
888:
889: HierarchicalName(String n, Properties syntax)
890: throws InvalidNameException {
891: super (n, syntax);
892: }
893:
894: // just like String.hashCode, only it pays no attention to length
895: public int hashCode() {
896: if (hashValue == -1) {
897:
898: String name = toString().toUpperCase();
899: int len = name.length();
900: int off = 0;
901: char val[] = new char[len];
902:
903: name.getChars(0, len, val, 0);
904:
905: for (int i = len; i > 0; i--) {
906: hashValue = (hashValue * 37) + val[off++];
907: }
908: }
909:
910: return hashValue;
911: }
912:
913: public Name getPrefix(int posn) {
914: Enumeration comps = super .getPrefix(posn).getAll();
915: return (new HierarchicalName(comps, mySyntax));
916: }
917:
918: public Name getSuffix(int posn) {
919: Enumeration comps = super .getSuffix(posn).getAll();
920: return (new HierarchicalName(comps, mySyntax));
921: }
922:
923: public Object clone() {
924: return (new HierarchicalName(getAll(), mySyntax));
925: }
926:
927: private static final long serialVersionUID = -6717336834584573168L;
928: }
929:
930: // This is the default name parser (used if setNameParser is not called)
931: final class HierarchicalNameParser implements NameParser {
932: static final Properties mySyntax = new Properties();
933: static {
934: mySyntax.put("jndi.syntax.direction", "left_to_right");
935: mySyntax.put("jndi.syntax.separator", "/");
936: mySyntax.put("jndi.syntax.ignorecase", "true");
937: mySyntax.put("jndi.syntax.escape", "\\");
938: mySyntax.put("jndi.syntax.beginquote", "\"");
939: //mySyntax.put("jndi.syntax.separator.ava", "+");
940: //mySyntax.put("jndi.syntax.separator.typeval", "=");
941: mySyntax.put("jndi.syntax.trimblanks", "false");
942: };
943:
944: public Name parse(String name) throws NamingException {
945: return new HierarchicalName(name, mySyntax);
946: }
947: }
|