1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
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
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
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
210
211
212
213 public void delete( Name dn ) throws NamingException
214 {
215 BigInteger id = getEntryId( dn.toString() );
216
217
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
322
323
324
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 }