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.configuration.ContextPartitionConfiguration;
40  import org.apache.ldap.server.enumeration.SearchResultEnumeration;
41  import org.apache.ldap.server.jndi.ContextFactoryConfiguration;
42  import org.apache.ldap.server.partition.ContextPartition;
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 ContextPartition} that uses general BTree operations.
51   *
52   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
53   * @version $Rev: 264732 $
54   */
55  public abstract class BTreeContextPartition implements ContextPartition
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 BTreeContextPartition()
109     {
110     }
111     
112 
113     public void init( ContextFactoryConfiguration factoryCfg, ContextPartitionConfiguration 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( cfg.getSuffix(),
181                 cfg.getNormalizedSuffix( factoryCfg.getGlobalRegistries().getMatchingRuleRegistry() ),
182                 cfg.getContextEntry() );
183     }
184 
185     
186     // ------------------------------------------------------------------------
187     // Public Accessors - not declared in any interfaces just for this class
188     // ------------------------------------------------------------------------
189 
190 
191     /***
192      * Gets the DefaultSearchEngine used by this ContextPartition to search the
193      * Database. 
194      *
195      * @return the search engine
196      */
197     public SearchEngine getSearchEngine()
198     {
199         return searchEngine;
200     }
201 
202 
203     // ------------------------------------------------------------------------
204     // ContextPartition Interface Method Implementations
205     // ------------------------------------------------------------------------
206 
207 
208     public void delete( Name dn ) throws NamingException
209     {
210         BigInteger id = getEntryId( dn.toString() );
211 
212         // don't continue if id is null
213         if ( id == null )
214         {
215             throw new LdapNameNotFoundException( "Could not find entry at '"
216                     + dn + "' to delete it!");
217         }
218 
219         if ( getChildCount( id ) > 0 )
220         {
221             LdapContextNotEmptyException cnee = new LdapContextNotEmptyException(
222                 "[66] Cannot delete entry " + dn + " it has children!" );
223             cnee.setRemainingName( dn );
224             throw cnee;
225         }
226         
227         delete( id );
228     }
229     
230     public abstract void add( String updn, Name dn, Attributes entry ) throws NamingException;
231     public abstract void modify( Name dn, int modOp, Attributes mods ) throws NamingException;
232     public abstract void modify( Name dn, ModificationItem[] mods ) throws NamingException;
233 
234 
235     public NamingEnumeration list( Name base ) throws NamingException
236     {
237         SearchResultEnumeration list;
238         list = new BTreeSearchResultEnumeration( ArrayUtils.EMPTY_STRING_ARRAY,
239                 list( getEntryId( base.toString() ) ), this, attributeTypeRegistry );
240         return list;
241     }
242     
243     
244     public NamingEnumeration search( Name base, Map env, ExprNode filter,
245                                      SearchControls searchCtls )
246         throws NamingException
247     {
248         String [] attrIds = searchCtls.getReturningAttributes();
249         NamingEnumeration underlying = null;
250         
251         underlying = searchEngine.search( base, env, filter, searchCtls );
252         
253         return new BTreeSearchResultEnumeration( attrIds, underlying, this, attributeTypeRegistry );
254     }
255 
256 
257     public Attributes lookup( Name dn ) throws NamingException
258     {
259         return lookup( getEntryId( dn.toString() ) );
260     }
261 
262 
263     public Attributes lookup( Name dn, String [] attrIds ) throws NamingException
264     {
265         if ( attrIds == null || attrIds.length == 0 )
266         {
267             return lookup( dn );
268         }
269 
270         Attributes entry = lookup( dn );
271         Attributes retval = new LockableAttributesImpl();
272 
273         for ( int ii = 0; ii < attrIds.length; ii++ )
274         {
275             Attribute attr = entry.get( attrIds[0] );
276 
277             if ( attr != null )
278             {
279                 retval.put( attr );
280             }
281         }
282 
283         return retval;
284     }
285 
286 
287     public boolean hasEntry( Name dn ) throws NamingException
288     {
289         return null != getEntryId( dn.toString() );
290     }
291 
292 
293     public abstract void modifyRn( Name dn, String newRdn, boolean deleteOldRdn ) throws NamingException;
294     public abstract void move( Name oldChildDn, Name newParentDn ) throws NamingException;
295     public abstract void move( Name oldChildDn, Name newParentDn, String newRdn,
296         boolean deleteOldRdn ) throws NamingException;
297 
298 
299     public abstract void sync() throws NamingException;
300     public abstract void destroy();
301     public abstract boolean isInitialized();
302 
303     public boolean isSuffix( Name dn ) throws NamingException
304     {
305         return getSuffix( true ).equals( dn ) ;
306     }
307 
308 
309     public void inspect() throws Exception
310     {
311         PartitionViewer viewer = new PartitionViewer( this, searchEngine );
312         viewer.execute();
313     }
314     
315     ////////////////////
316     // public abstract methods
317     
318     // ------------------------------------------------------------------------
319     // Index Operations 
320     // ------------------------------------------------------------------------
321 
322 
323     public abstract void addIndexOn( AttributeType attribute ) throws NamingException;
324     public abstract boolean hasUserIndexOn( String attribute );
325     public abstract boolean hasSystemIndexOn( String attribute );
326     public abstract Index getExistanceIndex();
327 
328     /***
329      * Gets the Index mapping the BigInteger primary keys of parents to the 
330      * BigInteger primary keys of their children.
331      *
332      * @return the hierarchy Index
333      */
334     public abstract Index getHierarchyIndex();
335     
336     /***
337      * Gets the Index mapping user provided distinguished names of entries as 
338      * Strings to the BigInteger primary keys of entries.
339      *
340      * @return the user provided distinguished name Index
341      */
342     public abstract Index getUpdnIndex();
343 
344     /***
345      * Gets the Index mapping the normalized distinguished names of entries as
346      * Strings to the BigInteger primary keys of entries.  
347      *
348      * @return the normalized distinguished name Index
349      */
350     public abstract Index getNdnIndex();
351 
352     /***
353      * Gets the alias index mapping parent entries with scope expanding aliases 
354      * children one level below them; this system index is used to dereference
355      * aliases on one/single level scoped searches.
356      * 
357      * @return the one alias index
358      */
359     public abstract Index getOneAliasIndex();
360 
361     /***
362      * Gets the alias index mapping relative entries with scope expanding 
363      * alias descendents; this system index is used to dereference aliases on 
364      * subtree scoped searches.
365      * 
366      * @return the sub alias index
367      */
368     public abstract Index getSubAliasIndex();
369 
370     /***
371      * Gets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
372      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
373      * 
374      * @return the index on the ALIAS_ATTRIBUTE
375      */
376     public abstract Index getAliasIndex();
377 
378     /***
379      * Sets the system index defined on the ALIAS_ATTRIBUTE which for LDAP would
380      * be the aliasedObjectName and for X.500 would be aliasedEntryName.
381      * 
382      * @param attrType the index on the ALIAS_ATTRIBUTE
383      */
384     public abstract void setAliasIndexOn( AttributeType attrType ) throws NamingException;
385 
386     /***
387      * Sets the attribute existance Index.
388      *
389      * @param attrType the attribute existance Index
390      */    
391     public abstract void setExistanceIndexOn( AttributeType attrType ) throws NamingException;
392 
393     /***
394      * Sets the hierarchy Index.
395      *
396      * @param attrType the hierarchy Index
397      */    
398     public abstract void setHierarchyIndexOn( AttributeType attrType ) throws NamingException;
399 
400     /***
401      * Sets the user provided distinguished name Index.
402      *
403      * @param attrType the updn Index
404      */    
405     public abstract void setUpdnIndexOn( AttributeType attrType ) throws NamingException;
406 
407     /***
408      * Sets the normalized distinguished name Index.
409      *
410      * @param attrType the ndn Index
411      */    
412     public abstract void setNdnIndexOn( AttributeType attrType ) throws NamingException;
413     
414     /***
415      * Sets the alias index mapping parent entries with scope expanding aliases 
416      * children one level below them; this system index is used to dereference
417      * aliases on one/single level scoped searches.
418      * 
419      * @param attrType a one level alias index
420      */
421     public abstract void setOneAliasIndexOn( AttributeType attrType ) throws NamingException;
422     
423     /***
424      * Sets the alias index mapping relative entries with scope expanding 
425      * alias descendents; this system index is used to dereference aliases on 
426      * subtree scoped searches.
427      * 
428      * @param attrType a subtree alias index
429      */
430     public abstract void setSubAliasIndexOn( AttributeType attrType ) throws NamingException;
431     public abstract Index getUserIndex( String attribute ) throws IndexNotFoundException;
432     public abstract Index getSystemIndex( String attribute ) throws IndexNotFoundException;
433     public abstract BigInteger getEntryId( String dn ) throws NamingException;
434     public abstract String getEntryDn( BigInteger id ) throws NamingException;
435     public abstract BigInteger getParentId( String dn ) throws NamingException;
436     public abstract BigInteger getParentId( BigInteger childId ) throws NamingException;
437 
438     /***
439      * Gets the user provided distinguished name.
440      *
441      * @param id the entry id
442      * @return the user provided distinguished name
443      * @throws NamingException if the updn index cannot be accessed
444      */
445     public abstract String getEntryUpdn( BigInteger id ) throws NamingException;
446 
447     /***
448      * Gets the user provided distinguished name.
449      *
450      * @param dn the normalized distinguished name
451      * @return the user provided distinguished name
452      * @throws NamingException if the updn and ndn indices cannot be accessed
453      */
454     public abstract String getEntryUpdn( String dn ) throws NamingException;
455     public abstract Attributes lookup( BigInteger id ) throws NamingException;
456     public abstract void delete( BigInteger id ) throws NamingException;
457     public abstract NamingEnumeration list( BigInteger id ) throws NamingException;
458     public abstract int getChildCount( BigInteger id ) throws NamingException;
459     public abstract Attributes getSuffixEntry() throws NamingException;
460     public abstract void setProperty( String key, String value ) throws NamingException;
461     public abstract String getProperty( String key ) throws NamingException;
462     public abstract Iterator getUserIndices();
463     public abstract Iterator getSystemIndices();
464     public abstract Attributes getIndices( BigInteger id ) throws NamingException;
465 
466     /***
467      * Gets the count of the total number of entries in the database.
468      *
469      * TODO shouldn't this be a BigInteger instead of an int? 
470      * 
471      * @return the number of entries in the database 
472      * @throws NamingException if there is a failure to read the count
473      */
474     public abstract int count() throws NamingException;
475 }