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