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