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.schemamanager.impl; 021 022 023import java.io.IOException; 024import java.util.ArrayList; 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.constants.SchemaConstants; 034import org.apache.directory.shared.ldap.model.entry.Entry; 035import org.apache.directory.shared.ldap.model.exception.LdapException; 036import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException; 037import org.apache.directory.shared.ldap.model.exception.LdapOtherException; 038import org.apache.directory.shared.ldap.model.exception.LdapProtocolErrorException; 039import org.apache.directory.shared.ldap.model.exception.LdapSchemaException; 040import org.apache.directory.shared.ldap.model.exception.LdapSchemaExceptionCodes; 041import org.apache.directory.shared.ldap.model.exception.LdapUnwillingToPerformException; 042import org.apache.directory.shared.ldap.model.message.ResultCodeEnum; 043import org.apache.directory.shared.ldap.model.name.Dn; 044import org.apache.directory.shared.ldap.model.schema.AttributeType; 045import org.apache.directory.shared.ldap.model.schema.EntityFactory; 046import org.apache.directory.shared.ldap.model.schema.LdapComparator; 047import org.apache.directory.shared.ldap.model.schema.LdapSyntax; 048import org.apache.directory.shared.ldap.model.schema.LoadableSchemaObject; 049import org.apache.directory.shared.ldap.model.schema.MatchingRule; 050import org.apache.directory.shared.ldap.model.schema.Normalizer; 051import org.apache.directory.shared.ldap.model.schema.ObjectClass; 052import org.apache.directory.shared.ldap.model.schema.SchemaManager; 053import org.apache.directory.shared.ldap.model.schema.SchemaObject; 054import org.apache.directory.shared.ldap.model.schema.SchemaObjectWrapper; 055import org.apache.directory.shared.ldap.model.schema.SyntaxChecker; 056import org.apache.directory.shared.ldap.model.schema.normalizers.OidNormalizer; 057import org.apache.directory.shared.ldap.model.schema.registries.AttributeTypeRegistry; 058import org.apache.directory.shared.ldap.model.schema.registries.ComparatorRegistry; 059import org.apache.directory.shared.ldap.model.schema.registries.DITContentRuleRegistry; 060import org.apache.directory.shared.ldap.model.schema.registries.DITStructureRuleRegistry; 061import org.apache.directory.shared.ldap.model.schema.registries.ImmutableAttributeTypeRegistry; 062import org.apache.directory.shared.ldap.model.schema.registries.ImmutableComparatorRegistry; 063import org.apache.directory.shared.ldap.model.schema.registries.ImmutableDITContentRuleRegistry; 064import org.apache.directory.shared.ldap.model.schema.registries.ImmutableDITStructureRuleRegistry; 065import org.apache.directory.shared.ldap.model.schema.registries.ImmutableLdapSyntaxRegistry; 066import org.apache.directory.shared.ldap.model.schema.registries.ImmutableMatchingRuleRegistry; 067import org.apache.directory.shared.ldap.model.schema.registries.ImmutableMatchingRuleUseRegistry; 068import org.apache.directory.shared.ldap.model.schema.registries.ImmutableNameFormRegistry; 069import org.apache.directory.shared.ldap.model.schema.registries.ImmutableNormalizerRegistry; 070import org.apache.directory.shared.ldap.model.schema.registries.ImmutableObjectClassRegistry; 071import org.apache.directory.shared.ldap.model.schema.registries.ImmutableSyntaxCheckerRegistry; 072import org.apache.directory.shared.ldap.model.schema.registries.LdapSyntaxRegistry; 073import org.apache.directory.shared.ldap.model.schema.registries.MatchingRuleRegistry; 074import org.apache.directory.shared.ldap.model.schema.registries.MatchingRuleUseRegistry; 075import org.apache.directory.shared.ldap.model.schema.registries.NameFormRegistry; 076import org.apache.directory.shared.ldap.model.schema.registries.NormalizerRegistry; 077import org.apache.directory.shared.ldap.model.schema.registries.ObjectClassRegistry; 078import org.apache.directory.shared.ldap.model.schema.registries.OidRegistry; 079import org.apache.directory.shared.ldap.model.schema.registries.Registries; 080import org.apache.directory.shared.ldap.model.schema.registries.Schema; 081import org.apache.directory.shared.ldap.model.schema.registries.SchemaLoader; 082import org.apache.directory.shared.ldap.model.schema.registries.SyntaxCheckerRegistry; 083import org.apache.directory.shared.ldap.schemaloader.JarLdifSchemaLoader; 084import org.apache.directory.shared.ldap.schemaloader.SchemaEntityFactory; 085import org.apache.directory.shared.util.Strings; 086import org.apache.directory.shared.util.exception.NotImplementedException; 087import org.slf4j.Logger; 088import org.slf4j.LoggerFactory; 089 090 091/** 092 * The SchemaManager class : it handles all the schema operations (addition, removal, 093 * modification). 094 * 095 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 096 */ 097public class DefaultSchemaManager implements SchemaManager 098{ 099 /** static class logger */ 100 private static final Logger LOG = LoggerFactory.getLogger( DefaultSchemaManager.class ); 101 102 /** The NamingContext this SchemaManager is associated with */ 103 private Dn namingContext; 104 105 /** The global registries for this namingContext */ 106 private volatile Registries registries; 107 108 /** The list of errors produced when loading some schema elements */ 109 private List<Throwable> errors; 110 111 /** The Schema schemaLoader used by this SchemaManager */ 112 private SchemaLoader schemaLoader; 113 114 /** the factory that generates respective SchemaObjects from LDIF entries */ 115 private final EntityFactory factory; 116 117 /** the normalized name for the schema modification attributes */ 118 private Dn schemaModificationAttributesDn; 119 120 /** A Map containing all the schema being dependent from a schema */ 121 private Map<String, Set<String>> schemaDependences = new HashMap<String, Set<String>>(); 122 123 /** A flag indicating that the SchemaManager is relaxed or not */ 124 private boolean isRelaxed = STRICT; 125 126 /** Two flags for RELAXED and STRICT, this is STRICT */ 127 public static final boolean STRICT = false; 128 129 /** Two flags for RELAXED and STRICT, this is RELAXED */ 130 public static final boolean RELAXED = true; 131 132 133 /** 134 * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader 135 * 136 * @param loader The schema loader to use 137 */ 138 public DefaultSchemaManager() throws Exception 139 { 140 // Default to the the root (one schemaManager for all the entries 141 namingContext = Dn.ROOT_DSE; 142 this.schemaLoader = new JarLdifSchemaLoader(); 143 errors = new ArrayList<Throwable>(); 144 registries = new Registries( this ); 145 factory = new SchemaEntityFactory(); 146 isRelaxed = STRICT; 147 loadAllEnabled(); 148 } 149 150 151 /** 152 * Creates a new instance of DefaultSchemaManager with the default schema schemaLoader 153 * 154 * @param loader The schema loader to use 155 */ 156 public DefaultSchemaManager( SchemaLoader loader ) 157 { 158 // Default to the the root (one schemaManager for all the entries 159 namingContext = Dn.ROOT_DSE; 160 this.schemaLoader = loader; 161 errors = new ArrayList<Throwable>(); 162 registries = new Registries( this ); 163 factory = new SchemaEntityFactory(); 164 isRelaxed = STRICT; 165 } 166 167 168 /** 169 * Creates a new instance of DefaultSchemaManager, for a specific 170 * naming context 171 * 172 * @param loader The schema loader to use 173 * @param namingContext The associated NamingContext 174 */ 175 public DefaultSchemaManager( SchemaLoader loader, Dn namingContext ) 176 { 177 this.namingContext = namingContext; 178 this.schemaLoader = loader; 179 errors = new ArrayList<Throwable>(); 180 registries = new Registries( this ); 181 factory = new SchemaEntityFactory(); 182 isRelaxed = STRICT; 183 } 184 185 186 //----------------------------------------------------------------------- 187 // Helper methods 188 //----------------------------------------------------------------------- 189 /** 190 * Clone the registries before doing any modification on it. Relax it 191 * too so that we can update it. 192 */ 193 private Registries cloneRegistries() throws LdapException 194 { 195 try 196 { 197 // Relax the controls at first 198 errors = new ArrayList<Throwable>(); 199 200 // Clone the Registries 201 Registries clonedRegistries = registries.clone(); 202 203 // And update references. We may have errors, that may be fixed 204 // by the new loaded schemas. 205 errors = clonedRegistries.checkRefInteg(); 206 207 // Now, relax the cloned Registries if there is no error 208 clonedRegistries.setRelaxed(); 209 210 return clonedRegistries; 211 } 212 catch ( CloneNotSupportedException cnse ) 213 { 214 throw new LdapOtherException( cnse.getMessage() ); 215 } 216 } 217 218 219 /** 220 * Transform a String[] array of schema to a Schema[] 221 */ 222 private Schema[] toArray( String... schemas ) throws LdapException 223 { 224 Schema[] schemaArray = new Schema[schemas.length]; 225 int n = 0; 226 227 for ( String schemaName : schemas ) 228 { 229 Schema schema = schemaLoader.getSchema( schemaName ); 230 231 if ( schema != null ) 232 { 233 schemaArray[n++] = schema; 234 } 235 else 236 { 237 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( 238 I18n.ERR_11001, schemaName ) ); 239 } 240 } 241 242 return schemaArray; 243 } 244 245 246 private void addSchemaObjects( Schema schema, Registries registries ) throws LdapException 247 { 248 // Create a content container for this schema 249 registries.addSchema( schema.getSchemaName() ); 250 251 // And inject any existing SchemaObject into the registries 252 try 253 { 254 addComparators( schema, registries ); 255 addNormalizers( schema, registries ); 256 addSyntaxCheckers( schema, registries ); 257 addSyntaxes( schema, registries ); 258 addMatchingRules( schema, registries ); 259 addAttributeTypes( schema, registries ); 260 addObjectClasses( schema, registries ); 261 addMatchingRuleUses( schema, registries ); 262 addDitContentRules( schema, registries ); 263 addNameForms( schema, registries ); 264 addDitStructureRules( schema, registries ); 265 } 266 catch ( IOException ioe ) 267 { 268 throw new LdapOtherException( ioe.getMessage() ); 269 } 270 271 // TODO Add some listener handling at this point 272 //notifyListenerOrRegistries( schema, registries ); 273 } 274 275 276 /** 277 * Delete all the schemaObjects for a given schema from the registries 278 */ 279 private void deleteSchemaObjects( Schema schema, Registries registries ) throws LdapException 280 { 281 Map<String, Set<SchemaObjectWrapper>> schemaObjects = registries.getObjectBySchemaName(); 282 Set<SchemaObjectWrapper> content = schemaObjects.get( Strings.toLowerCase( schema.getSchemaName() ) ); 283 284 List<SchemaObject> toBeDeleted = new ArrayList<SchemaObject>(); 285 286 // Buid an intermediate list to avoid concurrent modifications 287 for ( SchemaObjectWrapper schemaObjectWrapper : content ) 288 { 289 toBeDeleted.add( schemaObjectWrapper.get() ); 290 } 291 292 for ( SchemaObject schemaObject : toBeDeleted ) 293 { 294 registries.delete( errors, schemaObject ); 295 } 296 } 297 298 299 //----------------------------------------------------------------------- 300 // API methods 301 //----------------------------------------------------------------------- 302 /** 303 * {@inheritDoc} 304 */ 305 public boolean disable( Schema... schemas ) throws LdapException 306 { 307 boolean disabled = false; 308 309 // Reset the errors if not null 310 if ( errors != null ) 311 { 312 errors.clear(); 313 } 314 315 // Work on a cloned and relaxed registries 316 Registries clonedRegistries = cloneRegistries(); 317 clonedRegistries.setRelaxed(); 318 319 for ( Schema schema : schemas ) 320 { 321 unload( clonedRegistries, schema ); 322 } 323 324 // Build the cross references 325 errors = clonedRegistries.buildReferences(); 326 327 // Destroy the clonedRegistry 328 clonedRegistries.clear(); 329 330 if ( errors.isEmpty() ) 331 { 332 // Ok no errors. Check the registries now 333 errors = clonedRegistries.checkRefInteg(); 334 335 if ( errors.isEmpty() ) 336 { 337 // We are golden : let's apply the schemas in the real registries 338 for ( Schema schema : schemas ) 339 { 340 unload( registries, schema ); 341 schema.disable(); 342 } 343 344 // Build the cross references 345 errors = registries.buildReferences(); 346 registries.setStrict(); 347 348 disabled = true; 349 } 350 } 351 352 // clear the cloned registries 353 clonedRegistries.clear(); 354 355 return disabled; 356 } 357 358 359 /** 360 * {@inheritDoc} 361 */ 362 public boolean disable( String... schemaNames ) throws LdapException 363 { 364 Schema[] schemas = toArray( schemaNames ); 365 366 return disable( schemas ); 367 } 368 369 370 /** 371 * {@inheritDoc} 372 */ 373 public boolean disabledRelaxed( Schema... schemas ) 374 { 375 // TODO Auto-generated method stub 376 return false; 377 } 378 379 380 /** 381 * {@inheritDoc} 382 */ 383 public boolean disabledRelaxed( String... schemas ) 384 { 385 // TODO Auto-generated method stub 386 return false; 387 } 388 389 390 /** 391 * {@inheritDoc} 392 */ 393 public List<Schema> getDisabled() 394 { 395 List<Schema> disabled = new ArrayList<Schema>(); 396 397 for ( Schema schema : registries.getLoadedSchemas().values() ) 398 { 399 if ( schema.isDisabled() ) 400 { 401 disabled.add( schema ); 402 } 403 } 404 405 return disabled; 406 } 407 408 409 /** 410 * {@inheritDoc} 411 */ 412 public boolean enable( Schema... schemas ) throws LdapException 413 { 414 boolean enabled = false; 415 416 // Reset the errors if not null 417 if ( errors != null ) 418 { 419 errors.clear(); 420 } 421 422 // Work on a cloned and relaxed registries 423 Registries clonedRegistries = cloneRegistries(); 424 clonedRegistries.setRelaxed(); 425 426 Set<Schema> disabledSchemas = new HashSet<Schema>(); 427 428 for ( Schema schema : schemas ) 429 { 430 if ( schema.getDependencies() != null ) 431 { 432 for ( String dependency : schema.getDependencies() ) 433 { 434 Schema dependencySchema = schemaLoader.getSchema( dependency ); 435 436 if ( dependencySchema.isDisabled() ) 437 { 438 disabledSchemas.add( dependencySchema ); 439 } 440 } 441 } 442 443 schema.enable(); 444 load( clonedRegistries, schema ); 445 } 446 447 // Revert back the disabled schema to disabled 448 for ( Schema disabledSchema : disabledSchemas ) 449 { 450 if ( disabledSchema.isEnabled() ) 451 { 452 disabledSchema.disable(); 453 } 454 } 455 456 // Build the cross references 457 errors = clonedRegistries.buildReferences(); 458 459 // Destroy the clonedRegistry 460 clonedRegistries.clear(); 461 462 if ( errors.isEmpty() ) 463 { 464 // Ok no errors. Check the registries now 465 errors = clonedRegistries.checkRefInteg(); 466 467 if ( errors.isEmpty() ) 468 { 469 // We are golden : let's apply the schemas in the real registries 470 for ( Schema schema : schemas ) 471 { 472 schema.enable(); 473 load( registries, schema ); 474 } 475 476 // Build the cross references 477 errors = registries.buildReferences(); 478 registries.setStrict(); 479 480 enabled = true; 481 } 482 } 483 484 // clear the cloned registries 485 clonedRegistries.clear(); 486 487 return enabled; 488 } 489 490 491 /** 492 * {@inheritDoc} 493 */ 494 public boolean enable( String... schemaNames ) throws LdapException 495 { 496 Schema[] schemas = toArray( schemaNames ); 497 return enable( schemas ); 498 } 499 500 501 /** 502 * {@inheritDoc} 503 */ 504 public boolean enableRelaxed( Schema... schemas ) 505 { 506 // TODO Auto-generated method stub 507 return false; 508 } 509 510 511 /** 512 * {@inheritDoc} 513 */ 514 public boolean enableRelaxed( String... schemas ) 515 { 516 // TODO Auto-generated method stub 517 return false; 518 } 519 520 521 /** 522 * {@inheritDoc} 523 */ 524 public List<Schema> getEnabled() 525 { 526 List<Schema> enabled = new ArrayList<Schema>(); 527 528 for ( Schema schema : registries.getLoadedSchemas().values() ) 529 { 530 if ( schema.isEnabled() ) 531 { 532 enabled.add( schema ); 533 } 534 } 535 536 return enabled; 537 } 538 539 540 /** 541 * {@inheritDoc} 542 */ 543 public List<Throwable> getErrors() 544 { 545 return errors; 546 } 547 548 549 /** 550 * {@inheritDoc} 551 */ 552 public Registries getRegistries() 553 { 554 return registries; 555 } 556 557 558 /** 559 * {@inheritDoc} 560 */ 561 public boolean isDisabledAccepted() 562 { 563 // TODO Auto-generated method stub 564 return false; 565 } 566 567 568 /** 569 * {@inheritDoc} 570 */ 571 public boolean load( Schema... schemas ) throws LdapException 572 { 573 if ( schemas.length == 0 ) 574 { 575 return true; 576 } 577 578 boolean loaded = false; 579 580 // Reset the errors if not null 581 if ( errors != null ) 582 { 583 errors.clear(); 584 } 585 586 // Work on a cloned and relaxed registries 587 Registries clonedRegistries = cloneRegistries(); 588 clonedRegistries.setRelaxed(); 589 590 // Load the schemas 591 for ( Schema schema : schemas ) 592 { 593 boolean singleSchemaLoaded = load( clonedRegistries, schema ); 594 595 // return false if the schema was not loaded in the first place 596 if ( !singleSchemaLoaded ) 597 { 598 return false; 599 } 600 } 601 602 // Build the cross references 603 errors = clonedRegistries.buildReferences(); 604 605 if ( errors.isEmpty() ) 606 { 607 // Ok no errors. Check the registries now 608 errors = clonedRegistries.checkRefInteg(); 609 610 if ( errors.isEmpty() ) 611 { 612 // We are golden : let's apply the schema in the real registries 613 registries.setRelaxed(); 614 615 // Load the schemas 616 for ( Schema schema : schemas ) 617 { 618 load( registries, schema ); 619 620 // Update the schema dependences if needed 621 622 if ( schema.getDependencies() != null ) 623 { 624 for ( String dep : schema.getDependencies() ) 625 { 626 Set<String> deps = schemaDependences.get( dep ); 627 628 if ( deps == null ) 629 { 630 deps = new HashSet<String>(); 631 deps.add( schema.getSchemaName() ); 632 } 633 634 // Replace the dependences 635 schemaDependences.put( dep, deps ); 636 } 637 } 638 639 // add the schema to the schemaLoader 640 schemaLoader.addSchema( schema ); 641 } 642 643 // Build the cross references 644 errors = registries.buildReferences(); 645 registries.setStrict(); 646 647 loaded = true; 648 } 649 } 650 651 // clear the cloned registries 652 clonedRegistries.clear(); 653 654 return loaded; 655 } 656 657 658 /** 659 * {@inheritDoc} 660 */ 661 public boolean load( String... schemaNames ) throws Exception 662 { 663 if ( schemaNames.length == 0 ) 664 { 665 return true; 666 } 667 668 Schema[] schemas = toArray( schemaNames ); 669 670 return load( schemas ); 671 } 672 673 674 /** 675 * Load the schema in the registries. We will load everything accordingly to the two flags : 676 * - isRelaxed 677 * - disabledAccepted 678 */ 679 private boolean load( Registries registries, Schema schema ) throws LdapException 680 { 681 if ( schema == null ) 682 { 683 LOG.info( "The schema is null" ); 684 return false; 685 } 686 687 // First avoid loading twice the same schema 688 if ( registries.isSchemaLoaded( schema.getSchemaName() ) ) 689 { 690 return true; 691 } 692 693 if ( schema.isDisabled() ) 694 { 695 if ( registries.isDisabledAccepted() ) 696 { 697 LOG.info( "Loading {} disabled schema: \n{}", schema.getSchemaName(), schema ); 698 699 registries.schemaLoaded( schema ); 700 addSchemaObjects( schema, registries ); 701 } 702 else 703 { 704 return false; 705 } 706 } 707 else 708 { 709 LOG.info( "Loading {} enabled schema: \n{}", schema.getSchemaName(), schema ); 710 711 // Check that the dependencies, if any, are correct 712 if ( schema.getDependencies() != null ) 713 { 714 for ( String dependency : schema.getDependencies() ) 715 { 716 Schema dependencySchema = schemaLoader.getSchema( dependency ); 717 718 if ( dependencySchema == null ) 719 { 720 // The dependency has not been loaded. 721 String msg = I18n.err( I18n.ERR_11002, schema.getSchemaName() ); 722 LOG.info( msg ); 723 Throwable error = new LdapProtocolErrorException( msg ); 724 errors.add( error ); 725 return false; 726 } 727 728 // If the dependency is disabled, then enable it 729 if ( dependencySchema.isDisabled() ) 730 { 731 dependencySchema.enable(); 732 733 if ( load( registries, dependencySchema ) == false ) 734 { 735 dependencySchema.disable(); 736 737 return false; 738 } 739 } 740 } 741 } 742 743 registries.schemaLoaded( schema ); 744 addSchemaObjects( schema, registries ); 745 } 746 747 return true; 748 } 749 750 751 /** 752 * Unload the schema from the registries. We will unload everything accordingly to the two flags : 753 * - isRelaxed 754 * - disabledAccepted 755 */ 756 // False positive 757 @SuppressWarnings("PMD.UnusedPrivateMethod") 758 private boolean unload( Registries registries, Schema schema ) throws LdapException 759 { 760 if ( schema == null ) 761 { 762 LOG.info( "The schema is null" ); 763 return false; 764 } 765 766 // First avoid unloading twice the same schema 767 if ( !registries.isSchemaLoaded( schema.getSchemaName() ) ) 768 { 769 return true; 770 } 771 772 if ( schema.isEnabled() ) 773 { 774 LOG.info( "Unloading {} schema: \n{}", schema.getSchemaName(), schema ); 775 776 deleteSchemaObjects( schema, registries ); 777 registries.schemaUnloaded( schema ); 778 } 779 780 return true; 781 } 782 783 784 /** 785 * Add all the Schema's AttributeTypes 786 */ 787 private void addAttributeTypes( Schema schema, Registries registries ) throws LdapException, IOException 788 { 789 for ( Entry entry : schemaLoader.loadAttributeTypes( schema ) ) 790 { 791 AttributeType attributeType = factory.getAttributeType( this, entry, registries, schema.getSchemaName() ); 792 793 addSchemaObject( registries, attributeType, schema ); 794 } 795 } 796 797 798 /** 799 * Add all the Schema's comparators 800 */ 801 private void addComparators( Schema schema, Registries registries ) throws LdapException, IOException 802 { 803 for ( Entry entry : schemaLoader.loadComparators( schema ) ) 804 { 805 LdapComparator<?> comparator = factory.getLdapComparator( this, entry, registries, schema.getSchemaName() ); 806 807 addSchemaObject( registries, comparator, schema ); 808 } 809 } 810 811 812 /** 813 * Add all the Schema's DitContentRules 814 */ 815 // Not yet implemented, but may be used 816 @SuppressWarnings("PMD.UnusedFormalParameter") 817 private void addDitContentRules( Schema schema, Registries registries ) throws LdapException, IOException 818 { 819 if ( !schemaLoader.loadDitContentRules( schema ).isEmpty() ) 820 { 821 throw new NotImplementedException( I18n.err( I18n.ERR_11003 ) ); 822 } 823 } 824 825 826 /** 827 * Add all the Schema's DitStructureRules 828 */ 829 // Not yet implemented, but may be used 830 @SuppressWarnings("PMD.UnusedFormalParameter") 831 private void addDitStructureRules( Schema schema, Registries registries ) throws LdapException, IOException 832 { 833 if ( !schemaLoader.loadDitStructureRules( schema ).isEmpty() ) 834 { 835 throw new NotImplementedException( I18n.err( I18n.ERR_11004 ) ); 836 } 837 } 838 839 840 /** 841 * Add all the Schema's MatchingRules 842 */ 843 private void addMatchingRules( Schema schema, Registries registries ) throws LdapException, IOException 844 { 845 for ( Entry entry : schemaLoader.loadMatchingRules( schema ) ) 846 { 847 MatchingRule matchingRule = factory.getMatchingRule( this, entry, registries, schema.getSchemaName() ); 848 849 addSchemaObject( registries, matchingRule, schema ); 850 } 851 } 852 853 854 /** 855 * Add all the Schema's MatchingRuleUses 856 */ 857 // Not yet implemented, but may be used 858 @SuppressWarnings("PMD.UnusedFormalParameter") 859 private void addMatchingRuleUses( Schema schema, Registries registries ) throws LdapException, IOException 860 { 861 if ( !schemaLoader.loadMatchingRuleUses( schema ).isEmpty() ) 862 { 863 throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) ); 864 } 865 // for ( Entry entry : schemaLoader.loadMatchingRuleUses( schema ) ) 866 // { 867 // throw new NotImplementedException( I18n.err( I18n.ERR_11005 ) ); 868 // } 869 } 870 871 872 /** 873 * Add all the Schema's NameForms 874 */ 875 // Not yet implemented, but may be used 876 @SuppressWarnings("PMD.UnusedFormalParameter") 877 private void addNameForms( Schema schema, Registries registries ) throws LdapException, IOException 878 { 879 if ( !schemaLoader.loadNameForms( schema ).isEmpty() ) 880 { 881 throw new NotImplementedException( I18n.err( I18n.ERR_11006 ) ); 882 } 883 } 884 885 886 /** 887 * Add all the Schema's Normalizers 888 */ 889 private void addNormalizers( Schema schema, Registries registries ) throws LdapException, IOException 890 { 891 for ( Entry entry : schemaLoader.loadNormalizers( schema ) ) 892 { 893 Normalizer normalizer = factory.getNormalizer( this, entry, registries, schema.getSchemaName() ); 894 895 addSchemaObject( registries, normalizer, schema ); 896 } 897 } 898 899 900 /** 901 * Add all the Schema's ObjectClasses 902 */ 903 private void addObjectClasses( Schema schema, Registries registries ) throws LdapException, IOException 904 { 905 for ( Entry entry : schemaLoader.loadObjectClasses( schema ) ) 906 { 907 ObjectClass objectClass = factory.getObjectClass( this, entry, registries, schema.getSchemaName() ); 908 909 addSchemaObject( registries, objectClass, schema ); 910 } 911 } 912 913 914 /** 915 * Add all the Schema's Syntaxes 916 */ 917 private void addSyntaxes( Schema schema, Registries registries ) throws LdapException, IOException 918 { 919 for ( Entry entry : schemaLoader.loadSyntaxes( schema ) ) 920 { 921 LdapSyntax syntax = factory.getSyntax( this, entry, registries, schema.getSchemaName() ); 922 923 addSchemaObject( registries, syntax, schema ); 924 } 925 } 926 927 928 /**Add 929 * Register all the Schema's SyntaxCheckers 930 */ 931 private void addSyntaxCheckers( Schema schema, Registries registries ) throws LdapException, IOException 932 { 933 for ( Entry entry : schemaLoader.loadSyntaxCheckers( schema ) ) 934 { 935 SyntaxChecker syntaxChecker = factory.getSyntaxChecker( this, entry, registries, schema.getSchemaName() ); 936 937 addSchemaObject( registries, syntaxChecker, schema ); 938 } 939 } 940 941 942 /** 943 * Add the schemaObject into the registries. 944 * 945 * @param registries The Registries 946 * @param schemaObject The SchemaObject containing the SchemaObject description 947 * @param schema The associated schema 948 * @return the created schemaObject instance 949 * @throws LdapException If the registering failed 950 */ 951 private SchemaObject addSchemaObject( Registries registries, SchemaObject schemaObject, Schema schema ) 952 throws LdapException 953 { 954 if ( registries.isRelaxed() ) 955 { 956 if ( registries.isDisabledAccepted() || ( schema.isEnabled() && schemaObject.isEnabled() ) ) 957 { 958 registries.add( errors, schemaObject ); 959 } 960 else 961 { 962 errors.add( new Throwable() ); 963 } 964 } 965 else 966 { 967 if ( schema.isEnabled() && schemaObject.isEnabled() ) 968 { 969 registries.add( errors, schemaObject ); 970 } 971 else 972 { 973 errors.add( new Throwable() ); 974 } 975 } 976 977 return schemaObject; 978 } 979 980 981 /** 982 * {@inheritDoc} 983 */ 984 public boolean loadAllEnabled() throws Exception 985 { 986 Schema[] schemas = schemaLoader.getAllEnabled().toArray( new Schema[0] ); 987 988 return loadWithDeps( schemas ); 989 } 990 991 992 /** 993 * {@inheritDoc} 994 */ 995 public boolean loadAllEnabledRelaxed() throws Exception 996 { 997 Schema[] schemas = schemaLoader.getAllEnabled().toArray( new Schema[0] ); 998 999 return loadWithDepsRelaxed( schemas ); 1000 } 1001 1002 1003 /** 1004 * {@inheritDoc} 1005 */ 1006 public boolean loadDisabled( Schema... schemas ) throws LdapException 1007 { 1008 // Work on a cloned and relaxed registries 1009 Registries clonedRegistries = cloneRegistries(); 1010 1011 // Accept the disabled schemas 1012 clonedRegistries.setDisabledAccepted( true ); 1013 1014 // Load the schemas 1015 for ( Schema schema : schemas ) 1016 { 1017 // Enable the Schema object before loading it 1018 schema.enable(); 1019 load( clonedRegistries, schema ); 1020 } 1021 1022 clonedRegistries.clear(); 1023 1024 // Apply the change to the correct registries if no errors 1025 if ( errors.size() == 0 ) 1026 { 1027 // No error, we can enable the schema in the real registries 1028 for ( Schema schema : schemas ) 1029 { 1030 load( registries, schema ); 1031 } 1032 1033 return true; 1034 } 1035 else 1036 { 1037 for ( Schema schema : schemas ) 1038 { 1039 schema.disable(); 1040 } 1041 1042 return false; 1043 } 1044 } 1045 1046 1047 /** 1048 * {@inheritDoc} 1049 */ 1050 public boolean loadDisabled( String... schemaNames ) throws LdapException 1051 { 1052 Schema[] schemas = toArray( schemaNames ); 1053 1054 return loadDisabled( schemas ); 1055 } 1056 1057 1058 /** 1059 * {@inheritDoc} 1060 */ 1061 public boolean loadRelaxed( Schema... schemas ) throws Exception 1062 { 1063 // TODO Auto-generated method stub 1064 return false; 1065 } 1066 1067 1068 /** 1069 * {@inheritDoc} 1070 */ 1071 public boolean loadRelaxed( String... schemaNames ) throws Exception 1072 { 1073 Schema[] schemas = toArray( schemaNames ); 1074 return loadRelaxed( schemas ); 1075 } 1076 1077 1078 /** 1079 * {@inheritDoc} 1080 */ 1081 public boolean loadWithDeps( Schema... schemas ) throws Exception 1082 { 1083 boolean loaded = false; 1084 1085 // Reset the errors if not null 1086 if ( errors != null ) 1087 { 1088 errors.clear(); 1089 } 1090 1091 // Work on a cloned and relaxed registries 1092 Registries clonedRegistries = cloneRegistries(); 1093 clonedRegistries.setRelaxed(); 1094 1095 // Load the schemas 1096 for ( Schema schema : schemas ) 1097 { 1098 loadDepsFirst( clonedRegistries, schema ); 1099 } 1100 1101 // Build the cross references 1102 errors = clonedRegistries.buildReferences(); 1103 1104 if ( errors.isEmpty() ) 1105 { 1106 // Ok no errors. Check the registries now 1107 errors = clonedRegistries.checkRefInteg(); 1108 1109 if ( errors.isEmpty() ) 1110 { 1111 // We are golden : let's apply the schema in the real registries 1112 registries = clonedRegistries; 1113 registries.setStrict(); 1114 loaded = true; 1115 } 1116 } 1117 else 1118 { 1119 // clear the cloned registries 1120 clonedRegistries.clear(); 1121 } 1122 1123 return loaded; 1124 } 1125 1126 1127 /** 1128 * {@inheritDoc} 1129 */ 1130 public boolean loadWithDeps( String... schemas ) throws Exception 1131 { 1132 return loadWithDeps( toArray( schemas ) ); 1133 } 1134 1135 1136 /** 1137 * Recursive method which loads schema's with their dependent schemas first 1138 * and tracks what schemas it has seen so the recursion does not go out of 1139 * control with dependency cycle detection. 1140 * 1141 * @param registries The Registries in which the schemas will be loaded 1142 * @param schema the current schema we are attempting to load 1143 * @throws Exception if there is a cycle detected and/or another 1144 * failure results while loading, producing and or registering schema objects 1145 */ 1146 private void loadDepsFirst( Registries registries, Schema schema ) throws Exception 1147 { 1148 if ( schema == null ) 1149 { 1150 LOG.info( "The schema is null" ); 1151 return; 1152 } 1153 1154 if ( schema.isDisabled() && !registries.isDisabledAccepted() ) 1155 { 1156 LOG.info( "The schema is disabled and the registries does not accepted disabled schema" ); 1157 return; 1158 } 1159 1160 String schemaName = schema.getSchemaName(); 1161 1162 if ( registries.isSchemaLoaded( schemaName ) ) 1163 { 1164 LOG.info( "{} schema has already been loaded" + schema.getSchemaName() ); 1165 return; 1166 } 1167 1168 String[] deps = schema.getDependencies(); 1169 1170 // if no deps then load this guy and return 1171 if ( ( deps == null ) || ( deps.length == 0 ) ) 1172 { 1173 load( registries, schema ); 1174 1175 return; 1176 } 1177 1178 /* 1179 * We got deps and need to load them before this schema. We go through 1180 * all deps loading them with their deps first if they have not been 1181 * loaded. 1182 */ 1183 for ( String depName : deps ) 1184 { 1185 if ( registries.isSchemaLoaded( schemaName ) ) 1186 { 1187 // The schema is already loaded. Loop on the next schema 1188 continue; 1189 } 1190 else 1191 { 1192 // Call recursively this method 1193 Schema schemaDep = schemaLoader.getSchema( depName ); 1194 loadDepsFirst( registries, schemaDep ); 1195 } 1196 } 1197 1198 // Now load the current schema 1199 load( registries, schema ); 1200 } 1201 1202 1203 /** 1204 * {@inheritDoc} 1205 */ 1206 public boolean loadWithDepsRelaxed( Schema... schemas ) throws Exception 1207 { 1208 registries.setRelaxed(); 1209 1210 // Load the schemas 1211 for ( Schema schema : schemas ) 1212 { 1213 loadDepsFirstRelaxed( schema ); 1214 } 1215 1216 // Build the cross references 1217 errors = registries.buildReferences(); 1218 1219 // Check the registries now 1220 errors = registries.checkRefInteg(); 1221 1222 return true; 1223 } 1224 1225 1226 /** 1227 * {@inheritDoc} 1228 */ 1229 public boolean loadWithDepsRelaxed( String... schemas ) throws Exception 1230 { 1231 return loadWithDepsRelaxed( toArray( schemas ) ); 1232 } 1233 1234 1235 /** 1236 * Recursive method which loads schema's with their dependent schemas first 1237 * and tracks what schemas it has seen so the recursion does not go out of 1238 * control with dependency cycle detection. 1239 * 1240 * @param schema the current schema we are attempting to load 1241 * @throws Exception if there is a cycle detected and/or another 1242 * failure results while loading, producing and or registering schema objects 1243 */ 1244 private void loadDepsFirstRelaxed( Schema schema ) throws Exception 1245 { 1246 if ( schema == null ) 1247 { 1248 LOG.info( "The schema is null" ); 1249 return; 1250 } 1251 1252 if ( schema.isDisabled() && !registries.isDisabledAccepted() ) 1253 { 1254 LOG.info( "The schema is disabled and the registries does not accepted disabled schema" ); 1255 return; 1256 } 1257 1258 String schemaName = schema.getSchemaName(); 1259 1260 if ( registries.isSchemaLoaded( schemaName ) ) 1261 { 1262 LOG.info( "{} schema has already been loaded" + schema.getSchemaName() ); 1263 return; 1264 } 1265 1266 String[] deps = schema.getDependencies(); 1267 1268 // if no deps then load this guy and return 1269 if ( ( deps == null ) || ( deps.length == 0 ) ) 1270 { 1271 load( registries, schema ); 1272 1273 return; 1274 } 1275 1276 /* 1277 * We got deps and need to load them before this schema. We go through 1278 * all deps loading them with their deps first if they have not been 1279 * loaded. 1280 */ 1281 for ( String depName : deps ) 1282 { 1283 if ( registries.isSchemaLoaded( schemaName ) ) 1284 { 1285 // The schema is already loaded. Loop on the next schema 1286 continue; 1287 } 1288 else 1289 { 1290 // Call recursively this method 1291 Schema schemaDep = schemaLoader.getSchema( depName ); 1292 loadDepsFirstRelaxed( schemaDep ); 1293 } 1294 } 1295 1296 // Now load the current schema 1297 load( registries, schema ); 1298 } 1299 1300 1301 /** 1302 * {@inheritDoc} 1303 */ 1304 public void setRegistries( Registries registries ) 1305 { 1306 // TODO Auto-generated method stub 1307 1308 } 1309 1310 1311 /** 1312 * {@inheritDoc} 1313 */ 1314 public boolean unload( Schema... schemas ) throws LdapException 1315 { 1316 boolean unloaded = false; 1317 1318 // Reset the errors if not null 1319 if ( errors != null ) 1320 { 1321 errors.clear(); 1322 } 1323 1324 // Work on a cloned and relaxed registries 1325 Registries clonedRegistries = cloneRegistries(); 1326 clonedRegistries.setRelaxed(); 1327 1328 // Load the schemas 1329 for ( Schema schema : schemas ) 1330 { 1331 unload( clonedRegistries, schema ); 1332 } 1333 1334 // Build the cross references 1335 errors = clonedRegistries.buildReferences(); 1336 1337 if ( errors.isEmpty() ) 1338 { 1339 // Ok no errors. Check the registries now 1340 errors = clonedRegistries.checkRefInteg(); 1341 1342 if ( errors.isEmpty() ) 1343 { 1344 // We are golden : let's apply the schema in the real registries 1345 registries.setRelaxed(); 1346 1347 // Load the schemas 1348 for ( Schema schema : schemas ) 1349 { 1350 unload( registries, schema ); 1351 1352 // Update the schema dependences 1353 for ( String dep : schema.getDependencies() ) 1354 { 1355 Set<String> deps = schemaDependences.get( dep ); 1356 1357 if ( deps != null ) 1358 { 1359 deps.remove( schema.getSchemaName() ); 1360 } 1361 } 1362 1363 schemaLoader.removeSchema( schema ); 1364 } 1365 1366 // Build the cross references 1367 errors = registries.buildReferences(); 1368 registries.setStrict(); 1369 1370 unloaded = true; 1371 } 1372 } 1373 1374 // clear the cloned registries 1375 clonedRegistries.clear(); 1376 1377 return unloaded; 1378 } 1379 1380 1381 /** 1382 * {@inheritDoc} 1383 */ 1384 public boolean unload( String... schemaNames ) throws LdapException 1385 { 1386 Schema[] schemas = toArray( schemaNames ); 1387 1388 return unload( schemas ); 1389 } 1390 1391 1392 /** 1393 * {@inheritDoc} 1394 */ 1395 public boolean verify( Schema... schemas ) throws Exception 1396 { 1397 // Work on a cloned registries 1398 Registries clonedRegistries = cloneRegistries(); 1399 1400 // Loop on all the schemas 1401 for ( Schema schema : schemas ) 1402 { 1403 try 1404 { 1405 // Inject the schema 1406 boolean loaded = load( clonedRegistries, schema ); 1407 1408 if ( !loaded ) 1409 { 1410 // We got an error : exit 1411 clonedRegistries.clear(); 1412 return false; 1413 } 1414 1415 // Now, check the registries 1416 List<Throwable> errors = clonedRegistries.checkRefInteg(); 1417 1418 if ( errors.size() != 0 ) 1419 { 1420 // We got an error : exit 1421 clonedRegistries.clear(); 1422 return false; 1423 } 1424 } 1425 catch ( Exception e ) 1426 { 1427 // We got an error : exit 1428 clonedRegistries.clear(); 1429 return false; 1430 } 1431 } 1432 1433 // We can now delete the cloned registries before exiting 1434 clonedRegistries.clear(); 1435 1436 return true; 1437 } 1438 1439 1440 /** 1441 * {@inheritDoc} 1442 */ 1443 public boolean verify( String... schemas ) throws Exception 1444 { 1445 return verify( toArray( schemas ) ); 1446 } 1447 1448 1449 /** 1450 * {@inheritDoc} 1451 */ 1452 public void setSchemaLoader( SchemaLoader schemaLoader ) 1453 { 1454 this.schemaLoader = schemaLoader; 1455 } 1456 1457 1458 /** 1459 * @return the namingContext 1460 */ 1461 public Dn getNamingContext() 1462 { 1463 return namingContext; 1464 } 1465 1466 1467 /** 1468 * Initializes the SchemaService 1469 * 1470 * @throws Exception If the initialization fails 1471 */ 1472 public void initialize() throws Exception 1473 { 1474 try 1475 { 1476 schemaModificationAttributesDn = new Dn( SchemaConstants.SCHEMA_MODIFICATIONS_DN ); 1477 schemaModificationAttributesDn.apply( new DefaultSchemaManager() ); 1478 } 1479 catch ( LdapInvalidDnException e ) 1480 { 1481 throw new RuntimeException( e ); 1482 } 1483 } 1484 1485 1486 /** 1487 * {@inheritDoc} 1488 */ 1489 public SchemaLoader getLoader() 1490 { 1491 return schemaLoader; 1492 } 1493 1494 1495 //----------------------------------------------------------------------------------- 1496 // Immutable accessors 1497 //----------------------------------------------------------------------------------- 1498 /** 1499 * {@inheritDoc} 1500 */ 1501 public AttributeTypeRegistry getAttributeTypeRegistry() 1502 { 1503 return new ImmutableAttributeTypeRegistry( registries.getAttributeTypeRegistry() ); 1504 } 1505 1506 1507 /** 1508 * {@inheritDoc} 1509 */ 1510 public ComparatorRegistry getComparatorRegistry() 1511 { 1512 return new ImmutableComparatorRegistry( registries.getComparatorRegistry() ); 1513 } 1514 1515 1516 /** 1517 * {@inheritDoc} 1518 */ 1519 public DITContentRuleRegistry getDITContentRuleRegistry() 1520 { 1521 return new ImmutableDITContentRuleRegistry( registries.getDitContentRuleRegistry() ); 1522 } 1523 1524 1525 /** 1526 * {@inheritDoc} 1527 */ 1528 public DITStructureRuleRegistry getDITStructureRuleRegistry() 1529 { 1530 return new ImmutableDITStructureRuleRegistry( registries.getDitStructureRuleRegistry() ); 1531 } 1532 1533 1534 /** 1535 * {@inheritDoc} 1536 */ 1537 public MatchingRuleRegistry getMatchingRuleRegistry() 1538 { 1539 return new ImmutableMatchingRuleRegistry( registries.getMatchingRuleRegistry() ); 1540 } 1541 1542 1543 /** 1544 * {@inheritDoc} 1545 */ 1546 public MatchingRuleUseRegistry getMatchingRuleUseRegistry() 1547 { 1548 return new ImmutableMatchingRuleUseRegistry( registries.getMatchingRuleUseRegistry() ); 1549 } 1550 1551 1552 /** 1553 * {@inheritDoc} 1554 */ 1555 public NameFormRegistry getNameFormRegistry() 1556 { 1557 return new ImmutableNameFormRegistry( registries.getNameFormRegistry() ); 1558 } 1559 1560 1561 /** 1562 * {@inheritDoc} 1563 */ 1564 public NormalizerRegistry getNormalizerRegistry() 1565 { 1566 return new ImmutableNormalizerRegistry( registries.getNormalizerRegistry() ); 1567 } 1568 1569 1570 /** 1571 * {@inheritDoc} 1572 */ 1573 public ObjectClassRegistry getObjectClassRegistry() 1574 { 1575 return new ImmutableObjectClassRegistry( registries.getObjectClassRegistry() ); 1576 } 1577 1578 1579 /** 1580 * {@inheritDoc} 1581 */ 1582 public LdapSyntaxRegistry getLdapSyntaxRegistry() 1583 { 1584 return new ImmutableLdapSyntaxRegistry( registries.getLdapSyntaxRegistry() ); 1585 } 1586 1587 1588 /** 1589 * {@inheritDoc} 1590 */ 1591 public SyntaxCheckerRegistry getSyntaxCheckerRegistry() 1592 { 1593 return new ImmutableSyntaxCheckerRegistry( registries.getSyntaxCheckerRegistry() ); 1594 } 1595 1596 1597 /** 1598 * {@inheritDoc} 1599 */ 1600 public AttributeType lookupAttributeTypeRegistry( String oid ) throws LdapException 1601 { 1602 return registries.getAttributeTypeRegistry().lookup( Strings.toLowerCase( oid ).trim() ); 1603 } 1604 1605 1606 /** 1607 * {@inheritDoc} 1608 */ 1609 public AttributeType getAttributeType( String oid ) 1610 { 1611 try 1612 { 1613 return registries.getAttributeTypeRegistry().lookup( Strings.toLowerCase( oid ).trim() ); 1614 } 1615 catch ( LdapException lnsae ) 1616 { 1617 return null; 1618 } 1619 } 1620 1621 1622 /** 1623 * {@inheritDoc} 1624 */ 1625 public LdapComparator<?> lookupComparatorRegistry( String oid ) throws LdapException 1626 { 1627 return registries.getComparatorRegistry().lookup( oid ); 1628 } 1629 1630 1631 /** 1632 * {@inheritDoc} 1633 */ 1634 public MatchingRule lookupMatchingRuleRegistry( String oid ) throws LdapException 1635 { 1636 return registries.getMatchingRuleRegistry().lookup( Strings.toLowerCase( oid ).trim() ); 1637 } 1638 1639 1640 /** 1641 * {@inheritDoc} 1642 */ 1643 public Normalizer lookupNormalizerRegistry( String oid ) throws LdapException 1644 { 1645 return registries.getNormalizerRegistry().lookup( oid ); 1646 } 1647 1648 1649 /** 1650 * {@inheritDoc} 1651 */ 1652 public ObjectClass lookupObjectClassRegistry( String oid ) throws LdapException 1653 { 1654 return registries.getObjectClassRegistry().lookup( Strings.toLowerCase( oid ).trim() ); 1655 } 1656 1657 1658 /** 1659 * {@inheritDoc} 1660 */ 1661 public LdapSyntax lookupLdapSyntaxRegistry( String oid ) throws LdapException 1662 { 1663 return registries.getLdapSyntaxRegistry().lookup( Strings.toLowerCase( oid ).trim() ); 1664 } 1665 1666 1667 /** 1668 * {@inheritDoc} 1669 */ 1670 public SyntaxChecker lookupSyntaxCheckerRegistry( String oid ) throws LdapException 1671 { 1672 return registries.getSyntaxCheckerRegistry().lookup( oid ); 1673 } 1674 1675 1676 /** 1677 * Check that the given OID exists in the globalOidRegistry. 1678 */ 1679 private boolean checkOidExist( SchemaObject schemaObject ) 1680 { 1681 if ( !( schemaObject instanceof LoadableSchemaObject ) ) 1682 { 1683 return registries.getGlobalOidRegistry().contains( schemaObject.getOid() ); 1684 } 1685 1686 if ( schemaObject instanceof LdapComparator<?> ) 1687 { 1688 return registries.getComparatorRegistry().contains( schemaObject.getOid() ); 1689 } 1690 1691 if ( schemaObject instanceof SyntaxChecker ) 1692 { 1693 return registries.getSyntaxCheckerRegistry().contains( schemaObject.getOid() ); 1694 } 1695 1696 if ( schemaObject instanceof Normalizer ) 1697 { 1698 return registries.getNormalizerRegistry().contains( schemaObject.getOid() ); 1699 } 1700 1701 return false; 1702 } 1703 1704 1705 /** 1706 * Get the inner SchemaObject if it's not a C/N/SC 1707 */ 1708 private SchemaObject getSchemaObject( SchemaObject schemaObject ) throws LdapException 1709 { 1710 if ( schemaObject instanceof LoadableSchemaObject ) 1711 { 1712 return schemaObject; 1713 } 1714 else 1715 { 1716 return registries.getGlobalOidRegistry().getSchemaObject( schemaObject.getOid() ); 1717 } 1718 } 1719 1720 1721 /** 1722 * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found. 1723 */ 1724 private String getSchemaName( SchemaObject schemaObject ) 1725 { 1726 String schemaName = Strings.toLowerCase( schemaObject.getSchemaName() ); 1727 1728 if ( Strings.isEmpty( schemaName ) ) 1729 { 1730 return MetaSchemaConstants.SCHEMA_OTHER; 1731 } 1732 1733 if ( schemaLoader.getSchema( schemaName ) == null ) 1734 { 1735 return null; 1736 } 1737 else 1738 { 1739 return schemaName; 1740 } 1741 } 1742 1743 1744 private SchemaObject copy( SchemaObject schemaObject ) 1745 { 1746 SchemaObject copy = null; 1747 1748 if ( !( schemaObject instanceof LoadableSchemaObject ) ) 1749 { 1750 copy = schemaObject.copy(); 1751 } 1752 else 1753 { 1754 // Check the schemaObject here. 1755 if ( ( ( LoadableSchemaObject ) schemaObject ).isValid() ) 1756 { 1757 copy = schemaObject; 1758 } 1759 else 1760 { 1761 // We have an invalid SchemaObject, no need to go any further 1762 Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( 1763 I18n.ERR_11007, schemaObject.getOid() ) ); 1764 errors.add( error ); 1765 } 1766 } 1767 1768 return copy; 1769 } 1770 1771 1772 //----------------------------------------------------------------------------------- 1773 // SchemaObject operations 1774 //----------------------------------------------------------------------------------- 1775 /** 1776 * {@inheritDoc} 1777 */ 1778 public boolean add( SchemaObject schemaObject ) throws LdapException 1779 { 1780 // First, clear the errors 1781 errors.clear(); 1782 1783 // Clone the schemaObject 1784 SchemaObject copy = copy( schemaObject ); 1785 1786 if ( copy == null ) 1787 { 1788 return false; 1789 } 1790 1791 if ( registries.isRelaxed() ) 1792 { 1793 // Apply the addition right away 1794 registries.add( errors, copy ); 1795 1796 return errors.isEmpty(); 1797 } 1798 else 1799 { 1800 // Clone, apply, check, then apply again if ok 1801 // The new schemaObject's OID must not already exist 1802 if ( checkOidExist( copy ) ) 1803 { 1804 LdapSchemaException ldapSchemaException = new LdapSchemaException( 1805 LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_11008, schemaObject.getOid() ) ); 1806 ldapSchemaException.setSourceObject( schemaObject ); 1807 errors.add( ldapSchemaException ); 1808 1809 return false; 1810 } 1811 1812 // Build the new AttributeType from the given entry 1813 String schemaName = getSchemaName( copy ); 1814 1815 if ( schemaName == null ) 1816 { 1817 // The schema associated with the SchemaaObject does not exist. This is not valid. 1818 1819 LdapSchemaException ldapSchemaException = new LdapSchemaException( 1820 LdapSchemaExceptionCodes.NONEXISTENT_SCHEMA, I18n.err( I18n.ERR_11009, schemaObject.getOid(), 1821 copy.getSchemaName() ) ); 1822 ldapSchemaException.setSourceObject( schemaObject ); 1823 ldapSchemaException.setRelatedId( copy.getSchemaName() ); 1824 errors.add( ldapSchemaException ); 1825 1826 return false; 1827 } 1828 1829 // At this point, the constructed AttributeType has not been checked against the 1830 // existing Registries. It may be broken (missing SUP, or such), it will be checked 1831 // there, if the schema and the AttributeType are both enabled. 1832 Schema schema = getLoadedSchema( schemaName ); 1833 1834 if ( schema == null ) 1835 { 1836 // The SchemaObject must be associated with an existing schema 1837 String msg = I18n.err( I18n.ERR_11010, copy.getOid() ); 1838 LOG.info( msg ); 1839 Throwable error = new LdapProtocolErrorException( msg ); 1840 errors.add( error ); 1841 return false; 1842 } 1843 1844 if ( schema.isEnabled() && copy.isEnabled() ) 1845 { 1846 // As we may break the registries, work on a cloned registries 1847 Registries clonedRegistries = null; 1848 1849 try 1850 { 1851 clonedRegistries = registries.clone(); 1852 } 1853 catch ( CloneNotSupportedException cnse ) 1854 { 1855 throw new LdapOtherException( cnse.getMessage() ); 1856 } 1857 1858 // Inject the new SchemaObject in the cloned registries 1859 clonedRegistries.add( errors, copy ); 1860 1861 // Remove the cloned registries 1862 clonedRegistries.clear(); 1863 1864 // If we didn't get any error, apply the addition to the real retistries 1865 if ( errors.isEmpty() ) 1866 { 1867 // Copy again as the clonedRegistries clear has removed the previous copy 1868 copy = copy( schemaObject ); 1869 1870 // Apply the addition to the real registries 1871 registries.add( errors, copy ); 1872 1873 LOG.debug( "Added {} into the enabled schema {}", copy.getName(), schemaName ); 1874 1875 return true; 1876 } 1877 else 1878 { 1879 // We have some error : reject the addition and get out 1880 String msg = "Cannot add the SchemaObject " + copy.getOid() + " into the registries, " 1881 + "the resulting registries would be inconsistent :" + Strings.listToString( errors ); 1882 LOG.info( msg ); 1883 1884 return false; 1885 } 1886 } 1887 else 1888 { 1889 // At least, we register the OID in the globalOidRegistry, and associates it with the 1890 // schema 1891 registries.associateWithSchema( errors, copy ); 1892 1893 LOG.debug( "Added {} into the disabled schema {}", copy.getName(), schemaName ); 1894 return errors.isEmpty(); 1895 } 1896 } 1897 } 1898 1899 1900 /** 1901 * {@inheritDoc} 1902 */ 1903 public boolean delete( SchemaObject schemaObject ) throws LdapException 1904 { 1905 // First, clear the errors 1906 errors.clear(); 1907 1908 if ( registries.isRelaxed() ) 1909 { 1910 // Apply the addition right away 1911 registries.delete( errors, schemaObject ); 1912 1913 return errors.isEmpty(); 1914 } 1915 else 1916 { 1917 // Clone, apply, check, then apply again if ok 1918 // The new schemaObject's OID must exist 1919 if ( !checkOidExist( schemaObject ) ) 1920 { 1921 Throwable error = new LdapProtocolErrorException( I18n.err( I18n.ERR_11011, schemaObject.getOid() ) ); 1922 errors.add( error ); 1923 return false; 1924 } 1925 1926 // Get the SchemaObject to delete if it's not a LoadableSchemaObject 1927 SchemaObject toDelete = getSchemaObject( schemaObject ); 1928 1929 // First check that this SchemaObject does not have any referencing SchemaObjects 1930 Set<SchemaObjectWrapper> referencing = registries.getReferencing( toDelete ); 1931 1932 if ( ( referencing != null ) && !referencing.isEmpty() ) 1933 { 1934 String msg = I18n.err( I18n.ERR_11012, schemaObject.getOid(), Strings.setToString( referencing ) ); 1935 1936 Throwable error = new LdapProtocolErrorException( msg ); 1937 errors.add( error ); 1938 return false; 1939 } 1940 1941 String schemaName = getSchemaName( toDelete ); 1942 1943 // At this point, the deleted AttributeType may be referenced, it will be checked 1944 // there, if the schema and the AttributeType are both enabled. 1945 Schema schema = getLoadedSchema( schemaName ); 1946 1947 if ( schema == null ) 1948 { 1949 // The SchemaObject must be associated with an existing schema 1950 String msg = I18n.err( I18n.ERR_11013, schemaObject.getOid() ); 1951 LOG.info( msg ); 1952 Throwable error = new LdapProtocolErrorException( msg ); 1953 errors.add( error ); 1954 return false; 1955 } 1956 1957 if ( schema.isEnabled() && schemaObject.isEnabled() ) 1958 { 1959 // As we may break the registries, work on a cloned registries 1960 Registries clonedRegistries = null; 1961 1962 try 1963 { 1964 clonedRegistries = registries.clone(); 1965 } 1966 catch ( CloneNotSupportedException cnse ) 1967 { 1968 throw new LdapOtherException( cnse.getMessage() ); 1969 } 1970 1971 // Delete the SchemaObject from the cloned registries 1972 clonedRegistries.delete( errors, toDelete ); 1973 1974 // Remove the cloned registries 1975 clonedRegistries.clear(); 1976 1977 // If we didn't get any error, apply the deletion to the real retistries 1978 if ( errors.isEmpty() ) 1979 { 1980 // Apply the deletion to the real registries 1981 registries.delete( errors, toDelete ); 1982 1983 LOG.debug( "Removed {} from the enabled schema {}", toDelete.getName(), schemaName ); 1984 1985 return true; 1986 } 1987 else 1988 { 1989 // We have some error : reject the deletion and get out 1990 String msg = "Cannot delete the SchemaObject " + schemaObject.getOid() + " from the registries, " 1991 + "the resulting registries would be inconsistent :" + Strings.listToString( errors ); 1992 LOG.info( msg ); 1993 1994 return false; 1995 } 1996 } 1997 else 1998 { 1999 // At least, we register the OID in the globalOidRegistry, and associates it with the 2000 // schema 2001 registries.associateWithSchema( errors, schemaObject ); 2002 2003 LOG.debug( "Removed {} from the disabled schema {}", schemaObject.getName(), schemaName ); 2004 return errors.isEmpty(); 2005 } 2006 } 2007 } 2008 2009 2010 /** 2011 * {@inheritDoc} 2012 */ 2013 public Map<String, OidNormalizer> getNormalizerMapping() 2014 { 2015 return registries.getAttributeTypeRegistry().getNormalizerMapping(); 2016 } 2017 2018 2019 /** 2020 * {@inheritDoc} 2021 */ 2022 @SuppressWarnings("rawtypes") 2023 public OidRegistry getGlobalOidRegistry() 2024 { 2025 return registries.getGlobalOidRegistry(); 2026 } 2027 2028 2029 /** 2030 * {@inheritDoc} 2031 */ 2032 public Schema getLoadedSchema( String schemaName ) 2033 { 2034 return schemaLoader.getSchema( schemaName ); 2035 } 2036 2037 2038 /** 2039 * {@inheritDoc} 2040 */ 2041 public boolean isSchemaLoaded( String schemaName ) 2042 { 2043 try 2044 { 2045 Schema schema = schemaLoader.getSchema( schemaName ); 2046 return schema != null; 2047 } 2048 catch ( Exception e ) 2049 { 2050 return false; 2051 } 2052 } 2053 2054 2055 /** 2056 * {@inheritDoc} 2057 */ 2058 public SchemaObject unregisterAttributeType( String attributeTypeOid ) throws LdapException 2059 { 2060 return registries.getAttributeTypeRegistry().unregister( attributeTypeOid ); 2061 } 2062 2063 2064 /** 2065 * {@inheritDoc} 2066 */ 2067 public SchemaObject unregisterComparator( String comparatorOid ) throws LdapException 2068 { 2069 return registries.getComparatorRegistry().unregister( comparatorOid ); 2070 } 2071 2072 2073 /** 2074 * {@inheritDoc} 2075 */ 2076 public SchemaObject unregisterDitControlRule( String ditControlRuleOid ) throws LdapException 2077 { 2078 return registries.getDitContentRuleRegistry().unregister( ditControlRuleOid ); 2079 } 2080 2081 2082 /** 2083 * {@inheritDoc} 2084 */ 2085 public SchemaObject unregisterDitStructureRule( String ditStructureRuleOid ) throws LdapException 2086 { 2087 return registries.getDitStructureRuleRegistry().unregister( ditStructureRuleOid ); 2088 } 2089 2090 2091 /** 2092 * {@inheritDoc} 2093 */ 2094 public SchemaObject unregisterLdapSyntax( String ldapSyntaxOid ) throws LdapException 2095 { 2096 return registries.getLdapSyntaxRegistry().unregister( ldapSyntaxOid ); 2097 } 2098 2099 2100 /** 2101 * {@inheritDoc} 2102 */ 2103 public SchemaObject unregisterMatchingRule( String matchingRuleOid ) throws LdapException 2104 { 2105 return registries.getMatchingRuleRegistry().unregister( matchingRuleOid ); 2106 } 2107 2108 2109 /** 2110 * {@inheritDoc} 2111 */ 2112 public SchemaObject unregisterMatchingRuleUse( String matchingRuleUseOid ) throws LdapException 2113 { 2114 return registries.getMatchingRuleUseRegistry().unregister( matchingRuleUseOid ); 2115 } 2116 2117 2118 /** 2119 * {@inheritDoc} 2120 */ 2121 public SchemaObject unregisterNameForm( String nameFormOid ) throws LdapException 2122 { 2123 return registries.getNameFormRegistry().unregister( nameFormOid ); 2124 } 2125 2126 2127 /** 2128 * {@inheritDoc} 2129 */ 2130 public SchemaObject unregisterNormalizer( String normalizerOid ) throws LdapException 2131 { 2132 return registries.getNormalizerRegistry().unregister( normalizerOid ); 2133 } 2134 2135 2136 /** 2137 * {@inheritDoc} 2138 */ 2139 public SchemaObject unregisterObjectClass( String objectClassOid ) throws LdapException 2140 { 2141 return registries.getObjectClassRegistry().unregister( objectClassOid ); 2142 } 2143 2144 2145 /** 2146 * {@inheritDoc} 2147 */ 2148 public SchemaObject unregisterSyntaxChecker( String syntaxCheckerOid ) throws LdapException 2149 { 2150 return registries.getSyntaxCheckerRegistry().unregister( syntaxCheckerOid ); 2151 } 2152 2153 2154 /** 2155 * Tells if the SchemaManager is permissive or if it must be checked 2156 * against inconsistencies. 2157 * 2158 * @return True if SchemaObjects can be added even if they break the consistency 2159 */ 2160 public boolean isRelaxed() 2161 { 2162 return isRelaxed; 2163 } 2164 2165 2166 /** 2167 * Tells if the SchemaManager is strict. 2168 * 2169 * @return True if SchemaObjects cannot be added if they break the consistency 2170 */ 2171 public boolean isStrict() 2172 { 2173 return !isRelaxed; 2174 } 2175 2176 2177 /** 2178 * {@inheritDoc} 2179 */ 2180 public Set<String> listDependentSchemaNames( String schemaName ) 2181 { 2182 return schemaDependences.get( schemaName ); 2183 } 2184 2185 2186 /** 2187 * Change the SchemaManager to a relaxed mode, where invalid SchemaObjects 2188 * can be registered. 2189 */ 2190 public void setRelaxed() 2191 { 2192 isRelaxed = RELAXED; 2193 } 2194 2195 2196 /** 2197 * Change the SchemaManager to a strict mode, where invalid SchemaObjects 2198 * cannot be registered. 2199 */ 2200 public void setStrict() 2201 { 2202 isRelaxed = STRICT; 2203 } 2204 2205 2206 /** 2207 * {@inheritDoc} 2208 */ 2209 public boolean isDisabled( String schemaName ) 2210 { 2211 Schema schema = registries.getLoadedSchema( schemaName ); 2212 2213 return ( schema != null ) && schema.isDisabled(); 2214 } 2215 2216 2217 /** 2218 * {@inheritDoc} 2219 */ 2220 public boolean isDisabled( Schema schema ) 2221 { 2222 return ( schema != null ) && schema.isDisabled(); 2223 } 2224 2225 2226 /** 2227 * {@inheritDoc} 2228 */ 2229 public boolean isEnabled( String schemaName ) 2230 { 2231 Schema schema = registries.getLoadedSchema( schemaName ); 2232 2233 return ( schema != null ) && schema.isEnabled(); 2234 } 2235 2236 2237 /** 2238 * {@inheritDoc} 2239 */ 2240 public boolean isEnabled( Schema schema ) 2241 { 2242 return ( schema != null ) && schema.isEnabled(); 2243 } 2244}