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   *    https://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.api.ldap.model.schema.registries;
21  
22  
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import org.apache.directory.api.i18n.I18n;
32  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
33  import org.apache.directory.api.ldap.model.exception.LdapException;
34  import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
35  import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
36  import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
37  import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
38  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
39  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
40  import org.apache.directory.api.ldap.model.schema.AttributeType;
41  import org.apache.directory.api.ldap.model.schema.DitContentRule;
42  import org.apache.directory.api.ldap.model.schema.DitStructureRule;
43  import org.apache.directory.api.ldap.model.schema.LdapComparator;
44  import org.apache.directory.api.ldap.model.schema.LdapSyntax;
45  import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
46  import org.apache.directory.api.ldap.model.schema.MatchingRule;
47  import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
48  import org.apache.directory.api.ldap.model.schema.NameForm;
49  import org.apache.directory.api.ldap.model.schema.Normalizer;
50  import org.apache.directory.api.ldap.model.schema.ObjectClass;
51  import org.apache.directory.api.ldap.model.schema.SchemaErrorHandler;
52  import org.apache.directory.api.ldap.model.schema.SchemaObject;
53  import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
54  import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
55  import org.apache.directory.api.ldap.model.schema.registries.helper.AttributeTypeHelper;
56  import org.apache.directory.api.ldap.model.schema.registries.helper.DitContentRuleHelper;
57  import org.apache.directory.api.ldap.model.schema.registries.helper.DitStructureRuleHelper;
58  import org.apache.directory.api.ldap.model.schema.registries.helper.LdapSyntaxHelper;
59  import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleHelper;
60  import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleUseHelper;
61  import org.apache.directory.api.ldap.model.schema.registries.helper.NameFormHelper;
62  import org.apache.directory.api.ldap.model.schema.registries.helper.ObjectClassHelper;
63  import org.apache.directory.api.util.Strings;
64  import org.slf4j.Logger;
65  import org.slf4j.LoggerFactory;
66  
67  
68  /**
69   * Document this class.
70   *
71   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
72   */
73  public class Registries implements SchemaLoaderListener, Cloneable
74  {
75      /** A logger for this class */
76      private static final Logger LOG = LoggerFactory.getLogger( Registries.class );
77  
78      /**
79       * A String name to Schema object map for the schemas loaded into this
80       * registry. The loaded schemas may be disabled.
81       */
82      protected Map<String, Schema> loadedSchemas = new HashMap<>();
83  
84      /** The AttributeType registry */
85      protected DefaultAttributeTypeRegistry attributeTypeRegistry;
86  
87      /** The ObjectClass registry */
88      protected DefaultObjectClassRegistry objectClassRegistry;
89  
90      /** The LdapSyntax registry */
91      protected DefaultComparatorRegistry comparatorRegistry;
92  
93      /** The DitContentRule registry */
94      protected DefaultDitContentRuleRegistry ditContentRuleRegistry;
95  
96      /** The DitStructureRule registry */
97      protected DefaultDitStructureRuleRegistry ditStructureRuleRegistry;
98  
99      /** The MatchingRule registry */
100     protected DefaultMatchingRuleRegistry matchingRuleRegistry;
101 
102     /** The MatchingRuleUse registry */
103     protected DefaultMatchingRuleUseRegistry matchingRuleUseRegistry;
104 
105     /** The NameForm registry */
106     protected DefaultNameFormRegistry nameFormRegistry;
107 
108     /** The Normalizer registry */
109     protected DefaultNormalizerRegistry normalizerRegistry;
110 
111     /** The global OID registry */
112     protected OidRegistry<SchemaObject> globalOidRegistry;
113 
114     /** The SyntaxChecker registry */
115     protected DefaultSyntaxCheckerRegistry syntaxCheckerRegistry;
116 
117     /** The LdapSyntax registry */
118     protected DefaultLdapSyntaxRegistry ldapSyntaxRegistry;
119 
120     /** A map storing all the schema objects associated with a schema */
121     private Map<String, Set<SchemaObjectWrapper>> schemaObjects;
122 
123     /** A flag indicating that the Registries is relaxed or not */
124     private boolean isRelaxed;
125 
126     /** A flag indicating that disabled SchemaObject are accepted */
127     private boolean disabledAccepted;
128 
129     private SchemaErrorHandler errorHandler;
130 
131     /** Two flags for RELAXED and STRICT modes */
132     /** The strict mode */
133     public static final boolean STRICT = false;
134     
135     /** The relaxed mode */
136     public static final boolean RELAXED = true;
137 
138     /**
139      *  A map storing a relation between a SchemaObject and all the
140      *  referencing SchemaObjects.
141      */
142     protected Map<SchemaObjectWrapper, Set<SchemaObjectWrapper>> usedBy;
143 
144     /**
145      *  A map storing a relation between a SchemaObject and all the
146      *  SchemaObjects it uses.
147      */
148     protected Map<SchemaObjectWrapper, Set<SchemaObjectWrapper>> using;
149 
150 
151     /**
152      * Creates a new instance of Registries.
153      */
154     public Registries()
155     {
156         globalOidRegistry = new OidRegistry<>();
157         attributeTypeRegistry = new DefaultAttributeTypeRegistry();
158         comparatorRegistry = new DefaultComparatorRegistry();
159         ditContentRuleRegistry = new DefaultDitContentRuleRegistry();
160         ditStructureRuleRegistry = new DefaultDitStructureRuleRegistry();
161         ldapSyntaxRegistry = new DefaultLdapSyntaxRegistry();
162         matchingRuleRegistry = new DefaultMatchingRuleRegistry();
163         matchingRuleUseRegistry = new DefaultMatchingRuleUseRegistry();
164         nameFormRegistry = new DefaultNameFormRegistry();
165         normalizerRegistry = new DefaultNormalizerRegistry();
166         objectClassRegistry = new DefaultObjectClassRegistry();
167         syntaxCheckerRegistry = new DefaultSyntaxCheckerRegistry();
168         schemaObjects = new HashMap<>();
169         usedBy = new HashMap<>();
170         using = new HashMap<>();
171 
172         isRelaxed = STRICT;
173         disabledAccepted = false;
174     }
175 
176 
177     /**
178      * @return The AttributeType registry
179      */
180     public AttributeTypeRegistry getAttributeTypeRegistry()
181     {
182         return attributeTypeRegistry;
183     }
184 
185 
186     /**
187      * @return The Comparator registry
188      */
189     public ComparatorRegistry getComparatorRegistry()
190     {
191         return comparatorRegistry;
192     }
193 
194 
195     /**
196      * @return The DitContentRule registry
197      */
198     public DitContentRuleRegistry getDitContentRuleRegistry()
199     {
200         return ditContentRuleRegistry;
201     }
202 
203 
204     /**
205      * @return The DitStructureRule registry
206      */
207     public DitStructureRuleRegistry getDitStructureRuleRegistry()
208     {
209         return ditStructureRuleRegistry;
210     }
211 
212 
213     /**
214      * @return The MatchingRule registry
215      */
216     public MatchingRuleRegistry getMatchingRuleRegistry()
217     {
218         return matchingRuleRegistry;
219     }
220 
221 
222     /**
223      * @return The MatchingRuleUse registry
224      */
225     public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
226     {
227         return matchingRuleUseRegistry;
228     }
229 
230 
231     /**
232      * @return The NameForm registry
233      */
234     public NameFormRegistry getNameFormRegistry()
235     {
236         return nameFormRegistry;
237     }
238 
239 
240     /**
241      * @return The Normalizer registry
242      */
243     public NormalizerRegistry getNormalizerRegistry()
244     {
245         return normalizerRegistry;
246     }
247 
248 
249     /**
250      * @return The ObjectClass registry
251      */
252     public ObjectClassRegistry getObjectClassRegistry()
253     {
254         return objectClassRegistry;
255     }
256 
257 
258     /**
259      * @return The global Oid registry
260      */
261     public OidRegistry<SchemaObject> getGlobalOidRegistry()
262     {
263         return globalOidRegistry;
264     }
265 
266 
267     /**
268      * @return The SyntaxChecker registry
269      */
270     public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
271     {
272         return syntaxCheckerRegistry;
273     }
274 
275 
276     /**
277      * @return The LdapSyntax registry
278      */
279     public LdapSyntaxRegistry getLdapSyntaxRegistry()
280     {
281         return ldapSyntaxRegistry;
282     }
283 
284 
285     /**
286      * Get an OID from a name. As we have many possible registries, we
287      * have to look in all of them to get the one containing the OID.
288      *
289      * @param name The name we are looking at
290      * @return The associated OID
291      */
292     public String getOid( String name )
293     {
294         // we have many possible Registries to look at.
295         // AttributeType
296         try
297         {
298             AttributeType attributeType = attributeTypeRegistry.lookup( name );
299 
300             if ( attributeType != null )
301             {
302                 return attributeType.getOid();
303             }
304         }
305         catch ( LdapException ne )
306         {
307             // Fall down to the next registry
308         }
309 
310         // ObjectClass
311         try
312         {
313             ObjectClass objectClass = objectClassRegistry.lookup( name );
314 
315             if ( objectClass != null )
316             {
317                 return objectClass.getOid();
318             }
319         }
320         catch ( LdapException ne )
321         {
322             // Fall down to the next registry
323         }
324 
325         // LdapSyntax
326         try
327         {
328             LdapSyntax ldapSyntax = ldapSyntaxRegistry.lookup( name );
329 
330             if ( ldapSyntax != null )
331             {
332                 return ldapSyntax.getOid();
333             }
334         }
335         catch ( LdapException ne )
336         {
337             // Fall down to the next registry
338         }
339 
340         // MatchingRule
341         try
342         {
343             MatchingRule matchingRule = matchingRuleRegistry.lookup( name );
344 
345             if ( matchingRule != null )
346             {
347                 return matchingRule.getOid();
348             }
349         }
350         catch ( LdapException ne )
351         {
352             // Fall down to the next registry
353         }
354 
355         // MatchingRuleUse
356         try
357         {
358             MatchingRuleUse matchingRuleUse = matchingRuleUseRegistry.lookup( name );
359 
360             if ( matchingRuleUse != null )
361             {
362                 return matchingRuleUse.getOid();
363             }
364         }
365         catch ( LdapException ne )
366         {
367             // Fall down to the next registry
368         }
369 
370         // NameForm
371         try
372         {
373             NameForm nameForm = nameFormRegistry.lookup( name );
374 
375             if ( nameForm != null )
376             {
377                 return nameForm.getOid();
378             }
379         }
380         catch ( LdapException ne )
381         {
382             // Fall down to the next registry
383         }
384 
385         // DitContentRule
386         try
387         {
388             DitContentRule ditContentRule = ditContentRuleRegistry.lookup( name );
389 
390             if ( ditContentRule != null )
391             {
392                 return ditContentRule.getOid();
393             }
394         }
395         catch ( LdapException ne )
396         {
397             // Fall down to the next registry
398         }
399 
400         // DitStructureRule
401         try
402         {
403             DitStructureRule ditStructureRule = ditStructureRuleRegistry.lookup( name );
404 
405             if ( ditStructureRule != null )
406             {
407                 return ditStructureRule.getOid();
408             }
409         }
410         catch ( LdapException ne )
411         {
412             // No more registries to look at...
413         }
414 
415         return null;
416     }
417 
418 
419     /**
420      * Gets a schema that has been loaded into these Registries.
421      * 
422      * @param schemaName the name of the schema to lookup
423      * @return the loaded Schema if one corresponding to the name exists
424      */
425     public Schema getLoadedSchema( String schemaName )
426     {
427         return loadedSchemas.get( Strings.toLowerCaseAscii( schemaName ) );
428     }
429 
430 
431     /**
432      * Checks to see if a particular Schema is loaded.
433      *
434      * @param schemaName the name of the Schema to check
435      * @return true if the Schema is loaded, false otherwise
436      */
437     public boolean isSchemaLoaded( String schemaName )
438     {
439         return loadedSchemas.containsKey( Strings.toLowerCaseAscii( schemaName ) );
440     }
441 
442 
443     // ------------------------------------------------------------------------
444     // Code used to sanity check the resolution of entities in registries
445     // ------------------------------------------------------------------------
446     /**
447      * Attempts to resolve the dependent schema objects of all entities that
448      * refer to other objects within the registries.  Null references will be
449      * handed appropriately.
450      * The order in which the SchemaObjects must be :
451      * <ul>
452      *   <li>1) Normalizers, Comparators and SyntaxCheckers (as they depend on nothing)</li>
453      *   <li>2) Syntaxes (depend on SyntaxCheckers)</li>
454      *   <li>3) MatchingRules (depend on Syntaxes, Normalizers and Comparators</li>
455      *   <li>4) AttributeTypes (depend on MatchingRules, Syntaxes and AttributeTypes : in this case, we first handle the superior)</li>
456      *   <li>5) ObjectClasses (depend on AttributeTypes and ObjectClasses)</li>
457      * </ul>
458      * <br><br>
459      * Later, when we will support them :
460      * <ul>
461      *   <li>6) MatchingRuleUses (depend on matchingRules and AttributeTypes)</li>
462      *   <li>7) DitContentRules (depend on ObjectClasses and AttributeTypes)</li>
463      *   <li>8) NameForms (depends on ObjectClasses and AttributeTypes)</li>
464      *   <li>9) DitStructureRules (depends onNameForms and DitStructureRules)</li>
465      * </ul>
466      */
467     public void checkRefInteg()
468     {
469         // Step 1 :
470         // We start with Normalizers, Comparators and SyntaxCheckers
471         // as they depend on nothing
472         // Check the Normalizers
473         for ( Normalizer normalizer : normalizerRegistry )
474         {
475             resolve( normalizer );
476         }
477 
478         // Check the Comparators
479         for ( LdapComparator<?> comparator : comparatorRegistry )
480         {
481             resolve( comparator );
482         }
483 
484         // Check the SyntaxCheckers
485         for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry )
486         {
487             resolve( syntaxChecker );
488         }
489 
490         // Step 2 :
491         // Check the LdapSyntaxes
492         for ( LdapSyntax ldapSyntax : ldapSyntaxRegistry )
493         {
494             resolve( ldapSyntax );
495         }
496 
497         // Step 3 :
498         // Check the matchingRules
499         for ( MatchingRule matchingRule : matchingRuleRegistry )
500         {
501             resolve( matchingRule );
502         }
503 
504         // Step 4 :
505         // Check the AttributeTypes
506         for ( AttributeType attributeType : attributeTypeRegistry )
507         {
508             resolve( attributeType );
509         }
510 
511         //  Step 5 :
512         // Check the ObjectClasses
513         for ( ObjectClass objectClass : objectClassRegistry )
514         {
515             resolve( objectClass );
516         }
517 
518         // Step 6-9 aren't yet defined
519     }
520 
521 
522     /**
523      * Add the SchemaObjectReferences. This method does nothing, it's just
524      * a catch all. The other methods will be called for each specific
525      * schemaObject
526      *
527     public void addCrossReferences( SchemaObject schemaObject )
528     {
529         // Do nothing : it's a catch all method.
530     }
531     
532     
533     /**
534      * Delete the AT references (using and usedBy) :
535      * AT -&gt; MR (for EQUALITY, ORDERING and SUBSTR)
536      * AT -&gt; S
537      * AT -&gt; AT
538      * 
539      * @param attributeType The AttributeType to remove
540      */
541     public void delCrossReferences( AttributeType attributeType )
542     {
543         if ( attributeType.getEquality() != null )
544         {
545             delReference( attributeType, attributeType.getEquality() );
546         }
547 
548         if ( attributeType.getOrdering() != null )
549         {
550             delReference( attributeType, attributeType.getOrdering() );
551         }
552 
553         if ( attributeType.getSubstring() != null )
554         {
555             delReference( attributeType, attributeType.getSubstring() );
556         }
557 
558         if ( attributeType.getSyntax() != null )
559         {
560             delReference( attributeType, attributeType.getSyntax() );
561         }
562 
563         if ( attributeType.getSuperior() != null )
564         {
565             delReference( attributeType, attributeType.getSuperior() );
566         }
567     }
568 
569 
570     /**
571      * Build the AttributeType references. This has to be done recursively, as
572      * an AttributeType may inherit its parent's MatchingRules. The references
573      * to update are :
574      * - EQUALITY MR
575      * - ORDERING MR
576      * - SUBSTRING MR
577      * - SUP AT
578      * - SYNTAX
579      */
580     private void buildAttributeTypeReferences()
581     {
582         for ( AttributeType attributeType : attributeTypeRegistry )
583         {
584             if ( ( getUsing( attributeType ) == null ) || getUsing( attributeType ).isEmpty() )
585             {
586                 buildReference( attributeType );
587             }
588         }
589     }
590 
591 
592     /**
593      * Build the Comparator references
594      */
595     private void buildComparatorReferences()
596     {
597         for ( LdapComparator<?> comparator : comparatorRegistry )
598         {
599             buildReference( comparator );
600         }
601     }
602 
603 
604     /**
605      * Build the DitContentRule references
606      */
607     private void buildDitContentRuleReferences()
608     {
609         // TODO: implement
610     }
611 
612 
613     /**
614      * Build the DitStructureRule references
615      */
616     private void buildDitStructureRuleReferences()
617     {
618         // TODO: implement
619     }
620 
621 
622     /**
623      * Delete the MR references (using and usedBy) :
624      * MR -&gt; C
625      * MR -&gt; N
626      * MR -&gt; S
627      * 
628      * @param matchingRule The MatchinRule refere ce to delete
629      */
630     public void delCrossReferences( MatchingRule matchingRule )
631     {
632         if ( matchingRule.getLdapComparator() != null )
633         {
634             delReference( matchingRule, matchingRule.getLdapComparator() );
635         }
636 
637         if ( matchingRule.getNormalizer() != null )
638         {
639             delReference( matchingRule, matchingRule.getNormalizer() );
640         }
641 
642         if ( matchingRule.getSyntax() != null )
643         {
644             delReference( matchingRule, matchingRule.getSyntax() );
645         }
646     }
647 
648 
649     /**
650      * Build the SchemaObject references
651      * 
652      * @param schemaObject The SchemaObject to add
653      */
654     public void buildReference( SchemaObject schemaObject )
655     {
656         try
657         {
658             switch ( schemaObject.getObjectType() )
659             {
660                 case ATTRIBUTE_TYPE:
661                     AttributeTypeHelper.addToRegistries( ( AttributeType ) schemaObject, errorHandler, this );
662                     break;
663 
664                 case DIT_CONTENT_RULE:
665                     DitContentRuleHelper.addToRegistries( ( DitContentRule ) schemaObject, errorHandler, this );
666                     break;
667 
668                 case DIT_STRUCTURE_RULE:
669                     DitStructureRuleHelper.addToRegistries( ( DitStructureRule ) schemaObject, errorHandler, this );
670                     break;
671 
672                 case LDAP_SYNTAX:
673                     LdapSyntaxHelper.addToRegistries( ( LdapSyntax ) schemaObject, errorHandler, this );
674                     break;
675 
676                 case MATCHING_RULE:
677                     MatchingRuleHelper.addToRegistries( ( MatchingRule ) schemaObject, errorHandler, this );
678                     break;
679 
680                 case MATCHING_RULE_USE:
681                     MatchingRuleUseHelper.addToRegistries( ( MatchingRuleUse ) schemaObject, errorHandler, this );
682                     break;
683 
684                 case NAME_FORM:
685                     NameFormHelper.addToRegistries( ( NameForm ) schemaObject, errorHandler, this );
686                     break;
687 
688                 case OBJECT_CLASS:
689                     ObjectClassHelper.addToRegistries( ( ObjectClass ) schemaObject, errorHandler, this );
690                     break;
691 
692                 case SYNTAX_CHECKER:
693                 case NORMALIZER:
694                 case COMPARATOR:
695                     // Those are not registered
696                     break;
697 
698                 default:
699                     throw new IllegalArgumentException( 
700                         I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) );
701             }
702         }
703         catch ( LdapException ne )
704         {
705             // Not allowed.
706             String msg = I18n.err( I18n.ERR_13746_CANNOT_BUILD_REFERENCES, schemaObject.getName(), ne.getLocalizedMessage() );
707 
708             LdapProtocolErrorException error = new LdapProtocolErrorException( msg, ne );
709             errorHandler.handle( LOG, msg, error );
710         }
711     }
712 
713 
714     /**
715      * Unlink the SchemaObject references
716      * 
717      * @param schemaObject The SchemaObject to remove
718      */
719     public void removeReference( SchemaObject schemaObject )
720     {
721         try
722         {
723             switch ( schemaObject.getObjectType() )
724             {
725                 case ATTRIBUTE_TYPE:
726                     AttributeTypeHelper.removeFromRegistries( ( AttributeType ) schemaObject, errorHandler, this );
727                     break;
728 
729                 case LDAP_SYNTAX:
730                     LdapSyntaxHelper.removeFromRegistries( ( LdapSyntax ) schemaObject, errorHandler, this );
731                     break;
732 
733                 case MATCHING_RULE:
734                     MatchingRuleHelper.removeFromRegistries( ( MatchingRule ) schemaObject, errorHandler, this );
735                     break;
736 
737                 case OBJECT_CLASS:
738                     ObjectClassHelper.removeFromRegistries( ( ObjectClass ) schemaObject, errorHandler, this );
739                     break;
740                     
741                 case DIT_CONTENT_RULE :
742                     // TODO
743                     break;
744                     
745                 case DIT_STRUCTURE_RULE :
746                     // TODO
747                     break;
748                     
749                 case NAME_FORM :
750                     // TODO
751                     break;
752                     
753                 case MATCHING_RULE_USE :
754                     // TODO
755                     break;
756 
757                 case SYNTAX_CHECKER:
758                 case NORMALIZER:
759                 case COMPARATOR:
760                     // Those were not registered
761                     break;
762 
763                 default:
764                     throw new IllegalArgumentException( 
765                         I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) );
766             }
767         }
768         catch ( LdapException ne )
769         {
770             // Not allowed.
771             String msg = I18n.err( I18n.ERR_13747_CANNOT_REMOVE_REFERENCES, schemaObject.getName(), ne.getLocalizedMessage() );
772 
773             LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg, ne );
774             errorHandler.handle( LOG, msg, error );
775         }
776     }
777 
778 
779     /**
780      * Build the MatchingRule references
781      */
782     private void buildMatchingRuleReferences()
783     {
784         for ( MatchingRule matchingRule : matchingRuleRegistry )
785         {
786             buildReference( matchingRule );
787         }
788     }
789 
790 
791     /**
792      * Build the MatchingRuleUse references
793      */
794     private void buildMatchingRuleUseReferences()
795     {
796         for ( MatchingRuleUse matchingRuleUse : matchingRuleUseRegistry )
797         {
798             buildReference( matchingRuleUse );
799         }
800     }
801 
802 
803     /**
804      * Build the NameForm references
805      */
806     private void buildNameFormReferences()
807     {
808         // TODO: implement
809     }
810 
811 
812     /**
813      * Build the Normalizer references
814      */
815     private void buildNormalizerReferences()
816     {
817         for ( Normalizer normalizer : normalizerRegistry )
818         {
819             buildReference( normalizer );
820         }
821     }
822 
823 
824     /**
825      * Build the ObjectClasses references
826      */
827     private void buildObjectClassReferences()
828     {
829         // Remember the OC we have already processed
830         Set<String> done = new HashSet<>();
831 
832         // The ObjectClass
833         for ( ObjectClass objectClass : objectClassRegistry )
834         {
835             if ( done.contains( objectClass.getOid() ) )
836             {
837                 continue;
838             }
839             else
840             {
841                 done.add( objectClass.getOid() );
842             }
843 
844             buildReference( objectClass );
845         }
846     }
847 
848 
849     /**
850      * Build the Syntax references
851      */
852     private void buildLdapSyntaxReferences()
853     {
854         for ( LdapSyntax syntax : ldapSyntaxRegistry )
855         {
856             buildReference( syntax );
857         }
858     }
859 
860 
861     /**
862      * Build the SyntaxChecker references
863      */
864     private void buildSyntaxCheckerReferences()
865     {
866         for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry )
867         {
868             buildReference( syntaxChecker );
869         }
870     }
871 
872 
873     /**
874      * Build the usedBy and using references from the stored elements.
875      */
876     public void buildReferences()
877     {
878         // The Comparator references
879         buildComparatorReferences();
880 
881         // The Normalizer references
882         buildNormalizerReferences();
883 
884         // The SyntaxChecker references
885         buildSyntaxCheckerReferences();
886 
887         // The Syntax references
888         buildLdapSyntaxReferences();
889 
890         // The MatchingRules references
891         buildMatchingRuleReferences();
892 
893         // The AttributeType references
894         buildAttributeTypeReferences();
895 
896         // The MatchingRuleUse references
897         buildMatchingRuleUseReferences();
898 
899         // The ObjectClasses references
900         buildObjectClassReferences();
901 
902         // The DitContentRules references
903         buildDitContentRuleReferences();
904 
905         // The NameForms references
906         buildNameFormReferences();
907 
908         // The DitStructureRules references
909         buildDitStructureRuleReferences();
910     }
911 
912 
913     /**
914      * Attempts to resolve the SyntaxChecker associated with a Syntax.
915      *
916      * @param syntax the LdapSyntax to resolve the SyntaxChecker of
917      */
918     private void resolve( LdapSyntax syntax )
919     {
920         // A LdapSyntax must point to a valid SyntaxChecker
921         // or to the OctetString SyntaxChecker
922         try
923         {
924             LdapSyntaxHelper.addToRegistries( syntax, errorHandler, this );
925         }
926         catch ( LdapException e )
927         {
928             errorHandler.handle( LOG, e.getMessage(), e );
929         }
930     }
931 
932 
933     /**
934      * Attempts to resolve the Normalizer
935      *
936      * @param normalizer the Normalizer
937      */
938     private void resolve( Normalizer normalizer )
939     {
940         // This is currently doing nothing.
941     }
942 
943 
944     /**
945      * Attempts to resolve the LdapComparator
946      *
947      * @param comparator the LdapComparator
948      */
949     private void resolve( LdapComparator<?> comparator )
950     {
951         // This is currently doing nothing.
952     }
953 
954 
955     /**
956      * Attempts to resolve the SyntaxChecker
957      *
958      * @param syntaxChecker the SyntaxChecker
959      */
960     private void resolve( SyntaxChecker syntaxChecker )
961     {
962         // This is currently doing nothing.
963     }
964 
965 
966     /**
967      * Check if the Comparator, Normalizer and the syntax are
968      * existing for a matchingRule.
969      * 
970      * @param matchingRule The matching rule to use
971      */
972     private void resolve( MatchingRule matchingRule )
973     {
974         // Process the Syntax. It can't be null
975         String syntaxOid = matchingRule.getSyntaxOid();
976 
977         if ( syntaxOid != null )
978         {
979             // Check if the Syntax is present in the registries
980             try
981             {
982                 ldapSyntaxRegistry.lookup( syntaxOid );
983             }
984             catch ( LdapException ne )
985             {
986                 // This MR's syntax has not been loaded into the Registries.
987                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
988                     LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_13748_MATCHING_RULE_NO_SYNTAX, matchingRule.getOid() ),
989                     ne );
990                 ldapSchemaException.setSourceObject( matchingRule );
991                 errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
992             }
993         }
994         else
995         {
996             // This is an error.
997             LdapSchemaException ldapSchemaException = new LdapSchemaException(
998                 LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_13748_MATCHING_RULE_NO_SYNTAX, matchingRule.getOid() ) );
999             ldapSchemaException.setSourceObject( matchingRule );
1000             errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
1001         }
1002 
1003         // Process the Normalizer
1004         Normalizer normalizer = matchingRule.getNormalizer();
1005 
1006         if ( normalizer == null )
1007         {
1008             // Ok, no normalizer, this is an error
1009             LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err(
1010                 I18n.ERR_13220_NO_NORMALIZER, matchingRule.getOid() ) );
1011             errorHandler.handle( LOG, error.getMessage(), error );
1012         }
1013 
1014         // Process the Comparator
1015         LdapComparator<?> comparator = matchingRule.getLdapComparator();
1016 
1017         if ( comparator == null )
1018         {
1019             // Ok, no comparator, this is an error
1020             LdapSchemaViolationException error = new LdapSchemaViolationException( 
1021                 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, 
1022                 I18n.err( I18n.ERR_13863_MR_DOES_NOT_HAVE_A_COMP, matchingRule.getOid() ) );
1023             errorHandler.handle( LOG, error.getMessage(), error );
1024         }
1025     }
1026 
1027 
1028     /**
1029      * Check AttributeType referential integrity
1030      * 
1031      * @param attributeType The AttributeType
1032      * @param processed The set of superior to check
1033      */
1034     private void resolveRecursive( AttributeType attributeType, Set<String> processed )
1035     {
1036         // Process the Superior, if any
1037         String superiorOid = attributeType.getSuperiorOid();
1038 
1039         AttributeType superior = null;
1040 
1041         if ( superiorOid != null )
1042         {
1043             // Check if the Superior is present in the registries
1044             try
1045             {
1046                 superior = attributeTypeRegistry.lookup( superiorOid );
1047             }
1048             catch ( LdapException ne )
1049             {
1050                 // This AT's superior has not been loaded into the Registries.
1051                 if ( !processed.contains( superiorOid ) )
1052                 {
1053                     errorHandler.handle( LOG, ne.getMessage(), ne );
1054                 }
1055             }
1056 
1057             // We now have to process the superior, if it hasn't been
1058             // processed yet.
1059             if ( superior != null )
1060             {
1061                 if ( !processed.contains( superiorOid ) )
1062                 {
1063                     resolveRecursive( superior, processed );
1064                     processed.add( attributeType.getOid() );
1065                 }
1066                 else
1067                 {
1068                     // Not allowed : we have a cyle
1069                     LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.OTHER, 
1070                         I18n.err( I18n.ERR_13749_AT_WITH_CYCLE, attributeType.getOid() ) );
1071                     errorHandler.handle( LOG, error.getMessage(), error );
1072                     return;
1073                 }
1074             }
1075         }
1076 
1077         // Process the Syntax. If it's null, the attributeType must have
1078         // a Superior.
1079         String syntaxOid = attributeType.getSyntaxOid();
1080 
1081         if ( syntaxOid != null )
1082         {
1083             // Check if the Syntax is present in the registries
1084             try
1085             {
1086                 ldapSyntaxRegistry.lookup( syntaxOid );
1087             }
1088             catch ( LdapException ne )
1089             {
1090                 // This AT's syntax has not been loaded into the Registries.
1091                 errorHandler.handle( LOG, ne.getMessage(), ne );
1092             }
1093         }
1094         else
1095         {
1096             // No Syntax : get it from the AttributeType's superior
1097             if ( superior == null )
1098             {
1099                 // This is an error. if the AT does not have a Syntax,
1100                 // then it must have a superior, which syntax is get from.
1101                 LdapSchemaViolationException error = new LdapSchemaViolationException( 
1102                     ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, 
1103                     I18n.err( I18n.ERR_13864_AT_DOES_NOT_HAVE_A_SUPERIOR_NOR_SYNTAX, attributeType.getOid() ) );
1104                 errorHandler.handle( LOG, error.getMessage(), error );
1105             }
1106         }
1107 
1108         // Process the EQUALITY MatchingRule. It may be null, but if it's not
1109         // it must have been processed before
1110         String equalityOid = attributeType.getEqualityOid();
1111 
1112         if ( equalityOid != null )
1113         {
1114             // Check if the MatchingRule is present in the registries
1115             try
1116             {
1117                 matchingRuleRegistry.lookup( equalityOid );
1118             }
1119             catch ( LdapException ne )
1120             {
1121                 // This AT's EQUALITY matchingRule has not been loaded into the Registries.
1122                 errorHandler.handle( LOG, ne.getMessage(), ne );
1123             }
1124         }
1125 
1126         // Process the ORDERING MatchingRule. It may be null, but if it's not
1127         // it must have been processed before
1128         String orderingOid = attributeType.getOrderingOid();
1129 
1130         if ( orderingOid != null )
1131         {
1132             // Check if the MatchingRule is present in the registries
1133             try
1134             {
1135                 matchingRuleRegistry.lookup( orderingOid );
1136             }
1137             catch ( LdapException ne )
1138             {
1139                 // This AT's ORDERING matchingRule has not been loaded into the Registries.
1140                 errorHandler.handle( LOG, ne.getMessage(), ne );
1141             }
1142         }
1143 
1144         // Process the SUBSTR MatchingRule. It may be null, but if it's not
1145         // it must have been processed before
1146         String substringOid = attributeType.getSubstringOid();
1147 
1148         if ( substringOid != null )
1149         {
1150             // Check if the MatchingRule is present in the registries
1151             try
1152             {
1153                 matchingRuleRegistry.lookup( substringOid );
1154             }
1155             catch ( LdapException ne )
1156             {
1157                 // This AT's SUBSTR matchingRule has not been loaded into the Registries.
1158                 errorHandler.handle( LOG, ne.getMessage(), ne );
1159             }
1160         }
1161     }
1162 
1163 
1164     /**
1165      * Check the inheritance, and the existence of MatchingRules and LdapSyntax
1166      * for an attribute
1167      * 
1168      * @param attributeType The AttributeType
1169      */
1170     private void resolve( AttributeType attributeType )
1171     {
1172         // This set is used to avoid having more than one error
1173         // for an AttributeType. It's mandatory when processing
1174         // a Superior, as it may be broken and referenced more than once.
1175         Set<String> processed = new HashSet<>();
1176 
1177         // Store the AttributeType itself in the processed, to avoid cycle
1178         processed.add( attributeType.getOid() );
1179 
1180         // Call the recursive method, as we may have superiors to deal with
1181         resolveRecursive( attributeType, processed );
1182     }
1183 
1184 
1185     private List<AttributeType> getMustRecursive( List<AttributeType> musts, Set<ObjectClass> processed,
1186         ObjectClass objectClass )
1187     {
1188         if ( objectClass != null )
1189         {
1190             if ( processed.contains( objectClass ) )
1191             {
1192                 // We have found a cycle. It has already been reported,
1193                 // don't add a new error, just exit.
1194                 return null;
1195             }
1196 
1197             processed.add( objectClass );
1198 
1199             for ( AttributeType must : objectClass.getMustAttributeTypes() )
1200             {
1201                 musts.add( must );
1202             }
1203 
1204             for ( ObjectClass superior : objectClass.getSuperiors() )
1205             {
1206                 getMustRecursive( musts, processed, superior );
1207             }
1208         }
1209 
1210         return musts;
1211     }
1212 
1213 
1214     private void resolve( ObjectClass objectClass )
1215     {
1216         // This set is used to avoid having more than one error
1217         // for an ObjectClass. It's mandatory when processing
1218         // the Superiors, as they may be broken and referenced more than once.
1219         Set<String> processed = new HashSet<>();
1220 
1221         // Store the ObjectClass itself in the processed, to avoid cycle
1222         processed.add( objectClass.getOid() );
1223 
1224         // Call the recursive method, as we may have superiors to deal with
1225         resolveRecursive( objectClass, processed );
1226 
1227         // Check that the MAY and MUST AT are consistent (no AT in MAY and in MUST
1228         // in one of its superior
1229         List<AttributeType> musts = getMustRecursive( new ArrayList<AttributeType>(), new HashSet<ObjectClass>(),
1230             objectClass );
1231 
1232         if ( musts != null )
1233         {
1234             for ( AttributeType may : objectClass.getMayAttributeTypes() )
1235             {
1236                 if ( musts.contains( may ) )
1237                 {
1238                     // This is not allowed.
1239                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
1240                         LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST );
1241                     ldapSchemaException.setSourceObject( objectClass );
1242                     ldapSchemaException.setOtherObject( may );
1243                     errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
1244                 }
1245             }
1246         }
1247     }
1248 
1249 
1250     private void resolveRecursive( ObjectClass objectClass, Set<String> processed )
1251     {
1252         // Process the Superiors, if any
1253         List<String> superiorOids = objectClass.getSuperiorOids();
1254         ObjectClass superior = null;
1255 
1256         for ( String superiorOid : superiorOids )
1257         {
1258             // Check if the Superior is present in the registries
1259             try
1260             {
1261                 superior = objectClassRegistry.lookup( superiorOid );
1262             }
1263             catch ( LdapException ne )
1264             {
1265                 // This OC's superior has not been loaded into the Registries.
1266                 if ( !processed.contains( superiorOid ) )
1267                 {
1268                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
1269                         LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, ne );
1270                     ldapSchemaException.setSourceObject( objectClass );
1271                     ldapSchemaException.setRelatedId( superiorOid );
1272                     errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
1273                 }
1274             }
1275 
1276             // We now have to process the superior, if it hasn't been
1277             // processed yet.
1278             if ( superior != null )
1279             {
1280                 if ( !processed.contains( superior.getOid() ) )
1281                 {
1282                     resolveRecursive( superior, processed );
1283                     processed.add( objectClass.getOid() );
1284                 }
1285                 else
1286                 {
1287                     // Not allowed : we have a cyle
1288                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
1289                         LdapSchemaExceptionCodes.OC_CYCLE_CLASS_HIERARCHY );
1290                     ldapSchemaException.setSourceObject( objectClass );
1291                     ldapSchemaException.setOtherObject( superior );
1292                     errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
1293                     return;
1294                 }
1295             }
1296         }
1297 
1298         // Process the MAY attributeTypes.
1299         for ( String mayOid : objectClass.getMayAttributeTypeOids() )
1300         {
1301             // Check if the MAY AttributeType is present in the registries
1302             try
1303             {
1304                 attributeTypeRegistry.lookup( mayOid );
1305             }
1306             catch ( LdapException ne )
1307             {
1308                 // This AT has not been loaded into the Registries.
1309                 errorHandler.handle( LOG, ne.getMessage(), ne );
1310             }
1311         }
1312 
1313         // Process the MUST attributeTypes.
1314         for ( String mustOid : objectClass.getMustAttributeTypeOids() )
1315         {
1316             // Check if the MUST AttributeType is present in the registries
1317             try
1318             {
1319                 attributeTypeRegistry.lookup( mustOid );
1320             }
1321             catch ( LdapException ne )
1322             {
1323                 // This AT has not been loaded into the Registries.
1324                 errorHandler.handle( LOG, ne.getMessage(), ne );
1325             }
1326         }
1327 
1328         // All is done for this ObjectClass, let's apply the registries
1329         ObjectClassHelper.addToRegistries( objectClass, errorHandler, this );
1330     }
1331 
1332 
1333     /**
1334      * Applies the added SchemaObject to the given register
1335      *
1336      * @param schemaObject The SchemaObject to add
1337      * @param check A flag set when we want the schema checks to be done
1338      * @throws LdapException If we weren't able to add the SchemaObject
1339      */
1340     public void add( SchemaObject schemaObject, boolean check ) throws LdapException
1341     {
1342         // Relax the registries
1343         boolean wasRelaxed = isRelaxed;
1344         setRelaxed();
1345 
1346         // Register the SchemaObject in the registries
1347         register( schemaObject );
1348 
1349         // Associate the SchemaObject with its schema
1350         associateWithSchema( schemaObject );
1351 
1352         // Build the SchemaObject references
1353         if ( check )
1354         {
1355             buildReference( schemaObject );
1356         }
1357 
1358         // Lock the SchemaObject
1359         schemaObject.lock();
1360 
1361         if ( check && ( !errorHandler.wasError() ) )
1362         {
1363             // Check the registries now
1364             checkRefInteg();
1365         }
1366 
1367         // Get back to Strict mode
1368         if ( !wasRelaxed )
1369         {
1370             setStrict();
1371         }
1372     }
1373 
1374 
1375     /**
1376      * Remove the given SchemaObject from the registries
1377      * 
1378      * @param schemaObject The SchemaObject to delete
1379      * @throws LdapException If the deletion failed
1380      */
1381     public void delete( SchemaObject schemaObject ) throws LdapException
1382     {
1383         // Relax the registries
1384         boolean wasRelaxed = isRelaxed;
1385         setRelaxed();
1386 
1387         // Remove the SchemaObject from the registries
1388         SchemaObject removed = unregister( schemaObject );
1389 
1390         // Remove the SchemaObject from its schema
1391         dissociateFromSchema( removed );
1392 
1393         // Unlink the SchemaObject references
1394         removeReference( removed );
1395 
1396         if ( !errorHandler.wasError() )
1397         {
1398             // Check the registries now
1399             checkRefInteg();
1400         }
1401 
1402         // Restore the previous registries state
1403         if ( !wasRelaxed )
1404         {
1405             setStrict();
1406         }
1407     }
1408 
1409 
1410     /**
1411      * Merely adds the schema to the set of loaded schemas.  Does not
1412      * actually do any work to add schema objects to registries.
1413      * 
1414      * {@inheritDoc}
1415      */
1416     @Override
1417     public void schemaLoaded( Schema schema )
1418     {
1419         this.loadedSchemas.put( Strings.toLowerCaseAscii( schema.getSchemaName() ), schema );
1420     }
1421 
1422 
1423     /**
1424      * Merely removes the schema from the set of loaded schemas.  Does not
1425      * actually do any work to remove schema objects from registries.
1426      * 
1427      * {@inheritDoc}
1428      */
1429     @Override
1430     public void schemaUnloaded( Schema schema )
1431     {
1432         this.loadedSchemas.remove( Strings.toLowerCaseAscii( schema.getSchemaName() ) );
1433     }
1434 
1435 
1436     /**
1437      * Gets an unmodifiable Map of schema names to loaded Schema objects.
1438      * 
1439      * @return the map of loaded Schema objects
1440      */
1441     public Map<String, Schema> getLoadedSchemas()
1442     {
1443         return Collections.unmodifiableMap( loadedSchemas );
1444     }
1445 
1446 
1447     /**
1448      * @return Gets a reference to the Map associating a schemaName to
1449      * its contained SchemaObjects
1450      */
1451     public Map<String, Set<SchemaObjectWrapper>> getObjectBySchemaName()
1452     {
1453         return schemaObjects;
1454     }
1455 
1456 
1457     /**
1458      * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
1459      * 
1460      * @param schemaObject The SchemaObject
1461      * @return The associated Schema
1462      */
1463     private String getSchemaName( SchemaObject schemaObject )
1464     {
1465         String schemaName = Strings.toLowerCaseAscii( schemaObject.getSchemaName() );
1466 
1467         if ( loadedSchemas.containsKey( schemaName ) )
1468         {
1469             return schemaName;
1470         }
1471         else
1472         {
1473             return MetaSchemaConstants.SCHEMA_OTHER;
1474         }
1475     }
1476 
1477 
1478     /**
1479      * Tells if the given SchemaObject is present in one schema. The schema
1480      * may be disabled.
1481      *
1482      * @param schemaObject The schemaObject we are looking for
1483      * @return true if the schemaObject is present in a schema
1484      */
1485     public boolean contains( SchemaObject schemaObject )
1486     {
1487         String schemaName = schemaObject.getSchemaName();
1488 
1489         Set<SchemaObjectWrapper> setSchemaObjects = schemaObjects.get( schemaName );
1490 
1491         if ( ( setSchemaObjects == null ) || setSchemaObjects.isEmpty() )
1492         {
1493             return false;
1494         }
1495 
1496         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1497 
1498         return setSchemaObjects.contains( wrapper );
1499     }
1500 
1501 
1502     /**
1503      * Create a new schema association with its content
1504      *
1505      * @param schemaName The schema name
1506      * @return A set containing the associations
1507      */
1508     public Set<SchemaObjectWrapper> addSchema( String schemaName )
1509     {
1510         Set<SchemaObjectWrapper> content = new HashSet<>();
1511         schemaObjects.put( schemaName, content );
1512 
1513         return content;
1514     }
1515 
1516 
1517     /**
1518      * Register the given SchemaObject into the associated Registry
1519      * 
1520      * @param schemaObject The SchemaObject to register
1521      * @throws LdapException If the SchemaObject cannot be registered
1522      */
1523     private void register( SchemaObject schemaObject ) throws LdapException
1524     {
1525         if ( LOG.isDebugEnabled() )
1526         {
1527             LOG.debug( I18n.msg( I18n.MSG_13720_REGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) );
1528         }
1529 
1530         // Check that the SchemaObject is not already registered
1531         if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) )
1532         {
1533             String msg = I18n.err( I18n.ERR_13750_REGISTERING_FAILED_ALREADY_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() );
1534             LOG.error( msg );
1535             LdapUnwillingToPerformException error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1536             errorHandler.handle( LOG, msg, error );
1537             return;
1538         }
1539 
1540         try
1541         {
1542             // First call the specific registry's register method
1543             switch ( schemaObject.getObjectType() )
1544             {
1545                 case ATTRIBUTE_TYPE:
1546                     attributeTypeRegistry.register( ( AttributeType ) schemaObject );
1547                     break;
1548 
1549                 case COMPARATOR:
1550                     comparatorRegistry.register( ( LdapComparator<?> ) schemaObject );
1551                     break;
1552 
1553                 case DIT_CONTENT_RULE:
1554                     ditContentRuleRegistry.register( ( DitContentRule ) schemaObject );
1555                     break;
1556 
1557                 case DIT_STRUCTURE_RULE:
1558                     ditStructureRuleRegistry.register( ( DitStructureRule ) schemaObject );
1559                     break;
1560 
1561                 case LDAP_SYNTAX:
1562                     ldapSyntaxRegistry.register( ( LdapSyntax ) schemaObject );
1563                     break;
1564 
1565                 case MATCHING_RULE:
1566                     matchingRuleRegistry.register( ( MatchingRule ) schemaObject );
1567                     break;
1568 
1569                 case MATCHING_RULE_USE:
1570                     matchingRuleUseRegistry.register( ( MatchingRuleUse ) schemaObject );
1571                     break;
1572 
1573                 case NAME_FORM:
1574                     nameFormRegistry.register( ( NameForm ) schemaObject );
1575                     break;
1576 
1577                 case NORMALIZER:
1578                     normalizerRegistry.register( ( Normalizer ) schemaObject );
1579                     break;
1580 
1581                 case OBJECT_CLASS:
1582                     objectClassRegistry.register( ( ObjectClass ) schemaObject );
1583                     break;
1584 
1585                 case SYNTAX_CHECKER:
1586                     syntaxCheckerRegistry.register( ( SyntaxChecker ) schemaObject );
1587                     break;
1588 
1589                 default:
1590                     throw new IllegalArgumentException( 
1591                         I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) );
1592             }
1593         }
1594         catch ( Exception e )
1595         {
1596             errorHandler.handle( LOG, e.getMessage(), e );
1597         }
1598     }
1599 
1600 
1601     /**
1602      * Store the given SchemaObject in the Map associating SchemaObjetcs to their
1603      * related Schema.
1604      *
1605      * @param schemaObject The schemaObject to register
1606      */
1607     public void associateWithSchema( SchemaObject schemaObject )
1608     {
1609         if ( LOG.isDebugEnabled() )
1610         {
1611             LOG.debug( I18n.msg( I18n.MSG_13720_REGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) );
1612         }
1613 
1614         // Check that the SchemaObject is not already registered
1615         if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) )
1616         {
1617             String msg = I18n.err( I18n.ERR_13750_REGISTERING_FAILED_ALREADY_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() );
1618             LOG.error( msg );
1619             LdapUnwillingToPerformException error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1620             errorHandler.handle( LOG, msg, error );
1621             return;
1622         }
1623 
1624         // Get a normalized form of schema name
1625         String schemaName = getSchemaName( schemaObject );
1626 
1627         // And register the schemaObject within its schema
1628         Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
1629 
1630         if ( content == null )
1631         {
1632             content = new HashSet<>();
1633             schemaObjects.put( Strings.toLowerCaseAscii( schemaName ), content );
1634         }
1635 
1636         SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
1637 
1638         if ( content.contains( schemaObjectWrapper ) )
1639         {
1640             // Already present !
1641             // What should we do ?
1642             errorHandler.handle( LOG, I18n.msg( I18n.MSG_13719_REGISTRING_FAILED_ALREADY_PRESENT,
1643                     schemaObject.getObjectType(), schemaObject.getOid() ), null );
1644         }
1645         else
1646         {
1647             // Create the association
1648             content.add( schemaObjectWrapper );
1649 
1650             // Update the global OidRegistry if the SchemaObject is not
1651             // an instance of LoadableSchemaObject
1652             if ( !( schemaObject instanceof LoadableSchemaObject ) )
1653             {
1654                 try
1655                 {
1656                     globalOidRegistry.register( schemaObject );
1657                 }
1658                 catch ( LdapException ne )
1659                 {
1660                     errorHandler.handle( LOG, ne.getMessage(), ne );
1661                     return;
1662                 }
1663             }
1664 
1665             if ( LOG.isDebugEnabled() )
1666             {
1667                 LOG.debug( I18n.msg( I18n.MSG_13731_REGISTRED_FOR_OID, schemaObject.getName(), schemaObject.getOid() ) );
1668             }
1669         }
1670     }
1671 
1672 
1673     /**
1674      * Store the given SchemaObject in the Map associating SchemaObjetcs to their
1675      * related Schema.
1676      *
1677      * @param schemaObject The schemaObject to register
1678      * @throws LdapException If there is a problem
1679      */
1680 
1681     public void dissociateFromSchema( SchemaObject schemaObject ) throws LdapException
1682     {
1683         if ( LOG.isDebugEnabled() )
1684         {
1685             LOG.debug( I18n.msg( I18n.MSG_13741_UNREGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) );
1686         }
1687 
1688         // Check that the SchemaObject is already registered
1689         if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) )
1690         {
1691             String msg = I18n.err( I18n.ERR_13751_UNREGISTERING_FAILED_NOT_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() );
1692             LOG.error( msg );
1693             Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1694             errorHandler.handle( LOG, msg, error );
1695             return;
1696         }
1697 
1698         // Get a normalized form of schema name
1699         String schemaName = getSchemaName( schemaObject );
1700         String oid = schemaObject.getOid();
1701 
1702         // And unregister the schemaObject from its schema
1703         Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
1704 
1705         SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
1706 
1707         if ( !content.contains( schemaObjectWrapper ) )
1708         {
1709             // Not present !
1710             // What should we do ?
1711             if ( LOG.isInfoEnabled() )
1712             {
1713                 LOG.info( I18n.msg( I18n.MSG_13739_UNREGISTERED_FAILED_NOT_PRESENT, schemaObject.getObjectType(),
1714                     schemaObject.getOid() ) );
1715             }
1716         }
1717         else
1718         {
1719             // Remove the association
1720             content.remove( schemaObjectWrapper );
1721 
1722             // Update the global OidRegistry if the SchemaObject is not
1723             // an instance of LoadableSchemaObject
1724             if ( !( schemaObject instanceof LoadableSchemaObject ) )
1725             {
1726                 try
1727                 {
1728                     globalOidRegistry.unregister( oid );
1729                 }
1730                 catch ( LdapException ne )
1731                 {
1732                     errorHandler.handle( LOG, ne.getMessage(), ne );
1733                     return;
1734                 }
1735             }
1736 
1737             if ( LOG.isDebugEnabled() )
1738             {
1739                 LOG.debug( I18n.msg( I18n.MSG_13737_UNREGISTERED_FOR_OID, schemaObject.getName(), schemaObject.getOid() ) );
1740             }
1741         }
1742     }
1743 
1744 
1745     /**
1746      * Unregister a SchemaObject from the registries
1747      *
1748      * @param schemaObject The SchemaObject we want to deregister
1749      * @return The unregistred SchemaObject
1750      * @throws LdapException If the removal failed
1751      */
1752     private SchemaObject unregister( SchemaObject schemaObject ) throws LdapException
1753     {
1754         if ( LOG.isDebugEnabled() )
1755         {
1756             LOG.debug( I18n.msg( I18n.MSG_13741_UNREGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) );
1757         }
1758 
1759         // Check that the SchemaObject is present in the registries
1760         if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) )
1761         {
1762             String msg = I18n.err( I18n.ERR_13751_UNREGISTERING_FAILED_NOT_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() );
1763             LOG.error( msg );
1764             throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
1765         }
1766 
1767         SchemaObject unregistered;
1768 
1769         // First call the specific registry's register method
1770         switch ( schemaObject.getObjectType() )
1771         {
1772             case ATTRIBUTE_TYPE:
1773                 unregistered = attributeTypeRegistry.unregister( ( AttributeType ) schemaObject );
1774                 break;
1775 
1776             case COMPARATOR:
1777                 unregistered = comparatorRegistry.unregister( ( LdapComparator<?> ) schemaObject );
1778                 break;
1779 
1780             case DIT_CONTENT_RULE:
1781                 unregistered = ditContentRuleRegistry.unregister( ( DitContentRule ) schemaObject );
1782                 break;
1783 
1784             case DIT_STRUCTURE_RULE:
1785                 unregistered = ditStructureRuleRegistry.unregister( ( DitStructureRule ) schemaObject );
1786                 break;
1787 
1788             case LDAP_SYNTAX:
1789                 unregistered = ldapSyntaxRegistry.unregister( ( LdapSyntax ) schemaObject );
1790                 break;
1791 
1792             case MATCHING_RULE:
1793                 unregistered = matchingRuleRegistry.unregister( ( MatchingRule ) schemaObject );
1794                 break;
1795 
1796             case MATCHING_RULE_USE:
1797                 unregistered = matchingRuleUseRegistry.unregister( ( MatchingRuleUse ) schemaObject );
1798                 break;
1799 
1800             case NAME_FORM:
1801                 unregistered = nameFormRegistry.unregister( ( NameForm ) schemaObject );
1802                 break;
1803 
1804             case NORMALIZER:
1805                 unregistered = normalizerRegistry.unregister( ( Normalizer ) schemaObject );
1806                 break;
1807 
1808             case OBJECT_CLASS:
1809                 unregistered = objectClassRegistry.unregister( ( ObjectClass ) schemaObject );
1810                 break;
1811 
1812             case SYNTAX_CHECKER:
1813                 unregistered = syntaxCheckerRegistry.unregister( ( SyntaxChecker ) schemaObject );
1814                 break;
1815 
1816             default:
1817                 throw new IllegalArgumentException( 
1818                     I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) );
1819         }
1820 
1821         return unregistered;
1822     }
1823 
1824 
1825     /**
1826      * Checks if a specific SchemaObject is referenced by any other SchemaObject.
1827      *
1828      * @param schemaObject The SchemaObject we are looking for
1829      * @return true if there is at least one SchemaObjetc referencing the given one
1830      */
1831     public boolean isReferenced( SchemaObject schemaObject )
1832     {
1833         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1834 
1835         Set<SchemaObjectWrapper> set = usedBy.get( wrapper );
1836 
1837         boolean referenced = ( set != null ) && !set.isEmpty();
1838 
1839         if ( LOG.isDebugEnabled() )
1840         {
1841             if ( referenced )
1842             {
1843                 LOG.debug( I18n.msg( I18n.MSG_13735_REFERENCED, schemaObject.getObjectType(), schemaObject.getOid() ) );
1844             }
1845             else
1846             {
1847                 LOG.debug( I18n.msg( I18n.MSG_13734_NOT_REFERENCED, schemaObject.getObjectType(), schemaObject.getOid() ) );
1848             }
1849         }
1850 
1851         return referenced;
1852     }
1853 
1854 
1855     /**
1856      * Gets the Set of SchemaObjects referencing the given SchemaObject
1857      *
1858      * @param schemaObject The SchemaObject we are looking for
1859      * @return The Set of referencing SchemaObject, or null
1860      */
1861     public Set<SchemaObjectWrapper> getUsedBy( SchemaObject schemaObject )
1862     {
1863         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1864 
1865         return usedBy.get( wrapper );
1866     }
1867 
1868 
1869     /**
1870      * Dump the UsedBy data structure as a String
1871      * 
1872      * @return The UsedBy data structure
1873      */
1874     public String dumpUsedBy()
1875     {
1876         StringBuilder sb = new StringBuilder();
1877 
1878         sb.append( "USED BY :\n" );
1879 
1880         try
1881         {
1882             for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : usedBy.entrySet() )
1883             {
1884                 SchemaObjectWrapper wrapper = entry.getKey();
1885 
1886                 sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() )
1887                     .append( "] : {" );
1888 
1889                 boolean isFirst = true;
1890 
1891                 for ( SchemaObjectWrapper uses : entry.getValue() )
1892                 {
1893                     if ( isFirst )
1894                     {
1895                         isFirst = false;
1896                     }
1897                     else
1898                     {
1899                         sb.append( ", " );
1900                     }
1901 
1902                     sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
1903                 }
1904 
1905                 sb.append( "}\n" );
1906             }
1907         }
1908         catch ( Exception e )
1909         {
1910             e.printStackTrace();
1911         }
1912 
1913         return sb.toString();
1914     }
1915 
1916 
1917     /**
1918      * Dump the Using data structure as a String
1919      * 
1920      * @return The Using data structure
1921      */
1922     public String dumpUsing()
1923     {
1924         StringBuilder sb = new StringBuilder();
1925 
1926         sb.append( "USING :\n" );
1927 
1928         try
1929         {
1930             for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : using.entrySet() )
1931             {
1932                 SchemaObjectWrapper wrapper = entry.getKey();
1933 
1934                 sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() )
1935                     .append( "] : {" );
1936 
1937                 boolean isFirst = true;
1938 
1939                 for ( SchemaObjectWrapper uses : entry.getValue() )
1940                 {
1941                     if ( isFirst )
1942                     {
1943                         isFirst = false;
1944                     }
1945                     else
1946                     {
1947                         sb.append( ", " );
1948                     }
1949 
1950                     sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
1951                 }
1952 
1953                 sb.append( "}\n" );
1954             }
1955         }
1956         catch ( Exception e )
1957         {
1958             e.printStackTrace();
1959         }
1960 
1961         return sb.toString();
1962     }
1963 
1964 
1965     /**
1966      * Gets the Set of SchemaObjects referenced by the given SchemaObject
1967      *
1968      * @param schemaObject The SchemaObject we are looking for
1969      * @return The Set of referenced SchemaObject, or null
1970      */
1971     public Set<SchemaObjectWrapper> getUsing( SchemaObject schemaObject )
1972     {
1973         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1974 
1975         return using.get( wrapper );
1976     }
1977 
1978 
1979     /**
1980      * Add an association between a SchemaObject an the SchemaObject it refers
1981      *
1982      * @param reference The base SchemaObject
1983      * @param referee The SchemaObject pointing on the reference
1984      */
1985     private void addUsing( SchemaObject reference, SchemaObject referee )
1986     {
1987         if ( ( reference == null ) || ( referee == null ) )
1988         {
1989             return;
1990         }
1991 
1992         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
1993 
1994         Set<SchemaObjectWrapper> uses = getUsing( reference );
1995 
1996         if ( uses == null )
1997         {
1998             uses = new HashSet<>();
1999         }
2000 
2001         uses.add( new SchemaObjectWrapper( referee ) );
2002 
2003         // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
2004         using.put( wrapper, uses );
2005     }
2006 
2007 
2008     /**
2009      * Add an association between a SchemaObject an the SchemaObject it refers
2010      *
2011      * @param base The base SchemaObject
2012      * @param referenced The referenced SchemaObject
2013      */
2014     public void addReference( SchemaObject base, SchemaObject referenced )
2015     {
2016         if ( LOG.isDebugEnabled() )
2017         {
2018             LOG.debug( dump( "add", base, referenced ) );
2019         }
2020 
2021         addUsing( base, referenced );
2022         addUsedBy( referenced, base );
2023 
2024         // do not change to debug mode, this makes the server logs hard to read and useless
2025         // and even prevents the server from starting up
2026         if ( LOG.isTraceEnabled() )
2027         {
2028             LOG.trace( dumpUsedBy() );
2029             LOG.trace( dumpUsing() );
2030         }
2031     }
2032 
2033 
2034     /**
2035      * Add an association between a SchemaObject an the SchemaObject that refers it
2036      *
2037      * @param reference The base SchemaObject
2038      * @param referee The SchemaObject pointing on the reference
2039      */
2040     private void addUsedBy( SchemaObject referee, SchemaObject reference )
2041     {
2042         if ( ( reference == null ) || ( referee == null ) )
2043         {
2044             return;
2045         }
2046 
2047         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
2048 
2049         Set<SchemaObjectWrapper> uses = getUsedBy( referee );
2050 
2051         if ( uses == null )
2052         {
2053             uses = new HashSet<>();
2054         }
2055 
2056         uses.add( new SchemaObjectWrapper( reference ) );
2057 
2058         // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
2059         usedBy.put( wrapper, uses );
2060     }
2061 
2062 
2063     /**
2064      * Del an association between a SchemaObject an the SchemaObject it refers
2065      *
2066      * @param reference The base SchemaObject
2067      * @param referee The SchemaObject pointing on the reference
2068      */
2069     private void delUsing( SchemaObject reference, SchemaObject referee )
2070     {
2071         if ( ( reference == null ) || ( referee == null ) )
2072         {
2073             return;
2074         }
2075 
2076         Set<SchemaObjectWrapper> uses = getUsing( reference );
2077 
2078         if ( uses == null )
2079         {
2080             return;
2081         }
2082 
2083         uses.remove( new SchemaObjectWrapper( referee ) );
2084 
2085         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
2086 
2087         if ( uses.isEmpty() )
2088         {
2089             using.remove( wrapper );
2090         }
2091         else
2092         {
2093             using.put( wrapper, uses );
2094         }
2095     }
2096 
2097 
2098     /**
2099      * Del an association between a SchemaObject an the SchemaObject that refers it
2100      *
2101      * @param reference The base SchemaObject
2102      * @param referee The SchemaObject pointing on the reference
2103      */
2104     private void delUsedBy( SchemaObject referee, SchemaObject reference )
2105     {
2106         if ( ( reference == null ) || ( referee == null ) )
2107         {
2108             return;
2109         }
2110 
2111         Set<SchemaObjectWrapper> uses = getUsedBy( referee );
2112 
2113         if ( uses == null )
2114         {
2115             return;
2116         }
2117 
2118         uses.remove( new SchemaObjectWrapper( reference ) );
2119 
2120         SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
2121 
2122         if ( uses.isEmpty() )
2123         {
2124             usedBy.remove( wrapper );
2125         }
2126         else
2127         {
2128             usedBy.put( wrapper, uses );
2129         }
2130     }
2131 
2132 
2133     /**
2134      * Delete an association between a SchemaObject an the SchemaObject it refers
2135      *
2136      * @param base The base SchemaObject
2137      * @param referenced The referenced SchemaObject
2138      */
2139     public void delReference( SchemaObject base, SchemaObject referenced )
2140     {
2141         if ( LOG.isDebugEnabled() )
2142         {
2143             LOG.debug( dump( "del", base, referenced ) );
2144         }
2145 
2146         delUsing( base, referenced );
2147         delUsedBy( referenced, base );
2148 
2149         if ( LOG.isDebugEnabled() )
2150         {
2151             LOG.debug( dumpUsedBy() );
2152             LOG.debug( dumpUsing() );
2153         }
2154     }
2155 
2156 
2157     /**
2158      * Dump the reference operation as a String
2159      * 
2160      * @param op The operation
2161      * @param reference The reference
2162      * @param referee The referee
2163      * @return The resulting string
2164      */
2165     private String dump( String op, SchemaObject reference, SchemaObject referee )
2166     {
2167         return op + " : " + reference.getObjectType() + "[" + reference.getOid() + "]/[" + referee.getObjectType()
2168             + "[" + referee.getOid() + "]";
2169     }
2170 
2171 
2172     private boolean checkReferences( SchemaObject reference, SchemaObject referee, String message )
2173     {
2174         SchemaObjectWrapper referenceWrapper = new SchemaObjectWrapper( reference );
2175         SchemaObjectWrapper refereeWrapper = new SchemaObjectWrapper( referee );
2176 
2177         // Check the references : Syntax -> SyntaxChecker
2178         if ( !using.containsKey( referenceWrapper ) )
2179         {
2180             if ( LOG.isDebugEnabled() )
2181             {
2182                 LOG.debug( 
2183                     I18n.msg( I18n.MSG_13730_SYN_DOES_NOT_REFERENCE, reference.getObjectType(), reference.getOid(), message ) );
2184             }
2185 
2186             return false;
2187         }
2188 
2189         Set<SchemaObjectWrapper> usings = using.get( referenceWrapper );
2190 
2191         if ( !usings.contains( refereeWrapper ) )
2192         {
2193             if ( LOG.isDebugEnabled() )
2194             {
2195                 LOG.debug( I18n.msg( I18n.MSG_13732_NOT_REFERENCE_ANY, reference.getObjectType(), reference.getOid(), message ) );
2196             }
2197 
2198             return false;
2199         }
2200 
2201         // Check the referees : SyntaxChecker -> Syntax
2202         if ( !usedBy.containsKey( refereeWrapper ) )
2203         {
2204             if ( LOG.isDebugEnabled() )
2205             {
2206                 LOG.debug( I18n.msg( I18n.MSG_13733_NOT_REFERENCED_BY_ANY, referee.getObjectType(), referee.getOid(), message ) );
2207             }
2208 
2209             return false;
2210         }
2211 
2212         Set<SchemaObjectWrapper> used = usedBy.get( refereeWrapper );
2213 
2214         if ( !used.contains( referenceWrapper ) )
2215         {
2216             if ( LOG.isDebugEnabled() )
2217             {
2218                 LOG.debug( I18n.msg( I18n.MSG_13733_NOT_REFERENCED_BY_ANY, referee.getObjectType(), referee.getOid(), message ) );
2219             }
2220 
2221             return false;
2222         }
2223 
2224         return true;
2225     }
2226 
2227 
2228     /**
2229      * Check the registries for invalid relations. This check stops at the first error.
2230      *
2231      * @return true if the Registries is consistent, false otherwise
2232      */
2233     public boolean check()
2234     {
2235         // Check the Syntaxes : check for a SyntaxChecker
2236         if ( LOG.isDebugEnabled() )
2237         {
2238             LOG.debug( I18n.msg( I18n.MSG_13717_CHECKING_SYNTAXES ) );
2239         }
2240 
2241         for ( LdapSyntax syntax : ldapSyntaxRegistry )
2242         {
2243             // Check that each Syntax has a SyntaxChecker
2244             if ( syntax.getSyntaxChecker() == null )
2245             {
2246                 if ( LOG.isDebugEnabled() )
2247                 {
2248                     LOG.debug( I18n.msg( I18n.MSG_13729_SYN_WITH_NO_SYNTAX_CHECKER, syntax ) );
2249                 }
2250 
2251                 return false;
2252             }
2253 
2254             if ( !syntaxCheckerRegistry.contains( syntax.getSyntaxChecker().getOid() ) )
2255             {
2256                 if ( LOG.isDebugEnabled() )
2257                 {
2258                     LOG.debug( I18n.msg( I18n.MSG_13713_CANT_FIND_SC_FOR_SYN, syntax.getSyntaxChecker().getOid(),
2259                         syntax ) );
2260                 }
2261 
2262                 return false;
2263             }
2264 
2265             // Check the references : Syntax -> SyntaxChecker and SyntaxChecker -> Syntax
2266             if ( !checkReferences( syntax, syntax.getSyntaxChecker(), "SyntaxChecker" ) )
2267             {
2268                 return false;
2269             }
2270         }
2271 
2272         // Check the MatchingRules : check for a Normalizer, a Comparator and a Syntax
2273         if ( LOG.isDebugEnabled() )
2274         {
2275             LOG.debug( I18n.msg( I18n.MSG_13715_CHECKING_MATCHING_RULES ) );
2276         }
2277 
2278         for ( MatchingRule matchingRule : matchingRuleRegistry )
2279         {
2280             // Check that each MatchingRule has a Normalizer
2281             if ( matchingRule.getNormalizer() == null )
2282             {
2283                 if ( LOG.isDebugEnabled() )
2284                 {
2285                     LOG.debug( I18n.msg( I18n.MSG_13727_MR_WITH_NO_NORMALIZER, matchingRule ) );
2286                 }
2287 
2288                 return false;
2289             }
2290 
2291             // Check that each MatchingRule has a Normalizer
2292             if ( !normalizerRegistry.contains( matchingRule.getNormalizer().getOid() ) )
2293             {
2294                 if ( LOG.isDebugEnabled() )
2295                 {
2296                     LOG.debug( I18n.msg( I18n.MSG_13709_CANT_FIND_NORM_FOR_MR, matchingRule.getNormalizer()
2297                         .getOid(), matchingRule ) );
2298                 }
2299 
2300                 return false;
2301             }
2302 
2303             // Check that each MatchingRule has a Comparator
2304             if ( matchingRule.getLdapComparator() == null )
2305             {
2306                 if ( LOG.isDebugEnabled() )
2307                 {
2308                     LOG.debug( I18n.msg( I18n.MSG_13726_MR_WITH_NO_COMPARATOR, matchingRule ) );
2309                 }
2310 
2311                 return false;
2312             }
2313 
2314             if ( !comparatorRegistry.contains( matchingRule.getLdapComparator().getOid() ) )
2315             {
2316                 if ( LOG.isDebugEnabled() )
2317                 {
2318                     LOG.debug( I18n.msg( I18n.MSG_13707_CANT_FIND_AT_FOR_MR, matchingRule.getLdapComparator().getOid(), 
2319                         matchingRule ) );
2320                 } 
2321 
2322                 return false;
2323             }
2324 
2325             // Check that each MatchingRule has a Syntax
2326             if ( matchingRule.getSyntax() == null )
2327             {
2328                 if ( LOG.isDebugEnabled() )
2329                 {
2330                     LOG.debug( I18n.msg( I18n.MSG_13728_MR_WITH_NO_SYNTAX, matchingRule ) );
2331                 }
2332 
2333                 return false;
2334             }
2335 
2336             if ( !ldapSyntaxRegistry.contains( matchingRule.getSyntax().getOid() ) )
2337             {
2338                 if ( LOG.isDebugEnabled() )
2339                 {
2340                     LOG.debug( I18n.msg( I18n.MSG_13712_CANT_FIND_SYN_FOR_MR, matchingRule.getSyntax().getOid(),
2341                         matchingRule ) );
2342                 }
2343                     
2344                 return false;
2345             }
2346 
2347             // Check the references : MR -> S and S -> MR
2348             if ( !checkReferences( matchingRule, matchingRule.getSyntax(), "Syntax" ) )
2349             {
2350                 return false;
2351             }
2352 
2353             // Check the references : MR -> N
2354             if ( !checkReferences( matchingRule, matchingRule.getNormalizer(), "Normalizer" ) )
2355             {
2356                 return false;
2357             }
2358 
2359             // Check the references : MR -> C and C -> MR
2360             if ( !checkReferences( matchingRule, matchingRule.getLdapComparator(), "Comparator" ) )
2361             {
2362                 return false;
2363             }
2364         }
2365 
2366         // Check the ObjectClasses : check for MAY, MUST, SUPERIORS
2367         if ( LOG.isDebugEnabled() )
2368         {
2369             LOG.debug( I18n.msg( I18n.MSG_13716_CHECKING_OBJECT_CLASSES ) );
2370         }
2371 
2372         for ( ObjectClass objectClass : objectClassRegistry )
2373         {
2374             // Check that each ObjectClass has all the MAY AttributeTypes
2375             if ( objectClass.getMayAttributeTypes() != null )
2376             {
2377                 for ( AttributeType may : objectClass.getMayAttributeTypes() )
2378                 {
2379                     if ( !attributeTypeRegistry.contains( may.getOid() ) )
2380                     {
2381                         if ( LOG.isDebugEnabled() )
2382                         {
2383                             LOG.debug( I18n.msg( I18n.MSG_13705_CANT_FIND_AT_IN_MAY, may, objectClass ) );
2384                         }
2385 
2386                         return false;
2387                     }
2388 
2389                     // Check the references : OC -> AT  and AT -> OC (MAY)
2390                     if ( !checkReferences( objectClass, may, "AttributeType" ) )
2391                     {
2392                         return false;
2393                     }
2394                 }
2395             }
2396 
2397             // Check that each ObjectClass has all the MUST AttributeTypes
2398             if ( objectClass.getMustAttributeTypes() != null )
2399             {
2400                 for ( AttributeType must : objectClass.getMustAttributeTypes() )
2401                 {
2402                     if ( !attributeTypeRegistry.contains( must.getOid() ) )
2403                     {
2404                         if ( LOG.isDebugEnabled() )
2405                         {
2406                             LOG.debug( I18n.msg( I18n.MSG_13706_CANT_FIND_AT_IN_MUST, must, objectClass ) );
2407                         }
2408 
2409                         return false;
2410                     }
2411 
2412                     // Check the references : OC -> AT  and AT -> OC (MUST)
2413                     if ( !checkReferences( objectClass, must, "AttributeType" ) )
2414                     {
2415                         return false;
2416                     }
2417                 }
2418             }
2419 
2420             // Check that each ObjectClass has all the SUPERIORS ObjectClasses
2421             if ( objectClass.getSuperiors() != null )
2422             {
2423                 for ( ObjectClass superior : objectClass.getSuperiors() )
2424                 {
2425                     if ( !objectClassRegistry.contains( objectClass.getOid() ) )
2426                     {
2427                         if ( LOG.isDebugEnabled() )
2428                         {
2429                             LOG.debug( I18n.msg( I18n.MSG_13710_CANT_FIND_OC_WITH_SUPERIOR, superior, objectClass ) );
2430                         }
2431 
2432                         return false;
2433                     }
2434 
2435                     // Check the references : OC -> OC  and OC -> OC (SUPERIORS)
2436                     if ( !checkReferences( objectClass, superior, "ObjectClass" ) )
2437                     {
2438                         return false;
2439                     }
2440                 }
2441             }
2442         }
2443 
2444         // Check the AttributeTypes : check for MatchingRules, Syntaxes
2445         if ( LOG.isDebugEnabled() )
2446         {
2447             LOG.debug( I18n.msg( I18n.MSG_13714_CHECKING_ATTRIBUTE_TYPES ) );
2448         }
2449 
2450         for ( AttributeType attributeType : attributeTypeRegistry )
2451         {
2452             // Check that each AttributeType has a SYNTAX
2453             if ( attributeType.getSyntax() == null )
2454             {
2455                 if ( LOG.isDebugEnabled() )
2456                 {
2457                     LOG.debug( I18n.msg( I18n.MSG_13725_AT_WITH_NO_SYNTAX, attributeType ) );
2458                 }
2459 
2460                 return false;
2461             }
2462 
2463             if ( !ldapSyntaxRegistry.contains( attributeType.getSyntax().getOid() ) )
2464             {
2465                 if ( LOG.isDebugEnabled() )
2466                 {
2467                     LOG.debug( I18n.msg( I18n.MSG_13711_CANT_FIND_SYN_FOR_AT, attributeType.getSyntax().getOid(),
2468                         attributeType ) );
2469                 }
2470 
2471                 return false;
2472             }
2473 
2474             // Check the references for AT -> S and S -> AT
2475             if ( !checkReferences( attributeType, attributeType.getSyntax(), "AttributeType" ) )
2476             {
2477                 return false;
2478             }
2479 
2480             // Check the EQUALITY MatchingRule
2481             if ( attributeType.getEquality() != null )
2482             {
2483                 if ( !matchingRuleRegistry.contains( attributeType.getEquality().getOid() ) )
2484                 {
2485                     if ( LOG.isDebugEnabled() )
2486                     {
2487                         LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getEquality()
2488                             .getOid(), attributeType ) );
2489                     }
2490 
2491                     return false;
2492                 }
2493 
2494                 // Check the references for AT -> MR and MR -> AT
2495                 if ( !checkReferences( attributeType, attributeType.getEquality(), "AttributeType" ) )
2496                 {
2497                     return false;
2498                 }
2499             }
2500 
2501             // Check the ORDERING MatchingRule
2502             if ( attributeType.getOrdering() != null )
2503             {
2504                 if ( !matchingRuleRegistry.contains( attributeType.getOrdering().getOid() ) )
2505                 {
2506                     if ( LOG.isDebugEnabled() )
2507                     {
2508                         LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getOrdering()
2509                             .getOid(), attributeType ) );
2510                     }
2511 
2512                     return false;
2513                 }
2514 
2515                 // Check the references for AT -> MR and MR -> AT
2516                 if ( !checkReferences( attributeType, attributeType.getOrdering(), "AttributeType" ) )
2517                 {
2518                     return false;
2519                 }
2520             }
2521 
2522             // Check the SUBSTR MatchingRule
2523             if ( attributeType.getSubstring() != null )
2524             {
2525                 if ( !matchingRuleRegistry.contains( attributeType.getSubstring().getOid() ) )
2526                 {
2527                     if ( LOG.isDebugEnabled() )
2528                     {
2529                         LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getSubstring()
2530                             .getOid(), attributeType ) );
2531                     }
2532 
2533                     return false;
2534                 }
2535 
2536                 // Check the references for AT -> MR and MR -> AT
2537                 if ( !checkReferences( attributeType, attributeType.getSubstring(), "AttributeType" ) )
2538                 {
2539                     return false;
2540                 }
2541             }
2542 
2543             // Check the SUP
2544             if ( attributeType.getSuperior() != null )
2545             {
2546                 AttributeType superior = attributeType.getSuperior();
2547 
2548                 if ( !attributeTypeRegistry.contains( superior.getOid() ) )
2549                 {
2550                     if ( LOG.isDebugEnabled() )
2551                     {
2552                         LOG.debug( I18n.msg( I18n.MSG_13704_CANT_FIND_AT_WITH_SUPERIOR, superior, attributeType ) );
2553                     }
2554 
2555                     return false;
2556                 }
2557 
2558                 // Check the references : AT -> AT  and AT -> AT (SUPERIOR)
2559                 if ( !checkReferences( attributeType, superior, "AttributeType" ) )
2560                 {
2561                     return false;
2562                 }
2563             }
2564         }
2565 
2566         return true;
2567     }
2568 
2569 
2570     /**
2571      * Clone the Registries. This is done in two steps :
2572      * - first clone the SchemaObjetc registries
2573      * - second restore the relation between them
2574      */
2575     // False positive
2576     @Override
2577     public Registries clone() throws CloneNotSupportedException
2578     {
2579         // First clone the structure
2580         Registries clone = ( Registries ) super.clone();
2581 
2582         // Now, clone the oidRegistry
2583         clone.globalOidRegistry = globalOidRegistry.copy();
2584 
2585         // We have to clone every SchemaObject registries now
2586         clone.attributeTypeRegistry = attributeTypeRegistry.copy();
2587         clone.comparatorRegistry = comparatorRegistry.copy();
2588         clone.ditContentRuleRegistry = ditContentRuleRegistry.copy();
2589         clone.ditStructureRuleRegistry = ditStructureRuleRegistry.copy();
2590         clone.ldapSyntaxRegistry = ldapSyntaxRegistry.copy();
2591         clone.matchingRuleRegistry = matchingRuleRegistry.copy();
2592         clone.matchingRuleUseRegistry = matchingRuleUseRegistry.copy();
2593         clone.nameFormRegistry = nameFormRegistry.copy();
2594         clone.normalizerRegistry = normalizerRegistry.copy();
2595         clone.objectClassRegistry = objectClassRegistry.copy();
2596         clone.syntaxCheckerRegistry = syntaxCheckerRegistry.copy();
2597         clone.errorHandler = errorHandler;
2598 
2599         // Store all the SchemaObjects into the globalOid registry
2600         for ( AttributeType attributeType : clone.attributeTypeRegistry )
2601         {
2602             clone.globalOidRegistry.put( attributeType );
2603         }
2604 
2605         for ( DitContentRule ditContentRule : clone.ditContentRuleRegistry )
2606         {
2607             clone.globalOidRegistry.put( ditContentRule );
2608         }
2609 
2610         for ( DitStructureRule ditStructureRule : clone.ditStructureRuleRegistry )
2611         {
2612             clone.globalOidRegistry.put( ditStructureRule );
2613         }
2614 
2615         for ( MatchingRule matchingRule : clone.matchingRuleRegistry )
2616         {
2617             clone.globalOidRegistry.put( matchingRule );
2618         }
2619 
2620         for ( MatchingRuleUse matchingRuleUse : clone.matchingRuleUseRegistry )
2621         {
2622             clone.globalOidRegistry.put( matchingRuleUse );
2623         }
2624 
2625         for ( NameForm nameForm : clone.nameFormRegistry )
2626         {
2627             clone.globalOidRegistry.put( nameForm );
2628         }
2629 
2630         for ( ObjectClass objectClass : clone.objectClassRegistry )
2631         {
2632             clone.globalOidRegistry.put( objectClass );
2633         }
2634 
2635         for ( LdapSyntax syntax : clone.ldapSyntaxRegistry )
2636         {
2637             clone.globalOidRegistry.put( syntax );
2638         }
2639 
2640         // Clone the schema list
2641         clone.loadedSchemas = new HashMap<>();
2642 
2643         for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
2644         {
2645             // We don't clone the schemas
2646             clone.loadedSchemas.put( entry.getKey(), loadedSchemas.get( entry.getKey() ) );
2647         }
2648 
2649         // Clone the Using and usedBy structures
2650         // They will be empty
2651         clone.using = new HashMap<>();
2652         clone.usedBy = new HashMap<>();
2653 
2654         // Last, rebuild the using and usedBy references
2655         clone.buildReferences();
2656 
2657         // Now, check the registries. We don't care about errors
2658         clone.checkRefInteg();
2659 
2660         clone.schemaObjects = new HashMap<>();
2661 
2662         // Last, not least, clone the SchemaObjects Map, and reference all the copied
2663         // SchemaObjects
2664         for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
2665         {
2666             Set<SchemaObjectWrapper> objects = new HashSet<>();
2667 
2668             for ( SchemaObjectWrapper schemaObjectWrapper : entry.getValue() )
2669             {
2670                 SchemaObject original = schemaObjectWrapper.get();
2671 
2672                 try
2673                 {
2674                     if ( !( original instanceof LoadableSchemaObject ) )
2675                     {
2676                         SchemaObject copy = clone.globalOidRegistry.getSchemaObject( original.getOid() );
2677                         SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( copy );
2678                         objects.add( newWrapper );
2679                     }
2680                     else
2681                     {
2682                         SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( original );
2683                         objects.add( newWrapper );
2684                     }
2685                 }
2686                 catch ( LdapException ne )
2687                 {
2688                     // Nothing to do
2689                 }
2690             }
2691 
2692             clone.schemaObjects.put( entry.getKey(), objects );
2693         }
2694 
2695         return clone;
2696     }
2697 
2698 
2699     /**
2700      * Tells if the Registries is permissive or if it must be checked
2701      * against inconsistencies.
2702      *
2703      * @return True if SchemaObjects can be added even if they break the consistency
2704      */
2705     public boolean isRelaxed()
2706     {
2707         return isRelaxed;
2708     }
2709 
2710 
2711     /**
2712      * Tells if the Registries is strict.
2713      *
2714      * @return True if SchemaObjects cannot be added if they break the consistency
2715      */
2716     public boolean isStrict()
2717     {
2718         return !isRelaxed;
2719     }
2720 
2721 
2722     /**
2723      * Change the Registries to a relaxed mode, where invalid SchemaObjects
2724      * can be registered.
2725      */
2726     public void setRelaxed()
2727     {
2728         isRelaxed = RELAXED;
2729         globalOidRegistry.setRelaxed();
2730         attributeTypeRegistry.setRelaxed();
2731         comparatorRegistry.setRelaxed();
2732         ditContentRuleRegistry.setRelaxed();
2733         ditStructureRuleRegistry.setRelaxed();
2734         ldapSyntaxRegistry.setRelaxed();
2735         matchingRuleRegistry.setRelaxed();
2736         matchingRuleUseRegistry.setRelaxed();
2737         nameFormRegistry.setRelaxed();
2738         normalizerRegistry.setRelaxed();
2739         objectClassRegistry.setRelaxed();
2740         syntaxCheckerRegistry.setRelaxed();
2741     }
2742 
2743 
2744     /**
2745      * Change the Registries to a strict mode, where invalid SchemaObjects
2746      * cannot be registered.
2747      */
2748     public void setStrict()
2749     {
2750         isRelaxed = STRICT;
2751         globalOidRegistry.setStrict();
2752         attributeTypeRegistry.setStrict();
2753         comparatorRegistry.setStrict();
2754         ditContentRuleRegistry.setStrict();
2755         ditStructureRuleRegistry.setStrict();
2756         ldapSyntaxRegistry.setStrict();
2757         matchingRuleRegistry.setStrict();
2758         matchingRuleUseRegistry.setStrict();
2759         nameFormRegistry.setStrict();
2760         normalizerRegistry.setStrict();
2761         objectClassRegistry.setStrict();
2762         syntaxCheckerRegistry.setStrict();
2763     }
2764 
2765 
2766     public SchemaErrorHandler getErrorHandler()
2767     {
2768         return errorHandler;
2769     }
2770 
2771 
2772     public void setErrorHandler( SchemaErrorHandler errorHandler )
2773     {
2774         this.errorHandler = errorHandler;
2775         globalOidRegistry.setErrorHandler( errorHandler );
2776         attributeTypeRegistry.setErrorHandler( errorHandler );
2777         comparatorRegistry.setErrorHandler( errorHandler );
2778         ditContentRuleRegistry.setErrorHandler( errorHandler );
2779         ditStructureRuleRegistry.setErrorHandler( errorHandler );
2780         ldapSyntaxRegistry.setErrorHandler( errorHandler );
2781         matchingRuleRegistry.setErrorHandler( errorHandler );
2782         matchingRuleUseRegistry.setErrorHandler( errorHandler );
2783         nameFormRegistry.setErrorHandler( errorHandler );
2784         normalizerRegistry.setErrorHandler( errorHandler );
2785         objectClassRegistry.setErrorHandler( errorHandler );
2786         syntaxCheckerRegistry.setErrorHandler( errorHandler );
2787     }
2788 
2789 
2790     /**
2791      * Tells if the Registries accept disabled elements.
2792      *
2793      * @return True if disabled SchemaObjects can be added
2794      */
2795     public boolean isDisabledAccepted()
2796     {
2797         return disabledAccepted;
2798     }
2799 
2800 
2801     /**
2802      * Check that we can remove a given SchemaObject without breaking some of its references.
2803      * We will return the list of refereing objects.
2804      *
2805      * @param schemaObject The SchemaObject to remove
2806      * @return The list of SchemaObjects referencing the SchemaObjetc we want to remove
2807      */
2808     public Set<SchemaObjectWrapper> getReferencing( SchemaObject schemaObject )
2809     {
2810         SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
2811 
2812         return usedBy.get( schemaObjectWrapper );
2813     }
2814 
2815 
2816     /**
2817      * Change the Registries behavior regarding disabled SchemaObject element.
2818      *
2819      * @param disabledAccepted If <code>false</code>, then the Registries won't accept
2820      * disabled SchemaObject or enabled SchemaObject from disabled schema
2821      */
2822     public void setDisabledAccepted( boolean disabledAccepted )
2823     {
2824         this.disabledAccepted = disabledAccepted;
2825     }
2826 
2827 
2828     /**
2829      * Clear the registries from all its elements
2830      *
2831      * @throws LdapException If something goes wrong
2832      */
2833     public void clear() throws LdapException
2834     {
2835         // The AttributeTypeRegistry
2836         if ( attributeTypeRegistry != null )
2837         {
2838             attributeTypeRegistry.clear();
2839         }
2840 
2841         // The ComparatorRegistry
2842         if ( comparatorRegistry != null )
2843         {
2844             comparatorRegistry.clear();
2845         }
2846 
2847         // The DitContentRuleRegistry
2848         if ( ditContentRuleRegistry != null )
2849         {
2850             ditContentRuleRegistry.clear();
2851         }
2852 
2853         // The DitStructureRuleRegistry
2854         if ( ditStructureRuleRegistry != null )
2855         {
2856             ditStructureRuleRegistry.clear();
2857         }
2858 
2859         // The MatchingRuleRegistry
2860         if ( matchingRuleRegistry != null )
2861         {
2862             matchingRuleRegistry.clear();
2863         }
2864 
2865         // The MatchingRuleUseRegistry
2866         if ( matchingRuleUseRegistry != null )
2867         {
2868             matchingRuleUseRegistry.clear();
2869         }
2870 
2871         // The NameFormRegistry
2872         if ( nameFormRegistry != null )
2873         {
2874             nameFormRegistry.clear();
2875         }
2876 
2877         // The NormalizerRegistry
2878         if ( normalizerRegistry != null )
2879         {
2880             normalizerRegistry.clear();
2881         }
2882 
2883         // The ObjectClassRegistry
2884         if ( objectClassRegistry != null )
2885         {
2886             objectClassRegistry.clear();
2887         }
2888 
2889         // The SyntaxRegistry
2890         if ( ldapSyntaxRegistry != null )
2891         {
2892             ldapSyntaxRegistry.clear();
2893         }
2894 
2895         // The SyntaxCheckerRegistry
2896         if ( syntaxCheckerRegistry != null )
2897         {
2898             syntaxCheckerRegistry.clear();
2899         }
2900 
2901         // Clear the schemaObjects map
2902         for ( Map.Entry<String, Set<SchemaObjectWrapper>> entry : schemaObjects.entrySet() )
2903         {
2904             entry.getValue().clear();
2905         }
2906 
2907         schemaObjects.clear();
2908 
2909         // Clear the usedBy map
2910         for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : usedBy.entrySet() )
2911         {
2912             entry.getValue().clear();
2913         }
2914 
2915         usedBy.clear();
2916 
2917         // Clear the using map
2918         for ( Map.Entry<SchemaObjectWrapper, Set<SchemaObjectWrapper>> entry : using.entrySet() )
2919         {
2920             entry.getValue().clear();
2921         }
2922 
2923         using.clear();
2924 
2925         // Clear the global OID registry
2926         globalOidRegistry.clear();
2927 
2928         // Clear the loadedSchema Map
2929         loadedSchemas.clear();
2930     }
2931 
2932 
2933     /**
2934      * @see Object#toString()
2935      */
2936     @Override
2937     public String toString()
2938     {
2939         StringBuilder sb = new StringBuilder();
2940 
2941         sb.append( "Registries [" );
2942 
2943         if ( isRelaxed )
2944         {
2945             sb.append( "RELAXED," );
2946         }
2947         else
2948         {
2949             sb.append( "STRICT," );
2950         }
2951 
2952         if ( disabledAccepted )
2953         {
2954             sb.append( " Disabled accepted] :\n" );
2955         }
2956         else
2957         {
2958             sb.append( " Disabled forbidden] :\n" );
2959         }
2960 
2961         sb.append( "loaded schemas [" );
2962         boolean isFirst = true;
2963 
2964         for ( String schema : loadedSchemas.keySet() )
2965         {
2966             if ( isFirst )
2967             {
2968                 isFirst = false;
2969             }
2970             else
2971             {
2972                 sb.append( ", " );
2973             }
2974 
2975             sb.append( schema );
2976         }
2977 
2978         sb.append( "]\n" );
2979 
2980         sb.append( "AttributeTypes : " ).append( attributeTypeRegistry.size() ).append( "\n" );
2981         sb.append( "Comparators : " ).append( comparatorRegistry.size() ).append( "\n" );
2982         sb.append( "DitContentRules : " ).append( ditContentRuleRegistry.size() ).append( "\n" );
2983         sb.append( "DitStructureRules : " ).append( ditStructureRuleRegistry.size() ).append( "\n" );
2984         sb.append( "MatchingRules : " ).append( matchingRuleRegistry.size() ).append( "\n" );
2985         sb.append( "MatchingRuleUses : " ).append( matchingRuleUseRegistry.size() ).append( "\n" );
2986         sb.append( "NameForms : " ).append( nameFormRegistry.size() ).append( "\n" );
2987         sb.append( "Normalizers : " ).append( normalizerRegistry.size() ).append( "\n" );
2988         sb.append( "ObjectClasses : " ).append( objectClassRegistry.size() ).append( "\n" );
2989         sb.append( "Syntaxes : " ).append( ldapSyntaxRegistry.size() ).append( "\n" );
2990         sb.append( "SyntaxCheckers : " ).append( syntaxCheckerRegistry.size() ).append( "\n" );
2991 
2992         sb.append( "GlobalOidRegistry : " ).append( globalOidRegistry.size() ).append( '\n' );
2993 
2994         return sb.toString();
2995     }
2996 }