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.schema;
21  
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.directory.server.constants.MetaSchemaConstants;
31  import org.apache.directory.server.constants.ServerDNConstants;
32  import org.apache.directory.server.core.entry.DefaultServerAttribute;
33  import org.apache.directory.server.core.entry.ServerEntry;
34  import org.apache.directory.server.core.entry.ServerModification;
35  import org.apache.directory.server.core.filtering.EntryFilteringCursor;
36  import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
37  import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
38  import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
39  import org.apache.directory.server.core.partition.Partition;
40  import org.apache.directory.server.schema.bootstrap.Schema;
41  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
42  import org.apache.directory.server.schema.registries.OidRegistry;
43  import org.apache.directory.server.schema.registries.Registries;
44  import org.apache.directory.shared.ldap.constants.SchemaConstants;
45  import org.apache.directory.shared.ldap.entry.EntryAttribute;
46  import org.apache.directory.shared.ldap.entry.Modification;
47  import org.apache.directory.shared.ldap.entry.ModificationOperation;
48  import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
49  import org.apache.directory.shared.ldap.filter.AndNode;
50  import org.apache.directory.shared.ldap.filter.BranchNode;
51  import org.apache.directory.shared.ldap.filter.EqualityNode;
52  import org.apache.directory.shared.ldap.filter.ExprNode;
53  import org.apache.directory.shared.ldap.filter.OrNode;
54  import org.apache.directory.shared.ldap.filter.PresenceNode;
55  import org.apache.directory.shared.ldap.filter.SearchScope;
56  import org.apache.directory.shared.ldap.filter.SimpleNode;
57  import org.apache.directory.shared.ldap.message.AliasDerefMode;
58  import org.apache.directory.shared.ldap.name.LdapDN;
59  import org.apache.directory.shared.ldap.name.Rdn;
60  import org.apache.directory.shared.ldap.schema.AttributeType;
61  import org.apache.directory.shared.ldap.schema.AttributeTypeOptions;
62  import org.apache.directory.shared.ldap.schema.MatchingRule;
63  import org.apache.directory.shared.ldap.schema.ObjectClass;
64  import org.apache.directory.shared.ldap.schema.syntax.NumericOidSyntaxChecker;
65  import org.apache.directory.shared.ldap.util.DateUtils;
66  import org.slf4j.Logger;
67  import org.slf4j.LoggerFactory;
68  
69  import javax.naming.NamingException;
70  import javax.naming.directory.DirContext;
71  import javax.naming.directory.SearchControls;
72  
73  
74  /**
75   * A specialized data access object for managing schema objects in the
76   * schema partition.  
77   * 
78   * WARNING:
79   * This dao operates directly on a partition.  Hence no interceptors are available
80   * to perform the various expected services of respective interceptors.  Take care
81   * to normalize all filters and distinguished names.
82   * 
83   * A single write operation exists for enabling schemas needed for operating indices
84   * in partitions and enabling schemas that are dependencies of other schemas that 
85   * are enabled.  In both these limited cases there is no need to worry about issues
86   * with a lack of replication propagation because these same updates will take place
87   * on replicas when the original operation is propagated or when replicas start up.
88   * 
89   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
90   * @version $Rev$
91   */
92  public class SchemaPartitionDao
93  {
94      /** static class logger */
95      private final Logger LOG = LoggerFactory.getLogger( getClass() );
96      private static final NumericOidSyntaxChecker NUMERIC_OID_CHECKER = new NumericOidSyntaxChecker();
97      private static final String[] SCHEMA_ATTRIBUTES = new String[]
98          { SchemaConstants.CREATORS_NAME_AT_OID, "m-dependencies", SchemaConstants.OBJECT_CLASS_AT_OID, 
99            SchemaConstants.CN_AT_OID, "m-disabled" };
100 
101     private final Partition partition;
102     private final SchemaEntityFactory factory;
103     private final OidRegistry oidRegistry;
104     private final AttributeTypeRegistry attrRegistry;
105 
106     private final String M_NAME_OID;
107     private final String CN_OID;
108     private final String M_OID_OID;
109     private final String OBJECTCLASS_OID;
110     private final String M_SYNTAX_OID;
111     private final String M_ORDERING_OID;
112     private final String M_SUBSTRING_OID;
113     private final String M_EQUALITY_OID;
114     private final String M_SUP_ATTRIBUTE_TYPE_OID;
115     private final String M_MUST_OID;
116     private final String M_MAY_OID;
117     private final String M_AUX_OID;
118     private final String M_OC_OID;
119     private final String M_SUP_OBJECT_CLASS_OID;
120     private final String M_DEPENDENCIES_OID;
121 
122     private final Set<AttributeTypeOptions> schemaAttributesToReturn = new HashSet<AttributeTypeOptions>();
123     private final AttributeType disabledAttributeType;
124 
125 
126     /**
127      * Creates a schema dao object backing information within a schema partition.
128      * 
129      * @param partition the schema partition
130      * @param registries the bootstrap registries that were used to start up the schema partition
131      * @throws NamingException if there are problems initializing this schema partion dao
132      */
133     public SchemaPartitionDao( Partition partition, Registries registries ) throws Exception
134     {
135         this.partition = partition;
136         this.factory = new SchemaEntityFactory( registries );
137         this.oidRegistry = registries.getOidRegistry();
138         this.attrRegistry = registries.getAttributeTypeRegistry();
139 
140         this.M_NAME_OID = oidRegistry.getOid( MetaSchemaConstants.M_NAME_AT );
141         this.CN_OID = oidRegistry.getOid( SchemaConstants.CN_AT );
142         this.disabledAttributeType = attrRegistry.lookup( MetaSchemaConstants.M_DISABLED_AT );
143         this.M_OID_OID = oidRegistry.getOid( MetaSchemaConstants.M_OID_AT );
144         this.OBJECTCLASS_OID = oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT );
145         this.M_SYNTAX_OID = oidRegistry.getOid( MetaSchemaConstants.M_SYNTAX_AT );
146         this.M_ORDERING_OID = oidRegistry.getOid( MetaSchemaConstants.M_ORDERING_AT );
147         this.M_EQUALITY_OID = oidRegistry.getOid( MetaSchemaConstants.M_EQUALITY_AT );
148         this.M_SUBSTRING_OID = oidRegistry.getOid( MetaSchemaConstants.M_SUBSTR_AT );
149         this.M_SUP_ATTRIBUTE_TYPE_OID = oidRegistry.getOid( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT );
150         this.M_MUST_OID = oidRegistry.getOid( MetaSchemaConstants.M_MUST_AT );
151         this.M_MAY_OID = oidRegistry.getOid( MetaSchemaConstants.M_MAY_AT );
152         this.M_AUX_OID = oidRegistry.getOid( MetaSchemaConstants.M_AUX_AT );
153         this.M_OC_OID = oidRegistry.getOid( MetaSchemaConstants.M_OC_AT );
154         this.M_SUP_OBJECT_CLASS_OID = oidRegistry.getOid( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT );
155         this.M_DEPENDENCIES_OID = oidRegistry.getOid( MetaSchemaConstants.M_DEPENDENCIES_AT );
156         
157         for ( String attrId : SCHEMA_ATTRIBUTES )
158         {
159             AttributeTypeOptions ato = new AttributeTypeOptions( attrRegistry.lookup( attrId ) );
160             schemaAttributesToReturn.add( ato );
161         }
162     }
163 
164 
165     public Map<String, Schema> getSchemas() throws Exception
166     {
167         Map<String, Schema> schemas = new HashMap<String, Schema>();
168         EntryFilteringCursor list = listSchemas();
169 
170         while ( list.next() )
171         {
172             ServerEntry sr = list.get();
173             Schema schema = factory.getSchema( sr );
174             schemas.put( schema.getSchemaName(), schema );
175         }
176 
177         return schemas;
178     }
179 
180 
181     public Set<String> getSchemaNames() throws Exception
182     {
183         Set<String> schemaNames = new HashSet<String>();
184         EntryFilteringCursor list = listSchemas();
185 
186         while ( list.next() )
187         {
188             ServerEntry sr = list.get();
189             schemaNames.add( sr.get( SchemaConstants.CN_AT ).getString() );
190         }
191 
192         return schemaNames;
193     }
194 
195 
196     private EntryFilteringCursor listSchemas() throws Exception
197     {
198         LdapDN base = new LdapDN( ServerDNConstants.OU_SCHEMA_DN );
199         base.normalize( attrRegistry.getNormalizerMapping() );
200         ExprNode filter = new EqualityNode<String>( oidRegistry.getOid( SchemaConstants.OBJECT_CLASS_AT ),
201             new ClientStringValue( MetaSchemaConstants.META_SCHEMA_OC ) );
202 
203         SearchOperationContext searchContext = new SearchOperationContext( null );
204         searchContext.setDn( base );
205         searchContext.setScope( SearchScope.ONELEVEL );
206         searchContext.setReturningAttributes( schemaAttributesToReturn );
207         searchContext.setFilter( filter );
208         return partition.search( searchContext );
209     }
210 
211 
212     public Schema getSchema( String schemaName ) throws Exception
213     {
214         LdapDN dn = new LdapDN( "cn=" + schemaName + ",ou=schema" );
215         dn.normalize( attrRegistry.getNormalizerMapping() );
216         return factory.getSchema( partition.lookup( new LookupOperationContext( null, dn ) ) );
217     }
218 
219 
220     public boolean hasMatchingRule( String oid ) throws Exception
221     {
222         BranchNode filter = new AndNode();
223         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue(
224             MetaSchemaConstants.META_MATCHING_RULE_OC ) ) );
225 
226         if ( NUMERIC_OID_CHECKER.isValidSyntax( oid ) )
227         {
228             filter.addNode( new EqualityNode<String>( M_OID_OID, new ClientStringValue( oid ) ) );
229         }
230         else
231         {
232             filter.addNode( new EqualityNode<String>( M_NAME_OID, new ClientStringValue( oid.toLowerCase() ) ) );
233         }
234 
235         SearchControls searchControls = new SearchControls();
236         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
237         EntryFilteringCursor cursor = null;
238 
239         try
240         {
241             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
242                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
243 
244             if ( !cursor.next() )
245             {
246                 return false;
247             }
248 
249             if ( cursor.next() )
250             {
251                 throw new NamingException( "Got more than one matchingRule for oid of " + oid );
252             }
253 
254             return true;
255         }
256         finally
257         {
258             if ( cursor != null )
259             {
260                 cursor.close();
261             }
262         }
263     }
264 
265 
266     public boolean hasAttributeType( String oid ) throws Exception
267     {
268         BranchNode filter = new AndNode();
269         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue(
270             MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC ) ) );
271 
272         if ( NUMERIC_OID_CHECKER.isValidSyntax( oid ) )
273         {
274             filter.addNode( new EqualityNode<String>( M_OID_OID, new ClientStringValue( oid ) ) );
275         }
276         else
277         {
278             filter.addNode( new EqualityNode<String>( M_NAME_OID, new ClientStringValue( oid.toLowerCase() ) ) );
279         }
280 
281         SearchControls searchControls = new SearchControls();
282         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
283         EntryFilteringCursor cursor = null;
284 
285         try
286         {
287             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
288                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
289 
290             if ( !cursor.next() )
291             {
292                 return false;
293             }
294 
295             if ( cursor.next() )
296             {
297                 throw new NamingException( "Got more than one attributeType for oid of " + oid );
298             }
299 
300             return true;
301         }
302         finally
303         {
304             if ( cursor != null )
305             {
306                 cursor.close();
307             }
308         }
309     }
310 
311 
312     public boolean hasObjectClass( String oid ) throws Exception
313     {
314         BranchNode filter = new AndNode();
315         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
316             new ClientStringValue( MetaSchemaConstants.META_OBJECT_CLASS_OC ) ) );
317 
318         if ( NUMERIC_OID_CHECKER.isValidSyntax( oid ) )
319         {
320             filter.addNode( new EqualityNode<String>( M_OID_OID, new ClientStringValue( oid ) ) );
321         }
322         else
323         {
324             filter.addNode( new EqualityNode<String>( M_NAME_OID, new ClientStringValue( oid.toLowerCase() ) ) );
325         }
326 
327         SearchControls searchControls = new SearchControls();
328         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
329         EntryFilteringCursor cursor = null;
330 
331         try
332         {
333             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
334                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
335 
336             if ( !cursor.next() )
337             {
338                 return false;
339             }
340 
341             if ( cursor.next() )
342             {
343                 throw new NamingException( "Got more than one attributeType for oid of " + oid );
344             }
345 
346             return true;
347         }
348         finally
349         {
350             if ( cursor != null )
351             {
352                 cursor.close();
353             }
354         }
355     }
356 
357 
358     public boolean hasSyntax( String oid ) throws Exception
359     {
360         BranchNode filter = new AndNode();
361         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
362                 new ClientStringValue( MetaSchemaConstants.META_SYNTAX_OC ) ) );
363 
364         if ( NUMERIC_OID_CHECKER.isValidSyntax( oid ) )
365         {
366             filter.addNode( new EqualityNode<String>( M_OID_OID, new ClientStringValue( oid ) ) );
367         }
368         else
369         {
370             filter.addNode( new EqualityNode<String>( M_NAME_OID, new ClientStringValue( oid.toLowerCase() ) ) );
371         }
372 
373         SearchControls searchControls = new SearchControls();
374         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
375         EntryFilteringCursor cursor = null;
376 
377         try
378         {
379             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
380                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
381 
382             if ( !cursor.next() )
383             {
384                 return false;
385             }
386 
387             if ( cursor.next() )
388             {
389                 throw new NamingException( "Got more than one syntax for oid of " + oid );
390             }
391 
392             return true;
393         }
394         finally
395         {
396             if ( cursor != null )
397             {
398                 cursor.close();
399             }
400         }
401     }
402 
403 
404     public boolean hasSyntaxChecker( String oid ) throws Exception
405     {
406         BranchNode filter = new AndNode();
407         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
408             new ClientStringValue( MetaSchemaConstants.META_SYNTAX_CHECKER_OC ) ) );
409 
410         if ( NUMERIC_OID_CHECKER.isValidSyntax( oid ) )
411         {
412             filter.addNode( new EqualityNode<String>( M_OID_OID, new ClientStringValue( oid ) ) );
413         }
414         else
415         {
416             filter.addNode( new EqualityNode<String>( M_NAME_OID, new ClientStringValue( oid.toLowerCase() ) ) );
417         }
418 
419         SearchControls searchControls = new SearchControls();
420         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
421         EntryFilteringCursor cursor = null;
422 
423         try
424         {
425             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
426                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
427 
428             if ( !cursor.next() )
429             {
430                 return false;
431             }
432 
433             if ( cursor.next() )
434             {
435                 throw new NamingException( "Got more than one syntaxChecker for oid of " + oid );
436             }
437 
438             return true;
439         }
440         finally
441         {
442             if ( cursor != null )
443             {
444                 cursor.close();
445             }
446         }
447     }
448 
449 
450     /**
451      * Given the non-normalized name (alias) or the OID for a schema entity.  This 
452      * method finds the schema under which that entity is located. 
453      * 
454      * NOTE: this method presumes that all alias names across schemas are unique.  
455      * This should be the case for LDAP but this can potentially be violated so 
456      * we should make sure this is a unique name.
457      * 
458      * @param entityName one of the names of the entity or it's numeric id
459      * @return the name of the schema that contains that entity or null if no entity with 
460      * that alias name exists
461      * @throws NamingException if more than one entity has the name, or if there 
462      * are underlying data access problems
463      */
464     public String findSchema( String entityName ) throws Exception
465     {
466         LdapDN dn = findDn( entityName );
467         if ( dn == null )
468         {
469             return null;
470         }
471 
472         Rdn rdn = dn.getRdn( 1 );
473         if ( !rdn.getNormType().equalsIgnoreCase( CN_OID ) )
474         {
475             throw new NamingException( "Attribute of second rdn in dn '" + dn.toNormName()
476                 + "' expected to be CN oid of " + CN_OID + " but was " + rdn.getNormType() );
477         }
478 
479         return ( String ) rdn.getValue();
480     }
481 
482 
483     public LdapDN findDn( String entityName ) throws Exception
484     {
485         ServerEntry sr = find( entityName );
486         LdapDN dn = sr.getDn();
487         dn.normalize( attrRegistry.getNormalizerMapping() );
488         return dn;
489     }
490 
491 
492     /**
493      * Given the non-normalized name (alias) or the OID for a schema entity.  This 
494      * method finds the entry of the schema entity. 
495      * 
496      * NOTE: this method presumes that all alias names across schemas are unique.  
497      * This should be the case for LDAP but this can potentially be violated so 
498      * we should make sure this is a unique name.
499      * 
500      * @param entityName one of the names of the entity or it's numeric id
501      * @return the search result for the entity or null if no such entity exists with 
502      * that alias or numeric oid
503      * @throws NamingException if more than one entity has the name, or if there 
504      * are underlying data access problems
505      */
506     public ServerEntry find( String entityName ) throws Exception
507     {
508         BranchNode filter = new OrNode();
509         SimpleNode<String> nameAVA = new EqualityNode<String>( M_NAME_OID, 
510             new ClientStringValue( entityName.toLowerCase() ) );
511         SimpleNode<String> oidAVA = new EqualityNode<String>( M_OID_OID, 
512             new ClientStringValue( entityName.toLowerCase() ) );
513         filter.addNode( nameAVA );
514         filter.addNode( oidAVA );
515         SearchControls searchControls = new SearchControls();
516         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
517         EntryFilteringCursor cursor = null;
518 
519         try
520         {
521             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
522                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
523 
524             if ( !cursor.next() )
525             {
526                 return null;
527             }
528 
529             ServerEntry sr = cursor.get();
530             
531             if ( cursor.next() )
532             {
533                 throw new NamingException( "Got more than one result for the entity name: " + entityName );
534             }
535 
536             return sr;
537         }
538         finally
539         {
540             if ( cursor != null )
541             {
542                 cursor.close();
543             }
544         }
545     }
546 
547 
548     /**
549      * Enables a schema by removing it's m-disabled attribute if present.
550      * 
551      * NOTE:
552      * This is a write operation and great care must be taken to make sure it
553      * is used in a limited capacity.  This method is called in two places 
554      * currently.  
555      * 
556      * (1) Within the initialization sequence to enable schemas required
557      *     for the correct operation of indices in other partitions.
558      * (2) Within the partition schema loader to auto enable schemas that are
559      *     depended on by other schemas which are enabled.
560      * 
561      * In both cases, the modifier is effectively the administrator since the 
562      * server is performing the operation directly or on behalf of a user.  In 
563      * case (1) during intialization there is no other user involved so naturally
564      * the modifier is the administrator.  In case (2) when a user enables a 
565      * schema with a dependency that is not enabled the server enables that 
566      * dependency on behalf of the user.  Again effectively it is the server that
567      * is modifying the schema entry and hence the admin is the modifier.
568      * 
569      * No need to worry about a lack of replication propagation in both cases.  In 
570      * case (1) all replicas will enable these schemas anyway on startup.  In case
571      * (2) the original operation that enabled the schema depending on the on that
572      * enableSchema() is called for itself will be replicated.  Hence the same chain 
573      * reaction will occur in a replica.
574      * 
575      * @param schemaName the name of the schema to enable
576      * @throws NamingException if there is a problem updating the schema entry
577      */
578     public void enableSchema( String schemaName ) throws Exception
579     {
580         LdapDN dn = new LdapDN( "cn=" + schemaName + ",ou=schema" );
581         dn.normalize( attrRegistry.getNormalizerMapping() );
582         ServerEntry entry = partition.lookup( new LookupOperationContext( null, dn ) );
583         EntryAttribute disabledAttr = entry.get( disabledAttributeType );
584         List<Modification> mods = new ArrayList<Modification>( 3 );
585 
586         if ( disabledAttr == null )
587         {
588             LOG.warn( "Does not make sense: you're trying to enable {} schema which is already enabled", schemaName );
589             return;
590         }
591 
592         boolean isDisabled = disabledAttr.contains( "TRUE" );
593         if ( !isDisabled )
594         {
595             LOG.warn( "Does not make sense: you're trying to enable {} schema which is already enabled", schemaName );
596             return;
597         }
598 
599         mods.add( new ServerModification( ModificationOperation.REMOVE_ATTRIBUTE, new DefaultServerAttribute(
600             MetaSchemaConstants.M_DISABLED_AT, attrRegistry.lookup( MetaSchemaConstants.M_DISABLED_AT ) ) ) );
601 
602         mods.add( new ServerModification( ModificationOperation.ADD_ATTRIBUTE, new DefaultServerAttribute(
603             SchemaConstants.MODIFIERS_NAME_AT, attrRegistry.lookup( SchemaConstants.MODIFIERS_NAME_AT ),
604             ServerDNConstants.ADMIN_SYSTEM_DN ) ) );
605 
606         mods.add( new ServerModification( ModificationOperation.ADD_ATTRIBUTE, new DefaultServerAttribute(
607             SchemaConstants.MODIFY_TIMESTAMP_AT, attrRegistry.lookup( SchemaConstants.MODIFY_TIMESTAMP_AT ), DateUtils
608                 .getGeneralizedTime() ) ) );
609 
610         partition.modify( new ModifyOperationContext( null, dn, mods ) );
611     }
612 
613 
614     /**
615      * Returns the set of matchingRules and attributeTypes which depend on the 
616      * provided syntax.
617      *
618      * @param numericOid the numeric identifier for the entity
619      * @return the set of matchingRules and attributeTypes depending on a syntax
620      * @throws NamingException if the dao fails to perform search operations
621      */
622     public Set<ServerEntry> listSyntaxDependents( String numericOid ) throws Exception
623     {
624         Set<ServerEntry> set = new HashSet<ServerEntry>();
625         BranchNode filter = new AndNode();
626 
627         // subfilter for (| (objectClass=metaMatchingRule) (objectClass=metaAttributeType))  
628         BranchNode or = new OrNode();
629         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
630             new ClientStringValue( MetaSchemaConstants.META_MATCHING_RULE_OC.toLowerCase() ) ) );
631         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
632             new ClientStringValue( MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC.toLowerCase() ) ) );
633 
634         filter.addNode( or );
635         filter.addNode( new EqualityNode<String>( M_SYNTAX_OID, new ClientStringValue( numericOid.toLowerCase() ) ) );
636 
637         SearchControls searchControls = new SearchControls();
638         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
639         EntryFilteringCursor cursor = null;
640 
641         try
642         {
643             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
644                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
645             
646             while ( cursor.next() )
647             {
648                 set.add( cursor.get() );
649             }
650         }
651         finally
652         {
653             if ( cursor != null )
654             {
655                 cursor.close();
656             }
657         }
658 
659         return set;
660     }
661 
662 
663     public Set<ServerEntry> listMatchingRuleDependents( MatchingRule mr ) throws Exception
664     {
665         Set<ServerEntry> set = new HashSet<ServerEntry>();
666         BranchNode filter = new AndNode();
667 
668         // ( objectClass = metaAttributeType )
669         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue(
670             MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC.toLowerCase() ) ) );
671 
672         BranchNode or = new OrNode();
673         or.addNode( new EqualityNode<String>( M_ORDERING_OID, new ClientStringValue( mr.getOid() ) ) );
674         or.addNode( new EqualityNode<String>( M_SUBSTRING_OID, new ClientStringValue( mr.getOid() ) ) );
675         or.addNode( new EqualityNode<String>( M_EQUALITY_OID, new ClientStringValue( mr.getOid() ) ) );
676         filter.addNode( or );
677 
678         String[] names = mr.getNamesRef();
679         
680         if ( ( names != null ) || ( names.length > 0 ) )
681         {
682             for ( String name : names )
683             {
684                 or.addNode( new EqualityNode<String>( M_ORDERING_OID, new ClientStringValue( name.toLowerCase() ) ) );
685                 or.addNode( new EqualityNode<String>( M_SUBSTRING_OID, new ClientStringValue( name.toLowerCase() ) ) );
686                 or.addNode( new EqualityNode<String>( M_EQUALITY_OID, new ClientStringValue( name.toLowerCase() ) ) );
687             }
688         }
689 
690         SearchControls searchControls = new SearchControls();
691         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
692         EntryFilteringCursor cursor = null;
693 
694         try
695         {
696             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
697                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
698             
699             while ( cursor.next() )
700             {
701                 set.add( cursor.get() );
702             }
703         }
704         finally
705         {
706             if ( cursor != null )
707             {
708                 cursor.close();
709             }
710         }
711 
712         return set;
713     }
714 
715 
716     public EntryFilteringCursor listAllNames() throws Exception
717     {
718         SearchControls searchControls = new SearchControls();
719         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
720         BranchNode filter = new AndNode();
721 
722         // (& (m-oid=*) (m-name=*) )
723         filter.addNode( new PresenceNode( M_OID_OID ) );
724         filter.addNode( new PresenceNode( M_NAME_OID ) );
725         return partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
726             AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
727     }
728 
729 
730     public Set<ServerEntry> listAttributeTypeDependents( AttributeType at ) throws Exception
731     {
732         /*
733          * Right now the following inefficient filter is being used:
734          * 
735          * ( & 
736          *      ( | ( objectClass = metaAttributeType ) ( objectClass = metaObjectClass ) )
737          *      ( | ( m-oid = $oid ) ( m-must = $oid ) ( m-supAttributeType = $oid ) )
738          * )
739          * 
740          * the reason why this is inefficient is because the or terms have large scan counts
741          * and several loops are going to be required.  The following search is better because
742          * it constrains the results better:
743          * 
744          * ( |
745          *      ( & ( objectClass = metaAttributeType ) ( m-supAttributeType = $oid ) )
746          *      ( & ( objectClass = metaObjectClass ) ( | ( m-may = $oid ) ( m-must = $oid ) ) )
747          * )
748          */
749 
750         Set<ServerEntry> set = new HashSet<ServerEntry>();
751         BranchNode filter = new AndNode();
752 
753         // ( objectClass = metaAttributeType )
754         BranchNode or = new OrNode();
755         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
756             new ClientStringValue( MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC.toLowerCase() ) ) );
757         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
758             new ClientStringValue( MetaSchemaConstants.META_OBJECT_CLASS_OC.toLowerCase() ) ) );
759         filter.addNode( or );
760 
761         or = new OrNode();
762         or.addNode( new EqualityNode<String>( M_MAY_OID, new ClientStringValue( at.getOid() ) ) );
763         or.addNode( new EqualityNode<String>( M_MUST_OID, new ClientStringValue( at.getOid() ) ) );
764         or.addNode( new EqualityNode<String>( M_SUP_ATTRIBUTE_TYPE_OID, new ClientStringValue( at.getOid() ) ) );
765         filter.addNode( or );
766 
767         SearchControls searchControls = new SearchControls();
768         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
769         EntryFilteringCursor cursor = null;
770 
771         try
772         {
773             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
774                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
775             
776             while ( cursor.next() )
777             {
778                 set.add( cursor.get() );
779             }
780         }
781         finally
782         {
783             if ( cursor != null )
784             {
785                 cursor.close();
786             }
787         }
788 
789         return set;
790     }
791 
792 
793     /**
794      * Lists the SearchResults of metaSchema objects that depend on a schema.
795      * 
796      * @param schemaName the name of the schema to search for dependees
797      * @return a set of SearchResults over the schemas whose m-dependency attribute contains schemaName
798      * @throws NamingException if there is a problem while searching the schema partition
799      */
800     public Set<ServerEntry> listSchemaDependents( String schemaName ) throws Exception
801     {
802         /*
803          * The following filter is being used:
804          * 
805          * ( & ( objectClass = metaSchema ) ( m-dependencies = $schemaName ) )
806          */
807 
808         Set<ServerEntry> set = new HashSet<ServerEntry>();
809         BranchNode filter = new AndNode();
810 
811         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, 
812             new ClientStringValue( MetaSchemaConstants.META_SCHEMA_OC.toLowerCase() ) ) );
813         filter.addNode( new EqualityNode<String>( M_DEPENDENCIES_OID, 
814             new ClientStringValue( schemaName.toLowerCase() ) ) );
815 
816         SearchControls searchControls = new SearchControls();
817         searchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
818         EntryFilteringCursor cursor = null;
819 
820         try
821         {
822             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
823                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
824             
825             while ( cursor.next() )
826             {
827                 set.add( cursor.get() );
828             }
829         }
830         finally
831         {
832             if ( cursor != null )
833             {
834                 cursor.close();
835             }
836         }
837 
838         return set;
839     }
840 
841 
842     /**
843      * Lists the SearchResults of metaSchema objects that depend on a schema.
844      * 
845      * @param schemaName the name of the schema to search for dependencies
846      * @return a set of SearchResults over the schemas whose m-dependency attribute contains schemaName
847      * @throws NamingException if there is a problem while searching the schema partition
848      */
849     public Set<ServerEntry> listEnabledSchemaDependents( String schemaName ) throws Exception
850     {
851         Set<ServerEntry> set = new HashSet<ServerEntry>();
852         BranchNode filter = new AndNode();
853 
854         filter.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue( 
855             MetaSchemaConstants.META_SCHEMA_OC.toLowerCase() ) ) );
856         filter.addNode( new EqualityNode<String>( M_DEPENDENCIES_OID, new ClientStringValue( 
857             schemaName.toLowerCase() ) ) );
858 
859         SearchControls searchControls = new SearchControls();
860         searchControls.setSearchScope( SearchControls.ONELEVEL_SCOPE );
861         EntryFilteringCursor cursor = null;
862 
863         try
864         {
865             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
866                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
867 
868             while ( cursor.next() )
869             {
870                 ServerEntry sr = cursor.get();
871                 EntryAttribute disabled = sr.get( disabledAttributeType );
872 
873                 if ( disabled == null )
874                 {
875                     set.add( sr );
876                 }
877                 else if ( disabled.get().equals( "FALSE" ) )
878                 {
879                     set.add( sr );
880                 }
881             }
882         }
883         finally
884         {
885             if ( cursor != null )
886             {
887                 cursor.close();
888             }
889         }
890 
891         return set;
892     }
893 
894 
895     public Set<ServerEntry> listObjectClassDependents( ObjectClass oc ) throws Exception
896     {
897         /*
898          * Right now the following inefficient filter is being used:
899          * 
900          * ( & 
901          *      ( | ( objectClass = metaObjectClass ) ( objectClass = metaDITContentRule ) 
902          *          ( objectClass = metaNameForm ) )
903          *      ( | ( m-oc = $oid ) ( m-aux = $oid ) ( m-supObjectClass = $oid ) )
904          * )
905          * 
906          * The reason why this is inefficient is because the or terms have large scan counts
907          * and several loops are going to be required.  For example all the objectClasses and 
908          * all the metaDITContentRules and all the metaNameForm candidates will be a massive 
909          * number.  This is probably going to be bigger than the 2nd term where a candidate 
910          * satisfies one of the terms.
911          * 
912          * The following search is better because it constrains the results better:
913          * 
914          * ( |
915          *      ( & ( objectClass = metaNameForm ) ( m-oc = $oid ) )
916          *      ( & ( objectClass = metaObjectClass ) ( m-supObjectClass = $oid ) )
917          *      ( & ( objectClass = metaDITContentRule ) ( m-aux = $oid ) )
918          * )
919          */
920 
921         Set<ServerEntry> set = new HashSet<ServerEntry>();
922         BranchNode filter = new AndNode();
923 
924         BranchNode or = new OrNode();
925         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue( MetaSchemaConstants.META_NAME_FORM_OC
926             .toLowerCase() ) ) );
927         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue( MetaSchemaConstants.META_OBJECT_CLASS_OC
928             .toLowerCase() ) ) );
929         or.addNode( new EqualityNode<String>( OBJECTCLASS_OID, new ClientStringValue(
930             MetaSchemaConstants.META_DIT_CONTENT_RULE_OC.toLowerCase() ) ) );
931         filter.addNode( or );
932 
933         or = new OrNode();
934         or.addNode( new EqualityNode<String>( M_AUX_OID, new ClientStringValue( oc.getOid() ) ) );
935         or.addNode( new EqualityNode<String>( M_OC_OID, new ClientStringValue( oc.getOid() ) ) );
936         or.addNode( new EqualityNode<String>( M_SUP_OBJECT_CLASS_OID, new ClientStringValue( oc.getOid() ) ) );
937         filter.addNode( or );
938 
939         SearchControls searchControls = new SearchControls();
940         searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
941         EntryFilteringCursor cursor = null;
942 
943         try
944         {
945             cursor = partition.search( new SearchOperationContext( null, partition.getSuffixDn(),
946                 AliasDerefMode.DEREF_ALWAYS, filter, searchControls ) );
947             
948             while ( cursor.next() )
949             {
950                 set.add( cursor.get() );
951             }
952         }
953         finally
954         {
955             if ( cursor != null )
956             {
957                 cursor.close();
958             }
959         }
960 
961         return set;
962     }
963 }