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 javax.naming.NamingException;
032
033 import org.apache.directory.shared.i18n.I18n;
034 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
035 import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
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: 919765 $
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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException ne )
723 {
724 // Not allowed.
725 String msg = I18n.err( I18n.ERR_04292, schemaObject.getName(), ne.getLocalizedMessage() );
726
727 Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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 ( NamingException ne )
744 {
745 // Not allowed.
746 String msg = I18n.err( I18n.ERR_04293, schemaObject.getName(), ne.getLocalizedMessage() );
747
748 Throwable error = new LdapSchemaViolationException( msg, ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 ( NamingException 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 LdapSchemaViolationException( I18n.err( I18n.ERR_04294, matchingRule.getOid() ),
1005 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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( I18n.err( I18n.ERR_04295, matchingRule.getOid() ),
1016 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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( I18n.err( I18n.ERR_04296, matchingRule.getOid() ),
1027 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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 ( NamingException 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( I18n.err( I18n.ERR_04297, attributeType.getOid() ),
1072 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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 ( NamingException 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( I18n.err( I18n.ERR_04298, attributeType.getOid() ),
1104 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
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 ( NamingException 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 ( NamingException 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 ( NamingException 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 LdapSchemaViolationException( I18n.err( I18n.ERR_04299, objectClass.getOid() ),
1239 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
1240 errors.add( error );
1241 return;
1242 }
1243 }
1244 }
1245 }
1246
1247
1248 private void resolveRecursive( ObjectClass objectClass, Set<String> processed, List<Throwable> errors )
1249 {
1250 // Process the Superiors, if any
1251 List<String> superiorOids = objectClass.getSuperiorOids();
1252 ObjectClass superior = null;
1253
1254 for ( String superiorOid : superiorOids )
1255 {
1256 // Check if the Superior is present in the registries
1257 try
1258 {
1259 superior = objectClassRegistry.lookup( superiorOid );
1260 }
1261 catch ( NamingException ne )
1262 {
1263 // This OC's superior has not been loaded into the Registries.
1264 if ( !processed.contains( superiorOid ) )
1265 {
1266 errors.add( ne );
1267 }
1268 }
1269
1270 // We now have to process the superior, if it hasn't been
1271 // processed yet.
1272 if ( superior != null )
1273 {
1274 if ( !processed.contains( superior.getOid() ) )
1275 {
1276 resolveRecursive( superior, processed, errors );
1277 processed.add( objectClass.getOid() );
1278 }
1279 else
1280 {
1281 // Not allowed : we have a cyle
1282 Throwable error = new LdapSchemaViolationException( I18n.err( I18n.ERR_04300, objectClass.getOid(), superior) ,
1283 ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
1284 errors.add( error );
1285 return;
1286 }
1287 }
1288 }
1289
1290 // Process the MAY attributeTypes.
1291 for ( String mayOid : objectClass.getMayAttributeTypeOids() )
1292 {
1293 // Check if the MAY AttributeType is present in the registries
1294 try
1295 {
1296 attributeTypeRegistry.lookup( mayOid );
1297 }
1298 catch ( NamingException ne )
1299 {
1300 // This AT has not been loaded into the Registries.
1301 errors.add( ne );
1302 }
1303 }
1304
1305 // Process the MUST attributeTypes.
1306 for ( String mustOid : objectClass.getMustAttributeTypeOids() )
1307 {
1308 // Check if the MUST AttributeType is present in the registries
1309 try
1310 {
1311 attributeTypeRegistry.lookup( mustOid );
1312 }
1313 catch ( NamingException ne )
1314 {
1315 // This AT has not been loaded into the Registries.
1316 errors.add( ne );
1317 }
1318 }
1319
1320 // All is done for this ObjectClass, let's apply the registries
1321 try
1322 {
1323 objectClass.addToRegistries( errors, this );
1324 }
1325 catch ( NamingException ne )
1326 {
1327 // Do nothing. We may have a broken OC,
1328 // but at this point, it doesn't matter.
1329 }
1330 }
1331
1332
1333 /**
1334 * Applies the added SchemaObject to the given register
1335 */
1336 public List<Throwable> add( List<Throwable> errors, SchemaObject schemaObject ) throws NamingException
1337 {
1338 // Relax the registries
1339 boolean wasRelaxed = isRelaxed;
1340 setRelaxed();
1341
1342 // Register the SchemaObject in the registries
1343 register( errors, schemaObject );
1344
1345 // Associate the SchemaObject with its schema
1346 associateWithSchema( errors, schemaObject );
1347
1348 // Build the SchemaObject references
1349 buildReference( errors, schemaObject );
1350
1351 if ( errors.isEmpty() )
1352 {
1353 // Check the registries now
1354 List<Throwable> checkErrors = checkRefInteg();
1355
1356 errors.addAll( checkErrors );
1357 }
1358
1359 // Get back to Strict mode
1360 if ( !wasRelaxed )
1361 {
1362 setStrict();
1363 }
1364
1365 // return the errors
1366 return errors;
1367 }
1368
1369
1370 /**
1371 * Remove the given SchemaObject from the registries
1372 */
1373 public List<Throwable> delete( List<Throwable> errors, SchemaObject schemaObject ) throws NamingException
1374 {
1375 // Relax the registries
1376 boolean wasRelaxed = isRelaxed;
1377 setRelaxed();
1378
1379 // Remove the SchemaObject from the registries
1380 SchemaObject removed = unregister( errors, schemaObject );
1381
1382 // Remove the SchemaObject from its schema
1383 dissociateFromSchema( errors, removed );
1384
1385 // Unlink the SchemaObject references
1386 removeReference( errors, removed );
1387
1388 if ( errors.isEmpty() )
1389 {
1390 // Check the registries now
1391 List<Throwable> checkErrors = checkRefInteg();
1392
1393 errors.addAll( checkErrors );
1394 }
1395
1396 // Restore the previous registries state
1397 if ( !wasRelaxed )
1398 {
1399 setStrict();
1400 }
1401
1402 // return the errors
1403 return errors;
1404 }
1405
1406
1407 /**
1408 * Merely adds the schema to the set of loaded schemas. Does not
1409 * actually do any work to add schema objects to registries.
1410 *
1411 * {@inheritDoc}
1412 */
1413 public void schemaLoaded( Schema schema )
1414 {
1415 this.loadedSchemas.put( StringTools.toLowerCase( schema.getSchemaName() ), schema );
1416 }
1417
1418
1419 /**
1420 * Merely removes the schema from the set of loaded schemas. Does not
1421 * actually do any work to remove schema objects from registries.
1422 *
1423 * {@inheritDoc}
1424 */
1425 public void schemaUnloaded( Schema schema )
1426 {
1427 this.loadedSchemas.remove( StringTools.toLowerCase( schema.getSchemaName() ) );
1428 }
1429
1430
1431 /**
1432 * Gets an unmodifiable Map of schema names to loaded Schema objects.
1433 *
1434 * @return the map of loaded Schema objects
1435 */
1436 public Map<String, Schema> getLoadedSchemas()
1437 {
1438 return Collections.unmodifiableMap( loadedSchemas );
1439 }
1440
1441
1442 /**
1443 * @return Gets a reference to the Map associating a schemaName to
1444 * its contained SchemaObjects
1445 */
1446 public Map<String, Set<SchemaObjectWrapper>> getObjectBySchemaName()
1447 {
1448 return schemaObjects;
1449 }
1450
1451
1452 /**
1453 * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found.
1454 */
1455 private String getSchemaName( SchemaObject schemaObject )
1456 {
1457 String schemaName = StringTools.toLowerCase( schemaObject.getSchemaName() );
1458
1459 if ( loadedSchemas.containsKey( schemaName ) )
1460 {
1461 return schemaName;
1462 }
1463 else
1464 {
1465 return MetaSchemaConstants.SCHEMA_OTHER;
1466 }
1467 }
1468
1469
1470 /**
1471 * Tells if the given SchemaObject is present in one schema. The schema
1472 * may be disabled.
1473 *
1474 * @param schemaObject The schemaObject we are looking for
1475 * @return true if the schemaObject is present in a schema
1476 */
1477 public boolean contains( SchemaObject schemaObject )
1478 {
1479 String schemaName = schemaObject.getSchemaName();
1480
1481 Set<SchemaObjectWrapper> setSchemaObjects = schemaObjects.get( schemaName );
1482
1483 if ( ( setSchemaObjects == null ) || setSchemaObjects.isEmpty() )
1484 {
1485 return false;
1486 }
1487
1488 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1489
1490 return setSchemaObjects.contains( wrapper );
1491 }
1492
1493
1494 /**
1495 * Create a new schema association with its content
1496 *
1497 * @param schemaName The schema name
1498 */
1499 public Set<SchemaObjectWrapper> addSchema( String schemaName )
1500 {
1501 Set<SchemaObjectWrapper> content = new HashSet<SchemaObjectWrapper>();
1502 schemaObjects.put( schemaName, content );
1503
1504 return content;
1505 }
1506
1507
1508 /**
1509 * Register the given SchemaObject into the associated Registry
1510 */
1511 private void register( List<Throwable> errors, SchemaObject schemaObject ) throws NamingException
1512 {
1513 LOG.debug( "Registering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
1514
1515 // Check that the SchemaObject is not already registered
1516 if ( schemaObject instanceof LoadableSchemaObject )
1517 {
1518 // TODO : Check for existing Loadable SchemaObject
1519 }
1520 else
1521 {
1522 if ( globalOidRegistry.contains( schemaObject.getOid() ) )
1523 {
1524 // TODO : throw an exception here
1525 String msg = I18n.err( I18n.ERR_04301, schemaObject.getObjectType(), schemaObject.getOid() );
1526 LOG.error( msg );
1527 Throwable error = new LdapOperationNotSupportedException( msg, ResultCodeEnum.UNWILLING_TO_PERFORM );
1528 errors.add( error );
1529 return;
1530 }
1531 }
1532
1533 try
1534 {
1535 // First call the specific registry's register method
1536 switch ( schemaObject.getObjectType() )
1537 {
1538 case ATTRIBUTE_TYPE:
1539 attributeTypeRegistry.register( ( AttributeType ) schemaObject );
1540 break;
1541
1542 case COMPARATOR:
1543 comparatorRegistry.register( ( LdapComparator<?> ) schemaObject );
1544 break;
1545
1546 case DIT_CONTENT_RULE:
1547 ditContentRuleRegistry.register( ( DITContentRule ) schemaObject );
1548 break;
1549
1550 case DIT_STRUCTURE_RULE:
1551 ditStructureRuleRegistry.register( ( DITStructureRule ) schemaObject );
1552 break;
1553
1554 case LDAP_SYNTAX:
1555 ldapSyntaxRegistry.register( ( LdapSyntax ) schemaObject );
1556 break;
1557
1558 case MATCHING_RULE:
1559 matchingRuleRegistry.register( ( MatchingRule ) schemaObject );
1560 break;
1561
1562 case MATCHING_RULE_USE:
1563 matchingRuleUseRegistry.register( ( MatchingRuleUse ) schemaObject );
1564 break;
1565
1566 case NAME_FORM:
1567 nameFormRegistry.register( ( NameForm ) schemaObject );
1568 break;
1569
1570 case NORMALIZER:
1571 normalizerRegistry.register( ( Normalizer ) schemaObject );
1572 break;
1573
1574 case OBJECT_CLASS:
1575 objectClassRegistry.register( ( ObjectClass ) schemaObject );
1576 break;
1577
1578 case SYNTAX_CHECKER:
1579 syntaxCheckerRegistry.register( ( SyntaxChecker ) schemaObject );
1580 break;
1581 }
1582 }
1583 catch ( Exception e )
1584 {
1585 errors.add( e );
1586 }
1587 }
1588
1589
1590 /**
1591 * Store the given SchemaObject in the Map associating SchemaObjetcs to their
1592 * related Schema.
1593 *
1594 * @param schemaObject The schemaObject to register
1595 * @throws NamingException If there is a problem
1596 */
1597 public void associateWithSchema( List<Throwable> errors, SchemaObject schemaObject )
1598 {
1599 LOG.debug( "Registering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
1600
1601 // Check that the SchemaObject is not already registered
1602 if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) )
1603 {
1604 // TODO : throw an exception here
1605 String msg = I18n.err( I18n.ERR_04301, schemaObject.getObjectType(), schemaObject.getOid() );
1606 LOG.error( msg );
1607 Throwable error = new LdapOperationNotSupportedException( msg, ResultCodeEnum.UNWILLING_TO_PERFORM );
1608 errors.add( error );
1609 return;
1610 }
1611
1612 // Get a normalized form of schema name
1613 String schemaName = getSchemaName( schemaObject );
1614
1615 // And register the schemaObject within its schema
1616 Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
1617
1618 if ( content == null )
1619 {
1620 content = new HashSet<SchemaObjectWrapper>();
1621 schemaObjects.put( StringTools.toLowerCase( schemaName ), content );
1622 }
1623
1624 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
1625
1626 if ( content.contains( schemaObjectWrapper ) )
1627 {
1628 // Already present !
1629 // What should we do ?
1630 LOG.info( "Registering of {}:{} failed, is already present in the Registries",
1631 schemaObject.getObjectType(), schemaObject.getOid() );
1632 }
1633 else
1634 {
1635 // Create the association
1636 content.add( schemaObjectWrapper );
1637
1638 // Update the global OidRegistry if the SchemaObject is not
1639 // an instance of LoadableSchemaObject
1640 if ( !( schemaObject instanceof LoadableSchemaObject ) )
1641 {
1642 try
1643 {
1644 globalOidRegistry.register( schemaObject );
1645 }
1646 catch ( NamingException ne )
1647 {
1648 errors.add( ne );
1649 return;
1650 }
1651 }
1652
1653 LOG.debug( "registered {} for OID {}", schemaObject.getName(), schemaObject.getOid() );
1654 }
1655 }
1656
1657
1658 /**
1659 * Store the given SchemaObject in the Map associating SchemaObjetcs to their
1660 * related Schema.
1661 *
1662 * @param schemaObject The schemaObject to register
1663 * @throws NamingException If there is a problem
1664 */
1665
1666 public void dissociateFromSchema( List<Throwable> errors, SchemaObject schemaObject ) throws NamingException
1667 {
1668 LOG.debug( "Unregistering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
1669
1670 // Check that the SchemaObject is already registered
1671 if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) )
1672 {
1673 // TODO : throw an exception here
1674 String msg = I18n.err( I18n.ERR_04302, schemaObject.getObjectType(), schemaObject.getOid() );
1675 LOG.error( msg );
1676 Throwable error = new LdapOperationNotSupportedException( msg, ResultCodeEnum.UNWILLING_TO_PERFORM );
1677 errors.add( error );
1678 return;
1679 }
1680
1681 // Get a normalized form of schema name
1682 String schemaName = getSchemaName( schemaObject );
1683 String oid = schemaObject.getOid();
1684
1685 // And unregister the schemaObject from its schema
1686 Set<SchemaObjectWrapper> content = schemaObjects.get( schemaName );
1687
1688 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
1689
1690 if ( !content.contains( schemaObjectWrapper ) )
1691 {
1692 // Not present !
1693 // What should we do ?
1694 LOG.info( "Unregistering of {}:{} failed, is not present in the Registries", schemaObject.getObjectType(),
1695 schemaObject.getOid() );
1696 }
1697 else
1698 {
1699 // Remove the association
1700 content.remove( schemaObjectWrapper );
1701
1702 // Update the global OidRegistry if the SchemaObject is not
1703 // an instance of LoadableSchemaObject
1704 if ( !( schemaObject instanceof LoadableSchemaObject ) )
1705 {
1706 try
1707 {
1708 globalOidRegistry.unregister( oid );
1709 }
1710 catch ( NamingException ne )
1711 {
1712 errors.add( ne );
1713 return;
1714 }
1715 }
1716
1717 LOG.debug( "Unregistered {} for OID {}", schemaObject.getName(), schemaObject.getOid() );
1718 }
1719 }
1720
1721
1722 /**
1723 * Unregister a SchemaObject from the registries
1724 *
1725 * @param schemaObject The SchemaObject we want to deregister
1726 * @throws NamingException If the removal failed
1727 */
1728 private SchemaObject unregister( List<Throwable> errors, SchemaObject schemaObject ) throws NamingException
1729 {
1730 LOG.debug( "Unregistering {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
1731
1732 // Check that the SchemaObject is present in the registries
1733 if ( schemaObject instanceof LoadableSchemaObject )
1734 {
1735 // TODO : check for an existing Loadable SchemaObject
1736 }
1737 else
1738 {
1739 if ( !globalOidRegistry.contains( schemaObject.getOid() ) )
1740 {
1741 // TODO : throw an exception here
1742 String msg = I18n.err( I18n.ERR_04302, schemaObject.getObjectType(), schemaObject.getOid() );
1743 LOG.error( msg );
1744 throw new LdapOperationNotSupportedException( msg, ResultCodeEnum.UNWILLING_TO_PERFORM );
1745 }
1746 }
1747
1748 SchemaObject unregistered = null;
1749
1750 // First call the specific registry's register method
1751 switch ( schemaObject.getObjectType() )
1752 {
1753 case ATTRIBUTE_TYPE:
1754 unregistered = attributeTypeRegistry.unregister( ( AttributeType ) schemaObject );
1755 break;
1756
1757 case COMPARATOR:
1758 unregistered = comparatorRegistry.unregister( ( LdapComparator<?> ) schemaObject );
1759 break;
1760
1761 case DIT_CONTENT_RULE:
1762 unregistered = ditContentRuleRegistry.unregister( ( DITContentRule ) schemaObject );
1763 break;
1764
1765 case DIT_STRUCTURE_RULE:
1766 unregistered = ditStructureRuleRegistry.unregister( ( DITStructureRule ) schemaObject );
1767 break;
1768
1769 case LDAP_SYNTAX:
1770 unregistered = ldapSyntaxRegistry.unregister( ( LdapSyntax ) schemaObject );
1771 break;
1772
1773 case MATCHING_RULE:
1774 unregistered = matchingRuleRegistry.unregister( ( MatchingRule ) schemaObject );
1775 break;
1776
1777 case MATCHING_RULE_USE:
1778 unregistered = matchingRuleUseRegistry.unregister( ( MatchingRuleUse ) schemaObject );
1779 break;
1780
1781 case NAME_FORM:
1782 unregistered = nameFormRegistry.unregister( ( NameForm ) schemaObject );
1783 break;
1784
1785 case NORMALIZER:
1786 unregistered = normalizerRegistry.unregister( ( Normalizer ) schemaObject );
1787 break;
1788
1789 case OBJECT_CLASS:
1790 unregistered = objectClassRegistry.unregister( ( ObjectClass ) schemaObject );
1791 break;
1792
1793 case SYNTAX_CHECKER:
1794 unregistered = syntaxCheckerRegistry.unregister( ( SyntaxChecker ) schemaObject );
1795 break;
1796 }
1797
1798 return unregistered;
1799 }
1800
1801
1802 /**
1803 * Remove the given SchemaObject from the Map associating SchemaObjetcs to their
1804 * related Schema.
1805 *
1806 * @param schemaObject The schemaObject to remove
1807 * @throws NamingException If there is a problem
1808 */
1809 public void dissociateFromSchema( SchemaObject schemaObject ) throws NamingException
1810 {
1811 // And unregister the schemaObject within its schema
1812 Set<SchemaObjectWrapper> content = schemaObjects.get( StringTools.toLowerCase( schemaObject.getSchemaName() ) );
1813
1814 if ( content != null )
1815 {
1816 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
1817
1818 if ( content.contains( schemaObjectWrapper ) )
1819 {
1820 // remove the schemaObject
1821 content.remove( schemaObjectWrapper );
1822
1823 // Update the global OidRegistry if the SchemaObject is not
1824 // an instance of LoadableSchemaObject
1825 if ( !( schemaObject instanceof LoadableSchemaObject ) )
1826 {
1827 globalOidRegistry.unregister( schemaObject.getOid() );
1828 }
1829
1830 LOG.debug( "Unregistered {}:{}", schemaObject.getObjectType(), schemaObject.getOid() );
1831 }
1832 else
1833 {
1834 // Not present !!
1835 // What should we do ?
1836 LOG.debug( "Unregistering of {}:{} failed, not found in Registries", schemaObject.getObjectType(),
1837 schemaObject.getOid() );
1838 }
1839 }
1840 }
1841
1842
1843 /**
1844 * Checks if a specific SchemaObject is referenced by any other SchemaObject.
1845 *
1846 * @param schemaObject The SchemaObject we are looking for
1847 * @return true if there is at least one SchemaObjetc referencing the given one
1848 */
1849 public boolean isReferenced( SchemaObject schemaObject )
1850 {
1851 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1852
1853 Set<SchemaObjectWrapper> set = usedBy.get( wrapper );
1854
1855 boolean referenced = ( set != null ) && ( set.size() != 0 );
1856
1857 if ( LOG.isDebugEnabled() )
1858 {
1859 if ( referenced )
1860 {
1861 LOG.debug( "The {}:{} is referenced", schemaObject.getObjectType(), schemaObject.getOid() );
1862 }
1863 else
1864 {
1865 LOG.debug( "The {}:{} is not referenced", schemaObject.getObjectType(), schemaObject.getOid() );
1866 }
1867 }
1868
1869 return referenced;
1870 }
1871
1872
1873 /**
1874 * Gets the Set of SchemaObjects referencing the given SchemaObject
1875 *
1876 * @param schemaObject The SchemaObject we are looking for
1877 * @return The Set of referencing SchemaObject, or null
1878 */
1879 public Set<SchemaObjectWrapper> getUsedBy( SchemaObject schemaObject )
1880 {
1881 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1882
1883 return usedBy.get( wrapper );
1884 }
1885
1886
1887 /**
1888 * Dump the UsedBy data structure as a String
1889 */
1890 public String dumpUsedBy()
1891 {
1892 StringBuilder sb = new StringBuilder();
1893
1894 sb.append( "USED BY :\n" );
1895
1896 for ( SchemaObjectWrapper wrapper : usedBy.keySet() )
1897 {
1898 sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "] : {" );
1899
1900 boolean isFirst = true;
1901
1902 for ( SchemaObjectWrapper uses : usedBy.get( wrapper ) )
1903 {
1904 if ( isFirst )
1905 {
1906 isFirst = false;
1907 }
1908 else
1909 {
1910 sb.append( ", " );
1911 }
1912
1913 sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
1914 }
1915
1916 sb.append( "}\n" );
1917 }
1918
1919 return sb.toString();
1920 }
1921
1922
1923 /**
1924 * Dump the Using data structure as a String
1925 */
1926 public String dumpUsing()
1927 {
1928 StringBuilder sb = new StringBuilder();
1929
1930 sb.append( "USING :\n" );
1931
1932 for ( SchemaObjectWrapper wrapper : using.keySet() )
1933 {
1934 sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "] : {" );
1935
1936 boolean isFirst = true;
1937
1938 for ( SchemaObjectWrapper uses : using.get( wrapper ) )
1939 {
1940 if ( isFirst )
1941 {
1942 isFirst = false;
1943 }
1944 else
1945 {
1946 sb.append( ", " );
1947 }
1948
1949 sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" );
1950 }
1951
1952 sb.append( "}\n" );
1953 }
1954
1955 return sb.toString();
1956 }
1957
1958
1959 /**
1960 * Gets the Set of SchemaObjects referenced by the given SchemaObject
1961 *
1962 * @param schemaObject The SchemaObject we are looking for
1963 * @return The Set of referenced SchemaObject, or null
1964 */
1965 public Set<SchemaObjectWrapper> getUsing( SchemaObject schemaObject )
1966 {
1967 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject );
1968
1969 return using.get( wrapper );
1970 }
1971
1972
1973 /**
1974 * Add an association between a SchemaObject an the SchemaObject it refers
1975 *
1976 * @param reference The base SchemaObject
1977 * @param referee The SchemaObject pointing on the reference
1978 */
1979 private void addUsing( SchemaObject reference, SchemaObject referee )
1980 {
1981 if ( ( reference == null ) || ( referee == null ) )
1982 {
1983 return;
1984 }
1985
1986 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
1987
1988 Set<SchemaObjectWrapper> uses = getUsing( reference );
1989
1990 if ( uses == null )
1991 {
1992 uses = new HashSet<SchemaObjectWrapper>();
1993 }
1994
1995 uses.add( new SchemaObjectWrapper( referee ) );
1996
1997 // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
1998 using.put( wrapper, uses );
1999 }
2000
2001
2002 /**
2003 * Add an association between a SchemaObject an the SchemaObject it refers
2004 *
2005 * @param base The base SchemaObject
2006 * @param referenced The referenced SchemaObject
2007 */
2008 public void addReference( SchemaObject base, SchemaObject referenced )
2009 {
2010 if ( LOG.isDebugEnabled() )
2011 {
2012 LOG.debug( dump( "add", base, referenced ) );
2013 }
2014
2015 addUsing( base, referenced );
2016 addUsedBy( referenced, base );
2017
2018 if ( LOG.isDebugEnabled() )
2019 {
2020 LOG.debug( dumpUsedBy() );
2021 LOG.debug( dumpUsing() );
2022 }
2023 }
2024
2025
2026 /**
2027 * Add an association between a SchemaObject an the SchemaObject that refers it
2028 *
2029 * @param reference The base SchemaObject
2030 * @param referee The SchemaObject pointing on the reference
2031 */
2032 private void addUsedBy( SchemaObject referee, SchemaObject reference )
2033 {
2034 if ( ( reference == null ) || ( referee == null ) )
2035 {
2036 return;
2037 }
2038
2039 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
2040
2041 Set<SchemaObjectWrapper> uses = getUsedBy( referee );
2042
2043 if ( uses == null )
2044 {
2045 uses = new HashSet<SchemaObjectWrapper>();
2046 }
2047
2048 uses.add( new SchemaObjectWrapper( reference ) );
2049
2050 // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly
2051 usedBy.put( wrapper, uses );
2052 }
2053
2054
2055 /**
2056 * Del an association between a SchemaObject an the SchemaObject it refers
2057 *
2058 * @param reference The base SchemaObject
2059 * @param referee The SchemaObject pointing on the reference
2060 */
2061 private void delUsing( SchemaObject reference, SchemaObject referee )
2062 {
2063 if ( ( reference == null ) || ( referee == null ) )
2064 {
2065 return;
2066 }
2067
2068 Set<SchemaObjectWrapper> uses = getUsing( reference );
2069
2070 if ( uses == null )
2071 {
2072 return;
2073 }
2074
2075 uses.remove( new SchemaObjectWrapper( referee ) );
2076
2077 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference );
2078
2079 if ( uses.size() == 0 )
2080 {
2081 using.remove( wrapper );
2082 }
2083 else
2084 {
2085 using.put( wrapper, uses );
2086 }
2087
2088 return;
2089 }
2090
2091
2092 /**
2093 * Del an association between a SchemaObject an the SchemaObject that refers it
2094 *
2095 * @param reference The base SchemaObject
2096 * @param referee The SchemaObject pointing on the reference
2097 */
2098 private void delUsedBy( SchemaObject referee, SchemaObject reference )
2099 {
2100 if ( ( reference == null ) || ( referee == null ) )
2101 {
2102 return;
2103 }
2104
2105 Set<SchemaObjectWrapper> uses = getUsedBy( referee );
2106
2107 if ( uses == null )
2108 {
2109 return;
2110 }
2111
2112 uses.remove( new SchemaObjectWrapper( reference ) );
2113
2114 SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee );
2115
2116 if ( uses.size() == 0 )
2117 {
2118 usedBy.remove( wrapper );
2119 }
2120 else
2121 {
2122 usedBy.put( wrapper, uses );
2123 }
2124
2125 return;
2126 }
2127
2128
2129 /**
2130 * Delete an association between a SchemaObject an the SchemaObject it refers
2131 *
2132 * @param base The base SchemaObject
2133 * @param referenced The referenced SchemaObject
2134 */
2135 public void delReference( SchemaObject base, SchemaObject referenced )
2136 {
2137 if ( LOG.isDebugEnabled() )
2138 {
2139 LOG.debug( dump( "del", base, referenced ) );
2140 }
2141
2142 delUsing( base, referenced );
2143 delUsedBy( referenced, base );
2144
2145 if ( LOG.isDebugEnabled() )
2146 {
2147 LOG.debug( dumpUsedBy() );
2148 LOG.debug( dumpUsing() );
2149 }
2150 }
2151
2152
2153 /**
2154 * Dump the reference operation as a String
2155 */
2156 private String dump( String op, SchemaObject reference, SchemaObject referee )
2157 {
2158 return op + " : " + reference.getObjectType() + "[" + reference.getOid() + "]/[" + referee.getObjectType()
2159 + "[" + referee.getOid() + "]";
2160 }
2161
2162
2163 private boolean checkReferences( SchemaObject reference, SchemaObject referee, String message )
2164 {
2165 SchemaObjectWrapper referenceWrapper = new SchemaObjectWrapper( reference );
2166 SchemaObjectWrapper refereeWrapper = new SchemaObjectWrapper( referee );
2167
2168 // Check the references : Syntax -> SyntaxChecker
2169 if ( !using.containsKey( referenceWrapper ) )
2170 {
2171 LOG.debug( "The Syntax {}:{} does not reference any " + message, reference.getObjectType(), reference
2172 .getOid() );
2173
2174 return false;
2175 }
2176
2177 Set<SchemaObjectWrapper> usings = using.get( referenceWrapper );
2178
2179 if ( !usings.contains( refereeWrapper ) )
2180 {
2181 LOG.debug( "The {}:{} does not reference any " + message, reference.getObjectType(), reference.getOid() );
2182
2183 return false;
2184 }
2185
2186 // Check the referees : SyntaxChecker -> Syntax
2187 if ( !usedBy.containsKey( refereeWrapper ) )
2188 {
2189 LOG.debug( "The {}:{} is not referenced by any " + message, referee.getObjectType(), referee.getOid() );
2190
2191 return false;
2192 }
2193
2194 Set<SchemaObjectWrapper> used = usedBy.get( refereeWrapper );
2195
2196 if ( !used.contains( referenceWrapper ) )
2197 {
2198 LOG.debug( "The {}:{} is not referenced by any " + message, referee.getObjectType(), referee.getOid() );
2199
2200 return false;
2201 }
2202
2203 return true;
2204 }
2205
2206
2207 /**
2208 * Check the registries for invalid relations. This check stops at the first error.
2209 *
2210 * @return true if the Registries is consistent, false otherwise
2211 */
2212 public boolean check()
2213 {
2214 // Check the Syntaxes : check for a SyntaxChecker
2215 LOG.debug( "Checking Syntaxes" );
2216
2217 for ( LdapSyntax syntax : ldapSyntaxRegistry )
2218 {
2219 // Check that each Syntax has a SyntaxChecker
2220 if ( syntax.getSyntaxChecker() == null )
2221 {
2222 LOG.debug( "The Syntax {} has no SyntaxChecker", syntax );
2223
2224 return false;
2225 }
2226
2227 if ( !syntaxCheckerRegistry.contains( syntax.getSyntaxChecker().getOid() ) )
2228 {
2229 LOG.debug( "Cannot find the SyntaxChecker {} for the Syntax {}", syntax.getSyntaxChecker().getOid(),
2230 syntax );
2231
2232 return false;
2233 }
2234
2235 // Check the references : Syntax -> SyntaxChecker and SyntaxChecker -> Syntax
2236 if ( !checkReferences( syntax, syntax.getSyntaxChecker(), "SyntaxChecker" ) )
2237 {
2238 return false;
2239 }
2240 }
2241
2242 // Check the MatchingRules : check for a Normalizer, a Comparator and a Syntax
2243 LOG.debug( "Checking MatchingRules..." );
2244
2245 for ( MatchingRule matchingRule : matchingRuleRegistry )
2246 {
2247 // Check that each MatchingRule has a Normalizer
2248 if ( matchingRule.getNormalizer() == null )
2249 {
2250 LOG.debug( "The MatchingRule {} has no Normalizer", matchingRule );
2251
2252 return false;
2253 }
2254
2255 // Check that each MatchingRule has a Normalizer
2256 if ( !normalizerRegistry.contains( matchingRule.getNormalizer().getOid() ) )
2257 {
2258 LOG.debug( "Cannot find the Normalizer {} for the MatchingRule {}", matchingRule.getNormalizer()
2259 .getOid(), matchingRule );
2260
2261 return false;
2262 }
2263
2264 // Check that each MatchingRule has a Comparator
2265 if ( matchingRule.getLdapComparator() == null )
2266 {
2267 LOG.debug( "The MatchingRule {} has no Comparator", matchingRule );
2268
2269 return false;
2270 }
2271
2272 if ( !comparatorRegistry.contains( matchingRule.getLdapComparator().getOid() ) )
2273 {
2274 LOG.debug( "Cannot find the Comparator {} for the MatchingRule {}", matchingRule.getLdapComparator()
2275 .getOid(), matchingRule );
2276
2277 return false;
2278 }
2279
2280 // Check that each MatchingRule has a Syntax
2281 if ( matchingRule.getSyntax() == null )
2282 {
2283 LOG.debug( "The MatchingRule {} has no Syntax", matchingRule );
2284
2285 return false;
2286 }
2287
2288 if ( !ldapSyntaxRegistry.contains( matchingRule.getSyntax().getOid() ) )
2289 {
2290 LOG.debug( "Cannot find the Syntax {} for the MatchingRule {}", matchingRule.getSyntax().getOid(),
2291 matchingRule );
2292
2293 return false;
2294 }
2295
2296 // Check the references : MR -> S and S -> MR
2297 if ( !checkReferences( matchingRule, matchingRule.getSyntax(), "Syntax" ) )
2298 {
2299 return false;
2300 }
2301
2302 // Check the references : MR -> N
2303 if ( !checkReferences( matchingRule, matchingRule.getNormalizer(), "Normalizer" ) )
2304 {
2305 return false;
2306 }
2307
2308 // Check the references : MR -> C and C -> MR
2309 if ( !checkReferences( matchingRule, matchingRule.getLdapComparator(), "Comparator" ) )
2310 {
2311 return false;
2312 }
2313 }
2314
2315 // Check the ObjectClasses : check for MAY, MUST, SUPERIORS
2316 LOG.debug( "Checking ObjectClasses..." );
2317
2318 for ( ObjectClass objectClass : objectClassRegistry )
2319 {
2320 // Check that each ObjectClass has all the MAY AttributeTypes
2321 if ( objectClass.getMayAttributeTypes() != null )
2322 {
2323 for ( AttributeType may : objectClass.getMayAttributeTypes() )
2324 {
2325 if ( !attributeTypeRegistry.contains( may.getOid() ) )
2326 {
2327 LOG.debug( "Cannot find the AttributeType {} for the ObjectClass {} MAY", may, objectClass );
2328
2329 return false;
2330 }
2331
2332 // Check the references : OC -> AT and AT -> OC (MAY)
2333 if ( !checkReferences( objectClass, may, "AttributeType" ) )
2334 {
2335 return false;
2336 }
2337 }
2338 }
2339
2340 // Check that each ObjectClass has all the MUST AttributeTypes
2341 if ( objectClass.getMustAttributeTypes() != null )
2342 {
2343 for ( AttributeType must : objectClass.getMustAttributeTypes() )
2344 {
2345 if ( !attributeTypeRegistry.contains( must.getOid() ) )
2346 {
2347 LOG.debug( "Cannot find the AttributeType {} for the ObjectClass {} MUST", must, objectClass );
2348
2349 return false;
2350 }
2351
2352 // Check the references : OC -> AT and AT -> OC (MUST)
2353 if ( !checkReferences( objectClass, must, "AttributeType" ) )
2354 {
2355 return false;
2356 }
2357 }
2358 }
2359
2360 // Check that each ObjectClass has all the SUPERIORS ObjectClasses
2361 if ( objectClass.getSuperiors() != null )
2362 {
2363 for ( ObjectClass superior : objectClass.getSuperiors() )
2364 {
2365 if ( !objectClassRegistry.contains( objectClass.getOid() ) )
2366 {
2367 LOG.debug( "Cannot find the ObjectClass {} for the ObjectClass {} SUPERIORS", superior,
2368 objectClass );
2369
2370 return false;
2371 }
2372
2373 // Check the references : OC -> OC and OC -> OC (SUPERIORS)
2374 if ( !checkReferences( objectClass, superior, "ObjectClass" ) )
2375 {
2376 return false;
2377 }
2378 }
2379 }
2380 }
2381
2382 // Check the AttributeTypes : check for MatchingRules, Syntaxes
2383 LOG.debug( "Checking AttributeTypes..." );
2384
2385 for ( AttributeType attributeType : attributeTypeRegistry )
2386 {
2387 // Check that each AttributeType has a SYNTAX
2388 if ( attributeType.getSyntax() == null )
2389 {
2390 LOG.debug( "The AttributeType {} has no Syntax", attributeType );
2391
2392 return false;
2393 }
2394
2395 if ( !ldapSyntaxRegistry.contains( attributeType.getSyntax().getOid() ) )
2396 {
2397 LOG.debug( "Cannot find the Syntax {} for the AttributeType {}", attributeType.getSyntax().getOid(),
2398 attributeType );
2399
2400 return false;
2401 }
2402
2403 // Check the references for AT -> S and S -> AT
2404 if ( !checkReferences( attributeType, attributeType.getSyntax(), "AttributeType" ) )
2405 {
2406 return false;
2407 }
2408
2409 // Check the EQUALITY MatchingRule
2410 if ( attributeType.getEquality() != null )
2411 {
2412 if ( !matchingRuleRegistry.contains( attributeType.getEquality().getOid() ) )
2413 {
2414 LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getEquality()
2415 .getOid(), attributeType );
2416
2417 return false;
2418 }
2419
2420 // Check the references for AT -> MR and MR -> AT
2421 if ( !checkReferences( attributeType, attributeType.getEquality(), "AttributeType" ) )
2422 {
2423 return false;
2424 }
2425 }
2426
2427 // Check the ORDERING MatchingRule
2428 if ( attributeType.getOrdering() != null )
2429 {
2430 if ( !matchingRuleRegistry.contains( attributeType.getOrdering().getOid() ) )
2431 {
2432 LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getOrdering()
2433 .getOid(), attributeType );
2434
2435 return false;
2436 }
2437
2438 // Check the references for AT -> MR and MR -> AT
2439 if ( !checkReferences( attributeType, attributeType.getOrdering(), "AttributeType" ) )
2440 {
2441 return false;
2442 }
2443 }
2444
2445 // Check the SUBSTR MatchingRule
2446 if ( attributeType.getSubstring() != null )
2447 {
2448 if ( !matchingRuleRegistry.contains( attributeType.getSubstring().getOid() ) )
2449 {
2450 LOG.debug( "Cannot find the MatchingRule {} for the AttributeType {}", attributeType.getSubstring()
2451 .getOid(), attributeType );
2452
2453 return false;
2454 }
2455
2456 // Check the references for AT -> MR and MR -> AT
2457 if ( !checkReferences( attributeType, attributeType.getSubstring(), "AttributeType" ) )
2458 {
2459 return false;
2460 }
2461 }
2462
2463 // Check the SUP
2464 if ( attributeType.getSuperior() != null )
2465 {
2466 AttributeType superior = attributeType.getSuperior();
2467
2468 if ( !attributeTypeRegistry.contains( superior.getOid() ) )
2469 {
2470 LOG.debug( "Cannot find the AttributeType {} for the AttributeType {} SUPERIOR", superior,
2471 attributeType );
2472
2473 return false;
2474 }
2475
2476 // Check the references : AT -> AT and AT -> AT (SUPERIOR)
2477 if ( !checkReferences( attributeType, superior, "AttributeType" ) )
2478 {
2479 return false;
2480 }
2481 }
2482 }
2483
2484 return true;
2485 }
2486
2487
2488 /**
2489 * Clone the Registries. This is done in two steps :
2490 * - first clone the SchemaObjetc registries
2491 * - second restore the relation between them
2492 */
2493 public Registries clone() throws CloneNotSupportedException
2494 {
2495 // First clone the structure
2496 Registries clone = ( Registries ) super.clone();
2497
2498 // Now, clone the oidRegistry
2499 clone.globalOidRegistry = globalOidRegistry.copy();
2500
2501 // We have to clone every SchemaObject registries now
2502 clone.attributeTypeRegistry = attributeTypeRegistry.copy();
2503 clone.comparatorRegistry = comparatorRegistry.copy();
2504 clone.ditContentRuleRegistry = ditContentRuleRegistry.copy();
2505 clone.ditStructureRuleRegistry = ditStructureRuleRegistry.copy();
2506 clone.ldapSyntaxRegistry = ldapSyntaxRegistry.copy();
2507 clone.matchingRuleRegistry = matchingRuleRegistry.copy();
2508 clone.matchingRuleUseRegistry = matchingRuleUseRegistry.copy();
2509 clone.nameFormRegistry = nameFormRegistry.copy();
2510 clone.normalizerRegistry = normalizerRegistry.copy();
2511 clone.objectClassRegistry = objectClassRegistry.copy();
2512 clone.syntaxCheckerRegistry = syntaxCheckerRegistry.copy();
2513
2514 // Store all the SchemaObjects into the globalOid registry
2515 for ( AttributeType attributeType : clone.attributeTypeRegistry )
2516 {
2517 clone.globalOidRegistry.put( attributeType );
2518 }
2519
2520 for ( DITContentRule ditContentRule : clone.ditContentRuleRegistry )
2521 {
2522 clone.globalOidRegistry.put( ditContentRule );
2523 }
2524
2525 for ( DITStructureRule ditStructureRule : clone.ditStructureRuleRegistry )
2526 {
2527 clone.globalOidRegistry.put( ditStructureRule );
2528 }
2529
2530 for ( MatchingRule matchingRule : clone.matchingRuleRegistry )
2531 {
2532 clone.globalOidRegistry.put( matchingRule );
2533 }
2534
2535 for ( MatchingRuleUse matchingRuleUse : clone.matchingRuleUseRegistry )
2536 {
2537 clone.globalOidRegistry.put( matchingRuleUse );
2538 }
2539
2540 for ( NameForm nameForm : clone.nameFormRegistry )
2541 {
2542 clone.globalOidRegistry.put( nameForm );
2543 }
2544
2545 for ( ObjectClass objectClass : clone.objectClassRegistry )
2546 {
2547 clone.globalOidRegistry.put( objectClass );
2548 }
2549
2550 for ( LdapSyntax syntax : clone.ldapSyntaxRegistry )
2551 {
2552 clone.globalOidRegistry.put( syntax );
2553 }
2554
2555 // Clone the schema list
2556 clone.loadedSchemas = new HashMap<String, Schema>();
2557
2558 for ( String schemaName : loadedSchemas.keySet() )
2559 {
2560 // We don't clone the schemas
2561 clone.loadedSchemas.put( schemaName, loadedSchemas.get( schemaName ) );
2562 }
2563
2564 // Clone the Using and usedBy structures
2565 // They will be empty
2566 clone.using = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
2567 clone.usedBy = new HashMap<SchemaObjectWrapper, Set<SchemaObjectWrapper>>();
2568
2569 // Last, rebuild the using and usedBy references
2570 clone.buildReferences();
2571
2572 // Now, check the registries. We don't care about errors
2573 clone.checkRefInteg();
2574
2575 clone.schemaObjects = new HashMap<String, Set<SchemaObjectWrapper>>();
2576
2577 // Last, not least, clone the SchemaObjects Map, and reference all the copied
2578 // SchemaObjects
2579 for ( String schemaName : schemaObjects.keySet() )
2580 {
2581 Set<SchemaObjectWrapper> objects = new HashSet<SchemaObjectWrapper>();
2582
2583 for ( SchemaObjectWrapper schemaObjectWrapper : schemaObjects.get( schemaName ) )
2584 {
2585 SchemaObject original = schemaObjectWrapper.get();
2586
2587 try
2588 {
2589 if ( ! ( original instanceof LoadableSchemaObject ) )
2590 {
2591 SchemaObject copy = clone.globalOidRegistry.getSchemaObject( original.getOid() );
2592 SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( copy );
2593 objects.add( newWrapper );
2594 }
2595 else
2596 {
2597 SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( original );
2598 objects.add( newWrapper );
2599 }
2600 }
2601 catch ( NamingException ne )
2602 {
2603 int i = 0;
2604 i++;
2605 // Nothing to do
2606 }
2607 }
2608
2609 clone.schemaObjects.put( schemaName, objects );
2610 }
2611
2612 return clone;
2613 }
2614
2615
2616 /**
2617 * Tells if the Registries is permissive or if it must be checked
2618 * against inconsistencies.
2619 *
2620 * @return True if SchemaObjects can be added even if they break the consistency
2621 */
2622 public boolean isRelaxed()
2623 {
2624 return isRelaxed;
2625 }
2626
2627
2628 /**
2629 * Tells if the Registries is strict.
2630 *
2631 * @return True if SchemaObjects cannot be added if they break the consistency
2632 */
2633 public boolean isStrict()
2634 {
2635 return !isRelaxed;
2636 }
2637
2638
2639 /**
2640 * Change the Registries to a relaxed mode, where invalid SchemaObjects
2641 * can be registered.
2642 */
2643 public void setRelaxed()
2644 {
2645 isRelaxed = RELAXED;
2646 }
2647
2648
2649 /**
2650 * Change the Registries to a strict mode, where invalid SchemaObjects
2651 * cannot be registered.
2652 */
2653 public void setStrict()
2654 {
2655 isRelaxed = STRICT;
2656 }
2657
2658
2659 /**
2660 * Tells if the Registries accept disabled elements.
2661 *
2662 * @return True if disabled SchemaObjects can be added
2663 */
2664 public boolean isDisabledAccepted()
2665 {
2666 return disabledAccepted;
2667 }
2668
2669
2670 /**
2671 * Check that we can remove a given SchemaObject without breaking some of its references.
2672 * We will return the list of refereing objects.
2673 *
2674 * @param schemaObject The SchemaObject to remove
2675 * @return The list of SchemaObjects referencing the SchemaObjetc we want to remove
2676 */
2677 public Set<SchemaObjectWrapper> getReferencing( SchemaObject schemaObject )
2678 {
2679 SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject );
2680
2681 return usedBy.get( schemaObjectWrapper );
2682 }
2683
2684
2685 /**
2686 * Change the Registries behavior regarding disabled SchemaObject element.
2687 *
2688 * @param acceptDisabled If <code>false</code>, then the Registries won't accept
2689 * disabled SchemaObject or enabled SchemaObject from disabled schema
2690 */
2691 public void setDisabledAccepted( boolean disabledAccepted )
2692 {
2693 this.disabledAccepted = disabledAccepted;
2694 }
2695
2696
2697 /**
2698 * Clear the registries from all its elements
2699 *
2700 * @throws NamingException If something goes wrong
2701 */
2702 public void clear() throws NamingException
2703 {
2704 // The AttributeTypeRegistry
2705 if ( attributeTypeRegistry != null )
2706 {
2707 attributeTypeRegistry.clear();
2708 }
2709
2710 // The ComparatorRegistry
2711 if ( comparatorRegistry != null )
2712 {
2713 comparatorRegistry.clear();
2714 }
2715
2716 // The DitContentRuleRegistry
2717 if ( ditContentRuleRegistry != null )
2718 {
2719 ditContentRuleRegistry.clear();
2720 }
2721
2722 // The DitStructureRuleRegistry
2723 if ( ditStructureRuleRegistry != null )
2724 {
2725 ditStructureRuleRegistry.clear();
2726 }
2727
2728 // The MatchingRuleRegistry
2729 if ( matchingRuleRegistry != null )
2730 {
2731 matchingRuleRegistry.clear();
2732 }
2733
2734 // The MatchingRuleUseRegistry
2735 if ( matchingRuleUseRegistry != null )
2736 {
2737 matchingRuleUseRegistry.clear();
2738 }
2739
2740 // The NameFormRegistry
2741 if ( nameFormRegistry != null )
2742 {
2743 nameFormRegistry.clear();
2744 }
2745
2746 // The NormalizerRegistry
2747 if ( normalizerRegistry != null )
2748 {
2749 normalizerRegistry.clear();
2750 }
2751
2752 // The ObjectClassRegistry
2753 if ( objectClassRegistry != null )
2754 {
2755 objectClassRegistry.clear();
2756 }
2757
2758 // The SyntaxRegistry
2759 if ( ldapSyntaxRegistry != null )
2760 {
2761 ldapSyntaxRegistry.clear();
2762 }
2763
2764 // The SyntaxCheckerRegistry
2765 if ( syntaxCheckerRegistry != null )
2766 {
2767 syntaxCheckerRegistry.clear();
2768 }
2769
2770 // Clear the schemaObjects map
2771 for ( String schemaName : schemaObjects.keySet() )
2772 {
2773 Set<SchemaObjectWrapper> wrapperSet = schemaObjects.get( schemaName );
2774
2775 wrapperSet.clear();
2776 }
2777
2778 schemaObjects.clear();
2779
2780 // Clear the usedBy map
2781 for ( SchemaObjectWrapper wrapper : usedBy.keySet() )
2782 {
2783 Set<SchemaObjectWrapper> wrapperSet = usedBy.get( wrapper );
2784
2785 wrapperSet.clear();
2786 }
2787
2788 usedBy.clear();
2789
2790 // Clear the using map
2791 for ( SchemaObjectWrapper wrapper : using.keySet() )
2792 {
2793 Set<SchemaObjectWrapper> wrapperSet = using.get( wrapper );
2794
2795 wrapperSet.clear();
2796 }
2797
2798 using.clear();
2799
2800 // Clear the global OID registry
2801 globalOidRegistry.clear();
2802
2803 // Clear the loadedSchema Map
2804 loadedSchemas.clear();
2805 }
2806
2807
2808 /**
2809 * @see Object#toString()
2810 */
2811 public String toString()
2812 {
2813 StringBuilder sb = new StringBuilder();
2814
2815 sb.append( "Registries [" );
2816
2817 if ( isRelaxed )
2818 {
2819 sb.append( "RELAXED," );
2820 }
2821 else
2822 {
2823 sb.append( "STRICT," );
2824 }
2825
2826 if ( disabledAccepted )
2827 {
2828 sb.append( " Disabled accepted] :\n" );
2829 }
2830 else
2831 {
2832 sb.append( " Disabled forbidden] :\n" );
2833 }
2834
2835 sb.append( "loaded schemas [" );
2836 boolean isFirst = true;
2837
2838 for ( String schema : loadedSchemas.keySet() )
2839 {
2840 if ( isFirst )
2841 {
2842 isFirst = false;
2843 }
2844 else
2845 {
2846 sb.append( ", " );
2847 }
2848
2849 sb.append( schema );
2850 }
2851
2852 sb.append( "]\n" );
2853
2854 sb.append( "AttributeTypes : " ).append( attributeTypeRegistry.size() ).append( "\n" );
2855 sb.append( "Comparators : " ).append( comparatorRegistry.size() ).append( "\n" );
2856 sb.append( "DitContentRules : " ).append( ditContentRuleRegistry.size() ).append( "\n" );
2857 sb.append( "DitStructureRules : " ).append( ditStructureRuleRegistry.size() ).append( "\n" );
2858 sb.append( "MatchingRules : " ).append( matchingRuleRegistry.size() ).append( "\n" );
2859 sb.append( "MatchingRuleUses : " ).append( matchingRuleUseRegistry.size() ).append( "\n" );
2860 sb.append( "NameForms : " ).append( nameFormRegistry.size() ).append( "\n" );
2861 sb.append( "Normalizers : " ).append( normalizerRegistry.size() ).append( "\n" );
2862 sb.append( "ObjectClasses : " ).append( objectClassRegistry.size() ).append( "\n" );
2863 sb.append( "Syntaxes : " ).append( ldapSyntaxRegistry.size() ).append( "\n" );
2864 sb.append( "SyntaxCheckers : " ).append( syntaxCheckerRegistry.size() ).append( "\n" );
2865
2866 sb.append( "GlobalOidRegistry : " ).append( globalOidRegistry.size() ).append( '\n' );
2867
2868 return sb.toString();
2869 }
2870 }