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     */
020    package org.apache.directory.shared.ldap.schema.manager.impl;
021    
022    
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.HashSet;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import org.apache.directory.shared.i18n.I18n;
031    import org.apache.directory.shared.ldap.NotImplementedException;
032    import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
033    import org.apache.directory.shared.ldap.constants.SchemaConstants;
034    import org.apache.directory.shared.ldap.entry.Entry;
035    import org.apache.directory.shared.ldap.exception.LdapException;
036    import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
037    import org.apache.directory.shared.ldap.exception.LdapProtocolErrorException;
038    import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException;
039    //import org.apache.directory.shared.ldap.exception.LdapSchemaViolationException;
040    import org.apache.directory.shared.ldap.message.ResultCodeEnum;
041    import org.apache.directory.shared.ldap.name.DN;
042    import org.apache.directory.shared.ldap.schema.AttributeType;
043    import org.apache.directory.shared.ldap.schema.EntityFactory;
044    import org.apache.directory.shared.ldap.schema.LdapComparator;
045    import org.apache.directory.shared.ldap.schema.LdapSyntax;
046    import org.apache.directory.shared.ldap.schema.LoadableSchemaObject;
047    import org.apache.directory.shared.ldap.schema.MatchingRule;
048    import org.apache.directory.shared.ldap.schema.Normalizer;
049    import org.apache.directory.shared.ldap.schema.ObjectClass;
050    import org.apache.directory.shared.ldap.schema.SchemaManager;
051    import org.apache.directory.shared.ldap.schema.SchemaObject;
052    import org.apache.directory.shared.ldap.schema.SchemaObjectWrapper;
053    import org.apache.directory.shared.ldap.schema.SyntaxChecker;
054    import org.apache.directory.shared.ldap.schema.loader.ldif.SchemaEntityFactory;
055    import org.apache.directory.shared.ldap.schema.normalizers.OidNormalizer;
056    import org.apache.directory.shared.ldap.schema.registries.AttributeTypeRegistry;
057    import org.apache.directory.shared.ldap.schema.registries.ComparatorRegistry;
058    import org.apache.directory.shared.ldap.schema.registries.DITContentRuleRegistry;
059    import org.apache.directory.shared.ldap.schema.registries.DITStructureRuleRegistry;
060    import org.apache.directory.shared.ldap.schema.registries.ImmutableAttributeTypeRegistry;
061    import org.apache.directory.shared.ldap.schema.registries.ImmutableComparatorRegistry;
062    import org.apache.directory.shared.ldap.schema.registries.ImmutableDITContentRuleRegistry;
063    import org.apache.directory.shared.ldap.schema.registries.ImmutableDITStructureRuleRegistry;
064    import org.apache.directory.shared.ldap.schema.registries.ImmutableLdapSyntaxRegistry;
065    import org.apache.directory.shared.ldap.schema.registries.ImmutableMatchingRuleRegistry;
066    import org.apache.directory.shared.ldap.schema.registries.ImmutableMatchingRuleUseRegistry;
067    import org.apache.directory.shared.ldap.schema.registries.ImmutableNameFormRegistry;
068    import org.apache.directory.shared.ldap.schema.registries.ImmutableNormalizerRegistry;
069    import org.apache.directory.shared.ldap.schema.registries.ImmutableObjectClassRegistry;
070    import org.apache.directory.shared.ldap.schema.registries.ImmutableSyntaxCheckerRegistry;
071    import org.apache.directory.shared.ldap.schema.registries.LdapSyntaxRegistry;
072    import org.apache.directory.shared.ldap.schema.registries.MatchingRuleRegistry;
073    import org.apache.directory.shared.ldap.schema.registries.MatchingRuleUseRegistry;
074    import org.apache.directory.shared.ldap.schema.registries.NameFormRegistry;
075    import org.apache.directory.shared.ldap.schema.registries.NormalizerRegistry;
076    import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry;
077    import org.apache.directory.shared.ldap.schema.registries.OidRegistry;
078    import org.apache.directory.shared.ldap.schema.registries.Registries;
079    import org.apache.directory.shared.ldap.schema.registries.Schema;
080    import org.apache.directory.shared.ldap.schema.registries.SchemaLoader;
081    import org.apache.directory.shared.ldap.schema.registries.SyntaxCheckerRegistry;
082    import org.apache.directory.shared.ldap.util.StringTools;
083    import org.slf4j.Logger;
084    import org.slf4j.LoggerFactory;
085    
086    
087    /**
088     * The SchemaManager class : it handles all the schema operations (addition, removal,
089     * modification).
090     *
091     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
092     * @version $Rev$, $Date$
093     */
094    public class DefaultSchemaManager implements SchemaManager
095    {
096        /** static class logger */
097        private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaManager.class );
098    
099        /** The NamingContext this SchemaManager is associated with */
100        private DN namingContext;
101    
102        /** The global registries for this namingContext */
103        private volatile Registries registries;
104    
105        /** The list of errors produced when loading some schema elements */
106        private List<Throwable> errors;
107    
108        /** The Schema schemaLoader used by this SchemaManager */
109        private SchemaLoader schemaLoader;
110    
111        /** the factory that generates respective SchemaObjects from LDIF entries */
112        protected final EntityFactory factory;
113    
114        /** the normalized name for the schema modification attributes */
115        private DN schemaModificationAttributesDN;
116        
117        /** A Map containing all the schema being dependent from a schema */
118        private Map<String, Set<String>> schemaDependences = new HashMap<String, Set<String>>();
119    
120        /** A flag indicating that the SchemaManager is relaxed or not */
121        private boolean isRelaxed = STRICT;
122    
123        /** Two flags for RELAXED and STRUCT */
124        public static final boolean STRICT = false;
125        public static final boolean RELAXED = true;
126    
127    
128        /**
129         * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader
130         *
131         * @param loader The schema loader to use
132         */
133        public DefaultSchemaManager( SchemaLoader loader ) throws Exception
134        {
135            // Default to the the root (one schemaManager for all the entries
136            namingContext = DN.EMPTY_DN;
137            this.schemaLoader = loader;
138            errors = new ArrayList<Throwable>();
139            registries = new Registries( this );
140            factory = new SchemaEntityFactory();
141            isRelaxed = STRICT;
142        }
143    
144    
145        /**
146         * Creates a new instance of DefaultSchemaManager, for a specific
147         * naming context
148         *
149         * @param loader The schema loader to use
150         * @param namingContext The associated NamingContext
151         */
152        public DefaultSchemaManager( SchemaLoader loader, DN namingContext ) throws Exception
153        {
154            this.namingContext = namingContext;
155            this.schemaLoader = loader;
156            errors = new ArrayList<Throwable>();
157            registries = new Registries( this );
158            factory = new SchemaEntityFactory();
159            isRelaxed = STRICT;
160        }
161    
162    
163        //-----------------------------------------------------------------------
164        // Helper methods
165        //-----------------------------------------------------------------------
166        /**
167         * Clone the registries before doing any modification on it. Relax it
168         * too so that we can update it. 
169         */
170        private Registries cloneRegistries() throws Exception
171        {
172            // Relax the controls at first
173            errors = new ArrayList<Throwable>();
174    
175            // Clone the Registries
176            Registries clonedRegistries = registries.clone();
177    
178            // And update references. We may have errors, that may be fixed
179            // by the new loaded schemas.
180            errors = clonedRegistries.checkRefInteg();
181    
182            // Now, relax the cloned Registries if there is no error
183            clonedRegistries.setRelaxed();
184    
185            return clonedRegistries;
186        }
187    
188    
189        /**
190         * Transform a String[] array of schema to a Schema[]
191         */
192        private Schema[] toArray( String... schemas ) throws Exception
193        {
194            Schema[] schemaArray = new Schema[schemas.length];
195            int n = 0;
196    
197            for ( String schemaName : schemas )
198            {
199                Schema schema = schemaLoader.getSchema( schemaName );
200                
201                if ( schema != null )
202                {
203                    schemaArray[n++] = schema;
204                }
205                else
206                {
207                    throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_11001, schemaName ) );
208                }
209            }
210    
211            return schemaArray;
212        }
213    
214    
215        private void addSchemaObjects( Schema schema, Registries registries ) throws Exception
216        {
217            // Create a content container for this schema
218            registries.addSchema( schema.getSchemaName() );
219            
220            // And inject any existig SchemaObject into the registries 
221            addComparators( schema, registries );
222            addNormalizers( schema, registries );
223            addSyntaxCheckers( schema, registries );
224            addSyntaxes( schema, registries );
225            addMatchingRules( schema, registries );
226            addAttributeTypes( schema, registries );
227            addObjectClasses( schema, registries );
228            addMatchingRuleUses( schema, registries );
229            addDitContentRules( schema, registries );
230            addNameForms( schema, registries );
231            addDitStructureRules( schema, registries );
232    
233            // TODO Add some listener handling at this point
234            //notifyListenerOrRegistries( schema, registries );
235        }
236    
237    
238        /**
239         * Delete all the schemaObjects for a given schema from the registries
240         */
241        private void deleteSchemaObjects( Schema schema, Registries registries ) throws Exception
242        {
243            Map<String, Set<SchemaObjectWrapper>> schemaObjects = registries.getObjectBySchemaName();
244            Set<SchemaObjectWrapper> content = schemaObjects.get( StringTools.toLowerCase( schema.getSchemaName() ) );
245    
246            List<SchemaObject> toBeDeleted = new ArrayList<SchemaObject>();
247    
248            // Buid an intermediate list to avoid concurrent modifications
249            for ( SchemaObjectWrapper schemaObjectWrapper : content )
250            {
251                toBeDeleted.add( schemaObjectWrapper.get() );
252            }
253    
254            for ( SchemaObject schemaObject : toBeDeleted )
255            {
256                registries.delete( errors, schemaObject );
257            }
258        }
259    
260        
261        /**
262         * Tells if there are schemaObjects for a given schema from the registries
263         */
264        private boolean hasSchemaObjects( Schema schema, Registries registries ) throws Exception
265        {
266            Map<String, Set<SchemaObjectWrapper>> schemaObjects = registries.getObjectBySchemaName();
267            Set<SchemaObjectWrapper> content = schemaObjects.get( StringTools.toLowerCase( schema.getSchemaName() ) );
268    
269            if ( ( content == null ) || content.isEmpty() )
270            {
271                return false;
272            }
273            else
274            {
275                return true;
276            }
277        }
278    
279    
280        //-----------------------------------------------------------------------
281        // API methods
282        //-----------------------------------------------------------------------
283        /**
284         * {@inheritDoc}
285         */
286        public boolean disable( Schema... schemas ) throws Exception
287        {
288            boolean disabled = false;
289    
290            // Reset the errors if not null
291            if ( errors != null )
292            {
293                errors.clear();
294            }
295    
296            // Work on a cloned and relaxed registries
297            Registries clonedRegistries = cloneRegistries();
298            clonedRegistries.setRelaxed();
299    
300            for ( Schema schema : schemas )
301            {
302                unload( clonedRegistries, schema );
303            }
304    
305            // Build the cross references
306            errors = clonedRegistries.buildReferences();
307    
308            // Destroy the clonedRegistry
309            clonedRegistries.clear();
310    
311            if ( errors.isEmpty() )
312            {
313                // Ok no errors. Check the registries now
314                errors = clonedRegistries.checkRefInteg();
315    
316                if ( errors.isEmpty() )
317                {
318                    // We are golden : let's apply the schemas in the real registries
319                    for ( Schema schema : schemas )
320                    {
321                        unload( registries, schema );
322                        schema.disable();
323                    }
324    
325                    // Build the cross references
326                    errors = registries.buildReferences();
327                    registries.setStrict();
328    
329                    disabled = true;
330                }
331            }
332    
333            // clear the cloned registries
334            clonedRegistries.clear();
335    
336            return disabled;
337        }
338    
339    
340        /**
341         * {@inheritDoc}
342         */
343        public boolean disable( String... schemaNames ) throws Exception
344        {
345            Schema[] schemas = toArray( schemaNames );
346    
347            return disable( schemas );
348        }
349    
350    
351        /**
352         * {@inheritDoc}
353         */
354        public boolean disabledRelaxed( Schema... schemas )
355        {
356            // TODO Auto-generated method stub
357            return false;
358        }
359    
360    
361        /**
362         * {@inheritDoc}
363         */
364        public boolean disabledRelaxed( String... schemas )
365        {
366            // TODO Auto-generated method stub
367            return false;
368        }
369    
370    
371        /**
372         * {@inheritDoc}
373         */
374        public List<Schema> getDisabled()
375        {
376            List<Schema> disabled = new ArrayList<Schema>();
377    
378            for ( Schema schema : registries.getLoadedSchemas().values() )
379            {
380                if ( schema.isDisabled() )
381                {
382                    disabled.add( schema );
383                }
384            }
385    
386            return disabled;
387        }
388    
389    
390        /**
391         * {@inheritDoc}
392         */
393        public boolean enable( Schema... schemas ) throws Exception
394        {
395            boolean enabled = false;
396    
397            // Reset the errors if not null
398            if ( errors != null )
399            {
400                errors.clear();
401            }
402    
403            // Work on a cloned and relaxed registries
404            Registries clonedRegistries = cloneRegistries();
405            clonedRegistries.setRelaxed();
406    
407            for ( Schema schema : schemas )
408            {
409                schema.enable();
410                load( clonedRegistries, schema );
411            }
412    
413            // Build the cross references
414            errors = clonedRegistries.buildReferences();
415    
416            // Destroy the clonedRegistry
417            clonedRegistries.clear();
418    
419            if ( errors.isEmpty() )
420            {
421                // Ok no errors. Check the registries now
422                errors = clonedRegistries.checkRefInteg();
423    
424                if ( errors.isEmpty() )
425                {
426                    // We are golden : let's apply the schemas in the real registries
427                    for ( Schema schema : schemas )
428                    {
429                        schema.enable();
430                        load( registries, schema );
431                    }
432    
433                    // Build the cross references
434                    errors = registries.buildReferences();
435                    registries.setStrict();
436    
437                    enabled = true;
438                }
439            }
440    
441            // clear the cloned registries
442            clonedRegistries.clear();
443    
444            return enabled;
445        }
446    
447    
448        /**
449         * {@inheritDoc}
450         */
451        public boolean enable( String... schemaNames ) throws Exception
452        {
453            Schema[] schemas = toArray( schemaNames );
454            return enable( schemas );
455        }
456    
457    
458        /**
459         * {@inheritDoc}
460         */
461        public boolean enableRelaxed( Schema... schemas )
462        {
463            // TODO Auto-generated method stub
464            return false;
465        }
466    
467    
468        /**
469         * {@inheritDoc}
470         */
471        public boolean enableRelaxed( String... schemas )
472        {
473            // TODO Auto-generated method stub
474            return false;
475        }
476    
477    
478        /**
479         * {@inheritDoc}
480         */
481        public List<Schema> getEnabled()
482        {
483            List<Schema> enabled = new ArrayList<Schema>();
484    
485            for ( Schema schema : registries.getLoadedSchemas().values() )
486            {
487                if ( schema.isEnabled() )
488                {
489                    enabled.add( schema );
490                }
491            }
492    
493            return enabled;
494        }
495    
496    
497        /**
498         * {@inheritDoc}
499         */
500        public List<Throwable> getErrors()
501        {
502            return errors;
503        }
504    
505    
506        /**
507         * {@inheritDoc}
508         */
509        public Registries getRegistries()
510        {
511            return registries;
512        }
513    
514    
515        /**
516         * {@inheritDoc}
517         */
518        public boolean isDisabledAccepted()
519        {
520            // TODO Auto-generated method stub
521            return false;
522        }
523    
524    
525        /**
526         * {@inheritDoc}
527         */
528        public boolean load( Schema... schemas ) throws Exception
529        {
530            if ( schemas.length == 0 )
531            {
532                return true;
533            }
534            
535            boolean loaded = false;
536    
537            // Reset the errors if not null
538            if ( errors != null )
539            {
540                errors.clear();
541            }
542    
543            // Work on a cloned and relaxed registries
544            Registries clonedRegistries = cloneRegistries();
545            clonedRegistries.setRelaxed();
546    
547            // Load the schemas
548            for ( Schema schema : schemas )
549            {
550                if ( !load( clonedRegistries, schema ) && ( ! errors.isEmpty() ) )
551                {
552                    return false;
553                }
554            }
555    
556            // Build the cross references
557            errors = clonedRegistries.buildReferences();
558    
559            if ( errors.isEmpty() )
560            {
561                // Ok no errors. Check the registries now
562                errors = clonedRegistries.checkRefInteg();
563    
564                if ( errors.isEmpty() )
565                {
566                    // We are golden : let's apply the schema in the real registries
567                    registries.setRelaxed();
568    
569                    // Load the schemas
570                    for ( Schema schema : schemas )
571                    {
572                        load( registries, schema );
573                        
574                        // Update the schema dependences if needed
575                        
576                        if ( schema.getDependencies() != null )
577                        {
578                            for ( String dep : schema.getDependencies() )
579                            {
580                                Set<String> deps = schemaDependences.get( dep );
581                                
582                                if ( deps == null )
583                                {
584                                    deps = new HashSet<String>();
585                                    deps.add( schema.getSchemaName() );
586                                }
587                                
588                                // Replace the dependences
589                                schemaDependences.put( dep, deps );
590                            }
591                        }
592                        
593                        // add the schema to the schemaLoader
594                        schemaLoader.addSchema( schema );
595                    }
596    
597                    // Build the cross references
598                    errors = registries.buildReferences();
599                    registries.setStrict();
600    
601                    loaded = true;
602                }
603            }
604    
605            // clear the cloned registries
606            clonedRegistries.clear();
607    
608            return loaded;
609        }
610    
611    
612        /**
613         * {@inheritDoc}
614         */
615        public boolean load( String... schemaNames ) throws Exception
616        {
617            if ( schemaNames.length == 0 )
618            {
619                return true;
620            }
621            
622            Schema[] schemas = toArray( schemaNames );
623    
624            return load( schemas );
625        }
626    
627    
628        /**
629         * Load the schema in the registries. We will load everything accordingly to the two flags :
630         * - isRelaxed
631         * - disabledAccepted
632         */
633        private boolean load( Registries registries, Schema schema ) throws Exception
634        {
635            if ( schema == null )
636            {
637                LOG.info( "The schema is null" );
638                return false;
639            }
640    
641            // First avoid loading twice the same schema
642            if ( registries.isSchemaLoaded( schema.getSchemaName() ) )
643            {
644                return true;
645            }
646    
647            if ( schema.isDisabled() )
648            {
649                if ( registries.isDisabledAccepted() )
650                {
651                    LOG.info( "Loading {} disbaled schema: \n{}", schema.getSchemaName(), schema );
652    
653                    registries.schemaLoaded( schema );
654                    addSchemaObjects( schema, registries );
655                }
656                else
657                {
658                    return false;
659                }
660            }
661            else
662            {
663                LOG.info( "Loading {} enabled schema: \n{}", schema.getSchemaName(), schema );
664                
665                // Check that the dependencies, if any, are correct
666                if ( schema.getDependencies() != null )
667                {
668                    for ( String dependency : schema.getDependencies() )
669                    {
670                        if ( schemaLoader.getSchema( dependency ) == null )
671                        {
672                            // The dependency has not been loaded.
673                            String msg = I18n.err( I18n.ERR_11002, schema.getSchemaName() );
674                            LOG.info( msg );
675                            Throwable error = new LdapProtocolErrorException( msg );
676                            errors.add( error );
677                            return false;
678                        }
679                    }
680                }
681    
682                registries.schemaLoaded( schema );
683                addSchemaObjects( schema, registries );
684            }
685    
686            return true;
687        }
688    
689    
690        /**
691         * Unload the schema from the registries. We will unload everything accordingly to the two flags :
692         * - isRelaxed
693         * - disabledAccepted
694         */
695        private boolean unload( Registries registries, Schema schema ) throws Exception
696        {
697            if ( schema == null )
698            {
699                LOG.info( "The schema is null" );
700                return false;
701            }
702    
703            // First avoid unloading twice the same schema
704            if ( !registries.isSchemaLoaded( schema.getSchemaName() ) )
705            {
706                return true;
707            }
708    
709            if ( schema.isEnabled() )
710            {
711                LOG.info( "Unloading {} schema: \n{}", schema.getSchemaName(), schema );
712    
713                deleteSchemaObjects( schema, registries );
714                registries.schemaUnloaded( schema );
715            }
716    
717            return true;
718        }
719    
720    
721        /**
722         * Add all the Schema's AttributeTypes
723         */
724        private void addAttributeTypes( Schema schema, Registries registries ) throws Exception
725        {
726            for ( Entry entry : schemaLoader.loadAttributeTypes( schema ) )
727            {
728                AttributeType attributeType = factory.getAttributeType( this, entry, registries, schema.getSchemaName() );
729    
730                addSchemaObject( registries, attributeType, schema );
731            }
732        }
733    
734    
735        /**
736         * Add all the Schema's comparators
737         */
738        private void addComparators( Schema schema, Registries registries ) throws Exception
739        {
740            for ( Entry entry : schemaLoader.loadComparators( schema ) )
741            {
742                LdapComparator<?> comparator = factory.getLdapComparator( this, entry, registries, schema.getSchemaName() );
743    
744                addSchemaObject( registries, comparator, schema );
745            }
746        }
747    
748    
749        /**
750         * Add all the Schema's DitContentRules
751         */
752        private void addDitContentRules( Schema schema, Registries registries ) throws Exception
753        {
754            for ( Entry entry : schemaLoader.loadDitContentRules( schema ) )
755            {
756                throw new NotImplementedException( I18n.err( I18n.ERR_11003 ) );
757            }
758        }
759    
760    
761        /**
762         * Add all the Schema's DitStructureRules
763         */
764        private void addDitStructureRules( Schema schema, Registries registries ) throws Exception
765        {
766            for ( Entry entry : schemaLoader.loadDitStructureRules( schema ) )
767            {
768                throw new NotImplementedException( I18n.err( I18n.ERR_11004 ) );
769            }
770        }
771    
772    
773        /**
774         * Add all the Schema's MatchingRules
775         */
776        private void addMatchingRules( Schema schema, Registries registries ) throws Exception
777        {
778            for ( Entry entry : schemaLoader.loadMatchingRules( schema ) )
779            {
780                MatchingRule matchingRule = factory.getMatchingRule( this, entry, registries, schema.getSchemaName() );
781    
782                addSchemaObject( registries, matchingRule, schema );
783            }
784        }
785    
786    
787        /**
788         * Add all the Schema's MatchingRuleUses
789         */
790        private void addMatchingRuleUses( Schema schema, Registries registries ) throws Exception
791        {
792            for ( Entry entry : schemaLoader.loadMatchingRuleUses( schema ) )
793            {
794                throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) );
795            }
796        }
797    
798    
799        /**
800         * Add all the Schema's NameForms
801         */
802        private void addNameForms( Schema schema, Registries registries ) throws Exception
803        {
804            for ( Entry entry : schemaLoader.loadNameForms( schema ) )
805            {
806                throw new NotImplementedException( I18n.err( I18n.ERR_11006 ) );
807            }
808        }
809    
810    
811        /**
812         * Add all the Schema's Normalizers
813         */
814        private void addNormalizers( Schema schema, Registries registries ) throws Exception
815        {
816            for ( Entry entry : schemaLoader.loadNormalizers( schema ) )
817            {
818                Normalizer normalizer = factory.getNormalizer( this, entry, registries, schema.getSchemaName() );
819    
820                addSchemaObject( registries, normalizer, schema );
821            }
822        }
823    
824    
825        /**
826         * Add all the Schema's ObjectClasses
827         */
828        private void addObjectClasses( Schema schema, Registries registries ) throws Exception
829        {
830            for ( Entry entry : schemaLoader.loadObjectClasses( schema ) )
831            {
832                ObjectClass objectClass = factory.getObjectClass( this, entry, registries, schema.getSchemaName() );
833    
834                addSchemaObject( registries, objectClass, schema );
835            }
836        }
837    
838    
839        /**
840         * Add all the Schema's Syntaxes
841         */
842        private void addSyntaxes( Schema schema, Registries registries ) throws Exception
843        {
844            for ( Entry entry : schemaLoader.loadSyntaxes( schema ) )
845            {
846                LdapSyntax syntax = factory.getSyntax( this, entry, registries, schema.getSchemaName() );
847    
848                addSchemaObject( registries, syntax, schema );
849            }
850        }
851    
852    
853        /**Add
854         * Register all the Schema's SyntaxCheckers
855         */
856        private void addSyntaxCheckers( Schema schema, Registries registries ) throws Exception
857        {
858            for ( Entry entry : schemaLoader.loadSyntaxCheckers( schema ) )
859            {
860                SyntaxChecker syntaxChecker = factory.getSyntaxChecker( this, entry, registries, schema.getSchemaName() );
861    
862                addSchemaObject( registries, syntaxChecker, schema );
863            }
864        }
865    
866    
867        /**
868         * Add the schemaObject into the registries. 
869         *
870         * @param registries The Registries
871         * @param schemaObject The SchemaObject containing the SchemaObject description
872         * @param schema The associated schema
873         * @return the created schemaObject instance
874         * @throws Exception If the registering failed
875         */
876        private SchemaObject addSchemaObject( Registries registries, SchemaObject schemaObject, Schema schema )
877            throws Exception
878        {
879            if ( registries.isRelaxed() )
880            {
881                if ( registries.isDisabledAccepted() || ( schema.isEnabled() && schemaObject.isEnabled() ) )
882                {
883                    registries.add( errors, schemaObject );
884                }
885                else
886                {
887                    errors.add( new Throwable() );
888                }
889            }
890            else
891            {
892                if ( schema.isEnabled() && schemaObject.isEnabled() )
893                {
894                    registries.add( errors, schemaObject );
895                }
896                else
897                {
898                    errors.add( new Throwable() );
899                }
900            }
901    
902            return schemaObject;
903        }
904    
905    
906        /**
907         * {@inheritDoc}
908         */
909        public boolean loadAllEnabled() throws Exception
910        {
911            Schema[] schemas = schemaLoader.getAllEnabled().toArray( new Schema[0] );
912    
913            return loadWithDeps( schemas );
914        }
915    
916    
917        /**
918         * {@inheritDoc}
919         */
920        public boolean loadAllEnabledRelaxed() throws Exception
921        {
922            // TODO Auto-generated method stub
923            return false;
924        }
925    
926    
927        /**
928         * {@inheritDoc}
929         */
930        public boolean loadDisabled( Schema... schemas ) throws Exception
931        {
932            // Work on a cloned and relaxed registries
933            Registries clonedRegistries = cloneRegistries();
934    
935            // Accept the disabled schemas
936            clonedRegistries.setDisabledAccepted( true );
937    
938            // Load the schemas
939            for ( Schema schema : schemas )
940            {
941                // Enable the Schema object before loading it
942                schema.enable();
943                load( clonedRegistries, schema );
944            }
945    
946            clonedRegistries.clear();
947    
948            // Apply the change to the correct registries if no errors
949            if ( errors.size() == 0 )
950            {
951                // No error, we can enable the schema in the real registries
952                for ( Schema schema : schemas )
953                {
954                    load( registries, schema );
955                }
956                
957                return true;
958            }
959            else
960            {
961                for ( Schema schema : schemas )
962                {
963                    schema.disable();
964                }
965                
966                return false;
967            }
968        }
969    
970    
971        /**
972         * {@inheritDoc}
973         */
974        public boolean loadDisabled( String... schemaNames ) throws Exception
975        {
976            Schema[] schemas = toArray( schemaNames );
977    
978            return loadDisabled( schemas );
979        }
980    
981    
982        /**
983         * {@inheritDoc}
984         */
985        public boolean loadRelaxed( Schema... schemas ) throws Exception
986        {
987            // TODO Auto-generated method stub
988            return false;
989        }
990    
991    
992        /**
993         * {@inheritDoc}
994         */
995        public boolean loadRelaxed( String... schemaNames ) throws Exception
996        {
997            Schema[] schemas = toArray( schemaNames );
998            return false;
999        }
1000    
1001    
1002        /**
1003         * {@inheritDoc}
1004         */
1005        public boolean loadWithDeps( Schema... schemas ) throws Exception
1006        {
1007            boolean loaded = false;
1008    
1009            // Reset the errors if not null
1010            if ( errors != null )
1011            {
1012                errors.clear();
1013            }
1014    
1015            // Work on a cloned and relaxed registries
1016            Registries clonedRegistries = cloneRegistries();
1017            clonedRegistries.setRelaxed();
1018    
1019            // Load the schemas
1020            for ( Schema schema : schemas )
1021            {
1022                loadDepsFirst( clonedRegistries, schema );
1023            }
1024    
1025            // Build the cross references
1026            errors = clonedRegistries.buildReferences();
1027    
1028            if ( errors.isEmpty() )
1029            {
1030                // Ok no errors. Check the registries now
1031                errors = clonedRegistries.checkRefInteg();
1032    
1033                if ( errors.isEmpty() )
1034                {
1035                    // We are golden : let's apply the schema in the real registries
1036                    registries.setRelaxed();
1037    
1038                    // Load the schemas
1039                    for ( Schema schema : schemas )
1040                    {
1041                        loadDepsFirst( registries, schema );
1042                    }
1043    
1044                    // Build the cross references
1045                    errors = registries.buildReferences();
1046                    registries.setStrict();
1047    
1048                    loaded = true;
1049                }
1050            }
1051    
1052            // clear the cloned registries
1053            clonedRegistries.clear();
1054    
1055            return loaded;
1056        }
1057    
1058    
1059        /**
1060         * {@inheritDoc}
1061         */
1062        public boolean loadWithDeps( String... schemas ) throws Exception
1063        {
1064            return loadWithDeps( toArray( schemas ) );
1065        }
1066    
1067    
1068        /**
1069         * Recursive method which loads schema's with their dependent schemas first
1070         * and tracks what schemas it has seen so the recursion does not go out of
1071         * control with dependency cycle detection.
1072         *
1073         * @param registries The Registries in which the schemas will be loaded
1074         * @param schema the current schema we are attempting to load
1075         * @throws Exception if there is a cycle detected and/or another
1076         * failure results while loading, producing and or registering schema objects
1077         */
1078        private final void loadDepsFirst( Registries registries, Schema schema ) throws Exception
1079        {
1080            if ( schema == null )
1081            {
1082                LOG.info( "The schema is null" );
1083                return;
1084            }
1085    
1086            if ( schema.isDisabled() && !registries.isDisabledAccepted() )
1087            {
1088                LOG.info( "The schema is disabled and the registries does not accepted disabled schema" );
1089                return;
1090            }
1091    
1092            String schemaName = schema.getSchemaName();
1093    
1094            if ( registries.isSchemaLoaded( schemaName ) )
1095            {
1096                LOG.info( "{} schema has already been loaded" + schema.getSchemaName() );
1097                return;
1098            }
1099    
1100            String[] deps = schema.getDependencies();
1101    
1102            // if no deps then load this guy and return
1103            if ( ( deps == null ) || ( deps.length == 0 ) )
1104            {
1105                load( registries, schema );
1106    
1107                return;
1108            }
1109    
1110            /*
1111             * We got deps and need to load them before this schema.  We go through
1112             * all deps loading them with their deps first if they have not been
1113             * loaded.
1114             */
1115            for ( String depName : deps )
1116            {
1117                if ( registries.isSchemaLoaded( schemaName ) )
1118                {
1119                    // The schema is already loaded. Loop on the next schema
1120                    continue;
1121                }
1122                else
1123                {
1124                    // Call recursively this method
1125                    Schema schemaDep = schemaLoader.getSchema( depName );
1126                    loadDepsFirst( registries, schemaDep );
1127                }
1128            }
1129    
1130            // Now load the current schema
1131            load( registries, schema );
1132        }
1133    
1134    
1135        /**
1136         * {@inheritDoc}
1137         */
1138        public boolean loadWithDepsRelaxed( Schema... schemas ) throws Exception
1139        {
1140            // TODO Auto-generated method stub
1141            return false;
1142        }
1143    
1144    
1145        /**
1146         * {@inheritDoc}
1147         */
1148        public boolean loadWithDepsRelaxed( String... schemas ) throws Exception
1149        {
1150            // TODO Auto-generated method stub
1151            return false;
1152        }
1153    
1154    
1155        /**
1156         * {@inheritDoc}
1157         */
1158        public void setRegistries( Registries registries )
1159        {
1160            // TODO Auto-generated method stub
1161    
1162        }
1163    
1164    
1165        /**
1166         * {@inheritDoc}
1167         */
1168        public boolean unload( Schema... schemas ) throws Exception
1169        {
1170            boolean unloaded = false;
1171    
1172            // Reset the errors if not null
1173            if ( errors != null )
1174            {
1175                errors.clear();
1176            }
1177            
1178            // Work on a cloned and relaxed registries
1179            Registries clonedRegistries = cloneRegistries();
1180            clonedRegistries.setRelaxed();
1181    
1182            // Load the schemas
1183            for ( Schema schema : schemas )
1184            {
1185                unload( clonedRegistries, schema );
1186            }
1187    
1188            // Build the cross references
1189            errors = clonedRegistries.buildReferences();
1190    
1191            if ( errors.isEmpty() )
1192            {
1193                // Ok no errors. Check the registries now
1194                errors = clonedRegistries.checkRefInteg();
1195    
1196                if ( errors.isEmpty() )
1197                {
1198                    // We are golden : let's apply the schema in the real registries
1199                    registries.setRelaxed();
1200    
1201                    // Load the schemas
1202                    for ( Schema schema : schemas )
1203                    {
1204                        unload( registries, schema );
1205                        
1206                        // Update the schema dependences
1207                        for ( String dep : schema.getDependencies() )
1208                        {
1209                            Set<String> deps = schemaDependences.get( dep );
1210                            
1211                            if ( deps != null )
1212                            {
1213                                deps.remove( schema.getSchemaName() );
1214                            }
1215                        }
1216                        
1217                        schemaLoader.removeSchema( schema );
1218                    }
1219    
1220                    // Build the cross references
1221                    errors = registries.buildReferences();
1222                    registries.setStrict();
1223    
1224                    unloaded = true;
1225                }
1226            }
1227    
1228            // clear the cloned registries
1229            clonedRegistries.clear();
1230    
1231            return unloaded;
1232        }
1233    
1234    
1235        /**
1236         * {@inheritDoc}
1237         */
1238        public boolean unload( String... schemaNames ) throws Exception
1239        {
1240            Schema[] schemas = toArray( schemaNames );
1241    
1242            return unload( schemas );
1243        }
1244    
1245    
1246        /**
1247         * {@inheritDoc}
1248         */
1249        public boolean verify( Schema... schemas ) throws Exception
1250        {
1251            // Work on a cloned registries
1252            Registries clonedRegistries = cloneRegistries();
1253    
1254            // Loop on all the schemas 
1255            for ( Schema schema : schemas )
1256            {
1257                try
1258                {
1259                    // Inject the schema
1260                    boolean loaded = load( clonedRegistries, schema );
1261    
1262                    if ( !loaded )
1263                    {
1264                        // We got an error : exit
1265                        clonedRegistries.clear();
1266                        return false;
1267                    }
1268    
1269                    // Now, check the registries
1270                    List<Throwable> errors = clonedRegistries.checkRefInteg();
1271    
1272                    if ( errors.size() != 0 )
1273                    {
1274                        // We got an error : exit
1275                        clonedRegistries.clear();
1276                        return false;
1277                    }
1278                }
1279                catch ( Exception e )
1280                {
1281                    // We got an error : exit
1282                    clonedRegistries.clear();
1283                    return false;
1284                }
1285            }
1286    
1287            // We can now delete the cloned registries before exiting
1288            clonedRegistries.clear();
1289    
1290            return true;
1291        }
1292    
1293    
1294        /**
1295         * {@inheritDoc}
1296         */
1297        public boolean verify( String... schemas ) throws Exception
1298        {
1299            return verify( toArray( schemas ) );
1300        }
1301    
1302    
1303        /**
1304         * {@inheritDoc}
1305         */
1306        public void setSchemaLoader( SchemaLoader schemaLoader )
1307        {
1308            this.schemaLoader = schemaLoader;
1309        }
1310    
1311    
1312        /**
1313         * @return the namingContext
1314         */
1315        public DN getNamingContext()
1316        {
1317            return namingContext;
1318        }
1319    
1320    
1321        /**
1322         * Initializes the SchemaService
1323         *
1324         * @throws Exception If the initialization fails
1325         */
1326        public void initialize() throws Exception
1327        {
1328            try
1329            {
1330                schemaModificationAttributesDN = new DN( SchemaConstants.SCHEMA_MODIFICATIONS_DN );
1331                schemaModificationAttributesDN
1332                    .normalize( getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
1333            }
1334            catch ( LdapInvalidDnException e )
1335            {
1336                throw new RuntimeException( e );
1337            }
1338        }
1339    
1340    
1341        /**
1342         * {@inheritDoc}
1343         */
1344        public SchemaLoader getLoader()
1345        {
1346            return schemaLoader;
1347        }
1348    
1349    
1350        //-----------------------------------------------------------------------------------
1351        // Immutable accessors
1352        //-----------------------------------------------------------------------------------
1353        /**
1354         * {@inheritDoc}
1355         */
1356        public AttributeTypeRegistry getAttributeTypeRegistry()
1357        {
1358            return new ImmutableAttributeTypeRegistry( registries.getAttributeTypeRegistry() );
1359        }
1360    
1361    
1362        /**
1363         * {@inheritDoc}
1364         */
1365        public ComparatorRegistry getComparatorRegistry()
1366        {
1367            return new ImmutableComparatorRegistry( registries.getComparatorRegistry() );
1368        }
1369    
1370    
1371        /**
1372         * {@inheritDoc}
1373         */
1374        public DITContentRuleRegistry getDITContentRuleRegistry()
1375        {
1376            return new ImmutableDITContentRuleRegistry( registries.getDitContentRuleRegistry() );
1377        }
1378    
1379    
1380        /**
1381         * {@inheritDoc}
1382         */
1383        public DITStructureRuleRegistry getDITStructureRuleRegistry()
1384        {
1385            return new ImmutableDITStructureRuleRegistry( registries.getDitStructureRuleRegistry() );
1386        }
1387    
1388    
1389        /**
1390         * {@inheritDoc}
1391         */
1392        public MatchingRuleRegistry getMatchingRuleRegistry()
1393        {
1394            return new ImmutableMatchingRuleRegistry( registries.getMatchingRuleRegistry() );
1395        }
1396    
1397    
1398        /**
1399         * {@inheritDoc}
1400         */
1401        public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
1402        {
1403            return new ImmutableMatchingRuleUseRegistry( registries.getMatchingRuleUseRegistry() );
1404        }
1405    
1406    
1407        /**
1408         * {@inheritDoc}
1409         */
1410        public NameFormRegistry getNameFormRegistry()
1411        {
1412            return new ImmutableNameFormRegistry( registries.getNameFormRegistry() );
1413        }
1414    
1415    
1416        /**
1417         * {@inheritDoc}
1418         */
1419        public NormalizerRegistry getNormalizerRegistry()
1420        {
1421            return new ImmutableNormalizerRegistry( registries.getNormalizerRegistry() );
1422        }
1423    
1424    
1425        /**
1426         * {@inheritDoc}
1427         */
1428        public ObjectClassRegistry getObjectClassRegistry()
1429        {
1430            return new ImmutableObjectClassRegistry( registries.getObjectClassRegistry() );
1431        }
1432    
1433    
1434        /**
1435         * {@inheritDoc}
1436         */
1437        public LdapSyntaxRegistry getLdapSyntaxRegistry()
1438        {
1439            return new ImmutableLdapSyntaxRegistry( registries.getLdapSyntaxRegistry() );
1440        }
1441    
1442    
1443        /**
1444         * {@inheritDoc}
1445         */
1446        public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
1447        {
1448            return new ImmutableSyntaxCheckerRegistry( registries.getSyntaxCheckerRegistry() );
1449        }
1450    
1451    
1452        /**
1453         * {@inheritDoc}
1454         */
1455        public AttributeType lookupAttributeTypeRegistry( String oid ) throws LdapException
1456        {
1457            return registries.getAttributeTypeRegistry().lookup( StringTools.toLowerCase( oid ).trim() );
1458        }
1459    
1460    
1461        /**
1462         * {@inheritDoc}
1463         */
1464        public LdapComparator<?> lookupComparatorRegistry( String oid ) throws LdapException
1465        {
1466            return registries.getComparatorRegistry().lookup( oid );
1467        }
1468    
1469    
1470        /**
1471         * {@inheritDoc}
1472         */
1473        public MatchingRule lookupMatchingRuleRegistry( String oid ) throws LdapException
1474        {
1475            return registries.getMatchingRuleRegistry().lookup( StringTools.toLowerCase( oid ).trim() );
1476        }
1477    
1478    
1479        /**
1480         * {@inheritDoc}
1481         */
1482        public Normalizer lookupNormalizerRegistry( String oid ) throws LdapException
1483        {
1484            return registries.getNormalizerRegistry().lookup( oid );
1485        }
1486    
1487    
1488        /**
1489         * {@inheritDoc}
1490         */
1491        public ObjectClass lookupObjectClassRegistry( String oid ) throws LdapException
1492        {
1493            return registries.getObjectClassRegistry().lookup( StringTools.toLowerCase( oid ).trim() );
1494        }
1495    
1496    
1497        /**
1498         * {@inheritDoc}
1499         */
1500        public LdapSyntax lookupLdapSyntaxRegistry( String oid ) throws LdapException
1501        {
1502            return registries.getLdapSyntaxRegistry().lookup( StringTools.toLowerCase( oid ).trim() );
1503        }
1504    
1505    
1506        /**
1507         * {@inheritDoc}
1508         */
1509        public SyntaxChecker lookupSyntaxCheckerRegistry( String oid ) throws LdapException
1510        {
1511            return registries.getSyntaxCheckerRegistry().lookup( oid );
1512        }
1513    
1514    
1515        /**
1516         * Check that the given OID exists in the globalOidRegistry.
1517         */
1518        private boolean checkOidExist( SchemaObject schemaObject )
1519        {
1520            if ( !( schemaObject instanceof LoadableSchemaObject ) )
1521            {
1522                return registries.getGlobalOidRegistry().contains( schemaObject.getOid() );
1523            }
1524    
1525            if ( schemaObject instanceof LdapComparator<?> )
1526            {
1527                return registries.getComparatorRegistry().contains( schemaObject.getOid() );
1528            }
1529    
1530            if ( schemaObject instanceof SyntaxChecker )
1531            {
1532                return registries.getSyntaxCheckerRegistry().contains( schemaObject.getOid() );
1533            }
1534    
1535            if ( schemaObject instanceof Normalizer )
1536            {
1537                return registries.getNormalizerRegistry().contains( schemaObject.getOid() );
1538            }
1539    
1540            return false;
1541        }
1542        
1543        
1544        /**
1545         * Get the inner SchemaObject if it's not a C/N/SC
1546         */
1547        private SchemaObject getSchemaObject( SchemaObject schemaObject ) throws LdapException
1548        {
1549            if ( schemaObject instanceof LoadableSchemaObject )
1550            {
1551                return schemaObject;
1552            }
1553            else
1554            {
1555                return registries.getGlobalOidRegistry().getSchemaObject( schemaObject.getOid() );
1556            }
1557        }
1558    
1559    
1560        /**
1561         * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
1562         */
1563        private String getSchemaName( SchemaObject schemaObject )
1564        {
1565            String schemaName = StringTools.toLowerCase( schemaObject.getSchemaName() );
1566    
1567            if ( StringTools.isEmpty( schemaName ) )
1568            {
1569                return MetaSchemaConstants.SCHEMA_OTHER;
1570            }
1571    
1572            if ( schemaLoader.getSchema( schemaName ) == null )
1573            {
1574                return null;
1575            }
1576            else
1577            {
1578                return schemaName;
1579            }
1580        }
1581    
1582    
1583        private SchemaObject copy( SchemaObject schemaObject )
1584        {
1585            SchemaObject copy = null;
1586    
1587            if ( !( schemaObject instanceof LoadableSchemaObject ) )
1588            {
1589                copy = schemaObject.copy();
1590            }
1591            else
1592            {
1593                // Check the schemaObject here.
1594                if ( ( ( LoadableSchemaObject ) schemaObject ).isValid() )
1595                {
1596                    copy = schemaObject;
1597                }
1598                else
1599                {
1600                    // We have an invalid SchemaObject, no need to go any further
1601                    Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
1602                                    I18n.err( I18n.ERR_11007, schemaObject.getOid() ) );
1603                    errors.add( error );
1604                }
1605            }
1606    
1607            return copy;
1608        }
1609    
1610    
1611        //-----------------------------------------------------------------------------------
1612        // SchemaObject operations
1613        //-----------------------------------------------------------------------------------
1614        /**
1615         * {@inheritDoc}
1616         */
1617        public boolean add( SchemaObject schemaObject ) throws Exception
1618        {
1619            // First, clear the errors
1620            errors.clear();
1621    
1622            // Clone the schemaObject
1623            SchemaObject copy = copy( schemaObject );
1624    
1625            if ( copy == null )
1626            {
1627                return false;
1628            }
1629    
1630            if ( registries.isRelaxed() )
1631            {
1632                // Apply the addition right away
1633                registries.add( errors, copy );
1634    
1635                return errors.isEmpty();
1636            }
1637            else
1638            {
1639                // Clone, apply, check, then apply again if ok
1640                // The new schemaObject's OID must not already exist
1641                if ( checkOidExist( copy ) )
1642                {
1643                    Throwable error = new LdapProtocolErrorException(
1644                                    I18n.err( I18n.ERR_11008, schemaObject.getOid() ) );
1645                    errors.add( error );
1646    
1647                    return false;
1648                }
1649    
1650                // Build the new AttributeType from the given entry
1651                String schemaName = getSchemaName( copy );
1652    
1653                if ( schemaName == null )
1654                {
1655                    // The schema associated with the SchemzaObject does not exist. This is not valid.
1656                    Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_11009, schemaObject.getOid(),
1657                                            copy.getSchemaName() ) );
1658                    errors.add( error );
1659    
1660                    return false;
1661                }
1662    
1663                // At this point, the constructed AttributeType has not been checked against the 
1664                // existing Registries. It may be broken (missing SUP, or such), it will be checked
1665                // there, if the schema and the AttributeType are both enabled.
1666                Schema schema = getLoadedSchema( schemaName );
1667    
1668                if ( schema == null )
1669                {
1670                    // The SchemaObject must be associated with an existing schema
1671                    String msg = I18n.err( I18n.ERR_11010, copy.getOid() );
1672                    LOG.info( msg );
1673                    Throwable error = new LdapProtocolErrorException( msg );
1674                    errors.add( error );
1675                    return false;
1676                }
1677    
1678                if ( schema.isEnabled() && copy.isEnabled() )
1679                {
1680                    // As we may break the registries, work on a cloned registries
1681                    Registries clonedRegistries = registries.clone();
1682    
1683                    // Inject the new SchemaObject in the cloned registries
1684                    clonedRegistries.add( errors, copy );
1685    
1686                    // Remove the cloned registries
1687                    clonedRegistries.clear();
1688    
1689                    // If we didn't get any error, apply the addition to the real retistries
1690                    if ( errors.isEmpty() )
1691                    {
1692                        // Copy again as the clonedRegistries clear has removed the previous copy
1693                        copy = copy( schemaObject );
1694    
1695                        // Apply the addition to the real registries
1696                        registries.add( errors, copy );
1697    
1698                        LOG.debug( "Added {} into the enabled schema {}", copy.getName(), schemaName );
1699    
1700                        return true;
1701                    }
1702                    else
1703                    {
1704                        // We have some error : reject the addition and get out
1705                        String msg = "Cannot add the SchemaObject " + copy.getOid() + " into the registries, "
1706                            + "the resulting registries would be inconsistent :" + StringTools.listToString( errors );
1707                        LOG.info( msg );
1708    
1709                        return false;
1710                    }
1711                }
1712                else
1713                {
1714                    // At least, we register the OID in the globalOidRegistry, and associates it with the
1715                    // schema
1716                    registries.associateWithSchema( errors, copy );
1717    
1718                    LOG.debug( "Added {} into the disabled schema {}", copy.getName(), schemaName );
1719                    return errors.isEmpty();
1720                }
1721            }
1722        }
1723    
1724    
1725        /**
1726         * {@inheritDoc}
1727         */
1728        public boolean delete( SchemaObject schemaObject ) throws Exception
1729        {
1730            // First, clear the errors
1731            errors.clear();
1732    
1733            if ( registries.isRelaxed() )
1734            {
1735                // Apply the addition right away
1736                registries.delete( errors, schemaObject );
1737    
1738                return errors.isEmpty();
1739            }
1740            else
1741            {
1742                // Clone, apply, check, then apply again if ok
1743                // The new schemaObject's OID must exist
1744                if ( !checkOidExist( schemaObject ) )
1745                {
1746                    Throwable error = new LdapProtocolErrorException( 
1747                                    I18n.err( I18n.ERR_11011, schemaObject.getOid() ) );
1748                    errors.add( error );
1749                    return false;
1750                }
1751    
1752                // Get the SchemaObject to delete if it's not a LoadableSchemaObject
1753                SchemaObject toDelete = getSchemaObject( schemaObject );
1754    
1755                // First check that this SchemaObject does not have any referencing SchemaObjects
1756                Set<SchemaObjectWrapper> referencing = registries.getReferencing( toDelete );
1757    
1758                if ( ( referencing != null ) && !referencing.isEmpty() )
1759                {
1760                    String msg = I18n.err( I18n.ERR_11012, schemaObject.getOid(), StringTools.setToString( referencing ) );
1761    
1762                    Throwable error = new LdapProtocolErrorException( msg );
1763                    errors.add( error );
1764                    return false;
1765                }
1766    
1767                String schemaName = getSchemaName( toDelete );
1768    
1769                // At this point, the deleted AttributeType may be referenced, it will be checked
1770                // there, if the schema and the AttributeType are both enabled.
1771                Schema schema = getLoadedSchema( schemaName );
1772    
1773                if ( schema == null )
1774                {
1775                    // The SchemaObject must be associated with an existing schema
1776                    String msg = I18n.err( I18n.ERR_11013, schemaObject.getOid() );
1777                    LOG.info( msg );
1778                    Throwable error = new LdapProtocolErrorException( msg );
1779                    errors.add( error );
1780                    return false;
1781                }
1782    
1783                if ( schema.isEnabled() && schemaObject.isEnabled() )
1784                {
1785                    // As we may break the registries, work on a cloned registries
1786                    Registries clonedRegistries = registries.clone();
1787    
1788                    // Delete the SchemaObject from the cloned registries
1789                    clonedRegistries.delete( errors, toDelete );
1790    
1791                    // Remove the cloned registries
1792                    clonedRegistries.clear();
1793    
1794                    // If we didn't get any error, apply the deletion to the real retistries
1795                    if ( errors.isEmpty() )
1796                    {
1797                        // Apply the deletion to the real registries
1798                        registries.delete( errors, toDelete );
1799    
1800                        LOG.debug( "Removed {} from the enabled schema {}", toDelete.getName(), schemaName );
1801    
1802                        return true;
1803                    }
1804                    else
1805                    {
1806                        // We have some error : reject the deletion and get out
1807                        String msg = "Cannot delete the SchemaObject " + schemaObject.getOid() + " from the registries, "
1808                            + "the resulting registries would be inconsistent :" + StringTools.listToString( errors );
1809                        LOG.info( msg );
1810    
1811                        return false;
1812                    }
1813                }
1814                else
1815                {
1816                    // At least, we register the OID in the globalOidRegistry, and associates it with the
1817                    // schema
1818                    registries.associateWithSchema( errors, schemaObject );
1819    
1820                    LOG.debug( "Removed {} from the disabled schema {}", schemaObject.getName(), schemaName );
1821                    return errors.isEmpty();
1822                }
1823            }
1824        }
1825    
1826    
1827        /**
1828         * {@inheritDoc}
1829         */
1830        public Map<String, OidNormalizer> getNormalizerMapping()
1831        {
1832            return registries.getAttributeTypeRegistry().getNormalizerMapping();
1833        }
1834    
1835    
1836        /**
1837         * {@inheritDoc}
1838         */
1839        public OidRegistry getGlobalOidRegistry()
1840        {
1841            return registries.getGlobalOidRegistry();
1842        }
1843    
1844    
1845        /**
1846         * {@inheritDoc}
1847         */
1848        public Schema getLoadedSchema( String schemaName )
1849        {
1850            return schemaLoader.getSchema( schemaName );
1851        }
1852    
1853    
1854        /**
1855         * {@inheritDoc}
1856         */
1857        public boolean isSchemaLoaded( String schemaName )
1858        {
1859            try
1860            {
1861                Schema schema = schemaLoader.getSchema( schemaName );
1862                return schema != null;
1863            }
1864            catch ( Exception e )
1865            {
1866                return false;
1867            }
1868        }
1869    
1870    
1871        /**
1872         * {@inheritDoc}
1873         */
1874        public SchemaObject unregisterAttributeType( String attributeTypeOid ) throws LdapException
1875        {
1876            return registries.getAttributeTypeRegistry().unregister( attributeTypeOid );
1877        }
1878    
1879    
1880        /**
1881         * {@inheritDoc}
1882         */
1883        public SchemaObject unregisterComparator( String comparatorOid ) throws LdapException
1884        {
1885            return registries.getComparatorRegistry().unregister( comparatorOid );
1886        }
1887    
1888    
1889        /**
1890         * {@inheritDoc}
1891         */
1892        public SchemaObject unregisterDitControlRule( String ditControlRuleOid ) throws LdapException
1893        {
1894            return registries.getDitContentRuleRegistry().unregister( ditControlRuleOid );
1895        }
1896    
1897    
1898        /**
1899         * {@inheritDoc}
1900         */
1901        public SchemaObject unregisterDitStructureRule( String ditStructureRuleOid ) throws LdapException
1902        {
1903            return registries.getDitStructureRuleRegistry().unregister( ditStructureRuleOid );
1904        }
1905    
1906    
1907        /**
1908         * {@inheritDoc}
1909         */
1910        public SchemaObject unregisterLdapSyntax( String ldapSyntaxOid ) throws LdapException
1911        {
1912            return registries.getLdapSyntaxRegistry().unregister( ldapSyntaxOid );
1913        }
1914    
1915    
1916        /**
1917         * {@inheritDoc}
1918         */
1919        public SchemaObject unregisterMatchingRule( String matchingRuleOid ) throws LdapException
1920        {
1921            return registries.getMatchingRuleRegistry().unregister( matchingRuleOid );
1922        }
1923    
1924    
1925        /**
1926         * {@inheritDoc}
1927         */
1928        public SchemaObject unregisterMatchingRuleUse( String matchingRuleUseOid ) throws LdapException
1929        {
1930            return registries.getMatchingRuleUseRegistry().unregister( matchingRuleUseOid );
1931        }
1932    
1933    
1934        /**
1935         * {@inheritDoc}
1936         */
1937        public SchemaObject unregisterNameForm( String nameFormOid ) throws LdapException
1938        {
1939            return registries.getNameFormRegistry().unregister( nameFormOid );
1940        }
1941    
1942    
1943        /**
1944         * {@inheritDoc}
1945         */
1946        public SchemaObject unregisterNormalizer( String normalizerOid ) throws LdapException
1947        {
1948            return registries.getNormalizerRegistry().unregister( normalizerOid );
1949        }
1950    
1951    
1952        /**
1953         * {@inheritDoc}
1954         */
1955        public SchemaObject unregisterObjectClass( String objectClassOid ) throws LdapException
1956        {
1957            return registries.getObjectClassRegistry().unregister( objectClassOid );
1958        }
1959    
1960    
1961        /**
1962         * {@inheritDoc}
1963         */
1964        public SchemaObject unregisterSyntaxChecker( String syntaxCheckerOid ) throws LdapException
1965        {
1966            return registries.getSyntaxCheckerRegistry().unregister( syntaxCheckerOid );
1967        }
1968    
1969    
1970        /**
1971         * Tells if the SchemaManager is permissive or if it must be checked 
1972         * against inconsistencies.
1973         *
1974         * @return True if SchemaObjects can be added even if they break the consistency 
1975         */
1976        public boolean isRelaxed()
1977        {
1978            return isRelaxed;
1979        }
1980    
1981    
1982        /**
1983         * Tells if the SchemaManager is strict.
1984         *
1985         * @return True if SchemaObjects cannot be added if they break the consistency 
1986         */
1987        public boolean isStrict()
1988        {
1989            return !isRelaxed;
1990        }
1991    
1992        
1993        /**
1994         * {@inheritDoc}
1995         */
1996        public Set<String> listDependentSchemaNames( String schemaName )
1997        {
1998            return schemaDependences.get( schemaName );
1999        }
2000    
2001    
2002        /**
2003         * Change the SchemaManager to a relaxed mode, where invalid SchemaObjects
2004         * can be registered.
2005         */
2006        public void setRelaxed()
2007        {
2008            isRelaxed = RELAXED;
2009        }
2010    
2011    
2012        /**
2013         * Change the SchemaManager to a strict mode, where invalid SchemaObjects
2014         * cannot be registered.
2015         */
2016        public void setStrict()
2017        {
2018            isRelaxed = STRICT;
2019        }
2020    
2021    
2022        /**
2023         * {@inheritDoc}
2024         */
2025        public boolean isDisabled( String schemaName )
2026        {
2027            Schema schema = registries.getLoadedSchema( schemaName );
2028    
2029            return ( schema != null ) && schema.isDisabled();
2030        }
2031    
2032    
2033        /**
2034         * {@inheritDoc}
2035         */
2036        public boolean isDisabled( Schema schema )
2037        {
2038            return ( schema != null ) && schema.isDisabled();
2039        }
2040    
2041    
2042        /**
2043         * {@inheritDoc}
2044         */
2045        public boolean isEnabled( String schemaName )
2046        {
2047            Schema schema = registries.getLoadedSchema( schemaName );
2048    
2049            return ( schema != null ) && schema.isEnabled();
2050        }
2051    
2052    
2053        /**
2054         * {@inheritDoc}
2055         */
2056        public boolean isEnabled( Schema schema )
2057        {
2058            return ( schema != null ) && schema.isEnabled();
2059        }
2060    }