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 */ 020package org.apache.directory.server.xdbm; 021 022 023import java.net.URI; 024import java.util.Arrays; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.concurrent.locks.ReadWriteLock; 032 033import org.apache.directory.api.ldap.model.constants.SchemaConstants; 034import org.apache.directory.api.ldap.model.entry.Entry; 035import org.apache.directory.api.ldap.model.entry.Modification; 036import org.apache.directory.api.ldap.model.exception.LdapException; 037import org.apache.directory.api.ldap.model.name.Dn; 038import org.apache.directory.api.ldap.model.name.Rdn; 039import org.apache.directory.api.ldap.model.schema.AttributeType; 040import org.apache.directory.server.constants.ApacheSchemaConstants; 041import org.apache.directory.server.core.api.interceptor.context.ModDnAva; 042import org.apache.directory.server.core.api.partition.PartitionTxn; 043 044import com.github.benmanes.caffeine.cache.Cache; 045 046 047/** 048 * Represents an entry store based on the Table, Index, and MasterTable 049 * database structure. 050 * 051 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 052 */ 053public interface Store 054{ 055 /* 056 * W H Y H A V E A S T O R E I N T E R F A C E ? 057 * ------------------------------------------------------ 058 * 059 * Some may question why we have this Store interface when the Partition 060 * interface abstracts away partition implementation details in the server 061 * core. This is due to a complicated chicken and egg problem with the 062 * additional need to abstract stores for the SearchEngine. This way the 063 * SearchEngine and it's default implementation can be independent of the 064 * Partition interface. Once this is achieved the default SearchEngine 065 * implementation can be removed from the core. This will allow for 066 * better modularization, with the ability to easily substitute new 067 * SearchEngine implementations into ApacheDS. 068 * 069 * 070 * H I S T O R Y 071 * ------------- 072 * 073 * Originally the JdbmStore class came about due to a cyclic dependency. 074 * The bootstrap-partition module is created by the bootstrap-plugin 075 * module. The core depends on the bootstrap-partition module to 076 * bootstrap the server. The bootstrap-partition module depends on the 077 * bootstrap-plugin which builds a JdbmStore stuffing it with all the 078 * information needed for the server to bootstrap. The bootstrap-plugin 079 * hence must be built before it can generate the bootstrap-partition and 080 * it cannot have a dependency on the core. We could not use the 081 * JdbmPartition because it depends on the Partition interface and this 082 * is an integral part of the core. If we did then there would be a 083 * cyclic dependency between modules in the apacheds pom. To avoid this 084 * the JdbmStore class was created and the guts of the JDBM partition were 085 * put into the jdbm-store module. This jdbm-store module does not depend 086 * on core and can be used by the bootstrap-plugin to build the 087 * bootstrap-partition. 088 * 089 * Hence it's project dependencies that drove the creation of the 090 * JdbmStore class. Later we realized, the default SeachEngine used by 091 * all Table, Index, MasterTable scheme based partitions depends on 092 * BTreePartition which depends on Partition. We would like to remove 093 * this search engine out of the core so it can easily be swapped out, 094 * but most importantly so we can have the search depend on any kind of 095 * store. There's no reason why the SearchEngine should depend on a 096 * Partition (store with search capabilities) when it just needs a simple 097 * store and it's indices to conduct search operations. 098 */ 099 String[] SYS_INDEX_OID_ARRAY = 100 { 101 ApacheSchemaConstants.APACHE_PRESENCE_AT_OID, 102 ApacheSchemaConstants.APACHE_RDN_AT_OID, 103 ApacheSchemaConstants.APACHE_ALIAS_AT_OID, 104 ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID, 105 ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID, 106 SchemaConstants.ENTRY_CSN_AT_OID, 107 SchemaConstants.OBJECT_CLASS_AT_OID, 108 SchemaConstants.ADMINISTRATIVE_ROLE_AT_OID 109 }; 110 111 Set<String> SYS_INDEX_OIDS = Collections.unmodifiableSet( new HashSet<String>( Arrays 112 .asList( SYS_INDEX_OID_ARRAY ) ) ); 113 114 115 /** 116 * Sets the partition path (working directory) for the store. 117 * 118 * @param partitionPath the new partition path 119 */ 120 void setPartitionPath( URI partitionPath ); 121 122 123 /** 124 * Gets the partition path (working directory) for the store. 125 * 126 * @return The current partition path (working directory) for the store 127 */ 128 URI getPartitionPath(); 129 130 131 /** 132 * Sets the flag telling the server to flush on disk when some 133 * modification has been done. 134 * @param isSyncOnWrite A boolean set to true if we have to flush on disk 135 * when a modification occurs 136 */ 137 void setSyncOnWrite( boolean isSyncOnWrite ); 138 139 140 /** 141 * @return <code>true</code> if we write to disk for every modification 142 */ 143 boolean isSyncOnWrite(); 144 145 146 /** 147 * Sets the cache size for this store. 148 * @param cacheSize The cache size 149 */ 150 void setCacheSize( int cacheSize ); 151 152 153 /** 154 * Gets the cache size for this store. 155 * 156 * @return The cache size 157 */ 158 int getCacheSize(); 159 160 161 /** 162 * Adds a (system or user) index to the list of index for this store. 163 * Note that the attribute id returned by Index.getAttributeId() must be 164 * the numeric OID. 165 * @param index The index to add 166 * @throws Exception If the addition failed 167 */ 168 void addIndex( Index<?, String> index ) throws Exception; 169 170 171 //------------------------------------------------------------------------ 172 // System index 173 //------------------------------------------------------------------------ 174 /** 175 * @return The Presence system index 176 */ 177 Index<String, String> getPresenceIndex(); 178 179 180 /** 181 * @return The Alias system index 182 */ 183 Index<Dn, String> getAliasIndex(); 184 185 186 /** 187 * @return The OneAlias system index 188 */ 189 Index<String, String> getOneAliasIndex(); 190 191 192 /** 193 * @return The SubAlias system index 194 */ 195 Index<String, String> getSubAliasIndex(); 196 197 198 /** 199 * Retrieve the SuffixID 200 * 201 * @param partitionTxn The transaction to use 202 * @return The suddix ID 203 * @throws LdapException If we can't get the suffix ID 204 */ 205 String getSuffixId( PartitionTxn partitionTxn ) throws LdapException; 206 207 208 /** 209 * @return The Rdn system index 210 */ 211 Index<ParentIdAndRdn, String> getRdnIndex(); 212 213 214 /** 215 * @return The ObjectClass system index 216 */ 217 Index<String, String> getObjectClassIndex(); 218 219 220 /** 221 * @return The EntryCSN system index 222 */ 223 Index<String, String> getEntryCsnIndex(); 224 225 226 /** 227 * @return An iterator build on top of the User's index 228 */ 229 Iterator<String> getUserIndices(); 230 231 232 /** 233 * @return An iterator build on top of the System's index 234 */ 235 Iterator<String> getSystemIndices(); 236 237 238 /** 239 * Tells if an index is already present in the User's <strong>or</strong> System's index list 240 * 241 * @param attributeType The attributeType we are looking for 242 * @return <code>true</code> if the index is already present in the 243 * User's <strong>or</strong> System's index list 244 * @throws LdapException If something went wrong 245 */ 246 boolean hasIndexOn( AttributeType attributeType ) throws LdapException; 247 248 249 /** 250 * Tells if an index is already present in the User's index list 251 * 252 * @param attributeType The attributeType index we are looking for 253 * @return <code>true</code> if the index is already present in the 254 * User's index list 255 * @throws LdapException If something went wrong 256 */ 257 boolean hasUserIndexOn( AttributeType attributeType ) throws LdapException; 258 259 260 /** 261 * Tells if an index is already present in the System's index list 262 * @param attributeType The index we are looking for 263 * @return <code>true</code> if the index is already present in the 264 * System's index list 265 * @throws LdapException If something went wrong 266 */ 267 boolean hasSystemIndexOn( AttributeType attributeType ) throws LdapException; 268 269 270 /** 271 * Get the user <strong>or</strong> system index associated with the given attributeType 272 * 273 * @param attributeType The index attributeType we are looking for 274 * @return The associated user <strong>or</strong> system index 275 * @throws IndexNotFoundException If the index does not exist 276 */ 277 Index<?, String> getIndex( AttributeType attributeType ) throws IndexNotFoundException; 278 279 280 /** 281 * Get the user index associated with the given name 282 * @param attributeType The index name we are looking for 283 * @return The associated user index 284 * @throws IndexNotFoundException If the index does not exist 285 */ 286 Index<?, String> getUserIndex( AttributeType attributeType ) throws IndexNotFoundException; 287 288 289 /** 290 * Get the system index associated with the given name 291 * @param attributeType The index name we are looking for 292 * @return The associated system index 293 * @throws IndexNotFoundException If the index does not exist 294 */ 295 Index<?, String> getSystemIndex( AttributeType attributeType ) throws IndexNotFoundException; 296 297 298 /** 299 * Gets the entry's id. Returns <code>null</code> if the Dn doesn't exist in this store. 300 * Note that the Dn must be normalized! 301 * 302 * @param partitionTxn The transaction to use 303 * @param dn the normalized entry Dn 304 * @return the entry's id, or <code>null</code> if the Dn doesn't exists 305 * @throws LdapException If we can't get the entry ID 306 */ 307 String getEntryId( PartitionTxn partitionTxn, Dn dn ) throws LdapException; 308 309 310 /** 311 * Gets the Entry's Dn identified by the given id. 312 * 313 * @param partitionTxn The transaction to use 314 * @param id the entry's id 315 * @return the entry's Dn 316 * @throws LdapException If we can't get the entry Dn 317 */ 318 Dn getEntryDn( PartitionTxn partitionTxn, String id ) throws LdapException; 319 320 321 /** 322 * Gets the UUID of an entry's parent using the child entry's UUID. 323 * Note that the suffix entry returns 0, which does not map to any entry. 324 * 325 * @param partitionTxn The transaction to use 326 * @param childId the UUID of the entry 327 * @return the id of the parent entry or zero if the suffix entry UUID is used 328 * @throws LdapException on failures to access the underlying store 329 */ 330 String getParentId( PartitionTxn partitionTxn, String childId ) throws LdapException; 331 332 333 /** 334 * Gets the total count of entries within this store. 335 * 336 * @param partitionTxn The transaction to use 337 * @return the total count of entries within this store 338 * @throws LdapException on failures to access the underlying store 339 */ 340 long count( PartitionTxn partitionTxn ) throws LdapException; 341 342 343 /** 344 * Delete an entry from the store 345 * 346 * @param partitionTxn The transaction to use 347 * @param id The Entry UUID we want to delete 348 * @return the deleted entry if found 349 * @throws LdapException If the deletion failed for any reason 350 */ 351 Entry delete( PartitionTxn partitionTxn, String id ) throws LdapException; 352 353 354 /** 355 * Get back an entry knowing its UUID 356 * 357 * @param partitionTxn The transaction to use 358 * @param id The Entry UUID we want to get back 359 * @return The found Entry, or null if not found 360 * @throws LdapException If the lookup failed for any reason (except a not found entry) 361 */ 362 Entry fetch( PartitionTxn partitionTxn, String id ) throws LdapException; 363 364 365 /** 366 * Get back an entry knowing its UUID 367 * 368 * @param partitionTxn The transaction to use 369 * @param id The Entry UUID we want to get back 370 * @param dn The entry DN when we have it 371 * @return The found Entry, or null if not found 372 * @throws LdapException If the lookup failed for any reason (except a not found entry) 373 */ 374 Entry fetch( PartitionTxn partitionTxn, String id, Dn dn ) throws LdapException; 375 376 377 /** 378 * Gets the count of immediate children of the given entry UUID. 379 * 380 * @param partitionTxn The transaction to use 381 * @param id the entry UUID 382 * @return the child count 383 * @throws LdapException on failures to access the underlying store 384 */ 385 long getChildCount( PartitionTxn partitionTxn, String id ) throws LdapException; 386 387 388 /** 389 * Modify an entry applying the given list of modifications. 390 * 391 * @param partitionTxn The transaction to use 392 * @param dn The Entry's Dn 393 * @param mods The list of modifications 394 * @return The modified entry 395 * @throws LdapException If the modification failed 396 */ 397 Entry modify( PartitionTxn partitionTxn, Dn dn, Modification... mods ) throws LdapException; 398 399 400 /** 401 * Changes the relative distinguished name of an entry specified by a 402 * distinguished name with the optional removal of the old Rdn attribute 403 * value from the entry. Name changes propagate down as dn changes to the 404 * descendants of the entry where the Rdn changed. 405 * 406 * An Rdn change operation does not change parent child relationships. It 407 * merely propagates a name change at a point in the DIT where the Rdn is 408 * changed. The change propagates down the subtree rooted at the 409 * distinguished name specified. 410 * 411 * @param partitionTxn The transaction to use 412 * @param dn the normalized distinguished name of the entry to alter 413 * @param newRdn the new Rdn to set 414 * @param deleteOldRdn whether or not to remove the old Rdn attr/val 415 * @param entry the modified entry 416 * @throws LdapException if there are any errors propagating the name changes 417 */ 418 void rename( PartitionTxn partitionTxn, Dn dn, Rdn newRdn, boolean deleteOldRdn, Entry entry ) throws LdapException; 419 420 421 /** 422 * Move and Rename operation. The entry is moved from one part of the DIT to another part of 423 * the DIT. Its RDN is also changed in the process. 424 * 425 * @param partitionTxn The transaction to use 426 * @param oldDn The previous DN 427 * @param newSuperiorDn The previous parent's DN 428 * @param newRdn The new DN 429 * @param modAvas The changed Attributes caused by the renaming (added and removed attributes) 430 * @param modifiedEntry the entry to move 431 * @throws LdapException If the modification failed 432 */ 433 void moveAndRename( PartitionTxn partitionTxn, Dn oldDn, Dn newSuperiorDn, Rdn newRdn, Map<String, List<ModDnAva>> modAvas, 434 Entry modifiedEntry ) throws LdapException; 435 436 437 /** 438 * <p>Move an entry from one place to the other. The Rdn remains unchanged, 439 * the parent Dn changes</p> 440 * <p>We have to update some of the index when moving an entry. Assuming 441 * that the target destination does not exist, the following index must 442 * be updated :</p> 443 * <ul> 444 * <li><b>oneLevel</b> index</li> 445 * <li><b>subLevel</b> index</li> 446 * </ul> 447 * <p>If the moved entry is an alias, then we also have to update the 448 * following index :</p> 449 * <ul> 450 * <li><b>oneAlias</b> index</li> 451 * <li><b>subAlias</b> index</li> 452 * </ul> 453 * <p>The <b>Alias</b> index is not updated, as the entry UUID won't change.</p> 454 * <p>We have a few check we must do before moving the entry : 455 * <ul> 456 * <li>The destination must not exist 457 * <li>The moved entry must exist (this has already been checked) 458 * <li>The moved entry must not inherit from a referral (already checked) 459 * </ul> 460 * 461 * @param partitionTxn The transaction to use 462 * @param oldDn The previous entry Dn 463 * @param newSuperior The new superior Dn 464 * @param newDn The new Dn 465 * @param entry The entry to move 466 * @throws LdapException If the move failed 467 */ 468 void move( PartitionTxn partitionTxn, Dn oldDn, Dn newSuperior, Dn newDn, Entry entry ) throws LdapException; 469 470 471 /** 472 * Expose the Master table 473 * @return The masterTable instance 474 */ 475 MasterTable getMasterTable(); 476 477 478 /** 479 * @return The ReadWrite lock used to protect the server against concurrent read and writes 480 */ 481 ReadWriteLock getReadWriteLock(); 482 483 484 /** 485 * @return the Alias cache 486 * @return The cache 487 */ 488 Cache< String, Dn > getAliasCache(); 489}