1 /* 2 * Copyright (c) 1999, 2002, 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 package com.sun.jndi.toolkit.dir; 26 27 import javax.naming.*; 28 import javax.naming.directory.*; 29 import javax.naming.spi.*; 30 import 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 40 public 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 870 final 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) 927 final 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 }