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 }