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.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
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
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
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
205
206
207
208 public void delete( Name dn ) throws NamingException
209 {
210 BigInteger id = getEntryId( dn.toString() );
211
212
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
317
318
319
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 }