001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.api.ldap.schema.manager.impl;
021
022
023import java.io.IOException;
024import java.util.ArrayList;
025import java.util.Collection;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032import org.apache.directory.api.i18n.I18n;
033import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
034import org.apache.directory.api.ldap.model.entry.Entry;
035import org.apache.directory.api.ldap.model.exception.LdapException;
036import org.apache.directory.api.ldap.model.exception.LdapOtherException;
037import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
038import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
039import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
040import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
041import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
042import org.apache.directory.api.ldap.model.name.Dn;
043import org.apache.directory.api.ldap.model.schema.AttributeType;
044import org.apache.directory.api.ldap.model.schema.LdapComparator;
045import org.apache.directory.api.ldap.model.schema.LdapSyntax;
046import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
047import org.apache.directory.api.ldap.model.schema.LoggingSchemaErrorHandler;
048import org.apache.directory.api.ldap.model.schema.MatchingRule;
049import org.apache.directory.api.ldap.model.schema.Normalizer;
050import org.apache.directory.api.ldap.model.schema.ObjectClass;
051import org.apache.directory.api.ldap.model.schema.SchemaErrorHandler;
052import org.apache.directory.api.ldap.model.schema.SchemaManager;
053import org.apache.directory.api.ldap.model.schema.SchemaObject;
054import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
055import org.apache.directory.api.ldap.model.schema.SchemaUtils;
056import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
057import org.apache.directory.api.ldap.model.schema.normalizers.OidNormalizer;
058import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
059import org.apache.directory.api.ldap.model.schema.registries.ComparatorRegistry;
060import org.apache.directory.api.ldap.model.schema.registries.DitContentRuleRegistry;
061import org.apache.directory.api.ldap.model.schema.registries.DitStructureRuleRegistry;
062import org.apache.directory.api.ldap.model.schema.registries.ImmutableAttributeTypeRegistry;
063import org.apache.directory.api.ldap.model.schema.registries.ImmutableComparatorRegistry;
064import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitContentRuleRegistry;
065import org.apache.directory.api.ldap.model.schema.registries.ImmutableDitStructureRuleRegistry;
066import org.apache.directory.api.ldap.model.schema.registries.ImmutableLdapSyntaxRegistry;
067import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleRegistry;
068import org.apache.directory.api.ldap.model.schema.registries.ImmutableMatchingRuleUseRegistry;
069import org.apache.directory.api.ldap.model.schema.registries.ImmutableNameFormRegistry;
070import org.apache.directory.api.ldap.model.schema.registries.ImmutableNormalizerRegistry;
071import org.apache.directory.api.ldap.model.schema.registries.ImmutableObjectClassRegistry;
072import org.apache.directory.api.ldap.model.schema.registries.ImmutableSyntaxCheckerRegistry;
073import org.apache.directory.api.ldap.model.schema.registries.LdapSyntaxRegistry;
074import org.apache.directory.api.ldap.model.schema.registries.LowerCaseKeyMap;
075import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleRegistry;
076import org.apache.directory.api.ldap.model.schema.registries.MatchingRuleUseRegistry;
077import org.apache.directory.api.ldap.model.schema.registries.NameFormRegistry;
078import org.apache.directory.api.ldap.model.schema.registries.NormalizerRegistry;
079import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
080import org.apache.directory.api.ldap.model.schema.registries.OidRegistry;
081import org.apache.directory.api.ldap.model.schema.registries.Registries;
082import org.apache.directory.api.ldap.model.schema.registries.Schema;
083import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
084import org.apache.directory.api.ldap.model.schema.registries.SyntaxCheckerRegistry;
085import org.apache.directory.api.ldap.schema.loader.EntityFactory;
086import org.apache.directory.api.ldap.schema.loader.JarLdifSchemaLoader;
087import org.apache.directory.api.ldap.schema.loader.SchemaEntityFactory;
088import org.apache.directory.api.util.Strings;
089import org.slf4j.Logger;
090import org.slf4j.LoggerFactory;
091
092
093/**
094 * The SchemaManager class : it handles all the schema operations (addition, removal,
095 * modification).
096 *
097 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
098 */
099public 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    private 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    private 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}