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.schema.manager.impl;
21  
22  
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import org.apache.directory.api.i18n.I18n;
33  import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
34  import org.apache.directory.api.ldap.model.entry.Entry;
35  import org.apache.directory.api.ldap.model.exception.LdapException;
36  import org.apache.directory.api.ldap.model.exception.LdapOtherException;
37  import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
38  import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
39  import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
40  import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
41  import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
42  import org.apache.directory.api.ldap.model.name.Dn;
43  import org.apache.directory.api.ldap.model.schema.AttributeType;
44  import org.apache.directory.api.ldap.model.schema.LdapComparator;
45  import org.apache.directory.api.ldap.model.schema.LdapSyntax;
46  import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
47  import org.apache.directory.api.ldap.model.schema.LoggingSchemaErrorHandler;
48  import org.apache.directory.api.ldap.model.schema.MatchingRule;
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.SchemaManager;
53  import org.apache.directory.api.ldap.model.schema.SchemaObject;
54  import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
55  import org.apache.directory.api.ldap.model.schema.SchemaUtils;
56  import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
57  import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
58  import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
59  import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry;
60  import org.apache.directory.api.ldap.model.schema.registries.DitContentRuleRegistry;
61  import org.apache.directory.api.ldap.model.schema.registries.DitStructureRuleRegistry;
62  import org.apache.directory.api.ldap.model.schema.registries.ImmutableAttributeTypeRegistry;
63  import org.apache.directory.api.ldap.model.schema.registries.ImmutableComparatorRegistry;
64  import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitContentRuleRegistry;
65  import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitStructureRuleRegistry;
66  import org.apache.directory.api.ldap.model.schema.registries.ImmutableLdapSyntaxRegistry;
67  import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleRegistry;
68  import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleUseRegistry;
69  import org.apache.directory.api.ldap.model.schema.registries.ImmutableNameFormRegistry;
70  import org.apache.directory.api.ldap.model.schema.registries.ImmutableNormalizerRegistry;
71  import org.apache.directory.api.ldap.model.schema.registries.ImmutableObjectClassRegistry;
72  import org.apache.directory.api.ldap.model.schema.registries.ImmutableSyntaxCheckerRegistry;
73  import org.apache.directory.api.ldap.model.schema.registries.LdapSyntaxRegistry;
74  import org.apache.directory.api.ldap.model.schema.registries.LowerCaseKeyMap;
75  import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleRegistry;
76  import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleUseRegistry;
77  import org.apache.directory.api.ldap.model.schema.registries.NameFormRegistry;
78  import org.apache.directory.api.ldap.model.schema.registries.NormalizerRegistry;
79  import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
80  import org.apache.directory.api.ldap.model.schema.registries.OidRegistry;
81  import org.apache.directory.api.ldap.model.schema.registries.Registries;
82  import org.apache.directory.api.ldap.model.schema.registries.Schema;
83  import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
84  import org.apache.directory.api.ldap.model.schema.registries.SyntaxCheckerRegistry;
85  import org.apache.directory.api.ldap.schema.loader.EntityFactory;
86  import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
87  import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory;
88  import org.apache.directory.api.util.Strings;
89  import org.slf4j.Logger;
90  import org.slf4j.LoggerFactory;
91  
92  
93  /**
94   * The SchemaManager class : it handles all the schema operations (addition, removal,
95   * modification).
96   *
97   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
98   */
99  public class DefaultSchemaManager implements SchemaManager
100 {
101     /** static class logger */
102     private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaManager.class );
103 
104     /** The NamingContext this SchemaManager is associated with */
105     private Dn namingContext;
106 
107     /** The global registries for this namingContext */
108     private volatile Registries registries;
109 
110     /** the factory that generates respective SchemaObjects from LDIF entries */
111     private final EntityFactory factory;
112 
113     /** A Map containing all the schema being dependent from a schema */
114     private Map<String, Set<String>> schemaDependencies = new HashMap<>();
115     
116     /**
117      * A map of all available schema names to schema objects. This map is
118      * populated when this class is created with all the schemas present in
119      * the LDIF based schema repository.
120      */
121     private Map<String, Schema> schemaMap = new LowerCaseKeyMap();
122 
123     /** A flag indicating that the SchemaManager is relaxed or not */
124     private boolean isRelaxed = STRICT;
125     
126     /**
127      * Class that handles all the error that may occur during schema processing.
128      */
129     private SchemaErrorHandler errorHandler;
130 
131     /**
132      * Creates a new instance of DefaultSchemaManager with LDIF based SchemaLoader,
133      * Strict schema validation
134      */
135     public DefaultSchemaManager()
136     {
137         this( STRICT, jarLdifSchemaLoader().getAllSchemas() );
138         
139         try
140         {
141             loadAllEnabled();
142         }
143         catch ( LdapException e )
144         {
145             LOG.error( I18n.err( I18n.ERR_16077_SCHEMA_MANAGER_CANT_BE_LOADED, e.getMessage() ) );
146             throw new RuntimeException( e.getMessage() );
147         }
148     }
149 
150     /*
151       Static helper factory Create LDIF based SchemaLoader
152       needed to handle checked exceptions
153      */
154     private static SchemaLoader jarLdifSchemaLoader()
155     {
156         try
157         {
158             return new JarLdifSchemaLoader();
159         }
160         catch ( LdapException | IOException e )
161         {
162             LOG.error( I18n.err( I18n.ERR_16080_SCHEMA_LOADER_CANT_BE_CREATED, e.getMessage() ) );
163             throw new RuntimeException( e.getMessage() );
164         }
165     }
166 
167 
168     
169     /**
170      * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader
171      * Strict schema validation
172      * 
173      * @param schemas The list of schema to load
174      */
175     public DefaultSchemaManager( Collection<Schema> schemas )
176     {
177         this( STRICT, schemas );
178     }
179 
180     
181     /**
182      * Creates a new instance of DefaultSchemaManager with the given schemaLoader
183      *
184      * Schema validation strictness (i.e. relaxed/strict) controlled by the given schemaLoader
185      * 
186      * @param schemaLoader The schemaLoader containing the schemas to load
187      */
188     public DefaultSchemaManager( SchemaLoader schemaLoader )
189     {
190         this( schemaLoader.isRelaxed(), schemaLoader.getAllSchemas() );
191     }
192     
193 
194     /**
195      * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader
196      *
197      * @param relaxed If the schema  manager should be relaxed or not
198      * @param schemas The list of schema to load
199      */
200     public DefaultSchemaManager( boolean relaxed, Collection<Schema> schemas )
201     {
202         // Default to the the root (one schemaManager for all the entries
203         namingContext = Dn.ROOT_DSE;
204 
205         for ( Schema schema : schemas )
206         {
207             schemaMap.put( schema.getSchemaName(), schema );
208         }
209         
210         registries = new Registries();
211         factory = new SchemaEntityFactory();
212         isRelaxed = relaxed;
213         setErrorHandler( new LoggingSchemaErrorHandler() );
214     }
215 
216 
217     //-----------------------------------------------------------------------
218     // Helper methods
219     //-----------------------------------------------------------------------
220     /**
221      * Clone the registries before doing any modification on it. Relax it
222      * too so that we can update it.
223      * 
224      * @return The cloned Registries
225      * @throws LdapException If the Registries cannot be cloned
226      */
227     private Registries cloneRegistries() throws LdapException
228     {
229         try
230         {
231             // Relax the controls at first
232 
233             // Clone the Registries
234             Registries clonedRegistries = registries.clone();
235 
236             // And update references. We may have errors, that may be fixed
237             // by the new loaded schemas.
238             clonedRegistries.checkRefInteg();
239 
240             // Now, relax the cloned Registries if there is no error
241             clonedRegistries.setRelaxed();
242 
243             return clonedRegistries;
244         }
245         catch ( CloneNotSupportedException cnse )
246         {
247             throw new LdapOtherException( cnse.getMessage(), cnse );
248         }
249     }
250 
251 
252     /**
253      * Transform a String[] array of schema to a Schema[]
254      * 
255      * @param schemas The Schema names to process
256      * @return an array of Schema instance
257      * @throws LdapException If one of the Schema cannot be found
258      */
259     private Schema[] toArray( String... schemas ) throws LdapException
260     {
261         Schema[] schemaArray = new Schema[schemas.length];
262         int n = 0;
263 
264         for ( String schemaName : schemas )
265         {
266             Schema schema = schemaMap.get( schemaName );
267 
268             if ( schema != null )
269             {
270                 schemaArray[n++] = schema;
271             }
272             else
273             {
274                 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err(
275                     I18n.ERR_16078_CANNOT_LOAD_UNKNOWN_SCHEMA, schemaName ) );
276             }
277         }
278 
279         return schemaArray;
280     }
281 
282 
283     protected void addSchemaObjects( Schema schema, Registries registries ) throws LdapException
284     {
285         // Create a content container for this schema
286         registries.addSchema( schema.getSchemaName() );
287         schemaMap.put( schema.getSchemaName(), schema );
288 
289         // And inject any existing SchemaObject into the registries
290         try
291         {
292             addComparators( schema, registries );
293             addNormalizers( schema, registries );
294             addSyntaxCheckers( schema, registries );
295             addSyntaxes( schema, registries );
296             addMatchingRules( schema, registries );
297             addAttributeTypes( schema, registries );
298             addObjectClasses( schema, registries );
299             //addMatchingRuleUses( schema, registries );
300             //addDitContentRules( schema, registries );
301             //addNameForms( schema, registries );
302             //addDitStructureRules( schema, registries );
303         }
304         catch ( IOException ioe )
305         {
306             throw new LdapOtherException( ioe.getMessage(), ioe );
307         }
308     }
309 
310 
311     /**
312      * Delete all the schemaObjects for a given schema from the registries
313      * 
314      * @param schema The schema from which we want teh SchemaObjects to be deleted
315      * @param registries The Registries to process
316      * @throws LdapException If the SchemaObjects cannot be deleted
317      */
318     private void deleteSchemaObjects( Schema schema, Registries registries ) throws LdapException
319     {
320         Map<String, Set<SchemaObjectWrapper>> schemaObjects = registries.getObjectBySchemaName();
321         Set<SchemaObjectWrapper> content = schemaObjects.get( Strings.toLowerCaseAscii( schema.getSchemaName() ) );
322 
323         List<SchemaObject> toBeDeleted = new ArrayList<>();
324 
325         if ( content != null )
326         {
327             // Build an intermediate list to avoid concurrent modifications
328             for ( SchemaObjectWrapper schemaObjectWrapper : content )
329             {
330                 toBeDeleted.add( schemaObjectWrapper.get() );
331             }
332 
333             for ( SchemaObject schemaObject : toBeDeleted )
334             {
335                 registries.delete( schemaObject );
336             }
337         }
338     }
339 
340 
341     //-----------------------------------------------------------------------
342     // API methods
343     //-----------------------------------------------------------------------
344     /**
345      * {@inheritDoc}
346      */
347     @Override
348     public boolean disable( Schema... schemas ) throws LdapException
349     {
350         boolean disabled = false;
351 
352         // Reset the error handler
353         errorHandler.reset();
354 
355         // Work on a cloned and relaxed registries
356         Registries clonedRegistries = cloneRegistries();
357         clonedRegistries.setRelaxed();
358         
359         for ( Schema schema : schemas )
360         {
361             unload( clonedRegistries, schema );
362         }
363         
364         // Unload is producing some errors, not sure why. But they
365         // seem not relevant to disable functionality.
366         errorHandler.reset();
367         
368         // Build the cross references
369         clonedRegistries.buildReferences();
370 
371         // Destroy the clonedRegistry
372         clonedRegistries.clear();
373 
374         if ( !errorHandler.wasError() )
375         {
376             // Ok no errors. Check the registries now
377             clonedRegistries.checkRefInteg();
378             
379             if ( !errorHandler.wasError() )
380             {
381                 // We are golden : let's apply the schemas in the real registries
382                 for ( Schema schema : schemas )
383                 {
384                     unload( registries, schema );
385                     schema.disable();
386                 }
387                 
388                 // Unload is producing some errors, not sure why. But they
389                 // seem not relevant to disable functionality.
390                 errorHandler.reset();
391 
392                 // Build the cross references
393                 registries.buildReferences();
394                 registries.setStrict();
395 
396                 disabled = true;
397             }
398         }
399 
400         // clear the cloned registries
401         clonedRegistries.clear();
402 
403         return disabled;
404     }
405 
406 
407     /**
408      * {@inheritDoc}
409      */
410     @Override
411     public boolean disable( String... schemaNames ) throws LdapException
412     {
413         Schema[] schemas = toArray( schemaNames );
414 
415         return disable( schemas );
416     }
417 
418 
419     /**
420      * {@inheritDoc}
421      */
422     @Override
423     public boolean disabledRelaxed( Schema... schemas )
424     {
425         return false;
426     }
427 
428 
429     /**
430      * {@inheritDoc}
431      */
432     @Override
433     public boolean disabledRelaxed( String... schemas )
434     {
435         return false;
436     }
437 
438 
439     /**
440      * {@inheritDoc}
441      */
442     @Override
443     public List<Schema> getDisabled()
444     {
445         List<Schema> disabled = new ArrayList<>();
446 
447         for ( Schema schema : registries.getLoadedSchemas().values() )
448         {
449             if ( schema.isDisabled() )
450             {
451                 disabled.add( schema );
452             }
453         }
454 
455         return disabled;
456     }
457 
458 
459     /**
460      * {@inheritDoc}
461      */
462     @Override
463     public boolean enable( Schema... schemas ) throws LdapException
464     {
465         boolean enabled = false;
466 
467         // Reset the errors if not null
468         errorHandler.reset();
469 
470         // Work on a cloned and relaxed registries
471         Registries clonedRegistries = cloneRegistries();
472         clonedRegistries.setRelaxed();
473 
474         Set<Schema> disabledSchemas = new HashSet<>();
475 
476         for ( Schema schema : schemas )
477         {
478             if ( schema.getDependencies() != null )
479             {
480                 for ( String dependency : schema.getDependencies() )
481                 {
482                     Schema dependencySchema = schemaMap.get( dependency );
483 
484                     if ( dependencySchema.isDisabled() )
485                     {
486                         disabledSchemas.add( dependencySchema );
487                     }
488                 }
489             }
490 
491             schema.enable();
492             load( clonedRegistries, schema );
493         }
494 
495         // Revert back the disabled schema to disabled
496         for ( Schema disabledSchema : disabledSchemas )
497         {
498             if ( disabledSchema.isEnabled() )
499             {
500                 disabledSchema.disable();
501             }
502         }
503 
504         // Build the cross references
505         clonedRegistries.buildReferences();
506 
507         // Destroy the clonedRegistry
508         clonedRegistries.clear();
509 
510         if ( !errorHandler.wasError() )
511         {
512             // Ok no errors. Check the registries now
513             clonedRegistries.checkRefInteg();
514 
515             if ( !errorHandler.wasError() )
516             {
517                 // We are golden : let's apply the schemas in the real registries
518                 for ( Schema schema : schemas )
519                 {
520                     schema.enable();
521                     load( registries, schema );
522                 }
523 
524                 // Build the cross references
525                 registries.buildReferences();
526                 registries.setStrict();
527 
528                 enabled = true;
529             }
530         }
531 
532         // clear the cloned registries
533         clonedRegistries.clear();
534 
535         return enabled;
536     }
537 
538 
539     /**
540      * {@inheritDoc}
541      */
542     @Override
543     public boolean enable( String... schemaNames ) throws LdapException
544     {
545         Schema[] schemas = toArray( schemaNames );
546         return enable( schemas );
547     }
548 
549 
550     /**
551      * {@inheritDoc}
552      */
553     @Override
554     public boolean enableRelaxed( Schema... schemas )
555     {
556         return false;
557     }
558 
559 
560     /**
561      * {@inheritDoc}
562      */
563     @Override
564     public boolean enableRelaxed( String... schemas )
565     {
566         return false;
567     }
568 
569 
570     /**
571      * {@inheritDoc}
572      */
573     @Override
574     public List<Schema> getEnabled()
575     {
576         List<Schema> enabled = new ArrayList<>();
577 
578         for ( Schema schema : registries.getLoadedSchemas().values() )
579         {
580             if ( schema.isEnabled() )
581             {
582                 enabled.add( schema );
583             }
584         }
585 
586         return enabled;
587     }
588 
589 
590     /**
591      * {@inheritDoc}
592      */
593     @Override
594     public List<Schema> getAllSchemas()
595     {
596         List<Schema> schemas = new ArrayList<>();
597 
598         for ( Schema schema : schemaMap.values() )
599         {
600             if ( schema.isEnabled() )
601             {
602                 schemas.add( schema );
603             }
604         }
605 
606         return schemas;
607     }
608 
609 
610     /**
611      * {@inheritDoc}
612      */
613     @Override
614     public List<Throwable> getErrors()
615     {
616         return errorHandler.getErrors();
617     }
618 
619 
620     /**
621      * {@inheritDoc}
622      */
623     @Override
624     public Registries getRegistries()
625     {
626         return registries;
627     }
628 
629 
630     /**
631      * Currently not implemented.
632      * 
633      * @return Always FALSE
634      */
635     public boolean isDisabledAccepted()
636     {
637         return false;
638     }
639 
640 
641     /**
642      * {@inheritDoc}
643      */
644     @Override
645     public boolean load( Schema... schemas ) throws LdapException
646     {
647         if ( schemas.length == 0 )
648         {
649             return true;
650         }
651 
652         boolean loaded = false;
653 
654         // Reset the errors if not null
655         errorHandler.reset();
656 
657         // Work on a cloned and relaxed registries
658         Registries clonedRegistries = cloneRegistries();
659         clonedRegistries.setRelaxed();
660 
661         // Load the schemas
662         for ( Schema schema : schemas )
663         {
664             boolean singleSchemaLoaded = load( clonedRegistries, schema );
665 
666             // return false if the schema was not loaded in the first place
667             if ( !singleSchemaLoaded )
668             {
669                 return false;
670             }
671         }
672 
673         // Build the cross references
674         clonedRegistries.buildReferences();
675 
676         if ( !errorHandler.wasError() )
677         {
678             // Ok no errors. Check the registries now
679             clonedRegistries.checkRefInteg();
680 
681             if ( !errorHandler.wasError() )
682             {
683                 // We are golden : let's apply the schema in the real registries
684                 registries.setRelaxed();
685 
686                 // Load the schemas
687                 for ( Schema schema : schemas )
688                 {
689                     load( registries, schema );
690 
691                     // Update the schema dependences if needed
692                     if ( schema.getDependencies() != null )
693                     {
694                         for ( String dep : schema.getDependencies() )
695                         {
696                             Set<String> deps = schemaDependencies.get( dep );
697 
698                             if ( deps == null )
699                             {
700                                 deps = new HashSet<>();
701                                 deps.add( schema.getSchemaName() );
702                             }
703 
704                             // Replace the dependences
705                             schemaDependencies.put( dep, deps );
706                         }
707                     }
708 
709                     // add the schema to the SchemaMap
710                     schemaMap.put( schema.getSchemaName(), schema );
711                 }
712 
713                 // Build the cross references
714                 registries.buildReferences();
715                 registries.setStrict();
716 
717                 loaded = true;
718             }
719         }
720 
721         // clear the cloned registries
722         clonedRegistries.clear();
723 
724         return loaded;
725     }
726 
727 
728     /**
729      * {@inheritDoc}
730      */
731     @Override
732     public boolean load( String... schemaNames ) throws LdapException
733     {
734         if ( schemaNames.length == 0 )
735         {
736             return true;
737         }
738 
739         Schema[] schemas = toArray( schemaNames );
740 
741         return load( schemas );
742     }
743 
744 
745     /**
746      * Load the schema in the registries. We will load everything accordingly to the two flags :
747      * - isRelaxed
748      * - disabledAccepted
749      * 
750      * @param registries The Registries to process
751      * @param schema The schema to load in the Registries
752      * @return <tt>true</tt> if the schema has been loaded
753      * @throws LdapException If the schema cannot be loaded
754      */
755     private boolean load( Registries registries, Schema schema ) throws LdapException
756     {
757         if ( schema == null )
758         {
759             if ( LOG.isInfoEnabled() )
760             {
761                 LOG.info( I18n.msg( I18n.MSG_16013_SCHEMA_IS_NULL ) );
762             }
763             
764             return false;
765         }
766 
767         // First avoid loading twice the same schema
768         if ( registries.isSchemaLoaded( schema.getSchemaName() ) )
769         {
770             return true;
771         }
772 
773         if ( schema.isDisabled() )
774         {
775             if ( registries.isDisabledAccepted() )
776             {
777                 if ( LOG.isInfoEnabled() )
778                 {
779                     LOG.info( I18n.msg( I18n.MSG_16014_LOADING_DISABLED_SCHEMA, schema.getSchemaName(), schema ) );
780                 }
781 
782                 registries.schemaLoaded( schema );
783                 addSchemaObjects( schema, registries );
784             }
785             else
786             {
787                 return false;
788             }
789         }
790         else
791         {
792             if ( LOG.isInfoEnabled() )
793             {
794                 LOG.info( I18n.msg( I18n.MSG_16015_LOADING_ENABLED_SCHEMA, schema.getSchemaName(), schema ) );
795             }
796 
797             // Check that the dependencies, if any, are correct
798             if ( schema.getDependencies() != null )
799             {
800                 for ( String dependency : schema.getDependencies() )
801                 {
802                     Schema dependencySchema = schemaMap.get( dependency );
803 
804                     if ( dependencySchema == null )
805                     {
806                         // The dependency has not been loaded.
807                         String msg = I18n.err( I18n.ERR_16035_CANNOT_LOAD_SCHEMA, schema.getSchemaName() );
808                         
809                         if ( LOG.isInfoEnabled() )
810                         {
811                             LOG.info( msg );
812                         }
813                         
814                         LdapProtocolErrorException error = new LdapProtocolErrorException( msg );
815                         errorHandler.handle( LOG, msg, error );
816 
817                         return false;
818                     }
819 
820                     // If the dependency is disabled, then enable it
821                     if ( dependencySchema.isDisabled() )
822                     {
823                         dependencySchema.enable();
824 
825                         if ( !load( registries, dependencySchema ) )
826                         {
827                             dependencySchema.disable();
828 
829                             return false;
830                         }
831                     }
832                 }
833             }
834 
835             registries.schemaLoaded( schema );
836             addSchemaObjects( schema, registries );
837         }
838 
839         return true;
840     }
841 
842 
843     /**
844      * Unload the schema from the registries. We will unload everything accordingly to the two flags :
845      * - isRelaxed
846      * - disabledAccepted
847      * 
848      * @param registries The Registries to process
849      * @param schema The schema to unload from the Registries
850      * @return <tt>true</tt> if the schema has been unloaded
851      * @throws LdapException If the schema cannot be unloaded
852      */
853     private boolean unload( Registries registries, Schema schema ) throws LdapException
854     {
855         if ( schema == null )
856         {
857             if ( LOG.isInfoEnabled() )
858             {
859                 LOG.info( I18n.msg( I18n.MSG_16013_SCHEMA_IS_NULL )  );
860             }
861             
862             return false;
863         }
864 
865         // First avoid unloading twice the same schema
866         if ( !registries.isSchemaLoaded( schema.getSchemaName() ) )
867         {
868             return true;
869         }
870 
871         if ( schema.isEnabled() )
872         {
873             if ( LOG.isInfoEnabled() )
874             {
875                 LOG.info( I18n.msg( I18n.MSG_16016_UNLOADING_SCHEMA, schema.getSchemaName(), schema ) );
876             }
877 
878             deleteSchemaObjects( schema, registries );
879             registries.schemaUnloaded( schema );
880         }
881 
882         return true;
883     }
884 
885 
886     /**
887      * Add all the Schema's AttributeTypes
888      * 
889      * @param schema The schema in which the AttributeTypes will be added
890      * @param registries The Registries to process
891      * @throws LdapException If the AttributeTypes cannot be added
892      * @throws IOException If the AttributeTypes cannot be loaded
893      */
894     private void addAttributeTypes( Schema schema, Registries registries ) throws LdapException, IOException
895     {
896         if ( schema.getSchemaLoader() == null )
897         {
898             return;
899         }
900 
901         for ( Entry entry : schema.getSchemaLoader().loadAttributeTypes( schema ) )
902         {
903             AttributeType attributeType = factory.getAttributeType( this, entry, registries, schema.getSchemaName() );
904 
905             addSchemaObject( registries, attributeType, schema );
906         }
907     }
908 
909 
910     /**
911      * Add all the Schema's comparators
912      * 
913      * @param schema The schema in which the Comparators will be added
914      * @param registries The Registries to process
915      * @throws LdapException If the Comparators cannot be added
916      * @throws IOException If the Comparators cannot be loaded
917      */
918     private void addComparators( Schema schema, Registries registries ) throws LdapException, IOException
919     {
920         if ( schema.getSchemaLoader() == null )
921         {
922             return;
923         }
924         
925         for ( Entry entry : schema.getSchemaLoader().loadComparators( schema ) )
926         {
927             LdapComparator<?> comparator = factory.getLdapComparator( this, entry, registries, schema.getSchemaName() );
928 
929             addSchemaObject( registries, comparator, schema );
930         }
931     }
932 
933 
934     /**
935      * Add all the Schema's DitContentRules
936      */
937     // Not yet implemented, but may be used
938     //    @SuppressWarnings("PMD.UnusedFormalParameter")
939     //    private void addDitContentRules( Schema schema, Registries registries ) throws LdapException, IOException
940     //    {
941     //        if ( !schema.getSchemaLoader().loadDitContentRules( schema ).isEmpty() )
942     //        {
943     //            throw new NotImplementedException( I18n.err( I18n.ERR_11003 ) );
944     //        }
945     //    }
946 
947     /**
948      * Add all the Schema's DitStructureRules
949      */
950     // Not yet implemented, but may be used
951     //    @SuppressWarnings("PMD.UnusedFormalParameter")
952     //    private void addDitStructureRules( Schema schema, Registries registries ) throws LdapException, IOException
953     //    {
954     //        if ( !schema.getSchemaLoader().loadDitStructureRules( schema ).isEmpty() )
955     //        {
956     //            throw new NotImplementedException( I18n.err( I18n.ERR_11004 ) );
957     //        }
958     //    }
959 
960     /**
961      * Add all the Schema's MatchingRules
962      * 
963      * @param schema The schema in which the MatchingRules will be added
964      * @param registries The Registries to process
965      * @throws LdapException If the MatchingRules cannot be added
966      * @throws IOException If the MatchingRules cannot be loaded
967      */
968     private void addMatchingRules( Schema schema, Registries registries ) throws LdapException, IOException
969     {
970         if ( schema.getSchemaLoader() == null )
971         {
972             return;
973         }
974 
975         for ( Entry entry : schema.getSchemaLoader().loadMatchingRules( schema ) )
976         {
977             MatchingRule matchingRule = factory.getMatchingRule( this, entry, registries, schema.getSchemaName() );
978 
979             addSchemaObject( registries, matchingRule, schema );
980         }
981     }
982 
983 
984     /**
985      * Add all the Schema's MatchingRuleUses
986      */
987     // Not yet implemented, but may be used
988     //    @SuppressWarnings("PMD.UnusedFormalParameter")
989     //    private void addMatchingRuleUses( Schema schema, Registries registries ) throws LdapException, IOException
990     //    {
991     //        if ( !schema.getSchemaLoader().loadMatchingRuleUses( schema ).isEmpty() )
992     //        {
993     //            throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) );
994     //        }
995     //        // for ( Entry entry : schema.getSchemaLoader().loadMatchingRuleUses( schema ) )
996     //        // {
997     //        //     throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) );
998     //        // }
999     //    }
1000 
1001     /**
1002      * Add all the Schema's NameForms
1003      */
1004     // Not yet implemented, but may be used
1005     //    @SuppressWarnings("PMD.UnusedFormalParameter")
1006     //    private void addNameForms( Schema schema, Registries registries ) throws LdapException, IOException
1007     //    {
1008     //        if ( !schema.getSchemaLoader().loadNameForms( schema ).isEmpty() )
1009     //        {
1010     //            throw new NotImplementedException( I18n.err( I18n.ERR_11006 ) );
1011     //        }
1012     //    }
1013 
1014     /**
1015      * Add all the Schema's Normalizers
1016      * 
1017      * @param schema The schema in which the Normalizers will be added
1018      * @param registries The Registries to process
1019      * @throws LdapException If the Normalizers cannot be added
1020      * @throws IOException If the Normalizers cannot be loaded
1021      */
1022     private void addNormalizers( Schema schema, Registries registries ) throws LdapException, IOException
1023     {
1024         if ( schema.getSchemaLoader() == null )
1025         {
1026             return;
1027         }
1028 
1029         for ( Entry entry : schema.getSchemaLoader().loadNormalizers( schema ) )
1030         {
1031             Normalizer normalizer = factory.getNormalizer( this, entry, registries, schema.getSchemaName() );
1032 
1033             addSchemaObject( registries, normalizer, schema );
1034         }
1035     }
1036 
1037 
1038     /**
1039      * Add all the Schema's ObjectClasses
1040      * 
1041      * @param schema The schema in which the ObjectClasses will be added
1042      * @param registries The Registries to process
1043      * @throws LdapException If the ObjectClasses cannot be added
1044      * @throws IOException If the ObjectClasses cannot be loaded
1045      */
1046     private void addObjectClasses( Schema schema, Registries registries ) throws LdapException, IOException
1047     {
1048         if ( schema.getSchemaLoader() == null )
1049         {
1050             return;
1051         }
1052 
1053         for ( Entry entry : schema.getSchemaLoader().loadObjectClasses( schema ) )
1054         {
1055             ObjectClass objectClass = factory.getObjectClass( this, entry, registries, schema.getSchemaName() );
1056 
1057             addSchemaObject( registries, objectClass, schema );
1058         }
1059     }
1060 
1061 
1062     /**
1063      * Add all the Schema's Syntaxes
1064      * 
1065      * @param schema The schema in which the Syntaxes will be added
1066      * @param registries The Registries to process
1067      * @throws LdapException If the Syntaxes cannot be added
1068      * @throws IOException If the Syntaxes cannot be loaded
1069      */
1070     private void addSyntaxes( Schema schema, Registries registries ) throws LdapException, IOException
1071     {
1072         if ( schema.getSchemaLoader() == null )
1073         {
1074             return;
1075         }
1076 
1077         for ( Entry entry : schema.getSchemaLoader().loadSyntaxes( schema ) )
1078         {
1079             LdapSyntax syntax = factory.getSyntax( this, entry, registries, schema.getSchemaName() );
1080 
1081             addSchemaObject( registries, syntax, schema );
1082         }
1083     }
1084 
1085 
1086     /**
1087      * Register all the Schema's SyntaxCheckers
1088      * 
1089      * @param schema The schema in which the SyntaxChecker will be added
1090      * @param registries The Registries to process
1091      * @throws LdapException If the SyntaxChecker cannot be added
1092      * @throws IOException If the SyntaxChecker cannot be loaded
1093      */
1094     private void addSyntaxCheckers( Schema schema, Registries registries ) throws LdapException, IOException
1095     {
1096         if ( schema.getSchemaLoader() == null )
1097         {
1098             return;
1099         }
1100 
1101         for ( Entry entry : schema.getSchemaLoader().loadSyntaxCheckers( schema ) )
1102         {
1103             SyntaxChecker syntaxChecker = factory.getSyntaxChecker( this, entry, registries, schema.getSchemaName() );
1104 
1105             addSchemaObject( registries, syntaxChecker, schema );
1106         }
1107     }
1108 
1109 
1110     /**
1111      * Add the schemaObject into the registries.
1112      *
1113      * @param registries The Registries
1114      * @param schemaObject The SchemaObject containing the SchemaObject description
1115      * @param schema The associated schema
1116      * @return the created schemaObject instance
1117      * @throws LdapException If the registering failed
1118      */
1119     protected SchemaObject addSchemaObject( Registries registries, SchemaObject schemaObject, Schema schema )
1120         throws LdapException
1121     {
1122         if ( registries.isRelaxed() )
1123         {
1124             if ( registries.isDisabledAccepted() || ( schema.isEnabled() && schemaObject.isEnabled() ) )
1125             {
1126                 registries.add( schemaObject, false );
1127             }
1128             else
1129             {
1130                 // What kind of error is this? TODO: better message
1131                 errorHandler.handle( LOG, null, new Throwable() );
1132             }
1133         }
1134         else
1135         {
1136             if ( schema.isEnabled() && schemaObject.isEnabled() )
1137             {
1138                 registries.add( schemaObject, false );
1139             }
1140             else
1141             {
1142                 // What kind of error is this? TODO: better message
1143                 errorHandler.handle( LOG, null, new Throwable() );
1144             }
1145         }
1146 
1147         return schemaObject;
1148     }
1149 
1150 
1151     /**
1152      * {@inheritDoc}
1153      */
1154     @Override
1155     public boolean loadAllEnabled() throws LdapException
1156     {
1157         Schema[] schemas = new Schema[schemaMap.size()];
1158         int i = 0;
1159         
1160         for ( Schema schema : schemaMap.values() )
1161         {
1162             if ( schema.isEnabled() )
1163             {
1164                 schemas[i++] = schema;
1165             }
1166         }
1167         
1168         Schema[] enabledSchemas = new Schema[i];
1169         System.arraycopy( schemas, 0, enabledSchemas, 0, i );
1170         
1171         return loadWithDeps( enabledSchemas );
1172     }
1173 
1174 
1175     /**
1176      * {@inheritDoc}
1177      */
1178     @Override
1179     public boolean loadAllEnabledRelaxed() throws LdapException
1180     {
1181         Schema[] enabledSchemas = new Schema[schemaMap.size()];
1182         int i = 0;
1183         
1184         for ( Schema schema : schemaMap.values() )
1185         {
1186             if ( schema.isEnabled() )
1187             {
1188                 enabledSchemas[i++] = schema;
1189             }
1190         }
1191         
1192         return loadWithDepsRelaxed( enabledSchemas );
1193     }
1194 
1195 
1196     /**
1197      * {@inheritDoc}
1198      */
1199     @Override
1200     public boolean loadDisabled( Schema... schemas ) throws LdapException
1201     {
1202         // Work on a cloned and relaxed registries
1203         Registries clonedRegistries = cloneRegistries();
1204 
1205         // Accept the disabled schemas
1206         clonedRegistries.setDisabledAccepted( true );
1207 
1208         // Load the schemas
1209         for ( Schema schema : schemas )
1210         {
1211             // Enable the Schema object before loading it
1212             schema.enable();
1213             load( clonedRegistries, schema );
1214         }
1215 
1216         clonedRegistries.clear();
1217 
1218         // Apply the change to the correct registries if no errors
1219         if ( !errorHandler.wasError() )
1220         {
1221             // No error, we can enable the schema in the real registries
1222             for ( Schema schema : schemas )
1223             {
1224                 load( registries, schema );
1225             }
1226 
1227             return true;
1228         }
1229         else
1230         {
1231             for ( Schema schema : schemas )
1232             {
1233                 schema.disable();
1234             }
1235 
1236             return false;
1237         }
1238     }
1239 
1240 
1241     /**
1242      * {@inheritDoc}
1243      */
1244     @Override
1245     public boolean loadDisabled( String... schemaNames ) throws LdapException
1246     {
1247         Schema[] schemas = toArray( schemaNames );
1248 
1249         return loadDisabled( schemas );
1250     }
1251 
1252 
1253     /**
1254      * {@inheritDoc}
1255      */
1256     @Override
1257     public boolean loadRelaxed( Schema... schemas ) throws LdapException
1258     {
1259         return false;
1260     }
1261 
1262 
1263     /**
1264      * {@inheritDoc}
1265      */
1266     @Override
1267     public boolean loadRelaxed( String... schemaNames ) throws LdapException
1268     {
1269         Schema[] schemas = toArray( schemaNames );
1270         return loadRelaxed( schemas );
1271     }
1272 
1273 
1274     /**
1275      * {@inheritDoc}
1276      */
1277     @Override
1278     public boolean loadWithDeps( Schema... schemas ) throws LdapException
1279     {
1280         boolean loaded = false;
1281 
1282         // Reset the errors if not null
1283         errorHandler.reset();
1284 
1285         // Work on a cloned and relaxed registries
1286         Registries clonedRegistries = cloneRegistries();
1287         clonedRegistries.setRelaxed();
1288 
1289         // Load the schemas
1290         for ( Schema schema : schemas )
1291         {
1292             loadDepsFirst( clonedRegistries, schema );
1293         }
1294 
1295         // Build the cross references
1296         clonedRegistries.buildReferences();
1297 
1298         if ( !errorHandler.wasError() )
1299         {
1300             // Ok no errors. Check the registries now
1301             clonedRegistries.checkRefInteg();
1302 
1303             if ( !errorHandler.wasError() )
1304             {
1305                 // We are golden : let's apply the schema in the real registries
1306                 registries = clonedRegistries;
1307                 registries.setStrict();
1308                 loaded = true;
1309             }
1310         }
1311         else if ( isStrict() )
1312         {
1313             // clear the cloned registries
1314             clonedRegistries.clear();
1315         }
1316         else
1317         {
1318             // Relaxed mode
1319             registries = clonedRegistries;
1320             registries.setRelaxed();
1321             loaded = true;
1322         }
1323 
1324         return loaded;
1325     }
1326 
1327 
1328     /**
1329      * {@inheritDoc}
1330      */
1331     @Override
1332     public boolean loadWithDeps( String... schemas ) throws LdapException
1333     {
1334         return loadWithDeps( toArray( schemas ) );
1335     }
1336 
1337 
1338     /**
1339      * Recursive method which loads schema's with their dependent schemas first
1340      * and tracks what schemas it has seen so the recursion does not go out of
1341      * control with dependency cycle detection.
1342      *
1343      * @param registries The Registries in which the schemas will be loaded
1344      * @param schema the current schema we are attempting to load
1345      * @throws LdapException if there is a cycle detected and/or another
1346      * failure results while loading, producing and or registering schema objects
1347      */
1348     private void loadDepsFirst( Registries registries, Schema schema ) throws LdapException
1349     {
1350         if ( schema == null )
1351         {
1352             if ( LOG.isInfoEnabled() )
1353             {
1354                 LOG.info( I18n.msg( I18n.MSG_16013_SCHEMA_IS_NULL )  );
1355             }
1356             
1357             return;
1358         }
1359 
1360         if ( schema.isDisabled() && !registries.isDisabledAccepted() )
1361         {
1362             if ( LOG.isInfoEnabled() )
1363             {
1364                 LOG.info( I18n.msg( I18n.MSG_16017_UNACCEPTED_DISABLED_SCHEMA ) );
1365             }
1366             
1367             return;
1368         }
1369 
1370         String schemaName = schema.getSchemaName();
1371 
1372         if ( registries.isSchemaLoaded( schemaName ) )
1373         {
1374             if ( LOG.isInfoEnabled() )
1375             {
1376                 LOG.info( I18n.msg( I18n.MSG_16018_SCHEMA_ALREADY_LOADED, schema.getSchemaName() ) );
1377             }
1378             
1379             return;
1380         }
1381 
1382         String[] deps = schema.getDependencies();
1383 
1384         // if no deps then load this guy and return
1385         if ( ( deps == null ) || ( deps.length == 0 ) )
1386         {
1387             load( registries, schema );
1388 
1389             return;
1390         }
1391 
1392         /*
1393          * We got deps and need to load them before this schema.  We go through
1394          * all deps loading them with their deps first if they have not been
1395          * loaded.
1396          */
1397         for ( String depName : deps )
1398         {
1399             if ( !registries.isSchemaLoaded( depName ) )
1400             {
1401                 // Call recursively this method
1402                 Schema schemaDep = schemaMap.get( depName );
1403                 loadDepsFirst( registries, schemaDep );
1404             }
1405         }
1406 
1407         // Now load the current schema
1408         load( registries, schema );
1409     }
1410 
1411 
1412     /**
1413      * {@inheritDoc}
1414      */
1415     @Override
1416     public boolean loadWithDepsRelaxed( Schema... schemas ) throws LdapException
1417     {
1418         registries.setRelaxed();
1419 
1420         // Load the schemas
1421         for ( Schema schema : schemas )
1422         {
1423             loadDepsFirstRelaxed( schema );
1424         }
1425 
1426         // Build the cross references
1427         registries.buildReferences();
1428 
1429         // Check the registries now
1430         registries.checkRefInteg();
1431 
1432         return true;
1433     }
1434 
1435 
1436     /**
1437      * {@inheritDoc}
1438      */
1439     @Override
1440     public boolean loadWithDepsRelaxed( String... schemas ) throws LdapException
1441     {
1442         return loadWithDepsRelaxed( toArray( schemas ) );
1443     }
1444 
1445 
1446     /**
1447      * Recursive method which loads schema's with their dependent schemas first
1448      * and tracks what schemas it has seen so the recursion does not go out of
1449      * control with dependency cycle detection.
1450      *
1451      * @param schema the current schema we are attempting to load
1452      * @throws LdapException if there is a cycle detected and/or another
1453      * failure results while loading, producing and or registering schema objects
1454      */
1455     private void loadDepsFirstRelaxed( Schema schema ) throws LdapException
1456     {
1457         if ( schema == null )
1458         {
1459             if ( LOG.isInfoEnabled() )
1460             {
1461                 LOG.info( I18n.msg( I18n.MSG_16013_SCHEMA_IS_NULL )  );
1462             }
1463             
1464             return;
1465         }
1466 
1467         if ( schema.isDisabled() && !registries.isDisabledAccepted() )
1468         {
1469             if ( LOG.isInfoEnabled() )
1470             {
1471                 LOG.info( I18n.msg( I18n.MSG_16017_UNACCEPTED_DISABLED_SCHEMA ) );
1472             }
1473             
1474             return;
1475         }
1476 
1477         String schemaName = schema.getSchemaName();
1478 
1479         if ( registries.isSchemaLoaded( schemaName ) )
1480         {
1481             if ( LOG.isInfoEnabled() )
1482             {
1483                 LOG.info( I18n.msg( I18n.MSG_16018_SCHEMA_ALREADY_LOADED, schema.getSchemaName() ) );
1484             }
1485             
1486             return;
1487         }
1488 
1489         String[] deps = schema.getDependencies();
1490 
1491         // if no deps then load this guy and return
1492         if ( ( deps == null ) || ( deps.length == 0 ) )
1493         {
1494             load( registries, schema );
1495 
1496             return;
1497         }
1498 
1499         /*
1500          * We got deps and need to load them before this schema.  We go through
1501          * all deps loading them with their deps first if they have not been
1502          * loaded.
1503          */
1504         for ( String depName : deps )
1505         {
1506             if ( !registries.isSchemaLoaded( schemaName ) )
1507             {
1508                 // Call recursively this method
1509                 Schema schemaDep = schema.getSchemaLoader().getSchema( depName );
1510                 loadDepsFirstRelaxed( schemaDep );
1511             }
1512         }
1513 
1514         // Now load the current schema
1515         load( registries, schema );
1516     }
1517 
1518 
1519     /**
1520      * {@inheritDoc}
1521      */
1522     @Override
1523     public void setRegistries( Registries registries )
1524     {
1525         this.registries = registries;
1526     }
1527 
1528 
1529     /**
1530      * {@inheritDoc}
1531      */
1532     @Override
1533     public boolean unload( Schema... schemas ) throws LdapException
1534     {
1535         boolean unloaded = false;
1536 
1537         // Reset the errors if not null
1538         errorHandler.reset();
1539 
1540         // Work on a cloned and relaxed registries
1541         Registries clonedRegistries = cloneRegistries();
1542         clonedRegistries.setRelaxed();
1543 
1544         // Load the schemas
1545         for ( Schema schema : schemas )
1546         {
1547             unload( clonedRegistries, schema );
1548         }
1549 
1550         // Build the cross references
1551         clonedRegistries.buildReferences();
1552 
1553         if ( !errorHandler.wasError() )
1554         {
1555             // Ok no errors. Check the registries now
1556             clonedRegistries.checkRefInteg();
1557 
1558             if ( !errorHandler.wasError() )
1559             {
1560                 // We are golden : let's apply the schema in the real registries
1561                 registries.setRelaxed();
1562 
1563                 // Load the schemas
1564                 for ( Schema schema : schemas )
1565                 {
1566                     unload( registries, schema );
1567 
1568                     // Update the schema dependences
1569                     for ( String dep : schema.getDependencies() )
1570                     {
1571                         Set<String> deps = schemaDependencies.get( dep );
1572 
1573                         if ( deps != null )
1574                         {
1575                             deps.remove( schema.getSchemaName() );
1576                         }
1577                     }
1578 
1579                     schemaMap.remove( schema.getSchemaName() );
1580                 }
1581 
1582                 // Build the cross references
1583                 registries.buildReferences();
1584                 registries.setStrict();
1585 
1586                 unloaded = true;
1587             }
1588         }
1589 
1590         // clear the cloned registries
1591         clonedRegistries.clear();
1592 
1593         return unloaded;
1594     }
1595 
1596 
1597     /**
1598      * {@inheritDoc}
1599      */
1600     @Override
1601     public boolean unload( String... schemaNames ) throws LdapException
1602     {
1603         Schema[] schemas = toArray( schemaNames );
1604 
1605         return unload( schemas );
1606     }
1607 
1608 
1609     /**
1610      * {@inheritDoc}
1611      */
1612     @Override
1613     public boolean verify( Schema... schemas ) throws LdapException
1614     {
1615         errorHandler.reset();
1616         // Work on a cloned registries
1617         Registries clonedRegistries = cloneRegistries();
1618 
1619         // Loop on all the schemas
1620         for ( Schema schema : schemas )
1621         {
1622             try
1623             {
1624                 // Inject the schema
1625                 boolean loaded = load( clonedRegistries, schema );
1626 
1627                 if ( !loaded )
1628                 {
1629                     // We got an error : exit
1630                     clonedRegistries.clear();
1631                     return false;
1632                 }
1633 
1634                 // Now, check the registries
1635                 clonedRegistries.checkRefInteg();
1636 
1637                 if ( !errorHandler.wasError() )
1638                 {
1639                     // We got an error : exit
1640                     clonedRegistries.clear();
1641                     return false;
1642                 }
1643             }
1644             catch ( Exception e )
1645             {
1646                 // We got an error : exit
1647                 clonedRegistries.clear();
1648                 return false;
1649             }
1650         }
1651 
1652         // We can now delete the cloned registries before exiting
1653         clonedRegistries.clear();
1654 
1655         return true;
1656     }
1657 
1658 
1659     /**
1660      * {@inheritDoc}
1661      */
1662     @Override
1663     public boolean verify( String... schemas ) throws LdapException
1664     {
1665         return verify( toArray( schemas ) );
1666     }
1667 
1668 
1669     /**
1670      * @return the namingContext
1671      */
1672     @Override
1673     public Dn getNamingContext()
1674     {
1675         return namingContext;
1676     }
1677 
1678 
1679     /**
1680      * Initializes the SchemaService
1681      *
1682      * @throws LdapException If the initialization fails
1683      */
1684     @Override
1685     public void initialize() throws LdapException
1686     {
1687     }
1688 
1689 
1690     //-----------------------------------------------------------------------------------
1691     // Immutable accessors
1692     //-----------------------------------------------------------------------------------
1693     /**
1694      * {@inheritDoc}
1695      */
1696     @Override
1697     public AttributeTypeRegistry getAttributeTypeRegistry()
1698     {
1699         return new ImmutableAttributeTypeRegistry( registries.getAttributeTypeRegistry() );
1700     }
1701 
1702 
1703     /**
1704      * {@inheritDoc}
1705      */
1706     @Override
1707     public ComparatorRegistry getComparatorRegistry()
1708     {
1709         return new ImmutableComparatorRegistry( registries.getComparatorRegistry() );
1710     }
1711 
1712 
1713     /**
1714      * {@inheritDoc}
1715      */
1716     @Override
1717     public DitContentRuleRegistry getDITContentRuleRegistry()
1718     {
1719         return new ImmutableDitContentRuleRegistry( registries.getDitContentRuleRegistry() );
1720     }
1721 
1722 
1723     /**
1724      * {@inheritDoc}
1725      */
1726     @Override
1727     public DitStructureRuleRegistry getDITStructureRuleRegistry()
1728     {
1729         return new ImmutableDitStructureRuleRegistry( registries.getDitStructureRuleRegistry() );
1730     }
1731 
1732 
1733     /**
1734      * {@inheritDoc}
1735      */
1736     @Override
1737     public MatchingRuleRegistry getMatchingRuleRegistry()
1738     {
1739         return new ImmutableMatchingRuleRegistry( registries.getMatchingRuleRegistry() );
1740     }
1741 
1742 
1743     /**
1744      * {@inheritDoc}
1745      */
1746     @Override
1747     public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
1748     {
1749         return new ImmutableMatchingRuleUseRegistry( registries.getMatchingRuleUseRegistry() );
1750     }
1751 
1752 
1753     /**
1754      * {@inheritDoc}
1755      */
1756     @Override
1757     public NameFormRegistry getNameFormRegistry()
1758     {
1759         return new ImmutableNameFormRegistry( registries.getNameFormRegistry() );
1760     }
1761 
1762 
1763     /**
1764      * {@inheritDoc}
1765      */
1766     @Override
1767     public NormalizerRegistry getNormalizerRegistry()
1768     {
1769         return new ImmutableNormalizerRegistry( registries.getNormalizerRegistry() );
1770     }
1771 
1772 
1773     /**
1774      * {@inheritDoc}
1775      */
1776     @Override
1777     public ObjectClassRegistry getObjectClassRegistry()
1778     {
1779         return new ImmutableObjectClassRegistry( registries.getObjectClassRegistry() );
1780     }
1781 
1782 
1783     /**
1784      * {@inheritDoc}
1785      */
1786     @Override
1787     public LdapSyntaxRegistry getLdapSyntaxRegistry()
1788     {
1789         return new ImmutableLdapSyntaxRegistry( registries.getLdapSyntaxRegistry() );
1790     }
1791 
1792 
1793     /**
1794      * {@inheritDoc}
1795      */
1796     @Override
1797     public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
1798     {
1799         return new ImmutableSyntaxCheckerRegistry( registries.getSyntaxCheckerRegistry() );
1800     }
1801 
1802 
1803     /**
1804      * Get rid of AT's options (everything after the ';'
1805      * @param oid The AT's OID
1806      * @return The AT without its options
1807      */
1808     private String stripOptions( String oid )
1809     {
1810         int semiColonPos = oid.indexOf( ';' );
1811 
1812         if ( semiColonPos != -1 )
1813         {
1814             return oid.substring( 0, semiColonPos );
1815         }
1816         else
1817         {
1818             return oid;
1819         }
1820     }
1821 
1822 
1823     /**
1824      * {@inheritDoc}
1825      */
1826     @Override
1827     public AttributeType lookupAttributeTypeRegistry( String oid ) throws LdapException
1828     {
1829         String oidTrimmed = Strings.toLowerCaseAscii( oid ).trim();
1830         String oidNoOption = stripOptions( oidTrimmed );
1831         return registries.getAttributeTypeRegistry().lookup( oidNoOption );
1832     }
1833 
1834 
1835     /**
1836      * {@inheritDoc}
1837      */
1838     @Override
1839     public AttributeType getAttributeType( String oid )
1840     {
1841         try
1842         {
1843             // Get rid of the options
1844             String attributeTypeNoOptions = SchemaUtils.stripOptions( oid );
1845             return registries.getAttributeTypeRegistry().lookup( Strings.toLowerCaseAscii( attributeTypeNoOptions ).trim() );
1846         }
1847         catch ( LdapException lnsae )
1848         {
1849             return null;
1850         }
1851     }
1852 
1853 
1854     /**
1855      * {@inheritDoc}
1856      */
1857     @Override
1858     public LdapComparator<?> lookupComparatorRegistry( String oid ) throws LdapException
1859     {
1860         return registries.getComparatorRegistry().lookup( oid );
1861     }
1862 
1863 
1864     /**
1865      * {@inheritDoc}
1866      */
1867     @Override
1868     public MatchingRule lookupMatchingRuleRegistry( String oid ) throws LdapException
1869     {
1870         return registries.getMatchingRuleRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
1871     }
1872 
1873 
1874     /**
1875      * {@inheritDoc}
1876      */
1877     @Override
1878     public Normalizer lookupNormalizerRegistry( String oid ) throws LdapException
1879     {
1880         return registries.getNormalizerRegistry().lookup( oid );
1881     }
1882 
1883 
1884     /**
1885      * {@inheritDoc}
1886      */
1887     @Override
1888     public ObjectClass lookupObjectClassRegistry( String oid ) throws LdapException
1889     {
1890         return registries.getObjectClassRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
1891     }
1892 
1893 
1894     /**
1895      * {@inheritDoc}
1896      */
1897     @Override
1898     public LdapSyntax lookupLdapSyntaxRegistry( String oid ) throws LdapException
1899     {
1900         return registries.getLdapSyntaxRegistry().lookup( Strings.toLowerCaseAscii( oid ).trim() );
1901     }
1902 
1903 
1904     /**
1905      * {@inheritDoc}
1906      */
1907     @Override
1908     public SyntaxChecker lookupSyntaxCheckerRegistry( String oid ) throws LdapException
1909     {
1910         return registries.getSyntaxCheckerRegistry().lookup( oid );
1911     }
1912 
1913 
1914     /**
1915      * Check that the given OID exists in the globalOidRegistry.
1916      * 
1917      * @param schemaObject The SchemaObject to check
1918      * @return <tt>true</tt> if the OID exists
1919      */
1920     private boolean checkOidExist( SchemaObject schemaObject )
1921     {
1922         if ( !( schemaObject instanceof LoadableSchemaObject ) )
1923         {
1924             return registries.getGlobalOidRegistry().contains( schemaObject.getOid() );
1925         }
1926 
1927         if ( schemaObject instanceof LdapComparator<?> )
1928         {
1929             return registries.getComparatorRegistry().contains( schemaObject.getOid() );
1930         }
1931 
1932         if ( schemaObject instanceof SyntaxChecker )
1933         {
1934             return registries.getSyntaxCheckerRegistry().contains( schemaObject.getOid() );
1935         }
1936 
1937         if ( schemaObject instanceof Normalizer )
1938         {
1939             return registries.getNormalizerRegistry().contains( schemaObject.getOid() );
1940         }
1941 
1942         return false;
1943     }
1944 
1945 
1946     /**
1947      * Get the inner SchemaObject if it's not a C/N/SC
1948      * 
1949      * @param schemaObject The SchemaObject to retreive
1950      * @return The found SchemaObject
1951      * @throws LdapException If the SchemaObject can't be found
1952      */
1953     private SchemaObject getSchemaObject( SchemaObject schemaObject ) throws LdapException
1954     {
1955         if ( schemaObject instanceof LoadableSchemaObject )
1956         {
1957             return schemaObject;
1958         }
1959         else
1960         {
1961             return registries.getGlobalOidRegistry().getSchemaObject( schemaObject.getOid() );
1962         }
1963     }
1964 
1965 
1966     /**
1967      * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
1968      * 
1969      * @param schemaObject The schemaObject to read
1970      * @return The schema name
1971      */
1972     private String getSchemaName( SchemaObject schemaObject )
1973     {
1974         String schemaName = Strings.toLowerCaseAscii( schemaObject.getSchemaName() );
1975 
1976         if ( Strings.isEmpty( schemaName ) )
1977         {
1978             return MetaSchemaConstants.SCHEMA_OTHER;
1979         }
1980 
1981         if ( schemaMap.get( schemaName ) == null )
1982         {
1983             return null;
1984         }
1985         else
1986         {
1987             return schemaName;
1988         }
1989     }
1990 
1991 
1992     private SchemaObject copy( SchemaObject schemaObject )
1993     {
1994         SchemaObject copy = null;
1995 
1996         if ( !( schemaObject instanceof LoadableSchemaObject ) )
1997         {
1998             copy = schemaObject.copy();
1999         }
2000         else
2001         {
2002             // Check the schemaObject here.
2003             if ( ( ( LoadableSchemaObject ) schemaObject ).isValid() )
2004             {
2005                 copy = schemaObject;
2006             }
2007             else
2008             {
2009                 // We have an invalid SchemaObject, no need to go any further
2010                 LdapUnwillingToPerformException error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err(
2011                     I18n.ERR_16079_INVALID_SCHEMA_OBJECT_CANNOT_BE_LOADED, schemaObject.getOid() ) );
2012                 errorHandler.handle( LOG, error.getMessage(), error );
2013             }
2014         }
2015 
2016         return copy;
2017     }
2018 
2019 
2020     //-----------------------------------------------------------------------------------
2021     // SchemaObject operations
2022     //-----------------------------------------------------------------------------------
2023     /**
2024      * {@inheritDoc}
2025      */
2026     @Override
2027     public boolean add( SchemaObject schemaObject ) throws LdapException
2028     {
2029         // First, clear the errors
2030         errorHandler.reset();
2031 
2032         // Clone the schemaObject
2033         SchemaObject copy = copy( schemaObject );
2034 
2035         if ( copy == null )
2036         {
2037             return false;
2038         }
2039 
2040         if ( registries.isRelaxed() )
2041         {
2042             // Apply the addition right away
2043             registries.add( copy, true );
2044 
2045             return !errorHandler.wasError();
2046         }
2047         else
2048         {
2049             // Clone, apply, check, then apply again if ok
2050             // The new schemaObject's OID must not already exist
2051             if ( checkOidExist( copy ) )
2052             {
2053                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
2054                     LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_16036_OID_NOT_UNIQUE, 
2055                         schemaObject.getOid() ) );
2056                 ldapSchemaException.setSourceObject( schemaObject );
2057                 errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
2058 
2059                 return false;
2060             }
2061 
2062             // Build the new AttributeType from the given entry
2063             String schemaName = getSchemaName( copy );
2064 
2065             if ( schemaName == null )
2066             {
2067                 // The schema associated with the SchemaaObject does not exist. This is not valid.
2068 
2069                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
2070                     LdapSchemaExceptionCodes.NONEXISTENT_SCHEMA, I18n.err( I18n.ERR_16037_NON_EXISTING_SCHEMA, 
2071                         schemaObject.getOid(), copy.getSchemaName() ) );
2072                 ldapSchemaException.setSourceObject( schemaObject );
2073                 ldapSchemaException.setRelatedId( copy.getSchemaName() );
2074                 errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException );
2075 
2076                 return false;
2077             }
2078 
2079             // At this point, the constructed AttributeType has not been checked against the
2080             // existing Registries. It may be broken (missing SUP, or such), it will be checked
2081             // there, if the schema and the AttributeType are both enabled.
2082             Schema schema = getLoadedSchema( schemaName );
2083 
2084             if ( schema == null )
2085             {
2086                 // The SchemaObject must be associated with an existing schema
2087                 String msg = I18n.err( I18n.ERR_16038_NOT_ASSOCIATED_TO_A_SCHEMA, copy.getOid() );
2088                 Throwable error = new LdapProtocolErrorException( msg );
2089                 errorHandler.handle( LOG, msg, error );
2090                 return false;
2091             }
2092 
2093             if ( schema.isEnabled() && copy.isEnabled() )
2094             {
2095                 // As we may break the registries, work on a cloned registries
2096                 Registries clonedRegistries = null;
2097 
2098                 try
2099                 {
2100                     clonedRegistries = registries.clone();
2101                 }
2102                 catch ( CloneNotSupportedException cnse )
2103                 {
2104                     throw new LdapOtherException( cnse.getMessage(), cnse );
2105                 }
2106 
2107                 // Inject the new SchemaObject in the cloned registries
2108                 clonedRegistries.add( copy, true );
2109 
2110                 // Remove the cloned registries
2111                 clonedRegistries.clear();
2112 
2113                 // If we didn't get any error, apply the addition to the real registries
2114                 if ( !errorHandler.wasError() )
2115                 {
2116                     // Copy again as the clonedRegistries clear has removed the previous copy
2117                     copy = copy( schemaObject );
2118 
2119                     // Apply the addition to the real registries
2120                     registries.add( copy, true );
2121 
2122                     if ( LOG.isDebugEnabled() )
2123                     {
2124                         LOG.debug( I18n.msg( I18n.MSG_16019_ENABLED_SCHEMA_ADDED, copy.getName(), schemaName ) );
2125                     }
2126 
2127                     return true;
2128                 }
2129                 else
2130                 {
2131                     // We have some error : reject the addition and get out
2132                     errorHandler.handle( LOG, I18n.msg( I18n.MSG_16020_CANNOT_LOAD_SCHEMAOBJECT, 
2133                             copy.getOid(), Strings.listToString( errorHandler.getErrors() ) ), null );
2134                     return false;
2135                 }
2136             }
2137             else
2138             {
2139                 // At least, we register the OID in the globalOidRegistry, and associates it with the
2140                 // schema
2141                 registries.associateWithSchema( copy );
2142 
2143                 if ( LOG.isDebugEnabled() )
2144                 {
2145                     LOG.debug( I18n.msg( I18n.MSG_16021_ADDED_INTO_DISABLED_SCHEMA, copy.getName(), schemaName ) );
2146                 }
2147                 
2148                 return !errorHandler.wasError();
2149             }
2150         }
2151     }
2152 
2153 
2154     /**
2155      * {@inheritDoc}
2156      */
2157     @Override
2158     public boolean delete( SchemaObject schemaObject ) throws LdapException
2159     {
2160         // First, clear the errors
2161         errorHandler.reset();
2162 
2163         if ( registries.isRelaxed() )
2164         {
2165             // Apply the addition right away
2166             registries.delete( schemaObject );
2167 
2168             return !errorHandler.wasError();
2169         }
2170         else
2171         {
2172             // Clone, apply, check, then apply again if ok
2173             // The new schemaObject's OID must exist
2174             if ( !checkOidExist( schemaObject ) )
2175             {
2176                 Throwable error = new LdapProtocolErrorException( I18n.err( I18n.ERR_16039_OID_DOES_NOT_EXIST, 
2177                     schemaObject.getOid() ) );
2178                 errorHandler.handle( LOG, error.getMessage(), error );
2179                 return false;
2180             }
2181 
2182             // Get the SchemaObject to delete if it's not a LoadableSchemaObject
2183             SchemaObject toDelete = getSchemaObject( schemaObject );
2184 
2185             // First check that this SchemaObject does not have any referencing SchemaObjects
2186             Set<SchemaObjectWrapper> referencing = registries.getReferencing( toDelete );
2187 
2188             if ( ( referencing != null ) && !referencing.isEmpty() )
2189             {
2190                 String msg = I18n.err( I18n.ERR_16040_CANNOT_REMOVE_FROM_REGISTRY, schemaObject.getOid(), 
2191                     Strings.setToString( referencing ) );
2192 
2193                 Throwable error = new LdapProtocolErrorException( msg );
2194                 errorHandler.handle( LOG, msg, error );
2195                 return false;
2196             }
2197 
2198             String schemaName = getSchemaName( toDelete );
2199 
2200             // At this point, the deleted AttributeType may be referenced, it will be checked
2201             // there, if the schema and the AttributeType are both enabled.
2202             Schema schema = getLoadedSchema( schemaName );
2203 
2204             if ( schema == null )
2205             {
2206                 // The SchemaObject must be associated with an existing schema
2207                 String msg = I18n.err( I18n.ERR_16041_CANNOT_DELETE_SCHEMA_OBJECT, schemaObject.getOid() );
2208                 Throwable error = new LdapProtocolErrorException( msg );
2209                 errorHandler.handle( LOG, msg, error );
2210                 return false;
2211             }
2212 
2213             if ( schema.isEnabled() && schemaObject.isEnabled() )
2214             {
2215                 // As we may break the registries, work on a cloned registries
2216                 Registries clonedRegistries = null;
2217 
2218                 try
2219                 {
2220                     clonedRegistries = registries.clone();
2221                 }
2222                 catch ( CloneNotSupportedException cnse )
2223                 {
2224                     throw new LdapOtherException( cnse.getMessage(), cnse );
2225                 }
2226 
2227                 // Delete the SchemaObject from the cloned registries
2228                 clonedRegistries.delete( toDelete );
2229 
2230                 // Remove the cloned registries
2231                 clonedRegistries.clear();
2232 
2233                 // If we didn't get any error, apply the deletion to the real retistries
2234                 if ( !errorHandler.wasError() )
2235                 {
2236                     // Apply the deletion to the real registries
2237                     registries.delete( toDelete );
2238 
2239                     if ( LOG.isDebugEnabled() )
2240                     {
2241                         LOG.debug( I18n.msg( I18n.MSG_16022_REMOVED_FROM_ENABLED_SCHEMA, toDelete.getName(), schemaName ) );
2242                     }
2243 
2244                     return true;
2245                 }
2246                 else
2247                 {
2248                     // We have some error : reject the deletion and get out
2249                     errorHandler.handle( LOG, I18n.msg( I18n.MSG_16023_CANNOT_DELETE_SCHEMAOBJECT, 
2250                             schemaObject.getOid(), Strings.listToString( errorHandler.getErrors() ) ), null );
2251 
2252                     return false;
2253                 }
2254             }
2255             else
2256             {
2257                 // At least, we register the OID in the globalOidRegistry, and associates it with the
2258                 // schema
2259                 registries.associateWithSchema( schemaObject );
2260 
2261                 if ( LOG.isDebugEnabled() )
2262                 {
2263                     LOG.debug( I18n.msg( I18n.MSG_16024_REMOVED_FROM_DISABLED_SCHEMA, schemaObject.getName(), schemaName ) );
2264                 }
2265                 
2266                 return !errorHandler.wasError();
2267             }
2268         }
2269     }
2270 
2271 
2272     /**
2273      * {@inheritDoc}
2274      */
2275     @Override
2276     public Map<String, OidNormalizer> getNormalizerMapping()
2277     {
2278         return registries.getAttributeTypeRegistry().getNormalizerMapping();
2279     }
2280 
2281 
2282     /**
2283      * {@inheritDoc}
2284      */
2285     @SuppressWarnings("rawtypes")
2286     @Override
2287     public OidRegistry getGlobalOidRegistry()
2288     {
2289         return registries.getGlobalOidRegistry();
2290     }
2291 
2292 
2293     /**
2294      * {@inheritDoc}
2295      */
2296     @Override
2297     public Schema getLoadedSchema( String schemaName )
2298     {
2299         return schemaMap.get( schemaName );
2300     }
2301 
2302 
2303     /**
2304      * {@inheritDoc}
2305      */
2306     @Override
2307     public boolean isSchemaLoaded( String schemaName )
2308     {
2309         try
2310         {
2311             Schema schema = schemaMap.get( schemaName );
2312             
2313             return schema != null;
2314         }
2315         catch ( Exception e )
2316         {
2317             return false;
2318         }
2319     }
2320 
2321 
2322     /**
2323      * {@inheritDoc}
2324      */
2325     @Override
2326     public SchemaObject unregisterAttributeType( String attributeTypeOid ) throws LdapException
2327     {
2328         return registries.getAttributeTypeRegistry().unregister( attributeTypeOid );
2329     }
2330 
2331 
2332     /**
2333      * {@inheritDoc}
2334      */
2335     @Override
2336     public SchemaObject unregisterComparator( String comparatorOid ) throws LdapException
2337     {
2338         return registries.getComparatorRegistry().unregister( comparatorOid );
2339     }
2340 
2341 
2342     /**
2343      * {@inheritDoc}
2344      */
2345     @Override
2346     public SchemaObject unregisterDitControlRule( String ditControlRuleOid ) throws LdapException
2347     {
2348         return registries.getDitContentRuleRegistry().unregister( ditControlRuleOid );
2349     }
2350 
2351 
2352     /**
2353      * {@inheritDoc}
2354      */
2355     @Override
2356     public SchemaObject unregisterDitStructureRule( String ditStructureRuleOid ) throws LdapException
2357     {
2358         return registries.getDitStructureRuleRegistry().unregister( ditStructureRuleOid );
2359     }
2360 
2361 
2362     /**
2363      * {@inheritDoc}
2364      */
2365     @Override
2366     public SchemaObject unregisterLdapSyntax( String ldapSyntaxOid ) throws LdapException
2367     {
2368         return registries.getLdapSyntaxRegistry().unregister( ldapSyntaxOid );
2369     }
2370 
2371 
2372     /**
2373      * {@inheritDoc}
2374      */
2375     @Override
2376     public SchemaObject unregisterMatchingRule( String matchingRuleOid ) throws LdapException
2377     {
2378         return registries.getMatchingRuleRegistry().unregister( matchingRuleOid );
2379     }
2380 
2381 
2382     /**
2383      * {@inheritDoc}
2384      */
2385     @Override
2386     public SchemaObject unregisterMatchingRuleUse( String matchingRuleUseOid ) throws LdapException
2387     {
2388         return registries.getMatchingRuleUseRegistry().unregister( matchingRuleUseOid );
2389     }
2390 
2391 
2392     /**
2393      * {@inheritDoc}
2394      */
2395     @Override
2396     public SchemaObject unregisterNameForm( String nameFormOid ) throws LdapException
2397     {
2398         return registries.getNameFormRegistry().unregister( nameFormOid );
2399     }
2400 
2401 
2402     /**
2403      * {@inheritDoc}
2404      */
2405     @Override
2406     public SchemaObject unregisterNormalizer( String normalizerOid ) throws LdapException
2407     {
2408         return registries.getNormalizerRegistry().unregister( normalizerOid );
2409     }
2410 
2411 
2412     /**
2413      * {@inheritDoc}
2414      */
2415     @Override
2416     public SchemaObject unregisterObjectClass( String objectClassOid ) throws LdapException
2417     {
2418         return registries.getObjectClassRegistry().unregister( objectClassOid );
2419     }
2420 
2421 
2422     /**
2423      * {@inheritDoc}
2424      */
2425     @Override
2426     public SchemaObject unregisterSyntaxChecker( String syntaxCheckerOid ) throws LdapException
2427     {
2428         return registries.getSyntaxCheckerRegistry().unregister( syntaxCheckerOid );
2429     }
2430 
2431 
2432     /**
2433      * Tells if the SchemaManager is permissive or if it must be checked
2434      * against inconsistencies.
2435      *
2436      * @return True if SchemaObjects can be added even if they break the consistency
2437      */
2438     @Override
2439     public boolean isRelaxed()
2440     {
2441         return isRelaxed;
2442     }
2443 
2444     
2445     /**
2446      * Tells if the SchemaManager is strict.
2447      *
2448      * @return True if SchemaObjects cannot be added if they break the consistency
2449      */
2450     @Override
2451     public boolean isStrict()
2452     {
2453         return !isRelaxed;
2454     }
2455 
2456 
2457     /**
2458      * {@inheritDoc}
2459      */
2460     @Override
2461     public Set<String> listDependentSchemaNames( String schemaName )
2462     {
2463         return schemaDependencies.get( schemaName );
2464     }
2465 
2466 
2467     /**
2468      * Change the SchemaManager to a relaxed mode, where invalid SchemaObjects
2469      * can be registered.
2470      */
2471     @Override
2472     public void setRelaxed()
2473     {
2474         isRelaxed = RELAXED;
2475     }
2476 
2477 
2478     /**
2479      * Change the SchemaManager to a strict mode, where invalid SchemaObjects
2480      * cannot be registered.
2481      */
2482     @Override
2483     public void setStrict()
2484     {
2485         isRelaxed = STRICT;
2486     }
2487 
2488 
2489     public SchemaErrorHandler getErrorHandler()
2490     {
2491         return errorHandler;
2492     }
2493 
2494 
2495     public void setErrorHandler( SchemaErrorHandler errorHandler )
2496     {
2497         this.errorHandler = errorHandler;
2498         registries.setErrorHandler( errorHandler );
2499     }
2500 
2501 
2502     /**
2503      * {@inheritDoc}
2504      */
2505     @Override
2506     public boolean isDisabled( String schemaName )
2507     {
2508         Schema schema = registries.getLoadedSchema( schemaName );
2509 
2510         return ( schema != null ) && schema.isDisabled();
2511     }
2512 
2513 
2514     /**
2515      * {@inheritDoc}
2516      */
2517     @Override
2518     public boolean isDisabled( Schema schema )
2519     {
2520         return ( schema != null ) && schema.isDisabled();
2521     }
2522 
2523 
2524     /**
2525      * {@inheritDoc}
2526      */
2527     @Override
2528     public boolean isEnabled( String schemaName )
2529     {
2530         Schema schema = registries.getLoadedSchema( schemaName );
2531 
2532         return ( schema != null ) && schema.isEnabled();
2533     }
2534 
2535 
2536     /**
2537      * {@inheritDoc}
2538      */
2539     @Override
2540     public boolean isEnabled( Schema schema )
2541     {
2542         return ( schema != null ) && schema.isEnabled();
2543     }
2544 }