001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.server.core.partition.avl; 021 022 023 import java.io.File; 024 import java.util.ArrayList; 025 import java.util.HashMap; 026 import java.util.HashSet; 027 import java.util.Iterator; 028 import java.util.List; 029 import java.util.Map; 030 import java.util.Set; 031 032 import org.apache.directory.server.constants.ApacheSchemaConstants; 033 import org.apache.directory.server.core.entry.ClonedServerEntry; 034 import org.apache.directory.server.core.partition.impl.btree.LongComparator; 035 import org.apache.directory.server.i18n.I18n; 036 import org.apache.directory.server.xdbm.Index; 037 import org.apache.directory.server.xdbm.IndexCursor; 038 import org.apache.directory.server.xdbm.IndexEntry; 039 import org.apache.directory.server.xdbm.IndexNotFoundException; 040 import org.apache.directory.server.xdbm.Store; 041 import org.apache.directory.shared.ldap.constants.SchemaConstants; 042 import org.apache.directory.shared.ldap.cursor.Cursor; 043 import org.apache.directory.shared.ldap.entry.StringValue; 044 import org.apache.directory.shared.ldap.entry.EntryAttribute; 045 import org.apache.directory.shared.ldap.entry.Modification; 046 import org.apache.directory.shared.ldap.entry.ModificationOperation; 047 import org.apache.directory.shared.ldap.entry.ServerEntry; 048 import org.apache.directory.shared.ldap.entry.Value; 049 import org.apache.directory.shared.ldap.exception.LdapException; 050 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 051 import org.apache.directory.shared.ldap.exception.LdapNoSuchObjectException; 052 import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException; 053 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 054 import org.apache.directory.shared.ldap.name.AVA; 055 import org.apache.directory.shared.ldap.name.DN; 056 import org.apache.directory.shared.ldap.name.RDN; 057 import org.apache.directory.shared.ldap.schema.AttributeType; 058 import org.apache.directory.shared.ldap.schema.MatchingRule; 059 import org.apache.directory.shared.ldap.schema.SchemaManager; 060 import org.apache.directory.shared.ldap.util.NamespaceTools; 061 import org.slf4j.Logger; 062 import org.slf4j.LoggerFactory; 063 064 065 /** 066 * A Store implementation backed by in memory AVL trees. 067 * 068 * TODO - this class is extremely like the JdbmStore implementation of the 069 * Store interface which tells us that it's best for us to have some kind 070 * of abstract class. 071 * 072 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 073 * @version $Rev$, $Date$ 074 */ 075 public class AvlStore<E> implements Store<E, Long> 076 { 077 /** static logger */ 078 private static final Logger LOG = LoggerFactory.getLogger( AvlStore.class ); 079 080 /** Two static declaration to avoid lookup all over the code */ 081 private static AttributeType OBJECT_CLASS_AT; 082 private static AttributeType ALIASED_OBJECT_NAME_AT; 083 084 /** the master table storing entries by primary key */ 085 private AvlMasterTable<ServerEntry> master; 086 087 /** the normalized distinguished name index */ 088 private AvlIndex<String, E> ndnIdx; 089 090 /** the user provided distinguished name index */ 091 private AvlIndex<String, E> updnIdx; 092 093 /** the attribute existence index */ 094 private AvlIndex<String, E> existenceIdx; 095 096 /** a system index on aliasedObjectName attribute */ 097 private AvlIndex<String, E> aliasIdx; 098 099 /** a system index on the entries of descendants of root DN*/ 100 private AvlIndex<Long, E> subLevelIdx; 101 102 /** the parent child relationship index */ 103 private AvlIndex<Long, E> oneLevelIdx; 104 105 /** the one level scope alias index */ 106 private AvlIndex<Long, E> oneAliasIdx; 107 108 /** the subtree scope alias index */ 109 private AvlIndex<Long, E> subAliasIdx; 110 111 /** a system index on objectClass attribute*/ 112 private AvlIndex<String, E> objectClassIdx; 113 114 /** a system index on entryCSN attribute */ 115 private AvlIndex<String, E> entryCsnIdx; 116 117 /** a system index on entryUUID attribute */ 118 private AvlIndex<String, E> entryUuidIdx; 119 120 /** a map of attributeType numeric ID to user userIndices */ 121 private Map<String, AvlIndex<? extends Object, E>> userIndices = new HashMap<String, AvlIndex<? extends Object, E>>(); 122 123 /** a map of attributeType numeric ID to system userIndices */ 124 private Map<String, AvlIndex<? extends Object, E>> systemIndices = new HashMap<String, AvlIndex<? extends Object, E>>(); 125 126 /** true if initialized */ 127 private boolean initialized; 128 129 /** A pointer on the schemaManager */ 130 private SchemaManager schemaManager; 131 132 /** 133 * TODO we need to check out why we have so many suffix 134 * dn and string accessor/mutators on both Store and Partition 135 * interfaces. I think a lot of this comes from the fact 136 * that we implemented DN to have both the up and norm 137 * names. 138 */ 139 private DN suffixDn; 140 141 private String name; 142 143 144 /** 145 * {@inheritDoc} 146 */ 147 public void add( ServerEntry entry ) throws Exception 148 { 149 if ( entry instanceof ClonedServerEntry ) 150 { 151 throw new Exception( I18n.err( I18n.ERR_215 ) ); 152 } 153 154 DN normName = entry.getDn(); 155 156 Long id; 157 Long parentId; 158 159 id = master.getNextId(); 160 161 // 162 // Suffix entry cannot have a parent since it is the root so it is 163 // capped off using the zero value which no entry can have since 164 // entry sequences start at 1. 165 // 166 167 DN parentDn = null; 168 169 if ( normName.getNormName().equals( suffixDn.getNormName() ) ) 170 { 171 parentId = 0L; 172 } 173 else 174 { 175 parentDn = ( DN ) normName.clone(); 176 parentDn.remove( parentDn.size() - 1 ); 177 parentId = getEntryId( parentDn.getNormName() ); 178 } 179 180 // don't keep going if we cannot find the parent Id 181 if ( parentId == null ) 182 { 183 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_216, parentDn ) ); 184 } 185 186 EntryAttribute objectClass = entry.get( OBJECT_CLASS_AT ); 187 188 if ( objectClass == null ) 189 { 190 String msg = I18n.err( I18n.ERR_217, normName.getName(), entry ); 191 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, msg ); 192 } 193 194 // Start adding the system userIndices 195 // Why bother doing a lookup if this is not an alias. 196 // First, the ObjectClass index 197 for ( Value<?> value : objectClass ) 198 { 199 objectClassIdx.add( value.getString(), id ); 200 } 201 202 if ( objectClass.contains( SchemaConstants.ALIAS_OC ) ) 203 { 204 EntryAttribute aliasAttr = entry.get( ALIASED_OBJECT_NAME_AT ); 205 addAliasIndices( id, normName, aliasAttr.getString() ); 206 } 207 208 if ( !Character.isDigit( normName.getNormName().charAt( 0 ) ) ) 209 { 210 throw new IllegalStateException( I18n.err( I18n.ERR_218, normName.getNormName() ) ); 211 } 212 213 ndnIdx.add( normName.getNormName(), id ); 214 updnIdx.add( normName.getName(), id ); 215 oneLevelIdx.add( parentId, id ); 216 217 // Update the EntryCsn index 218 EntryAttribute entryCsn = entry.get( SchemaConstants.ENTRY_CSN_AT ); 219 220 if ( entryCsn == null ) 221 { 222 String msg = I18n.err( I18n.ERR_219, normName.getName(), entry ); 223 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, msg ); 224 } 225 226 entryCsnIdx.add( entryCsn.getString(), id ); 227 228 // Update the EntryUuid index 229 EntryAttribute entryUuid = entry.get( SchemaConstants.ENTRY_UUID_AT ); 230 231 if ( entryUuid == null ) 232 { 233 String msg = I18n.err( I18n.ERR_220, normName.getName(), entry ); 234 throw new LdapSchemaViolationException( ResultCodeEnum.OBJECT_CLASS_VIOLATION, msg ); 235 } 236 237 entryUuidIdx.add( entryUuid.getString(), id ); 238 239 Long tempId = parentId; 240 while ( tempId != null && tempId != 0 && tempId != 1 ) 241 { 242 subLevelIdx.add( tempId, id ); 243 tempId = getParentId( tempId ); 244 } 245 246 // making entry an ancestor/descendent of itself in sublevel index 247 subLevelIdx.add( id, id ); 248 249 // Now work on the user defined userIndices 250 for ( EntryAttribute attribute : entry ) 251 { 252 String attributeOid = attribute.getAttributeType().getOid(); 253 254 if ( hasUserIndexOn( attributeOid ) ) 255 { 256 Index<Object, E, Long> idx = ( Index<Object, E, Long> ) getUserIndex( attributeOid ); 257 258 // here lookup by attributeId is OK since we got attributeId from 259 // the entry via the enumeration - it's in there as is for sure 260 261 for ( Value<?> value : attribute ) 262 { 263 idx.add( value.get(), id ); 264 } 265 266 // Adds only those attributes that are indexed 267 existenceIdx.add( attributeOid, id ); 268 } 269 } 270 271 master.put( id, entry ); 272 } 273 274 275 /** 276 * {@inheritDoc} 277 */ 278 public void addIndex( Index<? extends Object, E, Long> index ) throws Exception 279 { 280 if ( index instanceof AvlIndex<?, ?> ) 281 { 282 userIndices.put( index.getAttributeId(), ( AvlIndex<? extends Object, E> ) index ); 283 } 284 else 285 { 286 userIndices.put( index.getAttributeId(), ( AvlIndex<? extends Object, E> ) convert( index ) ); 287 } 288 } 289 290 291 /** 292 * {@inheritDoc} 293 */ 294 public int count() throws Exception 295 { 296 return master.count(); 297 } 298 299 300 /** 301 * {@inheritDoc} 302 */ 303 @SuppressWarnings("unchecked") 304 public void delete( Long id ) throws Exception 305 { 306 ServerEntry entry = lookup( id ); 307 Long parentId = getParentId( id ); 308 309 EntryAttribute objectClass = entry.get( OBJECT_CLASS_AT ); 310 311 if ( objectClass.contains( SchemaConstants.ALIAS_OC ) ) 312 { 313 dropAliasIndices( id ); 314 } 315 316 for ( Value<?> value : objectClass ) 317 { 318 objectClassIdx.drop( value.getString(), id ); 319 } 320 321 ndnIdx.drop( id ); 322 updnIdx.drop( id ); 323 oneLevelIdx.drop( id ); 324 entryCsnIdx.drop( id ); 325 entryUuidIdx.drop( id ); 326 327 if ( id != 1 ) 328 { 329 subLevelIdx.drop( id ); 330 } 331 332 // Remove parent's reference to entry only if entry is not the upSuffix 333 if ( !parentId.equals( 0L ) ) 334 { 335 oneLevelIdx.drop( parentId, id ); 336 } 337 338 for ( EntryAttribute attribute : entry ) 339 { 340 String attributeOid = attribute.getAttributeType().getOid(); 341 342 if ( hasUserIndexOn( attributeOid ) ) 343 { 344 Index<?, E, Long> index = getUserIndex( attributeOid ); 345 346 // here lookup by attributeId is ok since we got attributeId from 347 // the entry via the enumeration - it's in there as is for sure 348 for ( Value<?> value : attribute ) 349 { 350 ( ( AvlIndex ) index ).drop( value.get(), id ); 351 } 352 353 existenceIdx.drop( attributeOid, id ); 354 } 355 } 356 357 master.delete( id ); 358 } 359 360 361 /** 362 * {@inheritDoc} 363 */ 364 public void destroy() throws Exception 365 { 366 // don't reset initialized flag 367 //initialized = false; 368 } 369 370 371 /** 372 * {@inheritDoc} 373 */ 374 public Index<String, E, Long> getAliasIndex() 375 { 376 return aliasIdx; 377 } 378 379 380 /** 381 * {@inheritDoc} 382 */ 383 public int getChildCount( Long id ) throws Exception 384 { 385 return oneLevelIdx.count( id ); 386 } 387 388 389 /** 390 * {@inheritDoc} 391 */ 392 public String getEntryDn( Long id ) throws Exception 393 { 394 return ndnIdx.reverseLookup( id ); 395 } 396 397 398 /** 399 * {@inheritDoc} 400 */ 401 public Long getEntryId( String dn ) throws Exception 402 { 403 return ndnIdx.forwardLookup( dn ); 404 } 405 406 407 /** 408 * {@inheritDoc} 409 */ 410 public String getEntryUpdn( Long id ) throws Exception 411 { 412 return updnIdx.reverseLookup( id ); 413 } 414 415 416 /** 417 * {@inheritDoc} 418 */ 419 public String getEntryUpdn( String dn ) throws Exception 420 { 421 Long id = ndnIdx.forwardLookup( dn ); 422 return updnIdx.reverseLookup( id ); 423 } 424 425 426 /** 427 * {@inheritDoc} 428 */ 429 public String getName() 430 { 431 return name; 432 } 433 434 435 /** 436 * {@inheritDoc} 437 */ 438 public Index<String, E, Long> getNdnIndex() 439 { 440 return ndnIdx; 441 } 442 443 444 /** 445 * {@inheritDoc} 446 */ 447 public Index<Long, E, Long> getOneAliasIndex() 448 { 449 return oneAliasIdx; 450 } 451 452 453 /** 454 * {@inheritDoc} 455 */ 456 public Index<Long, E, Long> getOneLevelIndex() 457 { 458 return oneLevelIdx; 459 } 460 461 462 /** 463 * {@inheritDoc} 464 */ 465 public Long getParentId( String dn ) throws Exception 466 { 467 Long childId = ndnIdx.forwardLookup( dn ); 468 return oneLevelIdx.reverseLookup( childId ); 469 } 470 471 472 /** 473 * {@inheritDoc} 474 */ 475 public Long getParentId( Long childId ) throws Exception 476 { 477 return oneLevelIdx.reverseLookup( childId ); 478 } 479 480 481 /** 482 * {@inheritDoc} 483 */ 484 public Index<String, E, Long> getPresenceIndex() 485 { 486 return existenceIdx; 487 } 488 489 490 /** 491 * {@inheritDoc} 492 */ 493 public String getProperty( String propertyName ) throws Exception 494 { 495 return master.getProperty( propertyName ); 496 } 497 498 499 /** 500 * {@inheritDoc} 501 */ 502 public Index<Long, E, Long> getSubAliasIndex() 503 { 504 return subAliasIdx; 505 } 506 507 508 /** 509 * {@inheritDoc} 510 */ 511 public Index<Long, E, Long> getSubLevelIndex() 512 { 513 return subLevelIdx; 514 } 515 516 517 /** 518 * {@inheritDoc} 519 */ 520 public DN getSuffix() 521 { 522 if ( suffixDn == null ) 523 { 524 return null; 525 } 526 527 try 528 { 529 return new DN( suffixDn.getNormName() ); 530 } 531 catch ( LdapInvalidDnException e ) 532 { 533 // shouldn't happen 534 LOG.error( "", e ); 535 } 536 537 return null; 538 } 539 540 541 /** 542 * {@inheritDoc} 543 */ 544 public DN getUpSuffix() 545 { 546 if ( suffixDn == null ) 547 { 548 return null; 549 } 550 551 try 552 { 553 return new DN( suffixDn.getName() ); 554 } 555 catch ( LdapInvalidDnException e ) 556 { 557 // shouldn't happen 558 LOG.error( "", e ); 559 } 560 561 return null; 562 } 563 564 565 public String getSuffixDn() 566 { 567 if ( suffixDn == null ) 568 { 569 return null; 570 } 571 572 return suffixDn.getName(); 573 } 574 575 576 /** 577 * {@inheritDoc} 578 */ 579 public Index<?, E, Long> getSystemIndex( String id ) throws IndexNotFoundException 580 { 581 try 582 { 583 id = schemaManager.getAttributeTypeRegistry().getOidByName( id ); 584 } 585 catch ( LdapException e ) 586 { 587 LOG.error( I18n.err( I18n.ERR_1, id ), e.getLocalizedMessage() ); 588 throw new IndexNotFoundException( I18n.err( I18n.ERR_1, id ), id, e ); 589 } 590 591 if ( systemIndices.containsKey( id ) ) 592 { 593 return systemIndices.get( id ); 594 } 595 596 throw new IndexNotFoundException( I18n.err( I18n.ERR_2, id, name ) ); 597 } 598 599 600 /** 601 * {@inheritDoc} 602 */ 603 public Index<?, E, Long> getIndex( String id ) throws IndexNotFoundException 604 { 605 try 606 { 607 id = schemaManager.getAttributeTypeRegistry().getOidByName( id ); 608 } 609 catch ( LdapException e ) 610 { 611 LOG.error( I18n.err( I18n.ERR_1, id ), e.getLocalizedMessage() ); 612 throw new IndexNotFoundException( I18n.err( I18n.ERR_1, id ), id, e ); 613 } 614 615 if ( userIndices.containsKey( id ) ) 616 { 617 return userIndices.get( id ); 618 } 619 if ( systemIndices.containsKey( id ) ) 620 { 621 return systemIndices.get( id ); 622 } 623 624 throw new IndexNotFoundException( I18n.err( I18n.ERR_2, id, name ) ); 625 } 626 627 628 /** 629 * {@inheritDoc} 630 */ 631 public Index<String, E, Long> getUpdnIndex() 632 { 633 return updnIdx; 634 } 635 636 637 /** 638 * {@inheritDoc} 639 */ 640 public Index<? extends Object, E, Long> getUserIndex( String id ) throws IndexNotFoundException 641 { 642 try 643 { 644 id = schemaManager.getAttributeTypeRegistry().getOidByName( id ); 645 } 646 catch ( LdapException e ) 647 { 648 LOG.error( I18n.err( I18n.ERR_1, id ), e.getLocalizedMessage() ); 649 throw new IndexNotFoundException( I18n.err( I18n.ERR_1, id ), id, e ); 650 } 651 652 if ( userIndices.containsKey( id ) ) 653 { 654 return userIndices.get( id ); 655 } 656 657 throw new IndexNotFoundException( I18n.err( I18n.ERR_3, id, name ) ); 658 } 659 660 661 /** 662 * {@inheritDoc} 663 */ 664 public Set<Index<? extends Object, E, Long>> getUserIndices() 665 { 666 return new HashSet<Index<? extends Object, E, Long>>( userIndices.values() ); 667 } 668 669 670 /** 671 * {@inheritDoc} 672 */ 673 public boolean hasIndexOn( String id ) throws Exception 674 { 675 return hasUserIndexOn( id ) || hasSystemIndexOn( id ); 676 } 677 678 679 /** 680 * {@inheritDoc} 681 */ 682 public boolean hasSystemIndexOn( String id ) throws Exception 683 { 684 return systemIndices.containsKey( id ); 685 } 686 687 688 /** 689 * {@inheritDoc} 690 */ 691 public boolean hasUserIndexOn( String id ) throws Exception 692 { 693 return userIndices.containsKey( id ); 694 } 695 696 697 /** 698 * {@inheritDoc} 699 * TODO why this and initRegistries on Store interface ??? 700 */ 701 public void init( SchemaManager schemaManager ) throws Exception 702 { 703 this.schemaManager = schemaManager; 704 705 OBJECT_CLASS_AT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT ); 706 ALIASED_OBJECT_NAME_AT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.ALIASED_OBJECT_NAME_AT ); 707 708 // Create the master table (the table containing all the entries) 709 master = new AvlMasterTable<ServerEntry>( name, new LongComparator(), null, false ); 710 711 suffixDn.normalize( schemaManager.getNormalizerMapping() ); 712 // ------------------------------------------------------------------- 713 // Initializes the user and system indices 714 // ------------------------------------------------------------------- 715 716 setupSystemIndices(); 717 setupUserIndices(); 718 719 // We are done ! 720 initialized = true; 721 } 722 723 724 private void setupSystemIndices() throws Exception 725 { 726 // let's check and make sure the supplied indices are OK 727 728 if ( ndnIdx == null ) 729 { 730 AttributeType attributeType = schemaManager 731 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_N_DN_AT_OID ); 732 ndnIdx = new AvlIndex<String, E>(); 733 ndnIdx.setAttributeId( ApacheSchemaConstants.APACHE_N_DN_AT_OID ); 734 ndnIdx.initialize( attributeType ); 735 systemIndices.put( ApacheSchemaConstants.APACHE_N_DN_AT_OID, ndnIdx ); 736 } 737 738 if ( updnIdx == null ) 739 { 740 AttributeType attributeType = schemaManager 741 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_UP_DN_AT_OID ); 742 updnIdx = new AvlIndex<String, E>(); 743 updnIdx.setAttributeId( ApacheSchemaConstants.APACHE_UP_DN_AT_OID ); 744 updnIdx.initialize( attributeType ); 745 systemIndices.put( ApacheSchemaConstants.APACHE_UP_DN_AT_OID, updnIdx ); 746 } 747 748 if ( existenceIdx == null ) 749 { 750 AttributeType attributeType = schemaManager 751 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_EXISTENCE_AT_OID ); 752 existenceIdx = new AvlIndex<String, E>(); 753 existenceIdx.setAttributeId( ApacheSchemaConstants.APACHE_EXISTENCE_AT_OID ); 754 existenceIdx.initialize( attributeType ); 755 systemIndices.put( ApacheSchemaConstants.APACHE_EXISTENCE_AT_OID, existenceIdx ); 756 } 757 758 if ( oneLevelIdx == null ) 759 { 760 AttributeType attributeType = schemaManager 761 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_ONE_LEVEL_AT_OID ); 762 oneLevelIdx = new AvlIndex<Long, E>(); 763 oneLevelIdx.setAttributeId( ApacheSchemaConstants.APACHE_ONE_LEVEL_AT_OID ); 764 oneLevelIdx.initialize( attributeType ); 765 systemIndices.put( ApacheSchemaConstants.APACHE_ONE_LEVEL_AT_OID, oneLevelIdx ); 766 } 767 768 if ( oneAliasIdx == null ) 769 { 770 AttributeType attributeType = schemaManager 771 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID ); 772 oneAliasIdx = new AvlIndex<Long, E>(); 773 oneAliasIdx.setAttributeId( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID ); 774 oneAliasIdx.initialize( attributeType ); 775 systemIndices.put( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID, oneAliasIdx ); 776 } 777 778 if ( subAliasIdx == null ) 779 { 780 AttributeType attributeType = schemaManager 781 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID ); 782 subAliasIdx = new AvlIndex<Long, E>(); 783 subAliasIdx.setAttributeId( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID ); 784 subAliasIdx.initialize( attributeType ); 785 systemIndices.put( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID, subAliasIdx ); 786 } 787 788 if ( aliasIdx == null ) 789 { 790 AttributeType attributeType = schemaManager 791 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_ALIAS_AT_OID ); 792 aliasIdx = new AvlIndex<String, E>(); 793 aliasIdx.setAttributeId( ApacheSchemaConstants.APACHE_ALIAS_AT_OID ); 794 aliasIdx.initialize( attributeType ); 795 systemIndices.put( ApacheSchemaConstants.APACHE_ALIAS_AT_OID, aliasIdx ); 796 } 797 798 if ( subLevelIdx == null ) 799 { 800 AttributeType attributeType = schemaManager 801 .lookupAttributeTypeRegistry( ApacheSchemaConstants.APACHE_SUB_LEVEL_AT_OID ); 802 subLevelIdx = new AvlIndex<Long, E>(); 803 subLevelIdx.setAttributeId( ApacheSchemaConstants.APACHE_SUB_LEVEL_AT_OID ); 804 subLevelIdx.initialize( attributeType ); 805 systemIndices.put( ApacheSchemaConstants.APACHE_SUB_LEVEL_AT_OID, subLevelIdx ); 806 } 807 808 if ( entryCsnIdx == null ) 809 { 810 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.ENTRY_CSN_AT_OID ); 811 entryCsnIdx = new AvlIndex<String, E>(); 812 entryCsnIdx.setAttributeId( SchemaConstants.ENTRY_CSN_AT_OID ); 813 entryCsnIdx.initialize( attributeType ); 814 systemIndices.put( SchemaConstants.ENTRY_CSN_AT_OID, entryCsnIdx ); 815 } 816 817 if ( entryUuidIdx == null ) 818 { 819 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.ENTRY_UUID_AT_OID ); 820 entryUuidIdx = new AvlIndex<String, E>(); 821 entryUuidIdx.setAttributeId( SchemaConstants.ENTRY_UUID_AT_OID ); 822 entryUuidIdx.initialize( attributeType ); 823 systemIndices.put( SchemaConstants.ENTRY_UUID_AT_OID, entryUuidIdx ); 824 } 825 826 if ( objectClassIdx == null ) 827 { 828 AttributeType attributeType = schemaManager 829 .lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT_OID ); 830 objectClassIdx = new AvlIndex<String, E>(); 831 objectClassIdx.setAttributeId( SchemaConstants.OBJECT_CLASS_AT_OID ); 832 objectClassIdx.initialize( attributeType ); 833 systemIndices.put( SchemaConstants.OBJECT_CLASS_AT_OID, objectClassIdx ); 834 } 835 836 } 837 838 839 private void setupUserIndices() throws Exception 840 { 841 if ( userIndices != null && userIndices.size() > 0 ) 842 { 843 Map<String, AvlIndex<? extends Object, E>> tmp = new HashMap<String, AvlIndex<? extends Object, E>>(); 844 845 for ( AvlIndex<? extends Object, E> index : userIndices.values() ) 846 { 847 String oid = schemaManager.getAttributeTypeRegistry().getOidByName( index.getAttributeId() ); 848 AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid ); 849 850 // Check that the attributeType has an EQUALITY matchingRule 851 MatchingRule mr = attributeType.getEquality(); 852 853 if ( mr != null ) 854 { 855 index.initialize( schemaManager.lookupAttributeTypeRegistry( oid ) ); 856 tmp.put( oid, index ); 857 } 858 else 859 { 860 LOG.error( I18n.err( I18n.ERR_4, attributeType.getName() ) ); 861 } 862 } 863 864 userIndices = tmp; 865 } 866 else 867 { 868 userIndices = new HashMap<String, AvlIndex<? extends Object, E>>(); 869 } 870 } 871 872 873 /** 874 * {@inheritDoc} 875 */ 876 public boolean isInitialized() 877 { 878 return initialized; 879 } 880 881 882 /** 883 * {@inheritDoc} 884 */ 885 public IndexCursor<Long, E, Long> list( Long id ) throws Exception 886 { 887 IndexCursor<Long, E, Long> cursor = oneLevelIdx.forwardCursor( id ); 888 cursor.beforeValue( id, null ); 889 return cursor; 890 } 891 892 893 /** 894 * {@inheritDoc} 895 */ 896 public ServerEntry lookup( Long id ) throws Exception 897 { 898 return master.get( id ); 899 } 900 901 902 /** 903 * Recursively modifies the distinguished name of an entry and the names of 904 * its descendants calling itself in the recursion. 905 * 906 * @param id the primary key of the entry 907 * @param updn User provided distinguished name to set as the new DN 908 * @param isMove whether or not the name change is due to a move operation 909 * which affects alias userIndices. 910 * @throws Exception if something goes wrong 911 */ 912 private void modifyDn( Long id, DN updn, boolean isMove ) throws Exception 913 { 914 String aliasTarget; 915 916 // update normalized DN index 917 ndnIdx.drop( id ); 918 919 if ( !updn.isNormalized() ) 920 { 921 updn.normalize( schemaManager.getNormalizerMapping() ); 922 } 923 924 ndnIdx.add( updn.getNormName(), id ); 925 926 // update user provided DN index 927 updnIdx.drop( id ); 928 updnIdx.add( updn.getName(), id ); 929 930 /* 931 * Read Alias Index Tuples 932 * 933 * If this is a name change due to a move operation then the one and 934 * subtree userIndices for aliases were purged before the aliases were 935 * moved. Now we must add them for each alias entry we have moved. 936 * 937 * aliasTarget is used as a marker to tell us if we're moving an 938 * alias. If it is null then the moved entry is not an alias. 939 */ 940 if ( isMove ) 941 { 942 aliasTarget = aliasIdx.reverseLookup( id ); 943 944 if ( null != aliasTarget ) 945 { 946 addAliasIndices( id, new DN( getEntryDn( id ) ), aliasTarget ); 947 } 948 } 949 950 Cursor<IndexEntry<Long, E, Long>> children = list( id ); 951 952 while ( children.next() ) 953 { 954 // Get the child and its id 955 IndexEntry<Long, E, Long> rec = children.get(); 956 Long childId = rec.getId(); 957 958 /* 959 * Calculate the DN for the child's new name by copying the parents 960 * new name and adding the child's old upRdn to new name as its RDN 961 */ 962 DN childUpdn = ( DN ) updn.clone(); 963 DN oldUpdn = new DN( getEntryUpdn( childId ) ); 964 965 String rdn = oldUpdn.get( oldUpdn.size() - 1 ); 966 DN rdnDN = new DN( rdn ); 967 rdnDN.normalize( schemaManager.getNormalizerMapping() ); 968 childUpdn.add( rdnDN.getRdn() ); 969 970 // Modify the child 971 ServerEntry entry = lookup( childId ); 972 entry.setDn( childUpdn ); 973 master.put( childId, entry ); 974 975 // Recursively change the names of the children below 976 modifyDn( childId, childUpdn, isMove ); 977 } 978 979 children.close(); 980 } 981 982 983 /** 984 * Adds a set of attribute values while affecting the appropriate userIndices. 985 * The entry is not persisted: it is only changed in anticipation for a put 986 * into the master table. 987 * 988 * @param id the primary key of the entry 989 * @param entry the entry to alter 990 * @param mods the attribute and values to add 991 * @throws Exception if index alteration or attribute addition fails 992 */ 993 @SuppressWarnings("unchecked") 994 private void add( Long id, ServerEntry entry, EntryAttribute mods ) throws Exception 995 { 996 if ( entry instanceof ClonedServerEntry ) 997 { 998 throw new Exception( I18n.err( I18n.ERR_215 ) ); 999 } 1000 1001 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() ); 1002 1003 // Special case for the ObjectClass index 1004 if ( modsOid.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) ) 1005 { 1006 for ( Value<?> value : mods ) 1007 { 1008 objectClassIdx.drop( value.getString(), id ); 1009 } 1010 } 1011 else if ( hasUserIndexOn( modsOid ) ) 1012 { 1013 Index<?, E, Long> index = getUserIndex( modsOid ); 1014 1015 for ( Value<?> value : mods ) 1016 { 1017 ( ( AvlIndex ) index ).add( value.get(), id ); 1018 } 1019 1020 // If the attr didn't exist for this id add it to existence index 1021 if ( !existenceIdx.forward( modsOid, id ) ) 1022 { 1023 existenceIdx.add( modsOid, id ); 1024 } 1025 } 1026 1027 // add all the values in mods to the same attribute in the entry 1028 AttributeType type = schemaManager.lookupAttributeTypeRegistry( modsOid ); 1029 1030 for ( Value<?> value : mods ) 1031 { 1032 entry.add( type, value ); 1033 } 1034 1035 if ( modsOid.equals( SchemaConstants.ALIASED_OBJECT_NAME_AT_OID ) ) 1036 { 1037 String ndnStr = ndnIdx.reverseLookup( id ); 1038 addAliasIndices( id, new DN( ndnStr ), mods.getString() ); 1039 } 1040 } 1041 1042 1043 /** 1044 * Completely removes the set of values for an attribute having the values 1045 * supplied while affecting the appropriate userIndices. The entry is not 1046 * persisted: it is only changed in anticipation for a put into the master 1047 * table. Note that an empty attribute w/o values will remove all the 1048 * values within the entry where as an attribute w/ values will remove those 1049 * attribute values it contains. 1050 * 1051 * @param id the primary key of the entry 1052 * @param entry the entry to alter 1053 * @param mods the attribute and its values to delete 1054 * @throws Exception if index alteration or attribute modification fails. 1055 */ 1056 @SuppressWarnings("unchecked") 1057 private void remove( Long id, ServerEntry entry, EntryAttribute mods ) throws Exception 1058 { 1059 if ( entry instanceof ClonedServerEntry ) 1060 { 1061 throw new Exception( I18n.err( I18n.ERR_215 ) ); 1062 } 1063 1064 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() ); 1065 1066 // Special case for the ObjectClass index 1067 if ( modsOid.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) ) 1068 { 1069 for ( Value<?> value : mods ) 1070 { 1071 objectClassIdx.drop( value.getString(), id ); 1072 } 1073 } 1074 else if ( hasUserIndexOn( modsOid ) ) 1075 { 1076 Index<?, E, Long> index = getUserIndex( modsOid ); 1077 1078 for ( Value<?> value : mods ) 1079 { 1080 ( ( AvlIndex ) index ).drop( value.get(), id ); 1081 } 1082 1083 /* 1084 * If no attribute values exist for this entryId in the index then 1085 * we remove the existance index entry for the removed attribute. 1086 */ 1087 if ( null == index.reverseLookup( id ) ) 1088 { 1089 existenceIdx.drop( modsOid, id ); 1090 } 1091 } 1092 1093 AttributeType attrType = schemaManager.lookupAttributeTypeRegistry( modsOid ); 1094 /* 1095 * If there are no attribute values in the modifications then this 1096 * implies the compelete removal of the attribute from the entry. Else 1097 * we remove individual attribute values from the entry in mods one 1098 * at a time. 1099 */ 1100 if ( mods.size() == 0 ) 1101 { 1102 entry.removeAttributes( attrType ); 1103 } 1104 else 1105 { 1106 EntryAttribute entryAttr = entry.get( attrType ); 1107 1108 for ( Value<?> value : mods ) 1109 { 1110 if ( value instanceof StringValue ) 1111 { 1112 entryAttr.remove( ( String ) value.get() ); 1113 } 1114 else 1115 { 1116 entryAttr.remove( ( byte[] ) value.get() ); 1117 } 1118 } 1119 1120 // if nothing is left just remove empty attribute 1121 if ( entryAttr.size() == 0 ) 1122 { 1123 entry.removeAttributes( entryAttr.getId() ); 1124 } 1125 } 1126 1127 // Aliases->single valued comp/partial attr removal is not relevant here 1128 if ( modsOid.equals( SchemaConstants.ALIASED_OBJECT_NAME_AT_OID ) ) 1129 { 1130 dropAliasIndices( id ); 1131 } 1132 } 1133 1134 1135 /** 1136 * Completely replaces the existing set of values for an attribute with the 1137 * modified values supplied affecting the appropriate userIndices. The entry 1138 * is not persisted: it is only changed in anticipation for a put into the 1139 * master table. 1140 * 1141 * @param id the primary key of the entry 1142 * @param entry the entry to alter 1143 * @param mods the replacement attribute and values 1144 * @throws Exception if index alteration or attribute modification 1145 * fails. 1146 */ 1147 @SuppressWarnings("unchecked") 1148 private void replace( Long id, ServerEntry entry, EntryAttribute mods ) throws Exception 1149 { 1150 if ( entry instanceof ClonedServerEntry ) 1151 { 1152 throw new Exception( I18n.err( I18n.ERR_215 ) ); 1153 } 1154 1155 String modsOid = schemaManager.getAttributeTypeRegistry().getOidByName( mods.getId() ); 1156 1157 // Special case for the ObjectClass index 1158 if ( modsOid.equals( SchemaConstants.OBJECT_CLASS_AT_OID ) ) 1159 { 1160 // if the id exists in the index drop all existing attribute 1161 // value index entries and add new ones 1162 if ( objectClassIdx.reverse( id ) ) 1163 { 1164 objectClassIdx.drop( id ); 1165 } 1166 1167 for ( Value<?> value : mods ) 1168 { 1169 objectClassIdx.add( value.getString(), id ); 1170 } 1171 } 1172 else if ( hasUserIndexOn( modsOid ) ) 1173 { 1174 Index<?, E, Long> index = getUserIndex( modsOid ); 1175 1176 // if the id exists in the index drop all existing attribute value index entries and add new ones 1177 if ( index.reverse( id ) ) 1178 { 1179 ( ( AvlIndex<?, E> ) index ).drop( id ); 1180 } 1181 1182 for ( Value<?> value : mods ) 1183 { 1184 ( ( AvlIndex<Object, E> ) index ).add( value.get(), id ); 1185 } 1186 1187 /* 1188 * If no attribute values exist for this entryId in the index then 1189 * we remove the existance index entry for the removed attribute. 1190 */ 1191 if ( null == index.reverseLookup( id ) ) 1192 { 1193 existenceIdx.drop( modsOid, id ); 1194 } 1195 } 1196 1197 String aliasAttributeOid = SchemaConstants.ALIASED_OBJECT_NAME_AT_OID; 1198 1199 if ( modsOid.equals( aliasAttributeOid ) ) 1200 { 1201 dropAliasIndices( id ); 1202 } 1203 1204 // replaces old attributes with new modified ones if they exist 1205 if ( mods.size() > 0 ) 1206 { 1207 entry.put( mods ); 1208 } 1209 else 1210 // removes old attributes if new replacements do not exist 1211 { 1212 entry.remove( mods ); 1213 } 1214 1215 if ( modsOid.equals( aliasAttributeOid ) && mods.size() > 0 ) 1216 { 1217 String ndnStr = ndnIdx.reverseLookup( id ); 1218 addAliasIndices( id, new DN( ndnStr ), mods.getString() ); 1219 } 1220 } 1221 1222 1223 public void modify( DN dn, ModificationOperation modOp, ServerEntry mods ) throws Exception 1224 { 1225 if ( mods instanceof ClonedServerEntry ) 1226 { 1227 throw new Exception( I18n.err( I18n.ERR_215 ) ); 1228 } 1229 1230 Long id = getEntryId( dn.getNormName() ); 1231 ServerEntry entry = ( ServerEntry ) master.get( id ); 1232 1233 for ( AttributeType attributeType : mods.getAttributeTypes() ) 1234 { 1235 EntryAttribute attr = mods.get( attributeType ); 1236 1237 switch ( modOp ) 1238 { 1239 case ADD_ATTRIBUTE: 1240 add( id, entry, attr ); 1241 break; 1242 1243 case REMOVE_ATTRIBUTE: 1244 remove( id, entry, attr ); 1245 break; 1246 1247 case REPLACE_ATTRIBUTE: 1248 replace( id, entry, attr ); 1249 1250 break; 1251 1252 default: 1253 throw new Exception( I18n.err( I18n.ERR_221 ) ); 1254 } 1255 } 1256 1257 master.put( id, entry ); 1258 } 1259 1260 1261 public void modify( DN dn, List<Modification> mods ) throws Exception 1262 { 1263 Long id = getEntryId( dn.getNormName() ); 1264 modify( id, mods ); 1265 } 1266 1267 1268 public void modify( long entryId, List<Modification> mods ) throws Exception 1269 { 1270 ServerEntry entry = ( ServerEntry ) master.get( entryId ); 1271 1272 for ( Modification mod : mods ) 1273 { 1274 EntryAttribute attrMods = mod.getAttribute(); 1275 1276 switch ( mod.getOperation() ) 1277 { 1278 case ADD_ATTRIBUTE: 1279 add( entryId, entry, attrMods ); 1280 break; 1281 1282 case REMOVE_ATTRIBUTE: 1283 remove( entryId, entry, attrMods ); 1284 break; 1285 1286 case REPLACE_ATTRIBUTE: 1287 replace( entryId, entry, attrMods ); 1288 break; 1289 1290 default: 1291 throw new Exception( I18n.err( I18n.ERR_221 ) ); 1292 } 1293 } 1294 1295 master.put( entryId, entry ); 1296 } 1297 1298 1299 public void move( DN oldChildDn, DN newParentDn, RDN newRdn, boolean deleteOldRdn ) throws Exception 1300 { 1301 Long childId = getEntryId( oldChildDn.getNormName() ); 1302 rename( oldChildDn, newRdn, deleteOldRdn ); 1303 DN newUpdn = move( oldChildDn, childId, newParentDn ); 1304 1305 // Update the current entry 1306 ServerEntry entry = lookup( childId ); 1307 entry.setDn( newUpdn ); 1308 master.put( childId, entry ); 1309 } 1310 1311 1312 public void move( DN oldChildDn, DN newParentDn ) throws Exception 1313 { 1314 Long childId = getEntryId( oldChildDn.getNormName() ); 1315 DN newUpdn = move( oldChildDn, childId, newParentDn ); 1316 1317 // Update the current entry 1318 ServerEntry entry = lookup( childId ); 1319 entry.setDn( newUpdn ); 1320 master.put( childId, entry ); 1321 } 1322 1323 1324 /** 1325 * Moves an entry under a new parent. The operation causes a shift in the 1326 * parent child relationships between the old parent, new parent and the 1327 * child moved. All other descendant entries under the child never change 1328 * their direct parent child relationships. Hence after the parent child 1329 * relationship changes are broken at the old parent and set at the new 1330 * parent a modifyDn operation is conducted to handle name changes 1331 * propagating down through the moved child and its descendants. 1332 * 1333 * @param oldChildDn the normalized dn of the child to be moved 1334 * @param childId the id of the child being moved 1335 * @param newParentDn the normalized dn of the new parent for the child 1336 * @throws Exception if something goes wrong 1337 */ 1338 private DN move( DN oldChildDn, Long childId, DN newParentDn ) throws Exception 1339 { 1340 // Get the child and the new parent to be entries and Ids 1341 Long newParentId = getEntryId( newParentDn.getNormName() ); 1342 Long oldParentId = getParentId( childId ); 1343 1344 /* 1345 * All aliases including and below oldChildDn, will be affected by 1346 * the move operation with respect to one and subtree userIndices since 1347 * their relationship to ancestors above oldChildDn will be 1348 * destroyed. For each alias below and including oldChildDn we will 1349 * drop the index tuples mapping ancestor ids above oldChildDn to the 1350 * respective target ids of the aliases. 1351 */ 1352 dropMovedAliasIndices( oldChildDn ); 1353 1354 /* 1355 * Drop the old parent child relationship and add the new one 1356 * Set the new parent id for the child replacing the old parent id 1357 */ 1358 oneLevelIdx.drop( oldParentId, childId ); 1359 oneLevelIdx.add( newParentId, childId ); 1360 1361 updateSubLevelIndex( childId, oldParentId, newParentId ); 1362 1363 /* 1364 * Build the new user provided DN (updn) for the child using the child's 1365 * user provided RDN & the new parent's UPDN. Basically add the child's 1366 * UpRdn String to the tail of the new parent's Updn Name. 1367 */ 1368 DN childUpdn = new DN( getEntryUpdn( childId ) ); 1369 String childRdn = childUpdn.get( childUpdn.size() - 1 ); 1370 DN newUpdn = new DN( getEntryUpdn( newParentId ) ); 1371 newUpdn.add( newUpdn.size(), childRdn ); 1372 1373 // Call the modifyDn operation with the new updn 1374 modifyDn( childId, newUpdn, true ); 1375 1376 return newUpdn; 1377 } 1378 1379 1380 /** 1381 * Changes the relative distinguished name of an entry specified by a 1382 * distinguished name with the optional removal of the old RDN attribute 1383 * value from the entry. Name changes propagate down as dn changes to the 1384 * descendants of the entry where the RDN changed. 1385 * 1386 * An RDN change operation does not change parent child relationships. It 1387 * merely propagates a name change at a point in the DIT where the RDN is 1388 * changed. The change propagates down the subtree rooted at the 1389 * distinguished name specified. 1390 * 1391 * @param dn the normalized distinguished name of the entry to alter 1392 * @param newRdn the new RDN to set 1393 * @param deleteOldRdn whether or not to remove the old RDN attr/val 1394 * @throws Exception if there are any errors propagating the name changes 1395 */ 1396 @SuppressWarnings("unchecked") 1397 public void rename( DN dn, RDN newRdn, boolean deleteOldRdn ) throws Exception 1398 { 1399 Long id = getEntryId( dn.getNormName() ); 1400 ServerEntry entry = lookup( id ); 1401 DN updn = entry.getDn(); 1402 1403 /* 1404 * H A N D L E N E W R D N 1405 * ==================================================================== 1406 * Add the new RDN attribute to the entry. If an index exists on the 1407 * new RDN attribute we add the index for this attribute value pair. 1408 * Also we make sure that the existance index shows the existance of the 1409 * new RDN attribute within this entry. 1410 */ 1411 1412 for ( AVA newAtav : newRdn ) 1413 { 1414 String newNormType = newAtav.getNormType(); 1415 Object newNormValue = newAtav.getNormValue().get(); 1416 AttributeType newRdnAttrType = schemaManager.lookupAttributeTypeRegistry( newNormType ); 1417 1418 entry.add( newRdnAttrType, newAtav.getUpValue() ); 1419 1420 if ( hasUserIndexOn( newNormType ) ) 1421 { 1422 Index<?, E, Long> index = getUserIndex( newNormType ); 1423 ( ( Index ) index ).add( newNormValue, id ); 1424 1425 // Make sure the altered entry shows the existence of the new attrib 1426 if ( !existenceIdx.forward( newNormType, id ) ) 1427 { 1428 existenceIdx.add( newNormType, id ); 1429 } 1430 } 1431 } 1432 1433 /* 1434 * H A N D L E O L D R D N 1435 * ==================================================================== 1436 * If the old RDN is to be removed we need to get the attribute and 1437 * value for it. Keep in mind the old RDN need not be based on the 1438 * same attr as the new one. We remove the RDN value from the entry 1439 * and remove the value/id tuple from the index on the old RDN attr 1440 * if any. We also test if the delete of the old RDN index tuple 1441 * removed all the attribute values of the old RDN using a reverse 1442 * lookup. If so that means we blew away the last value of the old 1443 * RDN attribute. In this case we need to remove the attrName/id 1444 * tuple from the existance index. 1445 * 1446 * We only remove an ATAV of the old RDN if it is not included in the 1447 * new RDN. 1448 */ 1449 1450 if ( deleteOldRdn ) 1451 { 1452 RDN oldRdn = updn.getRdn(); 1453 for ( AVA oldAtav : oldRdn ) 1454 { 1455 // check if the new ATAV is part of the old RDN 1456 // if that is the case we do not remove the ATAV 1457 boolean mustRemove = true; 1458 for ( AVA newAtav : newRdn ) 1459 { 1460 if ( oldAtav.equals( newAtav ) ) 1461 { 1462 mustRemove = false; 1463 break; 1464 } 1465 } 1466 1467 if ( mustRemove ) 1468 { 1469 String oldNormType = oldAtav.getNormType(); 1470 String oldNormValue = oldAtav.getNormValue().getString(); 1471 AttributeType oldRdnAttrType = schemaManager.lookupAttributeTypeRegistry( oldNormType ); 1472 entry.remove( oldRdnAttrType, oldNormValue ); 1473 1474 if ( hasUserIndexOn( oldNormType ) ) 1475 { 1476 Index<?, E, Long> index = getUserIndex( oldNormType ); 1477 ( ( AvlIndex ) index ).drop( oldNormValue, id ); 1478 1479 /* 1480 * If there is no value for id in this index due to our 1481 * drop above we remove the oldRdnAttr from the existance idx 1482 */ 1483 if ( null == index.reverseLookup( id ) ) 1484 { 1485 existenceIdx.drop( oldNormType, id ); 1486 } 1487 } 1488 } 1489 } 1490 } 1491 1492 /* 1493 * H A N D L E D N C H A N G E 1494 * ==================================================================== 1495 * 1) Build the new user defined distinguished name 1496 * - clone / copy old updn 1497 * - remove old upRdn from copy 1498 * - add the new upRdn to the copy 1499 * 2) Make call to recursive modifyDn method to change the names of the 1500 * entry and its descendants 1501 */ 1502 1503 DN newUpdn = ( DN ) updn.clone(); // copy da old updn 1504 newUpdn.remove( newUpdn.size() - 1 ); // remove old upRdn 1505 newUpdn.add( newRdn.getName() ); // add da new upRdn 1506 1507 // gotta normalize cuz this thang is cloned and not normalized by default 1508 newUpdn.normalize( schemaManager.getNormalizerMapping() ); 1509 1510 modifyDn( id, newUpdn, false ); // propagate dn changes 1511 1512 // Update the current entry 1513 entry.setDn( newUpdn ); 1514 master.put( id, entry ); 1515 } 1516 1517 1518 /** 1519 * {@inheritDoc} 1520 */ 1521 public void setAliasIndex( Index<String, E, Long> index ) throws Exception 1522 { 1523 protect( "aliasIndex" ); 1524 if ( index instanceof AvlIndex<?, ?> ) 1525 { 1526 this.aliasIdx = ( AvlIndex<String, E> ) index; 1527 } 1528 else 1529 { 1530 this.aliasIdx = ( AvlIndex<String, E> ) convert( index ); 1531 } 1532 1533 // FIXME is this attribute ID or its OID 1534 systemIndices.put( index.getAttributeId(), aliasIdx ); 1535 } 1536 1537 1538 /** 1539 * {@inheritDoc} 1540 */ 1541 public void setName( String name ) 1542 { 1543 protect( "name" ); 1544 this.name = name; 1545 } 1546 1547 1548 /** 1549 * {@inheritDoc} 1550 */ 1551 public void setNdnIndex( Index<String, E, Long> index ) throws Exception 1552 { 1553 protect( "ndnIndex" ); 1554 if ( index instanceof AvlIndex<?, ?> ) 1555 { 1556 this.ndnIdx = ( AvlIndex<String, E> ) index; 1557 } 1558 else 1559 { 1560 this.ndnIdx = ( AvlIndex<String, E> ) convert( index ); 1561 } 1562 1563 systemIndices.put( index.getAttributeId(), ndnIdx ); 1564 } 1565 1566 1567 /** 1568 * {@inheritDoc} 1569 */ 1570 public void setOneAliasIndex( Index<Long, E, Long> index ) throws Exception 1571 { 1572 protect( "oneAliasIndex" ); 1573 if ( index instanceof AvlIndex<?, ?> ) 1574 { 1575 this.oneAliasIdx = ( AvlIndex<Long, E> ) index; 1576 } 1577 else 1578 { 1579 this.oneAliasIdx = ( AvlIndex<Long, E> ) convert( index ); 1580 } 1581 1582 systemIndices.put( index.getAttributeId(), oneAliasIdx ); 1583 } 1584 1585 1586 /** 1587 * {@inheritDoc} 1588 */ 1589 public void setOneLevelIndex( Index<Long, E, Long> index ) throws Exception 1590 { 1591 protect( "oneLevelIndex" ); 1592 if ( index instanceof AvlIndex<?, ?> ) 1593 { 1594 this.oneLevelIdx = ( AvlIndex<Long, E> ) index; 1595 } 1596 else 1597 { 1598 this.oneLevelIdx = ( AvlIndex<Long, E> ) convert( index ); 1599 } 1600 1601 systemIndices.put( index.getAttributeId(), oneLevelIdx ); 1602 } 1603 1604 1605 /** 1606 * {@inheritDoc} 1607 */ 1608 public void setPresenceIndex( Index<String, E, Long> index ) throws Exception 1609 { 1610 protect( "presenceIndex" ); 1611 if ( index instanceof AvlIndex<?, ?> ) 1612 { 1613 this.existenceIdx = ( AvlIndex<String, E> ) index; 1614 } 1615 else 1616 { 1617 this.existenceIdx = ( AvlIndex<String, E> ) convert( index ); 1618 } 1619 1620 systemIndices.put( index.getAttributeId(), existenceIdx ); 1621 } 1622 1623 1624 /** 1625 * {@inheritDoc} 1626 */ 1627 public void setProperty( String propertyName, String propertyValue ) throws Exception 1628 { 1629 master.setProperty( propertyName, propertyValue ); 1630 } 1631 1632 1633 /** 1634 * {@inheritDoc} 1635 */ 1636 public void setSubAliasIndex( Index<Long, E, Long> index ) throws Exception 1637 { 1638 protect( "subAliasIndex" ); 1639 if ( index instanceof AvlIndex<?, ?> ) 1640 { 1641 this.subAliasIdx = ( AvlIndex<Long, E> ) index; 1642 } 1643 else 1644 { 1645 this.subAliasIdx = ( AvlIndex<Long, E> ) convert( index ); 1646 } 1647 1648 systemIndices.put( index.getAttributeId(), subAliasIdx ); 1649 } 1650 1651 1652 /** 1653 * {@inheritDoc} 1654 */ 1655 public void setSubLevelIndex( Index<Long, E, Long> index ) throws Exception 1656 { 1657 protect( "subLevelIndex" ); 1658 if ( index instanceof AvlIndex<?, ?> ) 1659 { 1660 this.subLevelIdx = ( AvlIndex<Long, E> ) index; 1661 } 1662 else 1663 { 1664 this.subLevelIdx = ( AvlIndex<Long, E> ) convert( index ); 1665 } 1666 1667 systemIndices.put( index.getAttributeId(), subLevelIdx ); 1668 } 1669 1670 1671 /** 1672 * {@inheritDoc} 1673 */ 1674 public void setSuffixDn( String suffixDn ) 1675 { 1676 protect( "suffixDn" ); 1677 try 1678 { 1679 this.suffixDn = new DN( suffixDn ); 1680 } 1681 catch ( LdapInvalidDnException e ) 1682 { 1683 throw new IllegalArgumentException( e ); 1684 } 1685 } 1686 1687 1688 /** 1689 * {@inheritDoc} 1690 */ 1691 public void setUpdnIndex( Index<String, E, Long> index ) throws Exception 1692 { 1693 protect( "updnIndex" ); 1694 if ( index instanceof AvlIndex<?, ?> ) 1695 { 1696 this.updnIdx = ( AvlIndex<String, E> ) index; 1697 } 1698 else 1699 { 1700 this.updnIdx = ( AvlIndex<String, E> ) convert( index ); 1701 } 1702 1703 systemIndices.put( index.getAttributeId(), updnIdx ); 1704 } 1705 1706 1707 /** 1708 * {@inheritDoc} 1709 */ 1710 public void setUserIndices( Set<Index<? extends Object, E, Long>> userIndices ) 1711 { 1712 protect( "setUserIndices" ); 1713 1714 for ( Index<? extends Object, E, Long> index : userIndices ) 1715 { 1716 if ( index instanceof AvlIndex<?, ?> ) 1717 { 1718 this.userIndices.put( index.getAttributeId(), ( AvlIndex<? extends Object, E> ) index ); 1719 continue; 1720 } 1721 1722 LOG.warn( "Supplied index {} is not a AvlIndex. " 1723 + "Will create new AvlIndex using copied configuration parameters.", index ); 1724 1725 AvlIndex<Object, E> avlIndex = ( AvlIndex<Object, E> ) convert( index ); 1726 1727 this.userIndices.put( index.getAttributeId(), avlIndex ); 1728 } 1729 } 1730 1731 1732 private <K> AvlIndex<K, E> convert( Index<K, E, Long> index ) 1733 { 1734 AvlIndex<K, E> avlIndex = new AvlIndex<K, E>(); 1735 avlIndex.setAttributeId( index.getAttributeId() ); 1736 return avlIndex; 1737 } 1738 1739 1740 private void protect( String method ) 1741 { 1742 if ( initialized ) 1743 { 1744 throw new IllegalStateException( I18n.err( I18n.ERR_222, method ) ); 1745 } 1746 } 1747 1748 1749 /** 1750 * {@inheritDoc} 1751 */ 1752 public Iterator<String> systemIndices() 1753 { 1754 return systemIndices.keySet().iterator(); 1755 } 1756 1757 1758 /** 1759 * {@inheritDoc} 1760 */ 1761 public Iterator<String> userIndices() 1762 { 1763 return userIndices.keySet().iterator(); 1764 } 1765 1766 1767 /** 1768 * Adds userIndices for an aliasEntry to be added to the database while checking 1769 * for constrained alias constructs like alias cycles and chaining. 1770 * 1771 * @param aliasDn normalized distinguished name for the alias entry 1772 * @param aliasTarget the user provided aliased entry dn as a string 1773 * @param aliasId the id of alias entry to add 1774 * @throws Exception if index addition fails, and if the alias is 1775 * not allowed due to chaining or cycle formation. 1776 * @throws Exception if the wrappedCursor btrees cannot be altered 1777 */ 1778 private void addAliasIndices( Long aliasId, DN aliasDn, String aliasTarget ) throws Exception 1779 { 1780 DN normalizedAliasTargetDn; // Name value of aliasedObjectName 1781 Long targetId; // Id of the aliasedObjectName 1782 DN ancestorDn; // Name of an alias entry relative 1783 Long ancestorId; // Id of an alias entry relative 1784 1785 // Access aliasedObjectName, normalize it and generate the Name 1786 normalizedAliasTargetDn = new DN( aliasTarget ); 1787 normalizedAliasTargetDn.normalize( schemaManager.getNormalizerMapping() ); 1788 1789 /* 1790 * Check For Cycles 1791 * 1792 * Before wasting time to lookup more values we check using the target 1793 * dn to see if we have the possible formation of an alias cycle. This 1794 * happens when the alias refers back to a target that is also a 1795 * relative of the alias entry. For detection we test if the aliased 1796 * entry Dn starts with the target Dn. If it does then we know the 1797 * aliased target is a relative and we have a perspecitive cycle. 1798 */ 1799 if ( aliasDn.isChildOf( normalizedAliasTargetDn ) ) 1800 { 1801 if ( aliasDn.equals( normalizedAliasTargetDn ) ) 1802 { 1803 throw new Exception( I18n.err( I18n.ERR_223 ) ); 1804 } 1805 1806 throw new Exception( I18n.err( I18n.ERR_224, aliasTarget, aliasDn ) ); 1807 } 1808 1809 /* 1810 * Check For Aliases External To Naming Context 1811 * 1812 * id may be null but the alias may be to a valid entry in 1813 * another namingContext. Such aliases are not allowed and we 1814 * need to point it out to the user instead of saying the target 1815 * does not exist when it potentially could outside of this upSuffix. 1816 */ 1817 if ( !normalizedAliasTargetDn.isChildOf( suffixDn ) ) 1818 { 1819 // Complain specifically about aliases to outside naming contexts 1820 throw new Exception( I18n.err( I18n.ERR_225, suffixDn.getName() ) ); 1821 } 1822 1823 // L O O K U P T A R G E T I D 1824 targetId = ndnIdx.forwardLookup( normalizedAliasTargetDn.getNormName() ); 1825 1826 /* 1827 * Check For Target Existance 1828 * 1829 * We do not allow the creation of inconsistant aliases. Aliases should 1830 * not be broken links. If the target does not exist we start screaming 1831 */ 1832 if ( null == targetId ) 1833 { 1834 // Complain about target not existing 1835 throw new Exception( I18n.err( I18n.ERR_226 ) ); 1836 } 1837 1838 /* 1839 * Detect Direct Alias Chain Creation 1840 * 1841 * Rather than resusitate the target to test if it is an alias and fail 1842 * due to chaing creation we use the alias index to determine if the 1843 * target is an alias. Hence if the alias we are about to create points 1844 * to another alias as its target in the aliasedObjectName attribute, 1845 * then we have a situation where an alias chain is being created. 1846 * Alias chaining is not allowed so we throw and exception. 1847 */ 1848 if ( null != aliasIdx.reverseLookup( targetId ) ) 1849 { 1850 // Complain about illegal alias chain 1851 throw new Exception( I18n.err( I18n.ERR_227 ) ); 1852 } 1853 1854 // Add the alias to the simple alias index 1855 aliasIdx.add( normalizedAliasTargetDn.getNormName(), aliasId ); 1856 1857 /* 1858 * Handle One Level Scope Alias Index 1859 * 1860 * The first relative is special with respect to the one level alias 1861 * index. If the target is not a sibling of the alias then we add the 1862 * index entry maping the parent's id to the aliased target id. 1863 */ 1864 ancestorDn = ( DN ) aliasDn.clone(); 1865 ancestorDn.remove( aliasDn.size() - 1 ); 1866 ancestorId = getEntryId( ancestorDn.getNormName() ); 1867 1868 // check if alias parent and aliased entry are the same 1869 DN normalizedAliasTargetParentDn = ( DN ) normalizedAliasTargetDn.clone(); 1870 normalizedAliasTargetParentDn.remove( normalizedAliasTargetDn.size() - 1 ); 1871 if ( !aliasDn.isChildOf( normalizedAliasTargetParentDn ) ) 1872 { 1873 oneAliasIdx.add( ancestorId, targetId ); 1874 } 1875 1876 /* 1877 * Handle Sub Level Scope Alias Index 1878 * 1879 * Walk the list of relatives from the parents up to the upSuffix, testing 1880 * to see if the alias' target is a descendant of the relative. If the 1881 * alias target is not a descentant of the relative it extends the scope 1882 * and is added to the sub tree scope alias index. The upSuffix node is 1883 * ignored since everything is under its scope. The first loop 1884 * iteration shall handle the parents. 1885 */ 1886 while ( !ancestorDn.equals( suffixDn ) && null != ancestorId ) 1887 { 1888 if ( !NamespaceTools.isDescendant( ancestorDn, normalizedAliasTargetDn ) ) 1889 { 1890 subAliasIdx.add( ancestorId, targetId ); 1891 } 1892 1893 ancestorDn.remove( ancestorDn.size() - 1 ); 1894 ancestorId = getEntryId( ancestorDn.getNormName() ); 1895 } 1896 } 1897 1898 1899 /** 1900 * Removes the index entries for an alias before the entry is deleted from 1901 * the master table. 1902 * 1903 * @todo Optimize this by walking the hierarchy index instead of the name 1904 * @param aliasId the id of the alias entry in the master table 1905 * @throws Exception if we cannot parse ldap names 1906 * @throws Exception if we cannot delete index values in the database 1907 */ 1908 private void dropAliasIndices( Long aliasId ) throws Exception 1909 { 1910 String targetDn = aliasIdx.reverseLookup( aliasId ); 1911 Long targetId = getEntryId( targetDn ); 1912 String aliasDn = getEntryDn( aliasId ); 1913 DN aliasDN = ( DN ) new DN( aliasDn ); 1914 1915 DN ancestorDn = ( DN ) aliasDN.clone(); 1916 ancestorDn.remove( aliasDN.size() - 1 ); 1917 Long ancestorId = getEntryId( ancestorDn.getNormName() ); 1918 1919 /* 1920 * We cannot just drop all tuples in the one level and subtree userIndices 1921 * linking baseIds to the targetId. If more than one alias refers to 1922 * the target then droping all tuples with a value of targetId would 1923 * make all other aliases to the target inconsistent. 1924 * 1925 * We need to walk up the path of alias ancestors until we reach the 1926 * upSuffix, deleting each ( ancestorId, targetId ) tuple in the 1927 * subtree scope alias. We only need to do this for the direct parent 1928 * of the alias on the one level subtree. 1929 */ 1930 oneAliasIdx.drop( ancestorId, targetId ); 1931 subAliasIdx.drop( ancestorId, targetId ); 1932 1933 while ( !ancestorDn.equals( suffixDn ) && ancestorDn.size() > suffixDn.size() ) 1934 { 1935 ancestorDn = ( DN ) ancestorDn.getPrefix( ancestorDn.size() - 1 ); 1936 ancestorId = getEntryId( ancestorDn.getNormName() ); 1937 1938 subAliasIdx.drop( ancestorId, targetId ); 1939 } 1940 1941 // Drops all alias tuples pointing to the id of the alias to be deleted 1942 aliasIdx.drop( aliasId ); 1943 } 1944 1945 1946 /** 1947 * 1948 * updates the SubLevel Index as part of a move operation. 1949 * 1950 * @param childId child id to be moved 1951 * @param oldParentId old parent's id 1952 * @param newParentId new parent's id 1953 * @throws Exception 1954 */ 1955 private void updateSubLevelIndex( Long childId, Long oldParentId, Long newParentId ) throws Exception 1956 { 1957 Long tempId = oldParentId; 1958 List<Long> parentIds = new ArrayList<Long>(); 1959 1960 // find all the parents of the oldParentId 1961 while ( tempId != 0 && tempId != 1 && tempId != null ) 1962 { 1963 parentIds.add( tempId ); 1964 tempId = getParentId( tempId ); 1965 } 1966 1967 // find all the children of the childId 1968 Cursor<IndexEntry<Long, E, Long>> cursor = subLevelIdx.forwardCursor( childId ); 1969 1970 List<Long> childIds = new ArrayList<Long>(); 1971 childIds.add( childId ); 1972 1973 while ( cursor.next() ) 1974 { 1975 childIds.add( cursor.get().getId() ); 1976 } 1977 1978 // detach the childId and all its children from oldParentId and all it parents excluding the root 1979 for ( Long pid : parentIds ) 1980 { 1981 for ( Long cid : childIds ) 1982 { 1983 subLevelIdx.drop( pid, cid ); 1984 } 1985 } 1986 1987 parentIds.clear(); 1988 tempId = newParentId; 1989 1990 // find all the parents of the newParentId 1991 while ( tempId != 0 && tempId != 1 && tempId != null ) 1992 { 1993 parentIds.add( tempId ); 1994 tempId = getParentId( tempId ); 1995 } 1996 1997 // attach the childId and all its children to newParentId and all it parents excluding the root 1998 for ( Long id : parentIds ) 1999 { 2000 for ( Long cid : childIds ) 2001 { 2002 subLevelIdx.add( id, cid ); 2003 } 2004 } 2005 } 2006 2007 2008 /** 2009 * For all aliases including and under the moved base, this method removes 2010 * one and subtree alias index tuples for old ancestors above the moved base 2011 * that will no longer be ancestors after the move. 2012 * 2013 * @param movedBase the base at which the move occured - the moved node 2014 * @throws Exception if system userIndices fail 2015 */ 2016 private void dropMovedAliasIndices( final DN movedBase ) throws Exception 2017 { 2018 // // Find all the aliases from movedBase down 2019 // IndexAssertion<Object,E> isBaseDescendant = new IndexAssertion<Object,E>() 2020 // { 2021 // public boolean assertCandidate( IndexEntry<Object,E> rec ) throws Exception 2022 // { 2023 // String dn = getEntryDn( rec.getId() ); 2024 // return dn.endsWith( movedBase.toString() ); 2025 // } 2026 // }; 2027 2028 Long movedBaseId = getEntryId( movedBase.getNormName() ); 2029 2030 if ( aliasIdx.reverseLookup( movedBaseId ) != null ) 2031 { 2032 dropAliasIndices( movedBaseId, movedBase ); 2033 } 2034 2035 // throw new NotImplementedException( "Fix the code below this line" ); 2036 2037 // NamingEnumeration<ForwardIndexEntry> aliases = 2038 // new IndexAssertionEnumeration( aliasIdx.listIndices( movedBase.toString(), true ), isBaseDescendant ); 2039 // 2040 // while ( aliases.hasMore() ) 2041 // { 2042 // ForwardIndexEntry entry = aliases.next(); 2043 // dropAliasIndices( (Long)entry.getId(), movedBase ); 2044 // } 2045 } 2046 2047 2048 /** 2049 * For the alias id all ancestor one and subtree alias tuples are moved 2050 * above the moved base. 2051 * 2052 * @param aliasId the id of the alias 2053 * @param movedBase the base where the move occured 2054 * @throws Exception if userIndices fail 2055 */ 2056 private void dropAliasIndices( Long aliasId, DN movedBase ) throws Exception 2057 { 2058 String targetDn = aliasIdx.reverseLookup( aliasId ); 2059 Long targetId = getEntryId( targetDn ); 2060 String aliasDn = getEntryDn( aliasId ); 2061 2062 /* 2063 * Start droping index tuples with the first ancestor right above the 2064 * moved base. This is the first ancestor effected by the move. 2065 */ 2066 DN ancestorDn = ( DN ) movedBase.getPrefix( 1 ); 2067 Long ancestorId = getEntryId( ancestorDn.getNormName() ); 2068 2069 /* 2070 * We cannot just drop all tuples in the one level and subtree userIndices 2071 * linking baseIds to the targetId. If more than one alias refers to 2072 * the target then droping all tuples with a value of targetId would 2073 * make all other aliases to the target inconsistent. 2074 * 2075 * We need to walk up the path of alias ancestors right above the moved 2076 * base until we reach the upSuffix, deleting each ( ancestorId, 2077 * targetId ) tuple in the subtree scope alias. We only need to do 2078 * this for the direct parent of the alias on the one level subtree if 2079 * the moved base is the alias. 2080 */ 2081 if ( aliasDn.equals( movedBase.toString() ) ) 2082 { 2083 oneAliasIdx.drop( ancestorId, targetId ); 2084 } 2085 2086 subAliasIdx.drop( ancestorId, targetId ); 2087 2088 while ( !ancestorDn.equals( suffixDn ) ) 2089 { 2090 ancestorDn = ( DN ) ancestorDn.getPrefix( 1 ); 2091 ancestorId = getEntryId( ancestorDn.getNormName() ); 2092 2093 subAliasIdx.drop( ancestorId, targetId ); 2094 } 2095 } 2096 2097 2098 /** 2099 * always returns 0 (zero), cause this is a inmemory store 2100 */ 2101 public int getCacheSize() 2102 { 2103 return 0; 2104 } 2105 2106 2107 public Index<String, E, Long> getEntryCsnIndex() 2108 { 2109 return entryCsnIdx; 2110 } 2111 2112 2113 public Index<String, E, Long> getEntryUuidIndex() 2114 { 2115 return entryUuidIdx; 2116 } 2117 2118 2119 public Index<String, E, Long> getObjectClassIndex() 2120 { 2121 return objectClassIdx; 2122 } 2123 2124 2125 public void setEntryCsnIndex( Index<String, E, Long> index ) throws Exception 2126 { 2127 protect( "entryCsnIndex" ); 2128 2129 if ( index instanceof AvlIndex<?, ?> ) 2130 { 2131 this.entryCsnIdx = ( AvlIndex<String, E> ) index; 2132 } 2133 else 2134 { 2135 this.entryCsnIdx = ( AvlIndex<String, E> ) convert( index ); 2136 } 2137 2138 systemIndices.put( index.getAttributeId(), entryCsnIdx ); 2139 } 2140 2141 2142 public void setSyncOnWrite( boolean sync ) 2143 { 2144 // do nothing 2145 } 2146 2147 2148 public void setWorkingDirectory( File wkDir ) 2149 { 2150 //do nothing 2151 } 2152 2153 2154 public File getWorkingDirectory() 2155 { 2156 // returns null always 2157 return null; 2158 } 2159 2160 2161 public boolean isSyncOnWrite() 2162 { 2163 return false; 2164 } 2165 2166 2167 public void setCacheSize( int size ) 2168 { 2169 // do nothing 2170 } 2171 2172 2173 public void setObjectClassIndex( Index<String, E, Long> index ) 2174 { 2175 protect( "objectClassIndex" ); 2176 2177 if ( index instanceof AvlIndex<?, ?> ) 2178 { 2179 this.objectClassIdx = ( AvlIndex<String, E> ) index; 2180 } 2181 else 2182 { 2183 objectClassIdx = convert( index ); 2184 } 2185 2186 systemIndices.put( index.getAttributeId(), objectClassIdx ); 2187 } 2188 2189 2190 public void setEntryUuidIndex( Index<String, E, Long> index ) 2191 { 2192 protect( "entryUuidIndex" ); 2193 if ( index instanceof AvlIndex<?, ?> ) 2194 { 2195 this.entryUuidIdx = ( AvlIndex<String, E> ) index; 2196 } 2197 else 2198 { 2199 entryUuidIdx = convert( index ); 2200 } 2201 2202 systemIndices.put( index.getAttributeId(), entryUuidIdx ); 2203 } 2204 2205 2206 /** 2207 * @{inhertDoc} 2208 */ 2209 public void sync() throws Exception 2210 { 2211 } 2212 2213 2214 /** 2215 * @{inhertDoc} 2216 */ 2217 public Long getDefaultId() 2218 { 2219 return 1L; 2220 } 2221 2222 }