View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.partition.impl.btree;
18  
19  
20  import java.math.BigInteger;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.Map;
24  
25  import javax.naming.Name;
26  import javax.naming.NamingEnumeration;
27  import javax.naming.NamingException;
28  import javax.naming.directory.Attribute;
29  import javax.naming.directory.Attributes;
30  import javax.naming.directory.ModificationItem;
31  import javax.naming.directory.SearchControls;
32  
33  import org.apache.ldap.common.exception.LdapContextNotEmptyException;
34  import org.apache.ldap.common.exception.LdapNameNotFoundException;
35  import org.apache.ldap.common.filter.ExprNode;
36  import org.apache.ldap.common.message.LockableAttributesImpl;
37  import org.apache.ldap.common.schema.AttributeType;
38  import org.apache.ldap.common.util.ArrayUtils;
39  import org.apache.ldap.server.DirectoryServiceConfiguration;
40  import org.apache.ldap.server.configuration.DirectoryPartitionConfiguration;
41  import org.apache.ldap.server.enumeration.SearchResultEnumeration;
42  import org.apache.ldap.server.partition.DirectoryPartition;
43  import org.apache.ldap.server.partition.Oid;
44  import org.apache.ldap.server.partition.impl.btree.gui.PartitionViewer;
45  import org.apache.ldap.server.schema.AttributeTypeRegistry;
46  import org.apache.ldap.server.schema.OidRegistry;
47  
48  
49  /***
50   * An abstract {@link DirectoryPartition} that uses general BTree operations.
51   *
52   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
53   * @version $Rev: 307234 $
54   */
55  public abstract class BTreeDirectoryPartition implements DirectoryPartition
56  {
57      /*** ===================================================================
58  
59       The following OID branch is reserved for the directory TLP once it
60       graduates the incubator:
61  
62         1.2.6.1.4.1.18060.1.1
63  
64       The following branch is reserved for the apache directory server:
65  
66         1.2.6.1.4.1.18060.1.1.1
67  
68        The following branch is reserved for use by apache directory server Syntaxes:
69  
70          1.2.6.1.4.1.18060.1.1.1.1
71  
72        The following branch is reserved for use by apache directory server MatchingRules:
73  
74          1.2.6.1.4.1.18060.1.1.1.2
75  
76        The following branch is reserved for use by apache directory server AttributeTypes:
77  
78          1.2.6.1.4.1.18060.1.1.1.3
79  
80            * 1.2.6.1.4.1.18060.1.1.1.3.1 - apacheNdn
81            * 1.2.6.1.4.1.18060.1.1.1.3.2 - apacheUpdn
82            * 1.2.6.1.4.1.18060.1.1.1.3.3 - apacheExistance
83            * 1.2.6.1.4.1.18060.1.1.1.3.4 - apacheHierarchy
84            * 1.2.6.1.4.1.18060.1.1.1.3.5 - apacheOneAlias
85            * 1.2.6.1.4.1.18060.1.1.1.3.6 - apacheSubAlias
86            * 1.2.6.1.4.1.18060.1.1.1.3.7 - apacheAlias
87  
88        The following branch is reserved for use by apache directory server ObjectClasses:
89  
90          1.2.6.1.4.1.18060.1.1.1.4
91  
92      ==================================================================== */
93  
94  
95      /***
96       * the search engine used to search the database
97       */
98      private SearchEngine searchEngine = null;
99      private AttributeTypeRegistry attributeTypeRegistry = null;
100 
101     // ------------------------------------------------------------------------
102     // C O N S T R U C T O R S
103     // ------------------------------------------------------------------------
104 
105     /***
106      * Creates a B-tree based context partition.
107      */
108     protected BTreeDirectoryPartition()
109     {
110     }
111     
112 
113     public void init( DirectoryServiceConfiguration factoryCfg, DirectoryPartitionConfiguration cfg ) throws NamingException
114     {
115         attributeTypeRegistry = factoryCfg.getGlobalRegistries().getAttributeTypeRegistry();
116         OidRegistry oidRegistry = factoryCfg.getGlobalRegistries().getOidRegistry();
117         ExpressionEvaluator evaluator = new ExpressionEvaluator( this, oidRegistry, attributeTypeRegistry );
118         ExpressionEnumerator enumerator = new ExpressionEnumerator( this, attributeTypeRegistry, evaluator );
119         this.searchEngine = new DefaultSearchEngine( this, evaluator, enumerator );
120 
121         HashSet sysOidSet = new HashSet();
122         sysOidSet.add( Oid.EXISTANCE );
123         sysOidSet.add( Oid.HIERARCHY );
124         sysOidSet.add( Oid.UPDN );
125         sysOidSet.add( Oid.NDN );
126         sysOidSet.add( Oid.ONEALIAS );
127         sysOidSet.add( Oid.SUBALIAS );
128         sysOidSet.add( Oid.ALIAS );
129 
130         Iterator i = cfg.getIndexedAttributes().iterator();
131         while( i.hasNext() )
132         {
133             String name = ( String ) i.next();
134             String oid = oidRegistry.getOid( name );
135             AttributeType type = attributeTypeRegistry.lookup( oid );
136 
137             // check if attribute is a system attribute
138             if ( sysOidSet.contains( oid ) )
139             {
140                 if ( oid.equals( Oid.EXISTANCE ) )
141                 {
142                     setExistanceIndexOn( type );
143                 }
144                 else if ( oid.equals( Oid.HIERARCHY ) )
145                 {
146                     setHierarchyIndexOn( type );
147                 }
148                 else if ( oid.equals( Oid.UPDN ) )
149                 {
150                     setUpdnIndexOn( type );
151                 }
152                 else if ( oid.equals( Oid.NDN ) )
153                 {
154                     setNdnIndexOn( type );
155                 }
156                 else if ( oid.equals( Oid.ONEALIAS ) )
157                 {
158                     setOneAliasIndexOn( type );
159                 }
160                 else if ( oid.equals( Oid.SUBALIAS ) )
161                 {
162                     setSubAliasIndexOn( type );
163                 }
164                 else if ( oid.equals( Oid.ALIAS ) )
165                 {
166                     setAliasIndexOn( type );
167                 }
168                 else
169                 {
170                     throw new NamingException( "Unidentified system index "
171                         + oid );
172                 }
173             }
174             else
175             {
176                 addIndexOn( type );
177             }
178         }
179 
180         // add entry for context, if it does not exist
181         Attributes suffixOnDisk = getSuffixEntry();
182         if ( suffixOnDisk == null )
183         {
184             add( cfg.getSuffix(),
185                  cfg.getNormalizedSuffix( factoryCfg.getGlobalRegistries().getMatchingRuleRegistry() ),
186                  cfg.getContextEntry() );
187         }
188     }
189 
190     
191     // ------------------------------------------------------------------------
192     // Public Accessors - not declared in any interfaces just for this class
193     // ------------------------------------------------------------------------
194 
195 
196     /***
197      * Gets the DefaultSearchEngine used by this ContextPartition to search the
198      * Database. 
199      *
200      * @return the search engine
201      */
202     public SearchEngine getSearchEngine()
203     {
204         return searchEngine;
205     }
206 
207 
208     // ------------------------------------------------------------------------
209     // ContextPartition Interface Method Implementations
210     // ------------------------------------------------------------------------
211 
212 
213     public void delete( Name dn ) throws NamingException
214     {
215         BigInteger id = getEntryId( dn.toString() );
216 
217         // don't continue if id is null
218         if ( id == null )
219         {
220             throw new LdapNameNotFoundException( "Could not find entry at '"
221                     + dn + "' to delete it!");
222         }
223 
224         if ( getChildCount( id ) > 0 )
225         {
226             LdapContextNotEmptyException cnee = new LdapContextNotEmptyException(
227                 "[66] Cannot delete entry " + dn + " it has children!" );
228             cnee.setRemainingName( dn );
229             throw cnee;
230         }
231         
232         delete( id );
233     }
234     
235     public abstract void add( String updn, Name dn, Attributes entry ) throws NamingException;
236     public abstract void modify( Name dn, int modOp, Attributes mods ) throws NamingException;
237     public abstract void modify( Name dn, ModificationItem[] mods ) throws NamingException;
238 
239 
240     public NamingEnumeration list( Name base ) throws NamingException
241     {
242         SearchResultEnumeration list;
243         list = new BTreeSearchResultEnumeration( ArrayUtils.EMPTY_STRING_ARRAY,
244                 list( getEntryId( base.toString() ) ), this, attributeTypeRegistry );
245         return list;
246     }
247     
248     
249     public NamingEnumeration search( Name base, Map env, ExprNode filter,
250                                      SearchControls searchCtls )
251         throws NamingException
252     {
253         String [] attrIds = searchCtls.getReturningAttributes();
254         NamingEnumeration underlying = null;
255         
256         underlying = searchEngine.search( base, env, filter, searchCtls );
257         
258         return new BTreeSearchResultEnumeration( attrIds, underlying, this, attributeTypeRegistry );
259     }
260 
261 
262     public Attributes lookup( Name dn ) throws NamingException
263     {
264         return lookup( getEntryId( dn.toString() ) );
265     }
266 
267 
268     public Attributes lookup( Name dn, String [] attrIds ) throws NamingException
269     {
270         if ( attrIds == null || attrIds.length == 0 )
271         {
272             return lookup( dn );
273         }
274 
275         Attributes entry = lookup( dn );
276         Attributes retval = new LockableAttributesImpl();
277 
278         for ( int ii = 0; ii < attrIds.length; ii++ )
279         {
280             Attribute attr = entry.get( attrIds[0] );
281 
282             if ( attr != null )
283             {
284                 retval.put( attr );
285             }
286         }
287 
288         return retval;
289     }
290 
291 
292     public boolean hasEntry( Name dn ) throws NamingException
293     {
294         return null != getEntryId( dn.toString() );
295     }
296 
297 
298     public abstract void modifyRn( Name dn, String newRdn, boolean deleteOldRdn ) throws NamingException;
299     public abstract void move( Name oldChildDn, Name newParentDn ) throws NamingException;
300     public abstract void move( Name oldChildDn, Name newParentDn, String newRdn,
301         boolean deleteOldRdn ) throws NamingException;
302 
303 
304     public abstract void sync() throws NamingException;
305     public abstract void destroy();
306     public abstract boolean isInitialized();
307 
308     public boolean isSuffix( Name dn ) throws NamingException
309     {
310         return getSuffix( true ).equals( dn ) ;
311     }
312 
313 
314     public void inspect() throws Exception
315     {
316         PartitionViewer viewer = new PartitionViewer( this, searchEngine );
317         viewer.execute();
318     }
319     
320     ////////////////////
321     // public abstract methods
322     
323     // ------------------------------------------------------------------------
324     // Index Operations 
325     // ------------------------------------------------------------------------
326 
327 
328     public abstract void addIndexOn( AttributeType attribute ) throws NamingException;
329     public abstract boolean hasUserIndexOn( String attribute );
330     public abstract boolean hasSystemIndexOn( String attribute );
331     public abstract Index getExistanceIndex();
332 
333     /***
334      * Gets the Index mapping the BigInteger primary keys of parents to the 
335      * BigInteger primary keys of their children.
336      *
337      * @return the hierarchy Index
338      */
339     public abstract Index getHierarchyIndex();
340     
341     /***
342      * Gets the Index mapping user provided distinguished names of entries as 
343      * Strings to the BigInteger primary keys of entries.
344      *
345      * @return the user provided distinguished name Index
346      */
347     public abstract Index getUpdnIndex();
348 
349     /***
350      * Gets the Index mapping the normalized distinguished names of entries as
351      * Strings to the BigInteger primary keys of entries.  
352      *
353      * @return the normalized distinguished name Index
354      */
355     public abstract Index getNdnIndex();
356 
357     /***
358      * Gets the alias index mapping parent entries with scope expanding aliases 
359      * children one level below them; this system index is used to dereference
360      * aliases on one/single level scoped searches.
361      * 
362      * @return the one alias index
363      */
364     public abstract Index getOneAliasIndex();
365 
366     /***
367      * Gets the alias index mapping relative entries with scope expanding 
368      * alias descendents; this system index is used to dereference aliases on 
369      * subtree scoped searches.
370      * 
371      * @return the sub alias index
372      */
373     public abstract Index getSubAliasIndex();
374 
375     /***
376      * Gets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
377      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
378      * 
379      * @return the index on the ALIAS_ATTRIBUTE
380      */
381     public abstract Index getAliasIndex();
382 
383     /***
384      * Sets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
385      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
386      * 
387      * @param attrType the index on the ALIAS_ATTRIBUTE
388      */
389     public abstract void setAliasIndexOn( AttributeType attrType ) throws NamingException;
390 
391     /***
392      * Sets the attribute existance Index.
393      *
394      * @param attrType the attribute existance Index
395      */    
396     public abstract void setExistanceIndexOn( AttributeType attrType ) throws NamingException;
397 
398     /***
399      * Sets the hierarchy Index.
400      *
401      * @param attrType the hierarchy Index
402      */    
403     public abstract void setHierarchyIndexOn( AttributeType attrType ) throws NamingException;
404 
405     /***
406      * Sets the user provided distinguished name Index.
407      *
408      * @param attrType the updn Index
409      */    
410     public abstract void setUpdnIndexOn( AttributeType attrType ) throws NamingException;
411 
412     /***
413      * Sets the normalized distinguished name Index.
414      *
415      * @param attrType the ndn Index
416      */    
417     public abstract void setNdnIndexOn( AttributeType attrType ) throws NamingException;
418     
419     /***
420      * Sets the alias index mapping parent entries with scope expanding aliases 
421      * children one level below them; this system index is used to dereference
422      * aliases on one/single level scoped searches.
423      * 
424      * @param attrType a one level alias index
425      */
426     public abstract void setOneAliasIndexOn( AttributeType attrType ) throws NamingException;
427     
428     /***
429      * Sets the alias index mapping relative entries with scope expanding 
430      * alias descendents; this system index is used to dereference aliases on 
431      * subtree scoped searches.
432      * 
433      * @param attrType a subtree alias index
434      */
435     public abstract void setSubAliasIndexOn( AttributeType attrType ) throws NamingException;
436     public abstract Index getUserIndex( String attribute ) throws IndexNotFoundException;
437     public abstract Index getSystemIndex( String attribute ) throws IndexNotFoundException;
438     public abstract BigInteger getEntryId( String dn ) throws NamingException;
439     public abstract String getEntryDn( BigInteger id ) throws NamingException;
440     public abstract BigInteger getParentId( String dn ) throws NamingException;
441     public abstract BigInteger getParentId( BigInteger childId ) throws NamingException;
442 
443     /***
444      * Gets the user provided distinguished name.
445      *
446      * @param id the entry id
447      * @return the user provided distinguished name
448      * @throws NamingException if the updn index cannot be accessed
449      */
450     public abstract String getEntryUpdn( BigInteger id ) throws NamingException;
451 
452     /***
453      * Gets the user provided distinguished name.
454      *
455      * @param dn the normalized distinguished name
456      * @return the user provided distinguished name
457      * @throws NamingException if the updn and ndn indices cannot be accessed
458      */
459     public abstract String getEntryUpdn( String dn ) throws NamingException;
460     public abstract Attributes lookup( BigInteger id ) throws NamingException;
461     public abstract void delete( BigInteger id ) throws NamingException;
462     public abstract NamingEnumeration list( BigInteger id ) throws NamingException;
463     public abstract int getChildCount( BigInteger id ) throws NamingException;
464     public abstract Attributes getSuffixEntry() throws NamingException;
465     public abstract void setProperty( String key, String value ) throws NamingException;
466     public abstract String getProperty( String key ) throws NamingException;
467     public abstract Iterator getUserIndices();
468     public abstract Iterator getSystemIndices();
469     public abstract Attributes getIndices( BigInteger id ) throws NamingException;
470 
471     /***
472      * Gets the count of the total number of entries in the database.
473      *
474      * TODO shouldn't this be a BigInteger instead of an int? 
475      * 
476      * @return the number of entries in the database 
477      * @throws NamingException if there is a failure to read the count
478      */
479     public abstract int count() throws NamingException;
480 }