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