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