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 }