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