1 /* 2 * Copyright (c) 1999, 2011, 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<String, Object> myEnv; 46 protected Hashtable<Name, Object> 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<String, Object> environment, boolean ignoreCase) { 74 this(environment, ignoreCase, false); 75 } 76 77 protected HierMemDirCtx(Hashtable<String, Object> environment, 78 boolean ignoreCase, 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<NameClassPair> list(String name) throws NamingException { 330 return list(myParser.parse(name)); 331 } 332 333 public NamingEnumeration<NameClassPair> list(Name name) throws NamingException { 334 HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); 335 return ctx.doList(); 336 } 337 338 protected NamingEnumeration<NameClassPair> doList () throws NamingException { 339 return new FlatNames(bindings.keys()); 340 } 341 342 343 public NamingEnumeration<Binding> listBindings(String name) throws NamingException { 344 return listBindings(myParser.parse(name)); 345 } 346 347 public NamingEnumeration<Binding> listBindings(Name name) throws NamingException { 348 HierMemDirCtx ctx = (HierMemDirCtx)doLookup(name, false); 349 return ctx.doListBindings(alwaysUseFactory); 350 } 351 352 protected NamingEnumeration<Binding> 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 @SuppressWarnings("unchecked") // clone() 451 public Object addToEnvironment(String propName, Object propVal) 452 throws NamingException { 453 myEnv = (myEnv == null) 454 ? new Hashtable<String, Object>(11, 0.75f) 455 : (Hashtable<String, Object>)myEnv.clone(); 456 457 return myEnv.put(propName, propVal); 458 } 459 460 @SuppressWarnings("unchecked") // clone() 461 public Object removeFromEnvironment(String propName) 462 throws NamingException { 463 if (myEnv == null) 464 return null; 465 466 myEnv = (Hashtable<String, Object>)myEnv.clone(); 467 return myEnv.remove(propName); 468 } 469 470 @SuppressWarnings("unchecked") // clone() 471 public Hashtable<String, Object> getEnvironment() throws NamingException { 472 if (myEnv == null) { 473 return new Hashtable<>(5, 0.75f); 474 } else { 475 return (Hashtable<String, Object>)myEnv.clone(); 476 } 477 } 478 479 public Attributes getAttributes(String name) 480 throws NamingException { 481 return getAttributes(myParser.parse(name)); 482 } 483 484 public Attributes getAttributes(Name name) 485 throws NamingException { 486 HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); 487 return ctx.doGetAttributes(); 488 } 489 490 protected Attributes doGetAttributes() throws NamingException { 491 return (Attributes)attrs.clone(); 492 } 493 494 public Attributes getAttributes(String name, String[] attrIds) 495 throws NamingException { 496 return getAttributes(myParser.parse(name), attrIds); 497 } 498 499 public Attributes getAttributes(Name name, String[] attrIds) 500 throws NamingException { 501 HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); 502 return ctx.doGetAttributes(attrIds); 503 } 504 505 protected Attributes doGetAttributes(String[] attrIds) 506 throws NamingException { 507 508 if (attrIds == null) { 509 return doGetAttributes(); 510 } 511 Attributes attrs = new BasicAttributes(ignoreCase); 512 Attribute attr = null; 513 for(int i=0; i<attrIds.length; i++) { 514 attr = this.attrs.get(attrIds[i]); 515 if (attr != null) { 516 attrs.put(attr); 517 } 518 } 519 return attrs; 520 } 521 522 public void modifyAttributes(String name, int mod_op, Attributes attrs) 523 throws NamingException { 524 modifyAttributes(myParser.parse(name), mod_op, attrs); 525 } 526 527 public void modifyAttributes(Name name, int mod_op, Attributes attrs) 528 throws NamingException { 529 530 if (attrs == null || attrs.size() == 0) { 531 throw new IllegalArgumentException( 532 "Cannot modify without an attribute"); 533 } 534 535 // turn it into a modification Enumeration and pass it on 536 NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll(); 537 ModificationItem[] mods = new ModificationItem[attrs.size()]; 538 for (int i = 0; i < mods.length && attrEnum.hasMoreElements(); i++) { 539 mods[i] = new ModificationItem(mod_op, attrEnum.next()); 540 } 541 542 modifyAttributes(name, mods); 543 } 544 545 public void modifyAttributes(String name, ModificationItem[] mods) 546 throws NamingException { 547 modifyAttributes(myParser.parse(name), mods); 548 } 549 550 public void modifyAttributes(Name name, ModificationItem[] mods) 551 throws NamingException { 552 HierMemDirCtx ctx = (HierMemDirCtx) doLookup(name, false); 553 ctx.doModifyAttributes(mods); 554 } 555 556 protected void doModifyAttributes(ModificationItem[] mods) 557 throws NamingException { 558 559 if (readOnlyEx != null) { 560 throw (NamingException) readOnlyEx.fillInStackTrace(); 561 } 562 563 applyMods(mods, attrs); 564 } 565 566 protected static Attributes applyMods(ModificationItem[] mods, 567 Attributes orig) throws NamingException { 568 569 ModificationItem mod; 570 Attribute existingAttr, modAttr; 571 NamingEnumeration<?> modVals; 572 573 for (int i = 0; i < mods.length; i++) { 574 mod = mods[i]; 575 modAttr = mod.getAttribute(); 576 577 switch(mod.getModificationOp()) { 578 case ADD_ATTRIBUTE: 579 if (debug) { 580 System.out.println("HierMemDSCtx: adding " + 581 mod.getAttribute().toString()); 582 } 583 existingAttr = orig.get(modAttr.getID()); 584 if (existingAttr == null) { 585 orig.put((Attribute)modAttr.clone()); 586 } else { 587 // Add new attribute values to existing attribute 588 modVals = modAttr.getAll(); 589 while (modVals.hasMore()) { 590 existingAttr.add(modVals.next()); 591 } 592 } 593 break; 594 case REPLACE_ATTRIBUTE: 595 if (modAttr.size() == 0) { 596 orig.remove(modAttr.getID()); 597 } else { 598 orig.put((Attribute)modAttr.clone()); 599 } 600 break; 601 case REMOVE_ATTRIBUTE: 602 existingAttr = orig.get(modAttr.getID()); 603 if (existingAttr != null) { 604 if (modAttr.size() == 0) { 605 orig.remove(modAttr.getID()); 606 } else { 607 // Remove attribute values from existing attribute 608 modVals = modAttr.getAll(); 609 while (modVals.hasMore()) { 610 existingAttr.remove(modVals.next()); 611 } 612 if (existingAttr.size() == 0) { 613 orig.remove(modAttr.getID()); 614 } 615 } 616 } 617 break; 618 default: 619 throw new AttributeModificationException("Unknown mod_op"); 620 } 621 } 622 623 return orig; 624 } 625 626 public NamingEnumeration<SearchResult> search(String name, 627 Attributes matchingAttributes) 628 throws NamingException { 629 return search(name, matchingAttributes, null); 630 } 631 632 public NamingEnumeration<SearchResult> search(Name name, 633 Attributes matchingAttributes) 634 throws NamingException { 635 return search(name, matchingAttributes, null); 636 } 637 638 public NamingEnumeration<SearchResult> search(String name, 639 Attributes matchingAttributes, 640 String[] attributesToReturn) 641 throws NamingException { 642 return search(myParser.parse(name), matchingAttributes, 643 attributesToReturn); 644 } 645 646 public NamingEnumeration<SearchResult> search(Name name, 647 Attributes matchingAttributes, 648 String[] attributesToReturn) 649 throws NamingException { 650 651 HierMemDirCtx target = (HierMemDirCtx) doLookup(name, false); 652 653 SearchControls cons = new SearchControls(); 654 cons.setReturningAttributes(attributesToReturn); 655 656 return new LazySearchEnumerationImpl( 657 target.doListBindings(false), 658 new ContainmentFilter(matchingAttributes), 659 cons, this, myEnv, 660 false); // alwaysUseFactory ignored because objReturnFlag == false 661 } 662 663 public NamingEnumeration<SearchResult> search(Name name, 664 String filter, 665 SearchControls cons) 666 throws NamingException { 667 DirContext target = (DirContext) doLookup(name, false); 668 669 SearchFilter stringfilter = new SearchFilter(filter); 670 return new LazySearchEnumerationImpl( 671 new HierContextEnumerator(target, 672 (cons != null) ? cons.getSearchScope() : 673 SearchControls.ONELEVEL_SCOPE), 674 stringfilter, 675 cons, this, myEnv, alwaysUseFactory); 676 } 677 678 public NamingEnumeration<SearchResult> search(Name name, 679 String filterExpr, 680 Object[] filterArgs, 681 SearchControls cons) 682 throws NamingException { 683 684 String strfilter = SearchFilter.format(filterExpr, filterArgs); 685 return search(name, strfilter, cons); 686 } 687 688 public NamingEnumeration<SearchResult> search(String name, 689 String filter, 690 SearchControls cons) 691 throws NamingException { 692 return search(myParser.parse(name), filter, cons); 693 } 694 695 public NamingEnumeration<SearchResult> search(String name, 696 String filterExpr, 697 Object[] filterArgs, 698 SearchControls cons) 699 throws NamingException { 700 return search(myParser.parse(name), filterExpr, filterArgs, cons); 701 } 702 703 // This function is called whenever a new object needs to be created. 704 // this is used so that if anyone subclasses us, they can override this 705 // and return object of their own kind. 706 protected HierMemDirCtx createNewCtx() throws NamingException { 707 return new HierMemDirCtx(myEnv, ignoreCase); 708 } 709 710 // If the supplied name is a composite name, return the name that 711 // is its first component. 712 protected Name canonizeName(Name name) throws NamingException { 713 Name canonicalName = name; 714 715 if(!(name instanceof HierarchicalName)) { 716 // If name is not of the correct type, make copy 717 canonicalName = new HierarchicalName(); 718 int n = name.size(); 719 for(int i = 0; i < n; i++) { 720 canonicalName.add(i, name.get(i)); 721 } 722 } 723 724 return canonicalName; 725 } 726 727 protected Name getInternalName(Name name) throws NamingException { 728 return (name.getPrefix(name.size() - 1)); 729 } 730 731 protected Name getLeafName(Name name) throws NamingException { 732 return (name.getSuffix(name.size() - 1)); 733 } 734 735 736 public DirContext getSchema(String name) throws NamingException { 737 throw new OperationNotSupportedException(); 738 } 739 740 public DirContext getSchema(Name name) throws NamingException { 741 throw new OperationNotSupportedException(); 742 } 743 744 public DirContext getSchemaClassDefinition(String name) 745 throws NamingException { 746 throw new OperationNotSupportedException(); 747 } 748 749 public DirContext getSchemaClassDefinition(Name name) 750 throws NamingException { 751 throw new OperationNotSupportedException(); 752 } 753 754 // Set context in readonly mode; throw e when update operation attempted. 755 public void setReadOnly(NamingException e) { 756 readOnlyEx = e; 757 } 758 759 // Set context to support case-insensitive names 760 public void setIgnoreCase(boolean ignoreCase) { 761 this.ignoreCase = ignoreCase; 762 } 763 764 public void setNameParser(NameParser parser) { 765 myParser = parser; 766 } 767 768 /* 769 * Common base class for FlatNames and FlatBindings. 770 */ 771 private abstract class BaseFlatNames<T> implements NamingEnumeration<T> { 772 Enumeration<Name> names; 773 774 BaseFlatNames (Enumeration<Name> names) { 775 this.names = names; 776 } 777 778 public final boolean hasMoreElements() { 779 try { 780 return hasMore(); 781 } catch (NamingException e) { 782 return false; 783 } 784 } 785 786 public final boolean hasMore() throws NamingException { 787 return names.hasMoreElements(); 788 } 789 790 public final T nextElement() { 791 try { 792 return next(); 793 } catch (NamingException e) { 794 throw new NoSuchElementException(e.toString()); 795 } 796 } 797 798 public abstract T next() throws NamingException; 799 800 public final void close() { 801 names = null; 802 } 803 } 804 805 // Class for enumerating name/class pairs 806 private final class FlatNames extends BaseFlatNames<NameClassPair> { 807 FlatNames (Enumeration<Name> names) { 808 super(names); 809 } 810 811 @Override 812 public NameClassPair next() throws NamingException { 813 Name name = names.nextElement(); 814 String className = bindings.get(name).getClass().getName(); 815 return new NameClassPair(name.toString(), className); 816 } 817 } 818 819 // Class for enumerating bindings 820 private final class FlatBindings extends BaseFlatNames<Binding> { 821 private Hashtable<Name, Object> bds; 822 private Hashtable<String, Object> env; 823 private boolean useFactory; 824 825 FlatBindings(Hashtable<Name, Object> bindings, 826 Hashtable<String, Object> env, 827 boolean useFactory) { 828 super(bindings.keys()); 829 this.env = env; 830 this.bds = bindings; 831 this.useFactory = useFactory; 832 } 833 834 @Override 835 public Binding next() throws NamingException { 836 Name name = names.nextElement(); 837 838 HierMemDirCtx obj = (HierMemDirCtx)bds.get(name); 839 840 Object answer = obj; 841 if (useFactory) { 842 Attributes attrs = obj.getAttributes(""); // only method available 843 try { 844 answer = DirectoryManager.getObjectInstance(obj, 845 name, HierMemDirCtx.this, env, attrs); 846 } catch (NamingException e) { 847 throw e; 848 } catch (Exception e) { 849 NamingException e2 = new NamingException( 850 "Problem calling getObjectInstance"); 851 e2.setRootCause(e); 852 throw e2; 853 } 854 } 855 856 return new Binding(name.toString(), answer); 857 } 858 } 859 860 public class HierContextEnumerator extends ContextEnumerator { 861 public HierContextEnumerator(Context context, int scope) 862 throws NamingException { 863 super(context, scope); 864 } 865 866 protected HierContextEnumerator(Context context, int scope, 867 String contextName, boolean returnSelf) throws NamingException { 868 super(context, scope, contextName, returnSelf); 869 } 870 871 protected NamingEnumeration<Binding> getImmediateChildren(Context ctx) 872 throws NamingException { 873 return ((HierMemDirCtx)ctx).doListBindings(false); 874 } 875 876 protected ContextEnumerator newEnumerator(Context ctx, int scope, 877 String contextName, boolean returnSelf) throws NamingException { 878 return new HierContextEnumerator(ctx, scope, contextName, 879 returnSelf); 880 } 881 } 882 } 883 884 // CompoundNames's HashCode() method isn't good enough for many strings. 885 // The only purpose of this subclass is to have a more discerning 886 // hash function. We'll make up for the performance hit by caching 887 // the hash value. 888 889 final class HierarchicalName extends CompoundName { 890 private int hashValue = -1; 891 892 // Creates an empty name 893 HierarchicalName() { 894 super(new Enumeration<String>() { 895 public boolean hasMoreElements() {return false;} 896 public String nextElement() {throw new NoSuchElementException();} 897 }, 898 HierarchicalNameParser.mySyntax); 899 } 900 901 HierarchicalName(Enumeration<String> comps, Properties syntax) { 902 super(comps, syntax); 903 } 904 905 HierarchicalName(String n, Properties syntax) throws InvalidNameException { 906 super(n, syntax); 907 } 908 909 // just like String.hashCode, only it pays no attention to length 910 public int hashCode() { 911 if (hashValue == -1) { 912 913 String name = toString().toUpperCase(Locale.ENGLISH); 914 int len = name.length(); 915 int off = 0; 916 char val[] = new char[len]; 917 918 name.getChars(0, len, val, 0); 919 920 for (int i = len; i > 0; i--) { 921 hashValue = (hashValue * 37) + val[off++]; 922 } 923 } 924 925 return hashValue; 926 } 927 928 public Name getPrefix(int posn) { 929 Enumeration<String> comps = super.getPrefix(posn).getAll(); 930 return (new HierarchicalName(comps, mySyntax)); 931 } 932 933 public Name getSuffix(int posn) { 934 Enumeration<String> comps = super.getSuffix(posn).getAll(); 935 return (new HierarchicalName(comps, mySyntax)); 936 } 937 938 public Object clone() { 939 return (new HierarchicalName(getAll(), mySyntax)); 940 } 941 942 private static final long serialVersionUID = -6717336834584573168L; 943 } 944 945 // This is the default name parser (used if setNameParser is not called) 946 final class HierarchicalNameParser implements NameParser { 947 static final Properties mySyntax = new Properties(); 948 static { 949 mySyntax.put("jndi.syntax.direction", "left_to_right"); 950 mySyntax.put("jndi.syntax.separator", "/"); 951 mySyntax.put("jndi.syntax.ignorecase", "true"); 952 mySyntax.put("jndi.syntax.escape", "\\"); 953 mySyntax.put("jndi.syntax.beginquote", "\""); 954 //mySyntax.put("jndi.syntax.separator.ava", "+"); 955 //mySyntax.put("jndi.syntax.separator.typeval", "="); 956 mySyntax.put("jndi.syntax.trimblanks", "false"); 957 }; 958 959 public Name parse(String name) throws NamingException { 960 return new HierarchicalName(name, mySyntax); 961 } 962 }