View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.partition.impl.btree;
21  
22  
23  import org.apache.directory.server.core.entry.ClonedServerEntry;
24  import org.apache.directory.server.core.entry.ServerEntry;
25  import org.apache.directory.server.core.filtering.EntryFilteringCursor;
26  import org.apache.directory.server.core.filtering.BaseEntryFilteringCursor;
27  import org.apache.directory.server.core.interceptor.context.AddOperationContext;
28  import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
29  import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
30  import org.apache.directory.server.core.interceptor.context.ListOperationContext;
31  import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
32  import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
33  import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
34  import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
35  import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
36  import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
37  import org.apache.directory.server.core.partition.Partition;
38  import org.apache.directory.server.core.partition.impl.btree.gui.PartitionViewer;
39  import org.apache.directory.server.schema.registries.Registries;
40  import org.apache.directory.server.xdbm.*;
41  import org.apache.directory.server.xdbm.search.Optimizer;
42  import org.apache.directory.server.xdbm.search.SearchEngine;
43  import org.apache.directory.shared.ldap.exception.LdapContextNotEmptyException;
44  import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
45  import org.apache.directory.shared.ldap.name.LdapDN;
46  import org.apache.directory.shared.ldap.schema.AttributeType;
47  
48  import javax.naming.directory.SearchControls;
49  import java.util.Collections;
50  import java.util.HashSet;
51  import java.util.Iterator;
52  import java.util.Set;
53  
54  
55  /**
56   * An abstract {@link Partition} that uses general BTree operations.
57   *
58   * @org.apache.xbean.XBean
59   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
60   * @version $Rev: 689396 $
61   */
62  public abstract class BTreePartition implements Partition
63  {
64      protected static final Set<String> SYS_INDEX_OIDS;
65  
66      static
67      {
68          Set<String> set = new HashSet<String>();
69          set.add( Store.ALIAS );
70          set.add( Store.PRESENCE );
71          set.add( Store.ONELEVEL );
72          set.add( Store.NDN );
73          set.add( Store.ONEALIAS );
74          set.add( Store.SUBALIAS );
75          set.add( Store.UPDN );
76          SYS_INDEX_OIDS = Collections.unmodifiableSet( set );
77      }
78  
79      /** the search engine used to search the database */
80      protected SearchEngine<ServerEntry> searchEngine;
81      protected Optimizer optimizer;
82  
83      protected Registries registries;
84  
85      protected String id;
86      protected int cacheSize = -1;
87      protected LdapDN suffixDn;
88      protected String suffix;
89      
90      /** The rootDSE context */
91      protected ServerEntry contextEntry;
92  
93  
94      // ------------------------------------------------------------------------
95      // C O N S T R U C T O R S
96      // ------------------------------------------------------------------------
97  
98  
99      /**
100      * Creates a B-tree based context partition.
101      */
102     protected BTreePartition()
103     {
104     }
105 
106     
107     // ------------------------------------------------------------------------
108     // C O N F I G U R A T I O N   M E T H O D S
109     // ------------------------------------------------------------------------
110 
111 
112     /**
113      * Used to specify the entry cache size for a Partition.  Various Partition
114      * implementations may interpret this value in different ways: i.e. total cache
115      * size limit verses the number of entries to cache.
116      *
117      * @param cacheSize the maximum size of the cache in the number of entries
118      */
119     public void setCacheSize( int cacheSize )
120     {
121         this.cacheSize = cacheSize;
122     }
123 
124 
125     /**
126      * Gets the entry cache size for this BTreePartition.
127      *
128      * @return the maximum size of the cache as the number of entries maximum before paging out
129      */
130     public int getCacheSize()
131     {
132         return cacheSize;
133     }
134 
135 
136     /**
137      * Gets the unique identifier for this partition.
138      *
139      * @return the unique identifier for this partition
140      */
141     public String getId()
142     {
143         return id;
144     }
145 
146 
147     /**
148      * Sets the unique identifier for this partition.
149      *
150      * @param id the unique identifier for this partition
151      */
152     public void setId( String id )
153     {
154         this.id = id;
155     }
156     
157     
158     // -----------------------------------------------------------------------
159     // E N D   C O N F I G U R A T I O N   M E T H O D S
160     // -----------------------------------------------------------------------
161 
162 
163     /**
164      * Allows for schema entity registries to be swapped out during runtime.  This is 
165      * primarily here to facilitate the swap out of a temporary bootstrap registry.  
166      * Registry changes require swapping out the search engine used by a partition 
167      * since the registries are used by elements in the search engine.
168      * 
169      * @param registries the schema entity registries
170      * @throws Exception 
171      */
172     public abstract void setRegistries( Registries registries ) throws Exception;
173 
174     
175     // ------------------------------------------------------------------------
176     // Public Accessors - not declared in any interfaces just for this class
177     // ------------------------------------------------------------------------
178 
179     /**
180      * Gets the DefaultSearchEngine used by this ContextPartition to search the
181      * Database. 
182      *
183      * @return the search engine
184      */
185     public SearchEngine<ServerEntry> getSearchEngine()
186     {
187         return searchEngine;
188     }
189 
190 
191     // ------------------------------------------------------------------------
192     // Partition Interface Method Implementations
193     // ------------------------------------------------------------------------
194 
195 
196     public void delete( DeleteOperationContext opContext ) throws Exception
197     {
198         LdapDN dn = opContext.getDn();
199         
200         Long id = getEntryId( dn.getNormName() );
201 
202         // don't continue if id is null
203         if ( id == null )
204         {
205             throw new LdapNameNotFoundException( "Could not find entry at '" + dn + "' to delete it!" );
206         }
207 
208         if ( getChildCount( id ) > 0 )
209         {
210             LdapContextNotEmptyException cnee = new LdapContextNotEmptyException( "[66] Cannot delete entry " + dn
211                 + " it has children!" );
212             cnee.setRemainingName( dn );
213             throw cnee;
214         }
215 
216         delete( id );
217     }
218 
219 
220     public abstract void add( AddOperationContext opContext ) throws Exception;
221 
222 
223     public abstract void modify( ModifyOperationContext opContext ) throws Exception;
224 
225 
226     public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
227     {
228         return new BaseEntryFilteringCursor( new ServerEntryCursorAdaptor( this, 
229             list( getEntryId( opContext.getDn().getNormName() ) ) ), opContext );
230     }
231 
232 
233     public EntryFilteringCursor search( SearchOperationContext opContext ) throws Exception
234     {
235         SearchControls searchCtls = opContext.getSearchControls();
236         IndexCursor<Long,ServerEntry> underlying;
237 
238         underlying = searchEngine.cursor( 
239             opContext.getDn(),
240             opContext.getAliasDerefMode(),
241             opContext.getFilter(), 
242             searchCtls );
243 
244         return new BaseEntryFilteringCursor( new ServerEntryCursorAdaptor( this, underlying ), opContext );
245     }
246 
247 
248     public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
249     {
250         Long id = getEntryId( opContext.getDn().getNormName() );
251         
252         if ( id == null )
253         {
254             return null;
255         }
256         
257         ClonedServerEntry entry = lookup( id );
258 
259         if ( ( opContext.getAttrsId() == null ) || ( opContext.getAttrsId().size() == 0 ) )
260         {
261             return entry;
262         }
263 
264         for ( AttributeType attributeType : ((ServerEntry)entry.getOriginalEntry()).getAttributeTypes() )
265         {
266             if ( ! opContext.getAttrsId().contains( attributeType.getOid() ) )
267             {
268                 entry.removeAttributes( attributeType );
269             }
270         }
271 
272         return entry;
273     }
274 
275 
276     public boolean hasEntry( EntryOperationContext opContext ) throws Exception
277     {
278         return null != getEntryId( opContext.getDn().getNormName() );
279     }
280 
281 
282     public abstract void rename( RenameOperationContext opContext ) throws Exception;
283 
284 
285     public abstract void move( MoveOperationContext opContext ) throws Exception;
286 
287 
288     public abstract void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception;
289 
290 
291     public abstract void sync() throws Exception;
292 
293 
294     public abstract void destroy() throws Exception;
295 
296 
297     public abstract boolean isInitialized();
298 
299 
300     public void inspect() throws Exception
301     {
302         PartitionViewer viewer = new PartitionViewer( this, registries );
303         viewer.execute();
304     }
305 
306 
307     ////////////////////
308     // public abstract methods
309 
310     // ------------------------------------------------------------------------
311     // Index Operations 
312     // ------------------------------------------------------------------------
313 
314     public abstract void addIndexOn( Index<Long,ServerEntry> index ) throws Exception;
315 
316 
317     public abstract boolean hasUserIndexOn( String attribute ) throws Exception;
318 
319 
320     public abstract boolean hasSystemIndexOn( String attribute ) throws Exception;
321 
322 
323     public abstract Index<String,ServerEntry> getPresenceIndex();
324 
325 
326     /**
327      * Gets the Index mapping the Long primary keys of parents to the 
328      * Long primary keys of their children.
329      *
330      * @return the one level Index
331      */
332     public abstract Index<Long,ServerEntry> getOneLevelIndex();
333 
334 
335     /**
336      * Gets the Index mapping the Long primary keys of ancestors to the 
337      * Long primary keys of their descendants.
338      *
339      * @return the sub tree level Index
340      */
341     public abstract Index<Long,ServerEntry> getSubLevelIndex();
342 
343 
344     /**
345      * Gets the Index mapping user provided distinguished names of entries as 
346      * Strings to the BigInteger primary keys of entries.
347      *
348      * @return the user provided distinguished name Index
349      */
350     public abstract Index<String,ServerEntry> getUpdnIndex();
351 
352 
353     /**
354      * Gets the Index mapping the normalized distinguished names of entries as
355      * Strings to the BigInteger primary keys of entries.  
356      *
357      * @return the normalized distinguished name Index
358      */
359     public abstract Index<String,ServerEntry> getNdnIndex();
360 
361 
362     /**
363      * Gets the alias index mapping parent entries with scope expanding aliases 
364      * children one level below them; this system index is used to dereference
365      * aliases on one/single level scoped searches.
366      * 
367      * @return the one alias index
368      */
369     public abstract Index<Long,ServerEntry> getOneAliasIndex();
370 
371 
372     /**
373      * Gets the alias index mapping relative entries with scope expanding 
374      * alias descendents; this system index is used to dereference aliases on 
375      * subtree scoped searches.
376      * 
377      * @return the sub alias index
378      */
379     public abstract Index<Long,ServerEntry> getSubAliasIndex();
380 
381 
382     /**
383      * Gets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
384      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
385      * 
386      * @return the index on the ALIAS_ATTRIBUTE
387      */
388     public abstract Index<String,ServerEntry> getAliasIndex();
389 
390 
391     /**
392      * Sets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
393      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
394      * 
395      * @param index the index on the ALIAS_ATTRIBUTE
396      * @throws Exception if there is a problem setting up the index
397      */
398     public abstract void setAliasIndexOn( Index<String,ServerEntry> index ) throws Exception;
399 
400 
401     /**
402      * Sets the attribute existance Index.
403      *
404      * @param index the attribute existance Index
405      * @throws Exception if there is a problem setting up the index
406      */
407     public abstract void setPresenceIndexOn( Index<String,ServerEntry> index ) throws Exception;
408 
409 
410     /**
411      * Sets the one level Index.
412      *
413      * @param index the one level Index
414      * @throws Exception if there is a problem setting up the index
415      */
416     public abstract void setOneLevelIndexOn( Index<Long,ServerEntry> index ) throws Exception;
417 
418     // TODO - add sub level index setter
419 
420     /**
421      * Sets the user provided distinguished name Index.
422      *
423      * @param index the updn Index
424      * @throws Exception if there is a problem setting up the index
425      */
426     public abstract void setUpdnIndexOn( Index<String,ServerEntry> index ) throws Exception;
427 
428 
429     /**
430      * Sets the normalized distinguished name Index.
431      *
432      * @param index the ndn Index
433      * @throws Exception if there is a problem setting up the index
434      */
435     public abstract void setNdnIndexOn( Index<String,ServerEntry> index ) throws Exception;
436 
437 
438     /**
439      * Sets the alias index mapping parent entries with scope expanding aliases 
440      * children one level below them; this system index is used to dereference
441      * aliases on one/single level scoped searches.
442      * 
443      * @param index a one level alias index
444      * @throws Exception if there is a problem setting up the index
445      */
446     public abstract void setOneAliasIndexOn( Index<Long,ServerEntry> index ) throws Exception;
447 
448 
449     /**
450      * Sets the alias index mapping relative entries with scope expanding 
451      * alias descendents; this system index is used to dereference aliases on 
452      * subtree scoped searches.
453      * 
454      * @param index a subtree alias index
455      * @throws Exception if there is a problem setting up the index
456      */
457     public abstract void setSubAliasIndexOn( Index<Long,ServerEntry> index ) throws Exception;
458 
459 
460     public abstract Index<?,ServerEntry> getUserIndex( String attribute ) throws Exception;
461 
462 
463     public abstract Index<?,ServerEntry> getSystemIndex( String attribute ) throws Exception;
464 
465 
466     public abstract Long getEntryId( String dn ) throws Exception;
467 
468 
469     public abstract String getEntryDn( Long id ) throws Exception;
470 
471 
472     public abstract Long getParentId( String dn ) throws Exception;
473 
474 
475     public abstract Long getParentId( Long childId ) throws Exception;
476 
477 
478     /**
479      * Gets the user provided distinguished name.
480      *
481      * @param id the entry id
482      * @return the user provided distinguished name
483      * @throws Exception if the updn index cannot be accessed
484      */
485     public abstract String getEntryUpdn( Long id ) throws Exception;
486 
487 
488     /**
489      * Gets the user provided distinguished name.
490      *
491      * @param dn the normalized distinguished name
492      * @return the user provided distinguished name
493      * @throws Exception if the updn and ndn indices cannot be accessed
494      */
495     public abstract String getEntryUpdn( String dn ) throws Exception;
496 
497 
498     public abstract ClonedServerEntry lookup( Long id ) throws Exception;
499 
500 
501     public abstract void delete( Long id ) throws Exception;
502 
503 
504     public abstract IndexCursor<Long,ServerEntry> list( Long id ) throws Exception;
505 
506 
507     public abstract int getChildCount( Long id ) throws Exception;
508 
509 
510     public abstract void setProperty( String key, String value ) throws Exception;
511 
512 
513     public abstract String getProperty( String key ) throws Exception;
514 
515 
516     public abstract Iterator<String> getUserIndices();
517 
518 
519     public abstract Iterator<String> getSystemIndices();
520 
521 
522     /**
523      * Gets the count of the total number of entries in the database.
524      *
525      * TODO shouldn't this be a BigInteger instead of an int? 
526      * 
527      * @return the number of entries in the database 
528      * @throws Exception if there is a failure to read the count
529      */
530     public abstract int count() throws Exception;
531 }