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