1 17 package org.apache.ldap.server.db.jdbm; 18 19 20 import jdbm.RecordManager; 21 import jdbm.helper.MRU; 22 import jdbm.recman.BaseRecordManager; 23 import jdbm.recman.CacheRecordManager; 24 import org.apache.ldap.common.MultiException; 25 import org.apache.ldap.common.exception.LdapNameNotFoundException; 26 import org.apache.ldap.common.exception.LdapSchemaViolationException; 27 import org.apache.ldap.common.message.LockableAttributesImpl; 28 import org.apache.ldap.common.message.ResultCodeEnum; 29 import org.apache.ldap.common.name.LdapName; 30 import org.apache.ldap.common.schema.AttributeType; 31 import org.apache.ldap.common.schema.Normalizer; 32 import org.apache.ldap.common.util.NamespaceTools; 33 import org.apache.ldap.server.db.*; 34 35 import javax.naming.Name ; 36 import javax.naming.NamingEnumeration ; 37 import javax.naming.NamingException ; 38 import javax.naming.directory.Attribute ; 39 import javax.naming.directory.Attributes ; 40 import javax.naming.directory.DirContext ; 41 import javax.naming.directory.ModificationItem ; 42 import java.io.File ; 43 import java.io.IOException ; 44 import java.math.BigInteger ; 45 import java.util.ArrayList ; 46 import java.util.HashMap ; 47 import java.util.Iterator ; 48 import java.util.Map ; 49 50 51 57 public class JdbmDatabase implements Database 58 { 59 60 private final RecordManager recMan; 61 62 private final Name upSuffix; 63 64 private final Name normSuffix; 65 66 private final String wkdir; 67 68 private final JdbmMasterTable master; 69 70 private final Map indices; 71 72 private final Map sysIndices; 73 74 75 private boolean closed = false; 76 77 78 private Index ndnIdx; 79 80 private Index updnIdx; 81 82 private Index existanceIdx; 83 84 private Index hierarchyIdx; 85 86 private Index oneAliasIdx; 87 88 private Index subAliasIdx; 89 90 private Index aliasIdx; 91 92 93 97 98 106 public JdbmDatabase ( final Name upSuffix, final Name normSuffix, final String wkdirPath ) 107 throws NamingException 108 { 109 this.upSuffix = upSuffix; 110 this.normSuffix = normSuffix; 111 this.wkdir = wkdirPath; 112 113 try 114 { 115 String path = wkdirPath + File.separator + "master"; 116 BaseRecordManager base = new BaseRecordManager( path ); 117 base.disableTransactions(); 118 recMan = new CacheRecordManager( base, new MRU( 1000 ) ); 119 } 120 catch ( IOException e ) 121 { 122 NamingException ne = new NamingException ( 123 "Could not initialize RecordManager" ); 124 ne.setRootCause( e ); 125 throw ne; 126 } 127 128 master = new JdbmMasterTable( recMan ); 129 indices = new HashMap (); 130 sysIndices = new HashMap (); 131 } 132 133 134 138 139 142 public void addIndexOn( AttributeType spec ) throws NamingException 143 { 144 Index idx = new JdbmIndex( spec, wkdir ); 145 indices.put( spec.getName().toLowerCase(), idx ); 146 } 147 148 149 152 public Index getExistanceIndex() 153 { 154 return existanceIdx; 155 } 156 157 158 161 public void setExistanceIndexOn( AttributeType attrType ) throws NamingException 162 { 163 if ( existanceIdx != null ) 164 { 165 NamingException e = new NamingException ( "Index already set!" ); 166 throw e; 167 } 168 169 existanceIdx = new JdbmIndex( attrType, wkdir ); 170 sysIndices.put( attrType.getName().toLowerCase(), existanceIdx ); 171 } 172 173 174 177 public Index getHierarchyIndex() 178 { 179 return hierarchyIdx; 180 } 181 182 183 186 public void setHierarchyIndexOn( AttributeType attrType ) throws NamingException 187 { 188 if ( hierarchyIdx != null ) 189 { 190 NamingException e = new NamingException ( "Index already set!" ); 191 throw e; 192 } 193 194 hierarchyIdx = new JdbmIndex( attrType, wkdir ); 195 sysIndices.put( attrType.getName().toLowerCase(), hierarchyIdx ); 196 } 197 198 199 202 public Index getAliasIndex() 203 { 204 return aliasIdx; 205 } 206 207 208 211 public void setAliasIndexOn( AttributeType attrType ) throws NamingException 212 { 213 if ( aliasIdx != null ) 214 { 215 NamingException e = new NamingException ( "Index already set!" ); 216 throw e; 217 } 218 219 aliasIdx = new JdbmIndex( attrType, wkdir ); 220 sysIndices.put( attrType.getName().toLowerCase(), aliasIdx ); 221 } 222 223 224 227 public Index getOneAliasIndex() 228 { 229 return oneAliasIdx; 230 } 231 232 233 236 public void setOneAliasIndexOn( AttributeType attrType ) throws NamingException 237 { 238 if ( oneAliasIdx != null ) 239 { 240 NamingException e = new NamingException ( "Index already set!" ); 241 throw e; 242 } 243 244 oneAliasIdx = new JdbmIndex( attrType, wkdir ); 245 sysIndices.put( attrType.getName().toLowerCase(), oneAliasIdx ); 246 } 247 248 249 252 public Index getSubAliasIndex() 253 { 254 return subAliasIdx; 255 } 256 257 258 261 public void setSubAliasIndexOn( AttributeType attrType ) throws NamingException 262 { 263 if ( subAliasIdx != null ) 264 { 265 NamingException e = new NamingException ( "Index already set!" ); 266 throw e; 267 } 268 269 subAliasIdx = new JdbmIndex( attrType, wkdir ); 270 sysIndices.put( attrType.getName().toLowerCase(), subAliasIdx ); 271 } 272 273 274 277 public Index getUpdnIndex() 278 { 279 return updnIdx; 280 } 281 282 283 286 public void setUpdnIndexOn( AttributeType attrType ) throws NamingException 287 { 288 if ( updnIdx != null ) 289 { 290 NamingException e = new NamingException ( "Index already set!" ); 291 throw e; 292 } 293 294 updnIdx = new JdbmIndex( attrType, wkdir ); 295 sysIndices.put( attrType.getName().toLowerCase(), updnIdx ); 296 } 297 298 299 302 public Index getNdnIndex() 303 { 304 return ndnIdx; 305 } 306 307 308 311 public void setNdnIndexOn( AttributeType attrType ) throws NamingException 312 { 313 if ( ndnIdx != null ) 314 { 315 NamingException e = new NamingException ( "Index already set!" ); 316 throw e; 317 } 318 319 ndnIdx = new JdbmIndex( attrType, wkdir ); 320 sysIndices.put( attrType.getName().toLowerCase(), ndnIdx ); 321 } 322 323 324 327 public Iterator getUserIndices() 328 { 329 return indices.keySet().iterator(); 330 } 331 332 333 336 public Iterator getSystemIndices() 337 { 338 return sysIndices.keySet().iterator(); 339 } 340 341 342 345 public boolean hasUserIndexOn( String attribute ) 346 { 347 return indices.containsKey( attribute ) || 348 indices.containsKey( attribute.toLowerCase() ); 349 } 350 351 352 355 public boolean hasSystemIndexOn( String attribute ) 356 { 357 return sysIndices.containsKey( attribute ) || 358 sysIndices.containsKey( attribute.toLowerCase() ); 359 } 360 361 362 368 public Index getUserIndex( String attribute ) throws IndexNotFoundException 369 { 370 String lowerCased = attribute.toLowerCase(); 371 372 if ( indices.containsKey( attribute ) ) 373 { 374 return ( Index ) indices.get( attribute ); 375 } 376 else if ( indices.containsKey( lowerCased ) ) 377 { 378 return ( Index ) indices.get( lowerCased ); 379 } 380 else 381 { 382 throw new IndexNotFoundException( "An index on attribute " + 383 attribute + " does not exist!" ); 384 } 385 } 386 387 388 394 public Index getSystemIndex( String indexName ) throws IndexNotFoundException 395 { 396 String lowerCased = indexName.toLowerCase(); 397 398 if ( sysIndices.containsKey( indexName ) ) 399 { 400 return ( Index ) sysIndices.get( indexName ); 401 } 402 else if ( sysIndices.containsKey( lowerCased ) ) 403 { 404 return ( Index ) sysIndices.get( lowerCased ); 405 } 406 else 407 { 408 throw new IndexNotFoundException( "A system index by the name of " + 409 indexName + " does not exist!" ); 410 } 411 } 412 413 414 417 public BigInteger getEntryId( String dn ) throws NamingException 418 { 419 return ndnIdx.forwardLookup( dn ); 420 } 421 422 423 426 public String getEntryDn( BigInteger id ) throws NamingException 427 { 428 return ( String ) ndnIdx.reverseLookup( id ); 429 } 430 431 432 435 public BigInteger getParentId( String dn ) throws NamingException 436 { 437 BigInteger childId = ndnIdx.forwardLookup( dn ); 438 return ( BigInteger ) hierarchyIdx.reverseLookup( childId ); 439 } 440 441 442 445 public BigInteger getParentId( BigInteger childId ) throws NamingException 446 { 447 return ( BigInteger ) hierarchyIdx.reverseLookup( childId ); 448 } 449 450 451 454 public String getEntryUpdn( BigInteger id ) throws NamingException 455 { 456 return ( String ) updnIdx.reverseLookup( id ); 457 } 458 459 460 463 public String getEntryUpdn( String dn ) throws NamingException 464 { 465 BigInteger id = ndnIdx.forwardLookup( dn ); 466 return ( String ) updnIdx.reverseLookup( id ); 467 } 468 469 470 473 public int count() throws NamingException 474 { 475 return master.count(); 476 } 477 478 479 487 private void dropAliasIndices( BigInteger aliasId ) throws NamingException 488 { 489 String targetDn = ( String ) aliasIdx.reverseLookup( aliasId ); 490 BigInteger targetId = getEntryId( targetDn ); 491 String aliasDn = getEntryDn( aliasId ); 492 Name ancestorDn = new LdapName( aliasDn ).getSuffix( 1 ); 493 BigInteger ancestorId = getEntryId( ancestorDn.toString() ); 494 495 506 oneAliasIdx.drop( ancestorId, targetId ); 507 subAliasIdx.drop( ancestorId, targetId ); 508 509 while ( ! ancestorDn.equals( upSuffix ) ) 510 { 511 ancestorDn = ancestorDn.getSuffix( 1 ); 512 ancestorId = getEntryId( ancestorDn.toString() ); 513 514 subAliasIdx.drop( ancestorId, targetId ); 515 } 516 517 aliasIdx.drop( aliasId ); 519 } 520 521 522 532 private void addAliasIndices( BigInteger aliasId, Name aliasDn, 533 String aliasTarget ) throws NamingException 534 { 535 Name targetDn = null; BigInteger targetId = null; Normalizer normalizer = null; Name ancestorDn = null; BigInteger ancestorId = null; 541 normalizer = oneAliasIdx.getAttribute().getEquality().getNormalizer(); 543 targetDn = new LdapName( ( String ) normalizer.normalize( aliasTarget ) ); 544 545 555 if ( aliasDn.startsWith( targetDn ) ) 556 { 557 if ( aliasDn.equals( targetDn ) ) 558 { 559 throw new NamingException ( "[36] aliasDereferencingProblem - " 560 + "attempt to create alias to itself." ); 561 } 562 563 throw new NamingException ( "[36] aliasDereferencingProblem - " 564 + "attempt to create alias with cycle to relative " 565 + aliasTarget + " not allowed from descendent alias " 566 + aliasDn ); 567 } 568 569 577 if ( ! targetDn.startsWith( upSuffix ) ) 578 { 579 throw new NamingException ( "[36] aliasDereferencingProblem -" 581 + " the alias points to an entry outside of the " + upSuffix 582 + " namingContext to an object whose existance cannot be" 583 + " determined." ); 584 } 585 586 targetId = ndnIdx.forwardLookup( targetDn.toString() ); 588 589 595 if ( null == targetId ) 596 { 597 throw new NamingException ( "[33] aliasProblem - " 599 + "the alias when dereferenced would not name a known object " 600 + "the aliasedObjectName must be set to a valid existing " 601 + "entry." ); 602 } 603 604 614 if ( null != aliasIdx.reverseLookup( targetId ) ) 615 { 616 throw new NamingException ( "[36] aliasDereferencingProblem -" 618 + " the alias points to another alias. Alias chaining is" 619 + " not supported by this backend." ); 620 } 621 622 aliasIdx.add( aliasTarget, aliasId ); 624 625 632 ancestorDn = aliasDn.getSuffix( 1 ); 633 ancestorId = getEntryId( ancestorDn.toString() ); 634 635 if ( ! NamespaceTools.isSibling( targetDn, aliasDn ) ) 636 { 637 oneAliasIdx.add( ancestorId, targetId ); 638 } 639 640 650 while ( ! ancestorDn.equals( upSuffix ) && null != ancestorId ) 651 { 652 if ( ! NamespaceTools.isDescendant( ancestorDn, targetDn ) ) 653 { 654 subAliasIdx.add( ancestorId, targetId ); 655 } 656 657 ancestorDn = ancestorDn.getSuffix( 1 ); 658 ancestorId = getEntryId( ancestorDn.toString() ); 659 } 660 } 661 662 663 666 public void add( String updn, Name dn, Attributes entry ) throws NamingException 667 { 668 BigInteger id; 669 BigInteger parentId = null; 670 671 id = master.getNextId(); 672 673 679 if ( dn.equals( normSuffix ) ) 680 { 681 parentId = BigInteger.ZERO; 682 } 683 else 684 { 685 parentId = getEntryId( dn.getSuffix( 1 ).toString() ); 686 } 687 688 if ( parentId == null ) 690 { 691 throw new LdapNameNotFoundException( "Id for parent '" + dn.getSuffix( 1 ).toString() + "' not found!" ); 692 } 693 694 Attribute objectClass = entry.get( "objectClass" ); 695 696 if ( objectClass == null ) 697 { 698 String msg = "Entry " + updn + " contains no objectClass attribute: " + entry; 699 700 throw new LdapSchemaViolationException( msg, ResultCodeEnum.OBJECTCLASSVIOLATION ); 701 } 702 703 706 if ( entry.get( "objectClass" ).contains( ALIAS_OBJECT ) ) 707 { 708 addAliasIndices( id, dn, ( String ) entry.get( ALIAS_ATTRIBUTE ).get() ); 709 } 710 711 ndnIdx.add( dn.toString(), id ); 712 updnIdx.add( updn, id ); 713 hierarchyIdx.add( parentId, id ); 714 715 NamingEnumeration list = entry.getIDs(); 717 while ( list.hasMore() ) 718 { 719 String attribute = ( String ) list.next(); 720 721 if ( hasUserIndexOn( attribute ) ) 722 { 723 Index idx = getUserIndex( attribute ); 724 NamingEnumeration values = entry.get( attribute ).getAll(); 725 726 while ( values.hasMore() ) 727 { 728 idx.add( values.next(), id ); 729 } 730 731 existanceIdx.add( attribute.toLowerCase(), id ); 733 } 734 } 735 736 master.put( entry, id ); 737 } 738 739 740 743 public Attributes lookup( BigInteger id ) throws NamingException 744 { 745 return master.get( id ); 746 } 747 748 749 752 public void delete( BigInteger id ) throws NamingException 753 { 754 Attributes entry = lookup( id ); 755 BigInteger parentId = getParentId( id ); 756 NamingEnumeration attrs = entry.getIDs(); 757 758 if ( entry.get( "objectClass" ).contains( ALIAS_OBJECT ) ) 759 { 760 dropAliasIndices( id ); 761 } 762 763 ndnIdx.drop( id ); 764 updnIdx.drop( id ); 765 hierarchyIdx.drop( id ); 766 767 if ( ! parentId.equals( BigInteger.ZERO ) ) 769 { 770 hierarchyIdx.drop( parentId, id ); 771 } 772 773 while ( attrs.hasMore() ) 774 { 775 String attr = ( ( String ) attrs.next() ); 776 777 if ( hasUserIndexOn( attr ) ) 778 { 779 Index index = getUserIndex( attr ); 780 NamingEnumeration values = entry.get( attr ).getAll(); 781 782 while ( values.hasMore() ) 783 { 784 index.drop( values.next(), id ); 785 } 786 787 existanceIdx.drop( attr.toLowerCase(), id ); 788 } 789 } 790 791 master.delete( id ); 792 } 793 794 795 798 public NamingEnumeration list( BigInteger id ) throws NamingException 799 { 800 return hierarchyIdx.listIndices( id ); 801 } 802 803 804 807 public int getChildCount( BigInteger id ) throws NamingException 808 { 809 return hierarchyIdx.count( id ); 810 } 811 812 813 816 public Name getSuffix() 817 { 818 return upSuffix; 819 } 820 821 822 825 public Attributes getSuffixEntry() throws NamingException 826 { 827 BigInteger id = getEntryId( upSuffix.toString() ); 828 829 if ( null == id ) 830 { 831 return null; 832 } 833 834 return lookup( id ); 835 } 836 837 838 841 public void sync() throws NamingException 842 { 843 ArrayList array = new ArrayList (); 844 array.addAll( indices.values() ); 845 array.add( ndnIdx ); 846 array.add( updnIdx ); 847 array.add( aliasIdx ); 848 array.add( oneAliasIdx ); 849 array.add( subAliasIdx ); 850 array.add( hierarchyIdx ); 851 array.add( existanceIdx ); 852 853 Iterator list = array.iterator(); 854 MultiException rootCause = null; 855 856 while ( list.hasNext() ) 858 { 859 Index idx = ( Index ) list.next(); 860 861 try 862 { 863 idx.sync(); 864 } 865 catch ( Throwable t ) 866 { 867 t.printStackTrace(); 868 if ( null == rootCause ) 869 { 870 rootCause = new MultiException(); 871 } 872 873 rootCause.addThrowable( t ); 874 } 875 } 876 877 try 878 { 879 master.sync(); 880 recMan.commit(); 881 } 882 catch ( Throwable t ) 883 { 884 t.printStackTrace(); 885 if ( null == rootCause ) 886 { 887 rootCause = new MultiException(); 888 } 889 890 rootCause.addThrowable( t ); 891 } 892 893 if ( null != rootCause ) 894 { 895 NamingException ne = new NamingException ( "Failed to sync all" ); 896 ne.setRootCause( rootCause ); 897 throw ne; 898 } 899 } 900 901 902 905 public synchronized void close() throws NamingException 906 { 907 if ( closed ) 908 { 909 return; 910 } 911 912 ArrayList array = new ArrayList (); 913 array.addAll( indices.values() ); 914 915 if ( null != ndnIdx ) 916 { 917 array.add( ndnIdx ); 918 } 919 920 if ( null != updnIdx ) 921 { 922 array.add( updnIdx ); 923 } 924 925 if ( null != aliasIdx ) 926 { 927 array.add( aliasIdx ); 928 } 929 930 if ( null != oneAliasIdx ) 931 { 932 array.add( oneAliasIdx ); 933 } 934 935 if ( null != subAliasIdx ) 936 { 937 array.add( subAliasIdx ); 938 } 939 940 if ( null != hierarchyIdx ) 941 { 942 array.add( hierarchyIdx ); 943 } 944 945 if ( null != existanceIdx ) 946 { 947 array.add( existanceIdx ); 948 } 949 950 Iterator list = array.iterator(); 951 MultiException rootCause = null; 952 953 while ( list.hasNext() ) 954 { 955 Index index = ( Index ) list.next(); 956 957 try 958 { 959 index.close(); 960 } 961 catch ( Throwable t ) 962 { 963 if ( null == rootCause ) 964 { 965 rootCause = new MultiException(); 966 } 967 968 rootCause.addThrowable( t ); 969 } 970 } 971 972 try 973 { 974 master.close(); 975 } 976 catch ( Throwable t ) 977 { 978 if ( null == rootCause ) 979 { 980 rootCause = new MultiException(); 981 } 982 983 rootCause.addThrowable( t ); 984 } 985 986 try 987 { 988 recMan.close(); 989 } 990 catch ( Throwable t ) 991 { 992 if ( null == rootCause ) 993 { 994 rootCause = new MultiException(); 995 } 996 997 rootCause.addThrowable( t ); 998 } 999 1000 closed = true; 1001 1002 if ( null != rootCause ) 1003 { 1004 NamingException ne = new NamingException ( "Failed to close all" ); 1005 ne.setRootCause( rootCause ); 1006 throw ne; 1007 } 1008 } 1009 1010 1011 1014 public boolean isClosed() 1015 { 1016 return closed; 1017 } 1018 1019 1020 1023 public void setProperty( String propertyName, String propertyValue ) 1024 throws NamingException 1025 { 1026 master.setProperty( propertyName, propertyValue ); 1027 } 1028 1029 1030 1033 public String getProperty( String propertyName ) throws NamingException 1034 { 1035 return master.getProperty( propertyName ); 1036 } 1037 1038 1039 1042 public Attributes getIndices( BigInteger id ) throws NamingException 1043 { 1044 Attributes attributes = new LockableAttributesImpl(); 1045 1046 attributes.put( "_nDn", getEntryDn( id ) ); 1048 attributes.put( "_upDn", getEntryUpdn( id ) ); 1049 attributes.put( "_parent", getParentId( id ) ); 1050 1051 Iterator idxList = this.indices.values().iterator(); 1053 while ( idxList.hasNext() ) 1054 { 1055 Index index = ( Index ) idxList.next(); 1056 NamingEnumeration list = index.listReverseIndices( id ); 1057 while ( list.hasMore() ) 1058 { 1059 IndexRecord rec = ( IndexRecord ) list.next(); 1060 Object val = rec.getIndexKey(); 1061 attributes.put( index.getAttribute().getName(), val ); 1062 } 1063 } 1064 1065 NamingEnumeration list = existanceIdx.listReverseIndices( id ); 1068 StringBuffer val = new StringBuffer (); 1069 while ( list.hasMore() ) 1070 { 1071 IndexRecord rec = ( IndexRecord ) list.next(); 1072 val.append( "_existance[" ); 1073 val.append( rec.getIndexKey() ); 1074 val.append( "]" ); 1075 attributes.put( val.toString(), rec.getEntryId() ); 1076 val.setLength( 0 ); 1077 } 1078 1079 list = hierarchyIdx.listIndices( id ); 1082 while ( list.hasMore() ) 1083 { 1084 IndexRecord rec = ( IndexRecord ) list.next(); 1085 attributes.put( "_child", rec.getEntryId() ); 1086 } 1087 1088 return attributes; 1089 } 1090 1091 1092 1103 private void add( BigInteger id, Attributes entry, Attribute mods ) 1104 throws NamingException 1105 { 1106 if ( hasUserIndexOn( mods.getID() ) ) 1107 { 1108 Index idx = getUserIndex( mods.getID() ); 1109 idx.add( mods, id ); 1110 1111 if ( ! existanceIdx.hasValue( mods.getID(), id ) ) 1113 { 1114 idx.add( mods.getID(), id ); 1115 } 1116 } 1117 1118 entry.put( mods ); 1119 1120 if ( mods.getID().equals( ALIAS_ATTRIBUTE ) ) 1121 { 1122 String ndnStr = ( String ) ndnIdx.reverseLookup( id ); 1123 addAliasIndices( id, new LdapName( ndnStr ), 1124 ( String ) mods.get() ); 1125 } 1126 } 1127 1128 1129 1143 private void remove( BigInteger id, Attributes entry, Attribute mods ) 1144 throws NamingException 1145 { 1146 if ( hasUserIndexOn( mods.getID() ) ) 1147 { 1148 Index idx = getUserIndex( mods.getID() ); 1149 idx.drop( mods, id ); 1150 1151 1155 if ( null == idx.reverseLookup( id ) ) 1156 { 1157 existanceIdx.drop( mods.getID(), id ); 1158 } 1159 } 1160 1161 1167 if ( mods.size() == 0 ) 1168 { 1169 entry.remove( mods.getID() ); 1170 } 1171 else 1172 { 1173 Attribute entryAttr = entry.get( mods.getID() ); 1174 NamingEnumeration values = mods.getAll(); 1175 while ( values.hasMore() ) 1176 { 1177 entryAttr.remove( values.next() ); 1178 } 1179 } 1180 1181 if ( mods.getID().equals( ALIAS_ATTRIBUTE ) ) 1183 { 1184 dropAliasIndices( id ); 1185 } 1186 } 1187 1188 1189 1201 private void replace( BigInteger id, Attributes entry, Attribute mods ) 1202 throws NamingException 1203 { 1204 if ( hasUserIndexOn( mods.getID() ) ) 1205 { 1206 Index idx = getUserIndex( mods.getID() ); 1207 1208 idx.drop( id ); 1210 idx.add( mods, id ); 1211 1212 1216 if ( null == idx.reverseLookup( id ) ) 1217 { 1218 existanceIdx.drop( mods.getID(), id ); 1219 } 1220 } 1221 1222 if ( mods.getID().equals( ALIAS_ATTRIBUTE ) ) 1223 { 1224 dropAliasIndices( id ); 1225 } 1226 1227 entry.put( mods ); 1229 1230 if ( mods.getID().equals( ALIAS_ATTRIBUTE ) ) 1231 { 1232 String ndnStr = ( String ) ndnIdx.reverseLookup( id ); 1233 addAliasIndices( id, new LdapName( ndnStr ), 1234 ( String ) mods.get() ); 1235 } 1236 } 1237 1238 1239 1243 public void modify( Name dn, int modOp, Attributes mods ) throws NamingException 1244 { 1245 NamingEnumeration attrs = null; 1246 BigInteger id = getEntryId( dn.toString() ); 1247 Attributes entry = master.get( id ); 1248 1249 switch ( modOp ) 1250 { 1251 case( DirContext.ADD_ATTRIBUTE ): 1252 attrs = mods.getIDs(); 1253 1254 while ( attrs.hasMore() ) 1255 { 1256 String attrId = ( String ) attrs.next(); 1257 Attribute attr = mods.get( attrId ); 1258 add( id, entry, attr ); 1259 } 1260 1261 break; 1262 case( DirContext.REMOVE_ATTRIBUTE ): 1263 attrs = mods.getIDs(); 1264 1265 while ( attrs.hasMore() ) 1266 { 1267 String attrId = ( String ) attrs.next(); 1268 Attribute attr = mods.get( attrId ); 1269 remove( id, entry, attr ); 1270 } 1271 1272 break; 1273 case( DirContext.REPLACE_ATTRIBUTE ): 1274 attrs = mods.getIDs(); 1275 1276 while ( attrs.hasMore() ) 1277 { 1278 String attrId = ( String ) attrs.next(); 1279 Attribute attr = mods.get( attrId ); 1280 replace( id, entry, attr ); 1281 } 1282 1283 break; 1284 default: 1285 throw new NamingException ( 1286 "Unidentified modification operation" ); 1287 } 1288 1289 master.put( entry, id ); 1290 } 1291 1292 1293 1297 public void modify( Name dn, ModificationItem [] mods ) throws NamingException 1298 { 1299 BigInteger id = getEntryId( dn.toString() ); 1300 Attributes entry = master.get( id ); 1301 1302 for ( int ii = 0; ii < mods.length; ii++ ) 1303 { 1304 Attribute attrMods = mods[ii].getAttribute(); 1305 1306 switch ( mods[ ii ].getModificationOp() ) 1307 { 1308 case( DirContext.ADD_ATTRIBUTE ): 1309 add( id, entry, attrMods ); 1310 break; 1311 case( DirContext.REMOVE_ATTRIBUTE ): 1312 remove( id, entry, attrMods ); 1313 break; 1314 case( DirContext.REPLACE_ATTRIBUTE ): 1315 replace( id, entry, attrMods ); 1316 break; 1317 default: 1318 throw new NamingException ( 1319 "Unidentified modification operation" ); 1320 } 1321 } 1322 1323 master.put( entry, id ); 1324 } 1325 1326 1327 1346 public void modifyRdn( Name dn, String newRdn, boolean deleteOldRdn ) 1347 throws NamingException 1348 { 1349 String newRdnAttr = NamespaceTools.getRdnAttribute( newRdn ); 1350 String newRdnValue = NamespaceTools.getRdnValue( newRdn ); 1351 BigInteger id = getEntryId( dn.toString() ); 1352 Attributes entry = lookup( id ); 1353 Name updn = new LdapName( getEntryUpdn( id ) ); 1354 1355 1363 1364 entry.put( newRdnAttr, newRdnValue ); 1365 1366 if ( hasUserIndexOn( newRdnAttr ) ) 1367 { 1368 Index idx = getUserIndex( newRdnAttr ); 1369 idx.add( newRdnValue, id ); 1370 1371 if ( ! existanceIdx.hasValue( newRdnAttr, id ) ) 1373 { 1374 existanceIdx.add( newRdnAttr, id ); 1375 } 1376 } 1377 1378 1391 1392 if ( deleteOldRdn ) 1393 { 1394 String oldRdn = updn.get( updn.size() - 1 ); 1395 String oldRdnAttr = NamespaceTools.getRdnAttribute( oldRdn ); 1396 String oldRdnValue = NamespaceTools.getRdnValue( oldRdn ); 1397 1398 entry.get( oldRdnAttr ).remove( oldRdnValue ); 1399 1400 if ( hasUserIndexOn( oldRdnAttr ) ) 1401 { 1402 Index idx = getUserIndex( oldRdnAttr ); 1403 idx.drop( oldRdnValue, id ); 1404 1405 1409 if ( null == idx.reverseLookup( id ) ) 1410 { 1411 existanceIdx.drop( oldRdnAttr, id ); 1412 } 1413 } 1414 } 1415 1416 1426 1427 Name newUpdn = ( Name ) updn.clone(); newUpdn.remove( newUpdn.size() - 1 ); newUpdn.add( newUpdn.size(), newRdn ); modifyDn( id, newUpdn, false ); } 1432 1433 1434 1440 1441 1451 private void modifyDn( BigInteger id, Name updn, boolean isMove ) 1452 throws NamingException 1453 { 1454 String aliasTarget = null; 1455 1456 ndnIdx.drop( id ); 1458 ndnIdx.add( ndnIdx.getNormalized( updn.toString() ), id ); 1459 1460 updnIdx.drop( id ); 1461 updnIdx.add( updn.toString(), id ); 1462 1463 1473 if ( isMove ) 1474 { 1475 aliasTarget = ( String ) aliasIdx.reverseLookup( id ); 1476 1477 if ( null != aliasTarget ) 1478 { 1479 addAliasIndices( id, new LdapName( getEntryDn( id ) ), 1480 aliasTarget ); 1481 } 1482 } 1483 1484 NamingEnumeration children = list( id ); 1485 while ( children.hasMore() ) 1486 { 1487 IndexRecord rec = ( IndexRecord ) children.next(); 1489 BigInteger childId = rec.getEntryId(); 1490 1491 1495 Name childUpdn = ( Name ) updn.clone(); 1496 Name oldUpdn = new LdapName( getEntryUpdn( childId ) ); 1497 String rdn = LdapName.getRdn( oldUpdn ); 1498 childUpdn.add( childUpdn.size(), rdn ); 1499 1500 modifyDn( childId, childUpdn, isMove ); 1502 } 1503 } 1504 1505 1506 1510 public void move( Name oldChildDn, Name newParentDn, String newRdn, 1511 boolean deleteOldRdn ) throws NamingException 1512 { 1513 modifyRdn( oldChildDn, newRdn, deleteOldRdn ); 1514 move( oldChildDn, newParentDn ); 1515 } 1516 1517 1518 1534 public void move( Name oldChildDn, Name newParentDn ) throws NamingException 1535 { 1536 BigInteger childId = getEntryId( oldChildDn.toString() ); 1538 BigInteger newParentId = getEntryId( newParentDn.toString() ); 1539 BigInteger oldParentId = getParentId( childId ); 1540 1541 1549 dropMovedAliasIndices( oldChildDn ); 1550 1551 1555 hierarchyIdx.drop( oldParentId, childId ); 1556 hierarchyIdx.add( newParentId, childId ); 1557 1558 1563 Name childUpdn = new LdapName( getEntryUpdn( childId ) ); 1564 String childRdn = childUpdn.get( childUpdn.size() - 1 ); 1565 Name newUpdn = new LdapName( getEntryUpdn( newParentId ) ); 1566 newUpdn.add( newUpdn.size(), childRdn ); 1567 1568 modifyDn( childId, newUpdn, true ); 1570 } 1571 1572 1573 1581 private void dropMovedAliasIndices( final Name movedBase ) throws NamingException 1582 { 1583 IndexAssertion isBaseDescendant = new IndexAssertion() 1585 { 1586 public boolean assertCandidate( IndexRecord rec ) 1587 throws NamingException 1588 { 1589 String dn = getEntryDn( rec.getEntryId() ); 1590 if ( dn.endsWith( movedBase.toString() ) ) 1591 { 1592 return true; 1593 } 1594 1595 return false; 1596 } 1597 }; 1598 1599 BigInteger movedBaseId = getEntryId( movedBase.toString() ); 1600 if ( aliasIdx.reverseLookup( movedBaseId ) != null ) 1601 { 1602 dropAliasIndices( movedBaseId, movedBase ); 1603 } 1604 1605 NamingEnumeration aliases = new IndexAssertionEnumeration( 1606 aliasIdx.listIndices( movedBase.toString(), true ), 1607 isBaseDescendant ); 1608 while ( aliases.hasMore() ) 1609 { 1610 IndexRecord entry = ( IndexRecord ) aliases.next(); 1611 dropAliasIndices( entry.getEntryId(), movedBase ); 1612 } 1613 } 1614 1615 1616 1624 private void dropAliasIndices( BigInteger aliasId, Name movedBase ) 1625 throws NamingException 1626 { 1627 String targetDn = ( String ) aliasIdx.reverseLookup( aliasId ); 1628 BigInteger targetId = getEntryId( targetDn ); 1629 String aliasDn = getEntryDn( aliasId ); 1630 1631 1635 Name ancestorDn = movedBase.getSuffix( 1 ); 1636 BigInteger ancestorId = getEntryId( ancestorDn.toString() ); 1637 1638 1650 if ( aliasDn.equals( movedBase.toString() ) ) 1651 { 1652 oneAliasIdx.drop( ancestorId, targetId ); 1653 } 1654 1655 subAliasIdx.drop( ancestorId, targetId ); 1656 1657 while ( ! ancestorDn.equals( upSuffix ) ) 1658 { 1659 ancestorDn = ancestorDn.getSuffix( 1 ); 1660 ancestorId = getEntryId( ancestorDn.toString() ); 1661 1662 subAliasIdx.drop( ancestorId, targetId ); 1663 } 1664 } 1665} 1666 1667 | Popular Tags |