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