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.impl.btree; 021 022 023 import java.io.File; 024 import java.util.Collections; 025 import java.util.HashSet; 026 import java.util.Iterator; 027 import java.util.Set; 028 029 import javax.naming.directory.SearchControls; 030 031 import org.apache.directory.server.constants.ApacheSchemaConstants; 032 import org.apache.directory.server.core.entry.ClonedServerEntry; 033 import org.apache.directory.server.core.filtering.BaseEntryFilteringCursor; 034 import org.apache.directory.server.core.filtering.EntryFilteringCursor; 035 import org.apache.directory.server.core.interceptor.context.AddOperationContext; 036 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext; 037 import org.apache.directory.server.core.interceptor.context.EntryOperationContext; 038 import org.apache.directory.server.core.interceptor.context.ListOperationContext; 039 import org.apache.directory.server.core.interceptor.context.LookupOperationContext; 040 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 041 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext; 042 import org.apache.directory.server.core.interceptor.context.MoveOperationContext; 043 import org.apache.directory.server.core.interceptor.context.RenameOperationContext; 044 import org.apache.directory.server.core.interceptor.context.SearchOperationContext; 045 import org.apache.directory.server.core.partition.AbstractPartition; 046 import org.apache.directory.server.core.partition.Partition; 047 import org.apache.directory.server.i18n.I18n; 048 import org.apache.directory.server.xdbm.Index; 049 import org.apache.directory.server.xdbm.IndexCursor; 050 import org.apache.directory.server.xdbm.search.Optimizer; 051 import org.apache.directory.server.xdbm.search.SearchEngine; 052 import org.apache.directory.shared.ldap.entry.ServerEntry; 053 import org.apache.directory.shared.ldap.exception.LdapContextNotEmptyException; 054 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 055 import org.apache.directory.shared.ldap.exception.LdapNoSuchObjectException; 056 import org.apache.directory.shared.ldap.name.DN; 057 import org.apache.directory.shared.ldap.schema.AttributeType; 058 import org.apache.directory.shared.ldap.schema.SchemaManager; 059 060 061 /** 062 * An abstract {@link Partition} that uses general BTree operations. 063 * 064 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 065 * @version $Rev: 927146 $ 066 */ 067 public abstract class BTreePartition<ID> extends AbstractPartition 068 { 069 protected static final Set<String> SYS_INDEX_OIDS; 070 071 static 072 { 073 Set<String> set = new HashSet<String>(); 074 set.add( ApacheSchemaConstants.APACHE_ALIAS_AT_OID ); 075 set.add( ApacheSchemaConstants.APACHE_EXISTENCE_AT_OID ); 076 set.add( ApacheSchemaConstants.APACHE_ONE_LEVEL_AT_OID ); 077 set.add( ApacheSchemaConstants.APACHE_N_DN_AT_OID ); 078 set.add( ApacheSchemaConstants.APACHE_ONE_ALIAS_AT_OID ); 079 set.add( ApacheSchemaConstants.APACHE_SUB_ALIAS_AT_OID ); 080 set.add( ApacheSchemaConstants.APACHE_UP_DN_AT_OID ); 081 //set.add( ApacheSchemaConstants.ENTRY_CSN_AT_OID ); 082 //set.add( ApacheSchemaConstants.ENTRY_UUID_AT_OID ); 083 //set.add( SchemaConstants.OBJECT_CLASS_AT_OID ); 084 SYS_INDEX_OIDS = Collections.unmodifiableSet( set ); 085 } 086 087 /** the search engine used to search the database */ 088 protected SearchEngine<ServerEntry, ID> searchEngine; 089 protected Optimizer optimizer; 090 091 protected SchemaManager schemaManager; 092 093 protected String id; 094 protected int cacheSize = -1; 095 protected DN suffix; 096 private File partitionDir; 097 098 /** The rootDSE context */ 099 protected ServerEntry contextEntry; 100 private Set<Index<? extends Object, ServerEntry, ID>> indexedAttributes; 101 102 103 // ------------------------------------------------------------------------ 104 // C O N S T R U C T O R S 105 // ------------------------------------------------------------------------ 106 107 /** 108 * Creates a B-tree based context partition. 109 */ 110 protected BTreePartition() 111 { 112 indexedAttributes = new HashSet<Index<? extends Object, ServerEntry, ID>>(); 113 } 114 115 116 // ------------------------------------------------------------------------ 117 // C O N F I G U R A T I O N M E T H O D S 118 // ------------------------------------------------------------------------ 119 120 /** 121 * {@inheritDoc} 122 */ 123 public void setSchemaManager( SchemaManager schemaManager ) 124 { 125 this.schemaManager = schemaManager; 126 } 127 128 129 /** 130 * {@inheritDoc} 131 */ 132 public SchemaManager getSchemaManager() 133 { 134 return schemaManager; 135 } 136 137 138 /** 139 * Gets the directory in which this Partition stores files. 140 * 141 * @return the directory in which this Partition stores files. 142 */ 143 public File getPartitionDir() 144 { 145 return partitionDir; 146 } 147 148 149 /** 150 * Sets the directory in which this Partition stores files. 151 * 152 * @param partitionDir the directory in which this Partition stores files. 153 */ 154 public void setPartitionDir( File partitionDir ) 155 { 156 this.partitionDir = partitionDir; 157 } 158 159 160 public void setIndexedAttributes( Set<Index<? extends Object, ServerEntry, ID>> indexedAttributes ) 161 { 162 this.indexedAttributes = indexedAttributes; 163 } 164 165 166 public void addIndexedAttributes( Index<? extends Object, ServerEntry, ID>... indexes ) 167 { 168 for ( Index<? extends Object, ServerEntry, ID> index : indexes ) 169 { 170 indexedAttributes.add( index ); 171 } 172 } 173 174 175 public Set<Index<? extends Object, ServerEntry, ID>> getIndexedAttributes() 176 { 177 return indexedAttributes; 178 } 179 180 181 /** 182 * Used to specify the entry cache size for a Partition. Various Partition 183 * implementations may interpret this value in different ways: i.e. total cache 184 * size limit verses the number of entries to cache. 185 * 186 * @param cacheSize the maximum size of the cache in the number of entries 187 */ 188 public void setCacheSize( int cacheSize ) 189 { 190 this.cacheSize = cacheSize; 191 } 192 193 194 /** 195 * Gets the entry cache size for this BTreePartition. 196 * 197 * @return the maximum size of the cache as the number of entries maximum before paging out 198 */ 199 public int getCacheSize() 200 { 201 return cacheSize; 202 } 203 204 205 /** 206 * Gets the unique identifier for this partition. 207 * 208 * @return the unique identifier for this partition 209 */ 210 public String getId() 211 { 212 return id; 213 } 214 215 216 /** 217 * Sets the unique identifier for this partition. 218 * 219 * @param id the unique identifier for this partition 220 */ 221 public void setId( String id ) 222 { 223 this.id = id; 224 } 225 226 227 // ----------------------------------------------------------------------- 228 // E N D C O N F I G U R A T I O N M E T H O D S 229 // ----------------------------------------------------------------------- 230 231 // ------------------------------------------------------------------------ 232 // Public Accessors - not declared in any interfaces just for this class 233 // ------------------------------------------------------------------------ 234 235 /** 236 * Gets the DefaultSearchEngine used by this ContextPartition to search the 237 * Database. 238 * 239 * @return the search engine 240 */ 241 public SearchEngine<ServerEntry, ID> getSearchEngine() 242 { 243 return searchEngine; 244 } 245 246 247 // ------------------------------------------------------------------------ 248 // Partition Interface Method Implementations 249 // ------------------------------------------------------------------------ 250 251 /** 252 * {@inheritDoc} 253 */ 254 public void delete( DeleteOperationContext opContext ) throws Exception 255 { 256 DN dn = opContext.getDn(); 257 258 ID id = getEntryId( dn.getNormName() ); 259 260 // don't continue if id is null 261 if ( id == null ) 262 { 263 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_699, dn ) ); 264 } 265 266 if ( getChildCount( id ) > 0 ) 267 { 268 LdapContextNotEmptyException cnee = new LdapContextNotEmptyException( I18n.err( I18n.ERR_700, dn ) ); 269 //cnee.setRemainingName( dn ); 270 throw cnee; 271 } 272 273 delete( id ); 274 } 275 276 277 public abstract void add( AddOperationContext opContext ) throws Exception; 278 279 280 public abstract void modify( ModifyOperationContext opContext ) throws Exception; 281 282 283 public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception 284 { 285 return new BaseEntryFilteringCursor( new ServerEntryCursorAdaptor<ID>( this, list( getEntryId( opContext 286 .getDn().getNormName() ) ) ), opContext ); 287 } 288 289 290 public EntryFilteringCursor search( SearchOperationContext opContext ) throws Exception 291 { 292 SearchControls searchCtls = opContext.getSearchControls(); 293 IndexCursor<ID, ServerEntry, ID> underlying; 294 295 underlying = searchEngine.cursor( opContext.getDn(), opContext.getAliasDerefMode(), opContext.getFilter(), 296 searchCtls ); 297 298 return new BaseEntryFilteringCursor( new ServerEntryCursorAdaptor<ID>( this, underlying ), opContext ); 299 } 300 301 302 public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception 303 { 304 ID id = getEntryId( opContext.getDn().getNormName() ); 305 306 if ( id == null ) 307 { 308 return null; 309 } 310 311 ClonedServerEntry entry = lookup( id ); 312 313 if ( ( opContext.getAttrsId() == null ) || ( opContext.getAttrsId().size() == 0 ) ) 314 { 315 return entry; 316 } 317 318 for ( AttributeType attributeType : ( ( ServerEntry ) entry.getOriginalEntry() ).getAttributeTypes() ) 319 { 320 if ( !opContext.getAttrsId().contains( attributeType.getOid() ) ) 321 { 322 entry.removeAttributes( attributeType ); 323 } 324 } 325 326 return entry; 327 } 328 329 330 public boolean hasEntry( EntryOperationContext opContext ) throws Exception 331 { 332 return null != getEntryId( opContext.getDn().getNormName() ); 333 } 334 335 336 public abstract void rename( RenameOperationContext opContext ) throws Exception; 337 338 339 public abstract void move( MoveOperationContext opContext ) throws Exception; 340 341 342 public abstract void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception; 343 344 345 public abstract void sync() throws Exception; 346 347 348 //////////////////// 349 // public abstract methods 350 351 // ------------------------------------------------------------------------ 352 // Index Operations 353 // ------------------------------------------------------------------------ 354 355 public abstract void addIndexOn( Index<? extends Object, ServerEntry, ID> index ) throws Exception; 356 357 358 public abstract boolean hasUserIndexOn( String attribute ) throws Exception; 359 360 361 public abstract boolean hasSystemIndexOn( String attribute ) throws Exception; 362 363 364 public abstract Index<String, ServerEntry, ID> getPresenceIndex(); 365 366 367 /** 368 * Gets the Index mapping the primary keys of parents to the 369 * primary keys of their children. 370 * 371 * @return the one level Index 372 */ 373 public abstract Index<ID, ServerEntry, ID> getOneLevelIndex(); 374 375 376 /** 377 * Gets the Index mapping the primary keys of ancestors to the 378 * primary keys of their descendants. 379 * 380 * @return the sub tree level Index 381 */ 382 public abstract Index<ID, ServerEntry, ID> getSubLevelIndex(); 383 384 385 /** 386 * Gets the Index mapping user provided distinguished names of entries as 387 * Strings to the BigInteger primary keys of entries. 388 * 389 * @return the user provided distinguished name Index 390 */ 391 public abstract Index<String, ServerEntry, ID> getUpdnIndex(); 392 393 394 /** 395 * Gets the Index mapping the normalized distinguished names of entries as 396 * Strings to the BigInteger primary keys of entries. 397 * 398 * @return the normalized distinguished name Index 399 */ 400 public abstract Index<String, ServerEntry, ID> getNdnIndex(); 401 402 403 /** 404 * Gets the alias index mapping parent entries with scope expanding aliases 405 * children one level below them; this system index is used to dereference 406 * aliases on one/single level scoped searches. 407 * 408 * @return the one alias index 409 */ 410 public abstract Index<ID, ServerEntry, ID> getOneAliasIndex(); 411 412 413 /** 414 * Gets the alias index mapping relative entries with scope expanding 415 * alias descendents; this system index is used to dereference aliases on 416 * subtree scoped searches. 417 * 418 * @return the sub alias index 419 */ 420 public abstract Index<ID, ServerEntry, ID> getSubAliasIndex(); 421 422 423 /** 424 * Gets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would 425 * be the aliasedObjectName and for X.500 would be aliasedEntryName. 426 * 427 * @return the index on the ALIAS_ATTRIBUTE 428 */ 429 public abstract Index<String, ServerEntry, ID> getAliasIndex(); 430 431 432 /** 433 * Sets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would 434 * be the aliasedObjectName and for X.500 would be aliasedEntryName. 435 * 436 * @org.apache.xbean.Property hidden="true" 437 * @param index the index on the ALIAS_ATTRIBUTE 438 * @throws Exception if there is a problem setting up the index 439 */ 440 public abstract void setAliasIndexOn( Index<String, ServerEntry, ID> index ) throws Exception; 441 442 443 /** 444 * Sets the attribute existence Index. 445 * 446 * @org.apache.xbean.Property hidden="true" 447 * @param index the attribute existence Index 448 * @throws Exception if there is a problem setting up the index 449 */ 450 public abstract void setPresenceIndexOn( Index<String, ServerEntry, ID> index ) throws Exception; 451 452 453 /** 454 * Sets the one level Index. 455 * 456 * @org.apache.xbean.Property hidden="true" 457 * @param index the one level Index 458 * @throws Exception if there is a problem setting up the index 459 */ 460 public abstract void setOneLevelIndexOn( Index<ID, ServerEntry, ID> index ) throws Exception; 461 462 463 // TODO - add sub level index setter 464 465 /** 466 * Sets the user provided distinguished name Index. 467 * 468 * @org.apache.xbean.Property hidden="true" 469 * @param index the updn Index 470 * @throws Exception if there is a problem setting up the index 471 */ 472 public abstract void setUpdnIndexOn( Index<String, ServerEntry, ID> index ) throws Exception; 473 474 475 /** 476 * Sets the normalized distinguished name Index. 477 * 478 * @org.apache.xbean.Property hidden="true" 479 * @param index the ndn Index 480 * @throws Exception if there is a problem setting up the index 481 */ 482 public abstract void setNdnIndexOn( Index<String, ServerEntry, ID> index ) throws Exception; 483 484 485 /** 486 * Sets the alias index mapping parent entries with scope expanding aliases 487 * children one level below them; this system index is used to dereference 488 * aliases on one/single level scoped searches. 489 * 490 * @org.apache.xbean.Property hidden="true" 491 * @param index a one level alias index 492 * @throws Exception if there is a problem setting up the index 493 */ 494 public abstract void setOneAliasIndexOn( Index<ID, ServerEntry, ID> index ) throws Exception; 495 496 497 /** 498 * Sets the alias index mapping relative entries with scope expanding 499 * alias descendents; this system index is used to dereference aliases on 500 * subtree scoped searches. 501 * 502 * @org.apache.xbean.Property hidden="true" 503 * @param index a subtree alias index 504 * @throws Exception if there is a problem setting up the index 505 */ 506 public abstract void setSubAliasIndexOn( Index<ID, ServerEntry, ID> index ) throws Exception; 507 508 509 /** 510 * {@inheritDoc} 511 */ 512 public void setSuffix( String suffix ) throws LdapInvalidDnException 513 { 514 this.suffix = new DN( suffix ); 515 } 516 517 518 /** 519 * {@inheritDoc} 520 */ 521 public String getSuffix() 522 { 523 return suffix.getName(); 524 } 525 526 527 /** 528 * {@inheritDoc} 529 */ 530 public DN getSuffixDn() 531 { 532 return suffix; 533 } 534 535 536 public abstract Index<? extends Object, ServerEntry, ID> getUserIndex( String attribute ) throws Exception; 537 538 539 public abstract Index<? extends Object, ServerEntry, ID> getSystemIndex( String attribute ) throws Exception; 540 541 542 public abstract ID getEntryId( String dn ) throws Exception; 543 544 545 public abstract String getEntryDn( ID id ) throws Exception; 546 547 548 public abstract ID getParentId( String dn ) throws Exception; 549 550 551 public abstract ID getParentId( ID childId ) throws Exception; 552 553 554 /** 555 * Gets the user provided distinguished name. 556 * 557 * @param id the entry id 558 * @return the user provided distinguished name 559 * @throws Exception if the updn index cannot be accessed 560 */ 561 public abstract String getEntryUpdn( ID id ) throws Exception; 562 563 564 /** 565 * Gets the user provided distinguished name. 566 * 567 * @param dn the normalized distinguished name 568 * @return the user provided distinguished name 569 * @throws Exception if the updn and ndn indices cannot be accessed 570 */ 571 public abstract String getEntryUpdn( String dn ) throws Exception; 572 573 574 public abstract ClonedServerEntry lookup( ID id ) throws Exception; 575 576 577 public abstract void delete( ID id ) throws Exception; 578 579 580 public abstract IndexCursor<ID, ServerEntry, ID> list( ID id ) throws Exception; 581 582 583 public abstract int getChildCount( ID id ) throws Exception; 584 585 586 public abstract void setProperty( String key, String value ) throws Exception; 587 588 589 public abstract String getProperty( String key ) throws Exception; 590 591 592 public abstract Iterator<String> getUserIndices(); 593 594 595 public abstract Iterator<String> getSystemIndices(); 596 597 598 /** 599 * Gets the count of the total number of entries in the database. 600 * 601 * TODO shouldn't this be a BigInteger instead of an int? 602 * 603 * @return the number of entries in the database 604 * @throws Exception if there is a failure to read the count 605 */ 606 public abstract int count() throws Exception; 607 }