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 */ 020 package org.apache.directory.shared.ldap.schema.loader.ldif; 021 022 023 import java.io.File; 024 import java.io.FileNotFoundException; 025 import java.io.FileWriter; 026 import java.io.FilenameFilter; 027 import java.util.ArrayList; 028 import java.util.List; 029 030 import org.apache.directory.shared.i18n.I18n; 031 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants; 032 import org.apache.directory.shared.ldap.constants.SchemaConstants; 033 import org.apache.directory.shared.ldap.entry.Entry; 034 import org.apache.directory.shared.ldap.ldif.LdifEntry; 035 import org.apache.directory.shared.ldap.ldif.LdifReader; 036 import org.apache.directory.shared.ldap.ldif.LdifUtils; 037 import org.apache.directory.shared.ldap.schema.registries.AbstractSchemaLoader; 038 import org.apache.directory.shared.ldap.schema.registries.Schema; 039 import org.apache.directory.shared.ldap.util.DateUtils; 040 import org.slf4j.Logger; 041 import org.slf4j.LoggerFactory; 042 043 044 /** 045 * Loads schema data from LDIF files containing entries representing schema 046 * objects, using the meta schema format. 047 * 048 * This class is used only for tests. 049 * 050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 051 * @version $Revision$ 052 */ 053 public class LdifSchemaLoader extends AbstractSchemaLoader 054 { 055 /** ldif file extension used */ 056 private static final String LDIF_EXT = "ldif"; 057 058 /** ou=schema LDIF file name */ 059 private static final String OU_SCHEMA_LDIF = "ou=schema." + LDIF_EXT; 060 061 /** static class logger */ 062 private static final Logger LOG = LoggerFactory.getLogger( LdifSchemaLoader.class ); 063 064 /** Speedup for DEBUG mode */ 065 private static final boolean IS_DEBUG = LOG.isDebugEnabled(); 066 067 /** 068 * the administrator DN - very ADS specific but we need some DN here for 069 * the modifiers name when the system modifies by itself enabled and 070 * disabled schemas in the repository. 071 */ 072 private static final String ADMIN_SYSTEM_DN = "uid=admin,ou=system"; 073 074 /** directory containing the schema LDIF file for ou=schema */ 075 private final File baseDirectory; 076 077 /** a filter for listing all the LDIF files within a directory */ 078 private final FilenameFilter ldifFilter = new FilenameFilter() 079 { 080 public boolean accept( File file, String name ) 081 { 082 return name.endsWith( LDIF_EXT ); 083 } 084 }; 085 086 087 /** 088 * Creates a new LDIF based SchemaLoader. The constructor checks to make 089 * sure the supplied base directory exists and contains a schema.ldif file 090 * and if not complains about it. 091 * 092 * @param baseDirectory the schema LDIF base directory 093 * @throws Exception if the base directory does not exist or does not 094 * a valid schema.ldif file 095 */ 096 public LdifSchemaLoader( File baseDirectory ) throws Exception 097 { 098 this.baseDirectory = baseDirectory; 099 100 if ( !baseDirectory.exists() ) 101 { 102 String msg = "Provided baseDirectory '" + baseDirectory.getAbsolutePath() + "' does not exist."; 103 LOG.error( msg ); 104 throw new IllegalArgumentException( msg ); 105 } 106 107 File schemaLdif = new File( baseDirectory, OU_SCHEMA_LDIF ); 108 109 if ( !schemaLdif.exists() ) 110 { 111 String msg = I18n.err( I18n.ERR_10004, schemaLdif.getAbsolutePath() ); 112 LOG.error( msg ); 113 throw new FileNotFoundException( msg ); 114 } 115 116 if ( IS_DEBUG ) 117 { 118 LOG.debug( "Using '{}' as the base schema load directory.", baseDirectory ); 119 } 120 121 initializeSchemas(); 122 } 123 124 125 /** 126 * Scans for LDIF files just describing the various schema contained in 127 * the schema repository. 128 * 129 * @throws Exception 130 */ 131 private void initializeSchemas() throws Exception 132 { 133 if ( IS_DEBUG ) 134 { 135 LOG.debug( "Initializing schema" ); 136 } 137 138 File schemaDirectory = new File( baseDirectory, SchemaConstants.OU_SCHEMA ); 139 String[] ldifFiles = schemaDirectory.list( ldifFilter ); 140 141 for ( String ldifFile : ldifFiles ) 142 { 143 File file = new File( schemaDirectory, ldifFile ); 144 145 try 146 { 147 LdifReader reader = new LdifReader( file ); 148 LdifEntry entry = reader.next(); 149 reader.close(); 150 Schema schema = getSchema( entry.getEntry() ); 151 152 if ( schema == null ) 153 { 154 // The entry was not a schema, skip it 155 continue; 156 } 157 158 schemaMap.put( schema.getSchemaName(), schema ); 159 160 if ( IS_DEBUG ) 161 { 162 LOG.debug( "Schema Initialized ... \n{}", schema ); 163 } 164 } 165 catch ( Exception e ) 166 { 167 LOG.error( I18n.err( I18n.ERR_10003, ldifFile ), e ); 168 throw e; 169 } 170 } 171 } 172 173 174 /** 175 * {@inheritDoc} 176 * 177 public List<Throwable> loadWithDependencies( Schema schema, Registries registries, boolean check ) throws Exception 178 { 179 // Relax the controls at first 180 List<Throwable> errors = new ArrayList<Throwable>(); 181 boolean wasRelaxed = registries.isRelaxed(); 182 registries.setRelaxed( true ); 183 184 Stack<String> beenthere = new Stack<String>(); 185 Map<String,Schema> notLoaded = new HashMap<String,Schema>(); 186 notLoaded.put( schema.getSchemaName(), schema ); 187 super.loadDepsFirst( schema, beenthere, notLoaded, schema, registries ); 188 189 // At the end, check the registries if required 190 if ( check ) 191 { 192 errors = registries.checkRefInteg(); 193 } 194 195 // Restore the Registries isRelaxed flag 196 registries.setRelaxed( wasRelaxed ); 197 198 return errors; 199 } 200 201 202 /** 203 * Loads a single schema if it has not been loaded already. If the schema 204 * load request was made because some other schema depends on this one then 205 * the schema is checked to see if it is disabled. If disabled it is 206 * enabled with a write to disk and then loaded. Listeners are notified that 207 * the schema has been loaded. 208 * 209 * {@inheritDoc} 210 * 211 public void load( Schema schema, Registries registries, boolean isDepLoad ) throws Exception 212 { 213 // if we're loading a dependency and it has not been enabled on 214 // disk then enable it on disk before we proceed to load it 215 if ( schema.isDisabled() && isDepLoad ) 216 { 217 enableSchema( schema ); 218 } 219 220 if ( registries.isSchemaLoaded( schema.getSchemaName() ) ) 221 { 222 LOG.info( "Will not attempt to load already loaded '{}' " + 223 "schema: \n{}", schema.getSchemaName(), schema ); 224 return; 225 } 226 227 LOG.info( "Loading {} schema: \n{}", schema.getSchemaName(), schema ); 228 229 registries.schemaLoaded( schema ); 230 231 loadComparators( schema ); 232 loadNormalizers( schema, registries ); 233 loadSyntaxCheckers( schema, registries ); 234 loadSyntaxes( schema, registries ); 235 loadMatchingRules( schema, registries ); 236 loadAttributeTypes( schema, registries ); 237 loadObjectClasses( schema, registries ); 238 loadMatchingRuleUses( schema, registries ); 239 loadDitContentRules( schema, registries ); 240 loadNameForms( schema, registries ); 241 loadDitStructureRules( schema, registries ); 242 243 notifyListenerOrRegistries( schema, registries ); 244 } 245 246 247 /** 248 * Utility method used to enable a specific schema on disk in the LDIF 249 * based schema repository. This method will remove the m-disabled AT 250 * in the schema file and update the modifiersName and modifyTimestamp. 251 * 252 * The modifiersName and modifyTimestamp on the schema.ldif file will 253 * also be updated to indicate a change to the schema. 254 * 255 * @param schema the disabled schema to enable 256 * @throws Exception if there are problems writing changes back to disk 257 */ 258 private void enableSchema( Schema schema ) throws Exception 259 { 260 // ------------------------------------------------------------------- 261 // Modifying the foo schema foo.ldif file to be enabled but still 262 // have to now update the timestamps and update the modifiersName 263 // ------------------------------------------------------------------- 264 265 File schemaLdifFile = new File( new File( baseDirectory, SchemaConstants.OU_SCHEMA ), "cn=" 266 + schema.getSchemaName() + "." + LDIF_EXT ); 267 LdifReader reader = new LdifReader( schemaLdifFile ); 268 LdifEntry ldifEntry = reader.next(); 269 Entry entry = ldifEntry.getEntry(); 270 271 entry.removeAttributes( "changeType" ); 272 entry.removeAttributes( SchemaConstants.MODIFIERS_NAME_AT ); 273 entry.removeAttributes( SchemaConstants.MODIFY_TIMESTAMP_AT ); 274 entry.removeAttributes( MetaSchemaConstants.M_DISABLED_AT ); 275 276 entry.add( SchemaConstants.MODIFIERS_NAME_AT, ADMIN_SYSTEM_DN ); 277 entry.add( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); 278 279 FileWriter out = new FileWriter( schemaLdifFile ); 280 out.write( LdifUtils.convertEntryToLdif( entry ) ); 281 out.flush(); 282 out.close(); 283 284 // ------------------------------------------------------------------- 285 // Now we need to update the timestamp on the schema.ldif file which 286 // shows that something changed below the schema directory in schema 287 // ------------------------------------------------------------------- 288 289 schemaLdifFile = new File( baseDirectory, "ou=schema." + LDIF_EXT ); 290 reader = new LdifReader( schemaLdifFile ); 291 ldifEntry = reader.next(); 292 entry = ldifEntry.getEntry(); 293 294 entry.removeAttributes( "changeType" ); 295 entry.removeAttributes( SchemaConstants.MODIFIERS_NAME_AT ); 296 entry.removeAttributes( SchemaConstants.MODIFY_TIMESTAMP_AT ); 297 298 entry.add( SchemaConstants.MODIFIERS_NAME_AT, ADMIN_SYSTEM_DN ); 299 entry.add( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); 300 301 out = new FileWriter( schemaLdifFile ); 302 out.write( LdifUtils.convertEntryToLdif( entry ) ); 303 out.flush(); 304 out.close(); 305 306 reader.close(); 307 } 308 309 310 /** 311 * Utility method to get the file for a schema directory. 312 * 313 * @param schema the schema to get the file for 314 * @return the file for the specific schema directory 315 */ 316 private final File getSchemaDirectory( Schema schema ) 317 { 318 return new File( new File( baseDirectory, SchemaConstants.OU_SCHEMA ), "cn=" + schema.getSchemaName() ); 319 } 320 321 322 /** 323 * {@inheritDoc} 324 */ 325 public List<Entry> loadComparators( Schema... schemas ) throws Exception 326 { 327 List<Entry> comparatorList = new ArrayList<Entry>(); 328 329 if ( schemas == null ) 330 { 331 return comparatorList; 332 } 333 334 for ( Schema schema : schemas ) 335 { 336 File comparatorsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.COMPARATORS_PATH ); 337 338 if ( !comparatorsDirectory.exists() ) 339 { 340 return comparatorList; 341 } 342 343 File[] comparators = comparatorsDirectory.listFiles( ldifFilter ); 344 345 for ( File ldifFile : comparators ) 346 { 347 LdifReader reader = new LdifReader( ldifFile ); 348 LdifEntry entry = reader.next(); 349 reader.close(); 350 351 comparatorList.add( entry.getEntry() ); 352 } 353 } 354 355 return comparatorList; 356 } 357 358 359 /** 360 * {@inheritDoc} 361 */ 362 public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws Exception 363 { 364 List<Entry> syntaxCheckerList = new ArrayList<Entry>(); 365 366 if ( schemas == null ) 367 { 368 return syntaxCheckerList; 369 } 370 371 for ( Schema schema : schemas ) 372 { 373 File syntaxCheckersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAX_CHECKERS_PATH ); 374 375 if ( !syntaxCheckersDirectory.exists() ) 376 { 377 return syntaxCheckerList; 378 } 379 380 File[] syntaxCheckerFiles = syntaxCheckersDirectory.listFiles( ldifFilter ); 381 382 for ( File ldifFile : syntaxCheckerFiles ) 383 { 384 LdifReader reader = new LdifReader( ldifFile ); 385 LdifEntry entry = reader.next(); 386 reader.close(); 387 388 syntaxCheckerList.add( entry.getEntry() ); 389 } 390 } 391 392 return syntaxCheckerList; 393 } 394 395 396 /** 397 * {@inheritDoc} 398 */ 399 public List<Entry> loadNormalizers( Schema... schemas ) throws Exception 400 { 401 List<Entry> normalizerList = new ArrayList<Entry>(); 402 403 if ( schemas == null ) 404 { 405 return normalizerList; 406 } 407 408 for ( Schema schema : schemas ) 409 { 410 File normalizersDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NORMALIZERS_PATH ); 411 412 if ( !normalizersDirectory.exists() ) 413 { 414 return normalizerList; 415 } 416 417 File[] normalizerFiles = normalizersDirectory.listFiles( ldifFilter ); 418 419 for ( File ldifFile : normalizerFiles ) 420 { 421 LdifReader reader = new LdifReader( ldifFile ); 422 LdifEntry entry = reader.next(); 423 reader.close(); 424 425 normalizerList.add( entry.getEntry() ); 426 } 427 } 428 429 return normalizerList; 430 } 431 432 433 /** 434 * {@inheritDoc} 435 */ 436 public List<Entry> loadMatchingRules( Schema... schemas ) throws Exception 437 { 438 List<Entry> matchingRuleList = new ArrayList<Entry>(); 439 440 if ( schemas == null ) 441 { 442 return matchingRuleList; 443 } 444 445 for ( Schema schema : schemas ) 446 { 447 File matchingRulesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.MATCHING_RULES_PATH ); 448 449 if ( !matchingRulesDirectory.exists() ) 450 { 451 return matchingRuleList; 452 } 453 454 File[] matchingRuleFiles = matchingRulesDirectory.listFiles( ldifFilter ); 455 456 for ( File ldifFile : matchingRuleFiles ) 457 { 458 LdifReader reader = new LdifReader( ldifFile ); 459 LdifEntry entry = reader.next(); 460 reader.close(); 461 462 matchingRuleList.add( entry.getEntry() ); 463 } 464 } 465 466 return matchingRuleList; 467 } 468 469 470 /** 471 * {@inheritDoc} 472 */ 473 public List<Entry> loadSyntaxes( Schema... schemas ) throws Exception 474 { 475 List<Entry> syntaxList = new ArrayList<Entry>(); 476 477 if ( schemas == null ) 478 { 479 return syntaxList; 480 } 481 482 for ( Schema schema : schemas ) 483 { 484 File syntaxesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.SYNTAXES_PATH ); 485 486 if ( !syntaxesDirectory.exists() ) 487 { 488 return syntaxList; 489 } 490 491 File[] syntaxFiles = syntaxesDirectory.listFiles( ldifFilter ); 492 493 for ( File ldifFile : syntaxFiles ) 494 { 495 LdifReader reader = new LdifReader( ldifFile ); 496 LdifEntry entry = reader.next(); 497 reader.close(); 498 499 syntaxList.add( entry.getEntry() ); 500 } 501 } 502 503 return syntaxList; 504 } 505 506 507 /** 508 * {@inheritDoc} 509 */ 510 public List<Entry> loadAttributeTypes( Schema... schemas ) throws Exception 511 { 512 List<Entry> attributeTypeList = new ArrayList<Entry>(); 513 514 if ( schemas == null ) 515 { 516 return attributeTypeList; 517 } 518 519 for ( Schema schema : schemas ) 520 { 521 // check that the attributeTypes directory exists for the schema 522 File attributeTypesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.ATTRIBUTES_TYPE_PATH ); 523 524 if ( !attributeTypesDirectory.exists() ) 525 { 526 return attributeTypeList; 527 } 528 529 // get list of attributeType LDIF schema files in attributeTypes 530 File[] attributeTypeFiles = attributeTypesDirectory.listFiles( ldifFilter ); 531 532 for ( File ldifFile : attributeTypeFiles ) 533 { 534 LdifReader reader = new LdifReader( ldifFile ); 535 LdifEntry entry = reader.next(); 536 reader.close(); 537 538 attributeTypeList.add( entry.getEntry() ); 539 } 540 } 541 542 return attributeTypeList; 543 } 544 545 546 /** 547 * {@inheritDoc} 548 */ 549 public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws Exception 550 { 551 List<Entry> matchingRuleUseList = new ArrayList<Entry>(); 552 553 if ( schemas == null ) 554 { 555 return matchingRuleUseList; 556 } 557 558 for ( Schema schema : schemas ) 559 { 560 File matchingRuleUsesDirectory = new File( getSchemaDirectory( schema ), 561 SchemaConstants.MATCHING_RULE_USE_PATH ); 562 563 if ( !matchingRuleUsesDirectory.exists() ) 564 { 565 return matchingRuleUseList; 566 } 567 568 File[] matchingRuleUseFiles = matchingRuleUsesDirectory.listFiles( ldifFilter ); 569 570 for ( File ldifFile : matchingRuleUseFiles ) 571 { 572 LdifReader reader = new LdifReader( ldifFile ); 573 LdifEntry entry = reader.next(); 574 reader.close(); 575 576 matchingRuleUseList.add( entry.getEntry() ); 577 } 578 } 579 580 return matchingRuleUseList; 581 } 582 583 584 /** 585 * {@inheritDoc} 586 */ 587 public List<Entry> loadNameForms( Schema... schemas ) throws Exception 588 { 589 List<Entry> nameFormList = new ArrayList<Entry>(); 590 591 if ( schemas == null ) 592 { 593 return nameFormList; 594 } 595 596 for ( Schema schema : schemas ) 597 { 598 File nameFormsDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.NAME_FORMS_PATH ); 599 600 if ( !nameFormsDirectory.exists() ) 601 { 602 return nameFormList; 603 } 604 605 File[] nameFormFiles = nameFormsDirectory.listFiles( ldifFilter ); 606 607 for ( File ldifFile : nameFormFiles ) 608 { 609 LdifReader reader = new LdifReader( ldifFile ); 610 LdifEntry entry = reader.next(); 611 reader.close(); 612 613 nameFormList.add( entry.getEntry() ); 614 } 615 } 616 617 return nameFormList; 618 } 619 620 621 /** 622 * {@inheritDoc} 623 */ 624 public List<Entry> loadDitContentRules( Schema... schemas ) throws Exception 625 { 626 List<Entry> ditContentRuleList = new ArrayList<Entry>(); 627 628 if ( schemas == null ) 629 { 630 return ditContentRuleList; 631 } 632 633 for ( Schema schema : schemas ) 634 { 635 File ditContentRulesDirectory = new File( getSchemaDirectory( schema ), 636 SchemaConstants.DIT_CONTENT_RULES_PATH ); 637 638 if ( !ditContentRulesDirectory.exists() ) 639 { 640 return ditContentRuleList; 641 } 642 643 File[] ditContentRuleFiles = ditContentRulesDirectory.listFiles( ldifFilter ); 644 645 for ( File ldifFile : ditContentRuleFiles ) 646 { 647 LdifReader reader = new LdifReader( ldifFile ); 648 LdifEntry entry = reader.next(); 649 reader.close(); 650 651 ditContentRuleList.add( entry.getEntry() ); 652 } 653 } 654 655 return ditContentRuleList; 656 } 657 658 659 /** 660 * {@inheritDoc} 661 */ 662 public List<Entry> loadDitStructureRules( Schema... schemas ) throws Exception 663 { 664 List<Entry> ditStructureRuleList = new ArrayList<Entry>(); 665 666 if ( schemas == null ) 667 { 668 return ditStructureRuleList; 669 } 670 671 for ( Schema schema : schemas ) 672 { 673 File ditStructureRulesDirectory = new File( getSchemaDirectory( schema ), 674 SchemaConstants.DIT_STRUCTURE_RULES_PATH ); 675 676 if ( !ditStructureRulesDirectory.exists() ) 677 { 678 return ditStructureRuleList; 679 } 680 681 File[] ditStructureRuleFiles = ditStructureRulesDirectory.listFiles( ldifFilter ); 682 683 for ( File ldifFile : ditStructureRuleFiles ) 684 { 685 LdifReader reader = new LdifReader( ldifFile ); 686 LdifEntry entry = reader.next(); 687 reader.close(); 688 689 ditStructureRuleList.add( entry.getEntry() ); 690 } 691 } 692 693 return ditStructureRuleList; 694 } 695 696 697 /** 698 * {@inheritDoc} 699 */ 700 public List<Entry> loadObjectClasses( Schema... schemas ) throws Exception 701 { 702 List<Entry> objectClassList = new ArrayList<Entry>(); 703 704 if ( schemas == null ) 705 { 706 return objectClassList; 707 } 708 709 for ( Schema schema : schemas ) 710 { 711 // get objectClasses directory, check if exists, return if not 712 File objectClassesDirectory = new File( getSchemaDirectory( schema ), SchemaConstants.OBJECT_CLASSES_PATH ); 713 714 if ( !objectClassesDirectory.exists() ) 715 { 716 return objectClassList; 717 } 718 719 // get list of objectClass LDIF files from directory and load 720 File[] objectClassFiles = objectClassesDirectory.listFiles( ldifFilter ); 721 722 for ( File ldifFile : objectClassFiles ) 723 { 724 LdifReader reader = new LdifReader( ldifFile ); 725 LdifEntry entry = reader.next(); 726 reader.close(); 727 728 objectClassList.add( entry.getEntry() ); 729 } 730 } 731 732 return objectClassList; 733 } 734 }