001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.core; 028 029import java.io.File; 030import java.io.FilenameFilter; 031import java.util.ArrayList; 032import java.util.Arrays; 033import java.util.LinkedList; 034import java.util.List; 035 036import org.forgerock.i18n.LocalizableMessage; 037import org.forgerock.i18n.slf4j.LocalizedLogger; 038import org.forgerock.opendj.config.server.ConfigException; 039import org.forgerock.opendj.ldap.ByteString; 040import org.forgerock.opendj.ldap.ModificationType; 041import org.forgerock.opendj.ldap.schema.CoreSchema; 042import org.forgerock.opendj.ldap.schema.SchemaBuilder; 043import org.forgerock.opendj.ldap.schema.Syntax; 044import org.opends.server.schema.*; 045import org.opends.server.types.*; 046import org.opends.server.util.LDIFReader; 047import org.opends.server.util.StaticUtils; 048 049import static org.opends.messages.ConfigMessages.*; 050import static org.opends.server.config.ConfigConstants.*; 051import static org.opends.server.schema.SchemaConstants.*; 052import static org.opends.server.types.CommonSchemaElements.*; 053import static org.opends.server.util.ServerConstants.*; 054import static org.opends.server.util.StaticUtils.*; 055 056/** 057 * This class defines a utility that will be used to manage the interaction with 058 * the Directory Server schema. It will be used to initially load all of the 059 * matching rules and attribute syntaxes that have been defined in the 060 * configuration, and will then read the actual schema definitions. At present, 061 * only attribute types and objectclasses are supported in the schema config 062 * files. Other components like DIT content rules, DIT structure rules, name 063 * forms, and matching rule use definitions will be ignored. 064 */ 065public class SchemaConfigManager 066{ 067 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 068 069 /** The schema that has been parsed from the server configuration. */ 070 private Schema schema; 071 072 private final ServerContext serverContext; 073 074 /** 075 * Creates a new instance of this schema config manager. 076 * 077 * @param serverContext 078 * The server context. 079 */ 080 public SchemaConfigManager(ServerContext serverContext) 081 { 082 this.serverContext = serverContext; 083 schema = new Schema(); 084 } 085 086 087 088 /** 089 * Retrieves the path to the directory containing the server schema files. 090 * 091 * @return The path to the directory containing the server schema files. 092 */ 093 public static String getSchemaDirectoryPath() 094 { 095 File schemaDir = 096 DirectoryServer.getEnvironmentConfig().getSchemaDirectory(); 097 if (schemaDir != null) { 098 return schemaDir.getAbsolutePath(); 099 } 100 return null; 101 } 102 103 104 105 /** 106 * Retrieves a reference to the schema information that has been read from the 107 * server configuration. Note that this information will not be complete 108 * until the <CODE>initializeMatchingRules</CODE>, 109 * <CODE>initializeAttributeSyntaxes</CODE>, and 110 * <CODE>initializeAttributeTypesAndObjectClasses</CODE> methods have been 111 * called. 112 * 113 * @return A reference to the schema information that has been read from the 114 * server configuration. 115 */ 116 public Schema getSchema() 117 { 118 return schema; 119 } 120 121 122 123 /** 124 * Initializes all the matching rules defined in the Directory Server 125 * configuration. This should only be called at Directory Server startup. 126 * 127 * @throws ConfigException If a configuration problem causes the matching 128 * rule initialization process to fail. 129 * 130 * @throws InitializationException If a problem occurs while initializing 131 * the matching rules that is not related to 132 * the server configuration. 133 */ 134 public void initializeMatchingRules() 135 throws ConfigException, InitializationException 136 { 137 MatchingRuleConfigManager matchingRuleConfigManager = 138 new MatchingRuleConfigManager(); 139 matchingRuleConfigManager.initializeMatchingRules(); 140 } 141 142 143 144 /** 145 * Initializes all the attribute syntaxes defined in the Directory Server 146 * configuration. This should only be called at Directory Server startup. 147 * 148 * @throws ConfigException If a configuration problem causes the syntax 149 * initialization process to fail. 150 * 151 * @throws InitializationException If a problem occurs while initializing 152 * the syntaxes that is not related to the 153 * server configuration. 154 */ 155 public void initializeAttributeSyntaxes() 156 throws ConfigException, InitializationException 157 { 158 AttributeSyntaxConfigManager syntaxConfigManager = 159 new AttributeSyntaxConfigManager(serverContext); 160 syntaxConfigManager.initializeAttributeSyntaxes(); 161 } 162 163 164 165 /** 166 * Filter implementation that accepts only ldif files. 167 */ 168 public static class SchemaFileFilter implements FilenameFilter 169 { 170 /** {@inheritDoc} */ 171 @Override 172 public boolean accept(File directory, String filename) 173 { 174 return filename.endsWith(".ldif"); 175 } 176 } 177 178 179 180 /** 181 * Initializes all the attribute type, object class, name form, DIT content 182 * rule, DIT structure rule, and matching rule use definitions by reading the 183 * server schema files. These files will be located in a single directory and 184 * will be processed in lexicographic order. However, to make the order 185 * easier to understand, they may be prefixed with a two digit number (with a 186 * leading zero if necessary) so that they will be read in numeric order. 187 * This should only be called at Directory Server startup. 188 * 189 * @throws ConfigException If a configuration problem causes the schema 190 * element initialization to fail. 191 * 192 * @throws InitializationException If a problem occurs while initializing 193 * the schema elements that is not related 194 * to the server configuration. 195 */ 196 public void initializeSchemaFromFiles() 197 throws ConfigException, InitializationException 198 { 199 // Construct the path to the directory that should contain the schema files 200 // and make sure that it exists and is a directory. Get a list of the files 201 // in that directory sorted in alphabetic order. 202 String schemaInstanceDirPath = getSchemaDirectoryPath(); 203 File schemaInstanceDir = null; 204 205 try 206 { 207 if (schemaInstanceDirPath != null) 208 { 209 schemaInstanceDir = new File(schemaInstanceDirPath); 210 } 211 } catch (Exception e) 212 { 213 schemaInstanceDir = null; 214 } 215 long oldestModificationTime = -1L; 216 long youngestModificationTime = -1L; 217 String[] fileNames; 218 219 try 220 { 221 if (schemaInstanceDir == null || ! schemaInstanceDir.exists()) 222 { 223 LocalizableMessage message = 224 ERR_CONFIG_SCHEMA_NO_SCHEMA_DIR.get(schemaInstanceDirPath); 225 throw new InitializationException(message); 226 } 227 if (! schemaInstanceDir.isDirectory()) 228 { 229 LocalizableMessage message = 230 ERR_CONFIG_SCHEMA_DIR_NOT_DIRECTORY.get(schemaInstanceDirPath); 231 throw new InitializationException(message); 232 } 233 234 235 FilenameFilter filter = new SchemaFileFilter(); 236 File[] schemaInstanceDirFiles = 237 schemaInstanceDir.listFiles(filter); 238 int fileNumber = schemaInstanceDirFiles.length ; 239 ArrayList<String> fileList = new ArrayList<>(fileNumber); 240 241 for (File f : schemaInstanceDirFiles) 242 { 243 if (f.isFile()) 244 { 245 fileList.add(f.getName()); 246 } 247 248 long modificationTime = f.lastModified(); 249 if (oldestModificationTime <= 0L || 250 modificationTime < oldestModificationTime) 251 { 252 oldestModificationTime = modificationTime; 253 } 254 255 if (youngestModificationTime <= 0 || 256 modificationTime > youngestModificationTime) 257 { 258 youngestModificationTime = modificationTime; 259 } 260 } 261 262 fileNames = new String[fileList.size()]; 263 fileList.toArray(fileNames); 264 Arrays.sort(fileNames); 265 } 266 catch (InitializationException ie) 267 { 268 logger.traceException(ie); 269 270 throw ie; 271 } 272 catch (Exception e) 273 { 274 logger.traceException(e); 275 276 LocalizableMessage message = ERR_CONFIG_SCHEMA_CANNOT_LIST_FILES.get( 277 schemaInstanceDirPath, getExceptionMessage(e)); 278 throw new InitializationException(message, e); 279 } 280 281 282 // If the oldest and youngest modification timestamps didn't get set for 283 // some reason, then set them to the current time. 284 if (oldestModificationTime <= 0) 285 { 286 oldestModificationTime = System.currentTimeMillis(); 287 } 288 289 if (youngestModificationTime <= 0) 290 { 291 youngestModificationTime = oldestModificationTime; 292 } 293 294 schema.setOldestModificationTime(oldestModificationTime); 295 schema.setYoungestModificationTime(youngestModificationTime); 296 297 298 // Iterate through the schema files and read them as an LDIF file containing 299 // a single entry. Then get the attributeTypes and objectClasses attributes 300 // from that entry and parse them to initialize the server schema. 301 for (String schemaFile : fileNames) 302 { 303 loadSchemaFile(serverContext, schema, schemaFile, false); 304 } 305 } 306 307 308 309 /** 310 * Loads the contents of the specified schema file into the provided schema. 311 * 312 * @param serverContext 313 * The server context. 314 * 315 * @param schema The schema in which the contents of the schema file are 316 * to be loaded. 317 * @param schemaFile The name of the schema file to be loaded into the 318 * provided schema. 319 * 320 * @return A list of the modifications that could be performed in order to 321 * obtain the contents of the file. 322 * 323 * @throws ConfigException If a configuration problem causes the schema 324 * element initialization to fail. 325 * 326 * @throws InitializationException If a problem occurs while initializing 327 * the schema elements that is not related 328 * to the server configuration. 329 */ 330 public static List<Modification> loadSchemaFile(ServerContext serverContext, Schema schema, String schemaFile) 331 throws ConfigException, InitializationException 332 { 333 return loadSchemaFile(serverContext, schema, schemaFile, true); 334 } 335 336 337 338 /** 339 * Loads the contents of the specified schema file into the provided schema. 340 * 341 * @param schema The schema in which the contents of the schema file 342 * are to be loaded. 343 * @param schemaFile The name of the schema file to be loaded into the 344 * provided schema. 345 * @param failOnError If {@code true}, indicates that this method should 346 * throw an exception if certain kinds of errors occur. 347 * If {@code false}, indicates that this method should 348 * log an error message and return without an exception. 349 * This should only be {@code false} when called from 350 * {@code initializeSchemaFromFiles}. 351 * 352 * @return A list of the modifications that could be performed in order to 353 * obtain the contents of the file, or {@code null} if a problem 354 * occurred and {@code failOnError} is {@code false}. 355 * 356 * @throws ConfigException If a configuration problem causes the schema 357 * element initialization to fail. 358 * 359 * @throws InitializationException If a problem occurs while initializing 360 * the schema elements that is not related 361 * to the server configuration. 362 */ 363 private static List<Modification> loadSchemaFile(ServerContext serverContext, Schema schema, String schemaFile, 364 boolean failOnError) throws ConfigException, InitializationException 365 { 366 // Create an LDIF reader to use when reading the files. 367 String schemaDirPath = getSchemaDirectoryPath(); 368 File f = new File(schemaDirPath, schemaFile); 369 LDIFReader reader; 370 try 371 { 372 reader = new LDIFReader(new LDIFImportConfig(f.getAbsolutePath())); 373 } 374 catch (Exception e) 375 { 376 logger.traceException(e); 377 378 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_OPEN_FILE.get( 379 schemaFile, schemaDirPath, getExceptionMessage(e)); 380 381 if (failOnError) 382 { 383 throw new ConfigException(message); 384 } 385 else 386 { 387 logger.error(message); 388 return null; 389 } 390 } 391 392 393 // Read the LDIF entry from the file and close the file. 394 Entry entry; 395 try 396 { 397 entry = reader.readEntry(false); 398 399 if (entry == null) 400 { 401 // The file was empty -- skip it. 402 reader.close(); 403 return new LinkedList<>(); 404 } 405 } 406 catch (Exception e) 407 { 408 logger.traceException(e); 409 410 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_READ_LDIF_ENTRY.get( 411 schemaFile, schemaDirPath, getExceptionMessage(e)); 412 413 if (failOnError) 414 { 415 throw new InitializationException(message, e); 416 } 417 else 418 { 419 logger.error(message); 420 StaticUtils.close(reader); 421 return null; 422 } 423 } 424 425 // If there are any more entries in the file, then print a warning message. 426 try 427 { 428 Entry e = reader.readEntry(false); 429 if (e != null) 430 { 431 logger.warn(WARN_CONFIG_SCHEMA_MULTIPLE_ENTRIES_IN_FILE, schemaFile, schemaDirPath); 432 } 433 } 434 catch (Exception e) 435 { 436 logger.traceException(e); 437 438 logger.warn(WARN_CONFIG_SCHEMA_UNPARSEABLE_EXTRA_DATA_IN_FILE, schemaFile, schemaDirPath, getExceptionMessage(e)); 439 } 440 finally 441 { 442 StaticUtils.close(reader); 443 } 444 445 // Get the attributeTypes attribute from the entry. 446 List<Modification> mods = new LinkedList<>(); 447 448 //parse the syntaxes first because attributes rely on these. 449 List<Attribute> ldapSyntaxList = getLdapSyntaxesAttributes(schema, entry, mods); 450 List<Attribute> attrList = getAttributeTypeAttributes(schema, entry, mods); 451 List<Attribute> ocList = getObjectClassesAttributes(schema, entry, mods); 452 List<Attribute> nfList = getNameFormsAttributes(schema, entry, mods); 453 List<Attribute> dcrList = getDITContentRulesAttributes(schema, entry, mods); 454 List<Attribute> dsrList = getDITStructureRulesAttributes(schema, entry, mods); 455 List<Attribute> mruList = getMatchingRuleUsesAttributes(schema, entry, mods); 456 457 // Loop on all the attribute of the schema entry to 458 // find the extra attribute that should be loaded in the Schema. 459 for (Attribute attribute : entry.getAttributes()) 460 { 461 if (!isSchemaAttribute(attribute)) 462 { 463 schema.addExtraAttribute(attribute.getName(), attribute); 464 } 465 } 466 467 parseLdapSyntaxesDefinitions(serverContext, schema, schemaFile, failOnError, 468 ldapSyntaxList); 469 parseAttributeTypeDefinitions(schema, schemaFile, failOnError, attrList); 470 parseObjectclassDefinitions(schema, schemaFile, failOnError, ocList); 471 parseNameFormDefinitions(schema, schemaFile, failOnError, nfList); 472 parseDITContentRuleDefinitions(schema, schemaFile, failOnError, dcrList); 473 parseDITStructureRuleDefinitions(schema, schemaFile, failOnError, dsrList); 474 parseMatchingRuleUseDefinitions(schema, schemaFile, failOnError, mruList); 475 476 return mods; 477 } 478 479 private static List<Attribute> getLdapSyntaxesAttributes(Schema schema, 480 Entry entry, List<Modification> mods) throws ConfigException 481 { 482 Syntax syntax = schema.getSyntax(SYNTAX_LDAP_SYNTAX_OID); 483 if (syntax == null) 484 { 485 syntax = CoreSchema.getLDAPSyntaxDescriptionSyntax(); 486 } 487 488 AttributeType ldapSyntaxAttrType = getAttributeType(schema, ATTR_LDAP_SYNTAXES, ATTR_LDAP_SYNTAXES_LC, syntax); 489 return createAddModifications(entry, mods, ldapSyntaxAttrType); 490 } 491 492 private static List<Attribute> getAttributeTypeAttributes(Schema schema, 493 Entry entry, List<Modification> mods) throws ConfigException, 494 InitializationException 495 { 496 Syntax syntax = schema.getSyntax(SYNTAX_ATTRIBUTE_TYPE_OID); 497 if (syntax == null) 498 { 499 syntax = CoreSchema.getAttributeTypeDescriptionSyntax(); 500 } 501 AttributeType attributeAttrType = getAttributeType( 502 schema, ATTR_ATTRIBUTE_TYPES, ATTR_ATTRIBUTE_TYPES_LC, syntax); 503 return createAddModifications(entry, mods, attributeAttrType); 504 } 505 506 /** Get the objectClasses attribute from the entry. */ 507 private static List<Attribute> getObjectClassesAttributes(Schema schema, 508 Entry entry, List<Modification> mods) throws ConfigException, 509 InitializationException 510 { 511 Syntax syntax = schema.getSyntax(SYNTAX_OBJECTCLASS_OID); 512 if (syntax == null) 513 { 514 syntax = CoreSchema.getObjectClassDescriptionSyntax(); 515 } 516 AttributeType objectclassAttrType = getAttributeType(schema, ATTR_OBJECTCLASSES, ATTR_OBJECTCLASSES_LC, syntax); 517 return createAddModifications(entry, mods, objectclassAttrType); 518 } 519 520 /** Get the name forms attribute from the entry. */ 521 private static List<Attribute> getNameFormsAttributes(Schema schema, 522 Entry entry, List<Modification> mods) throws ConfigException, 523 InitializationException 524 { 525 Syntax syntax = schema.getSyntax(SYNTAX_NAME_FORM_OID); 526 if (syntax == null) 527 { 528 syntax = CoreSchema.getNameFormDescriptionSyntax(); 529 } 530 AttributeType nameFormAttrType = getAttributeType( 531 schema, ATTR_NAME_FORMS, ATTR_NAME_FORMS_LC, syntax); 532 return createAddModifications(entry, mods, nameFormAttrType); 533 } 534 535 /** Get the DIT content rules attribute from the entry. */ 536 private static List<Attribute> getDITContentRulesAttributes(Schema schema, 537 Entry entry, List<Modification> mods) throws ConfigException, 538 InitializationException 539 { 540 Syntax syntax = schema.getSyntax(SYNTAX_DIT_CONTENT_RULE_OID); 541 if (syntax == null) 542 { 543 syntax = CoreSchema.getDITContentRuleDescriptionSyntax(); 544 } 545 AttributeType dcrAttrType = getAttributeType( 546 schema, ATTR_DIT_CONTENT_RULES, ATTR_DIT_CONTENT_RULES_LC, syntax); 547 return createAddModifications(entry, mods, dcrAttrType); 548 } 549 550 /** Get the DIT structure rules attribute from the entry. */ 551 private static List<Attribute> getDITStructureRulesAttributes(Schema schema, 552 Entry entry, List<Modification> mods) throws ConfigException, 553 InitializationException 554 { 555 Syntax syntax = schema.getSyntax(SYNTAX_DIT_STRUCTURE_RULE_OID); 556 if (syntax == null) 557 { 558 syntax = CoreSchema.getDITStructureRuleDescriptionSyntax(); 559 } 560 AttributeType dsrAttrType = getAttributeType(schema, ATTR_DIT_STRUCTURE_RULES, ATTR_DIT_STRUCTURE_RULES_LC, syntax); 561 return createAddModifications(entry, mods, dsrAttrType); 562 } 563 564 /** Get the matching rule uses attribute from the entry. */ 565 private static List<Attribute> getMatchingRuleUsesAttributes(Schema schema, 566 Entry entry, List<Modification> mods) throws ConfigException, 567 InitializationException 568 { 569 Syntax syntax = schema.getSyntax(SYNTAX_MATCHING_RULE_USE_OID); 570 if (syntax == null) 571 { 572 syntax = CoreSchema.getMatchingRuleUseDescriptionSyntax(); 573 } 574 AttributeType mruAttrType = getAttributeType(schema, ATTR_MATCHING_RULE_USE, ATTR_MATCHING_RULE_USE_LC, syntax); 575 return createAddModifications(entry, mods, mruAttrType); 576 } 577 578 private static AttributeType getAttributeType(Schema schema, String attrName, 579 String attrLowerName, Syntax syntax) 580 { 581 final AttributeType attrType = schema.getAttributeType(attrLowerName); 582 if (attrType != null) 583 { 584 return attrType; 585 } 586 return DirectoryServer.getDefaultAttributeType(attrName, syntax); 587 } 588 589 private static List<Attribute> createAddModifications(Entry entry, 590 List<Modification> mods, AttributeType attrType) 591 { 592 List<Attribute> attributes = entry.getAttribute(attrType); 593 if (attributes != null && !attributes.isEmpty()) 594 { 595 for (Attribute a : attributes) 596 { 597 mods.add(new Modification(ModificationType.ADD, a)); 598 } 599 } 600 return attributes; 601 } 602 603 /** Parse the ldapsyntaxes definitions if there are any. */ 604 private static void parseLdapSyntaxesDefinitions(ServerContext serverContext, Schema schema, 605 String schemaFile, boolean failOnError, List<Attribute> ldapSyntaxList) 606 throws ConfigException 607 { 608 if (ldapSyntaxList != null) 609 { 610 for (Attribute a : ldapSyntaxList) 611 { 612 for (ByteString v : a) 613 { 614 LDAPSyntaxDescription syntaxDescription; 615 try 616 { 617 syntaxDescription = LDAPSyntaxDescriptionSyntax.decodeLDAPSyntax(v, serverContext, schema, false, false); 618 setExtraProperty(syntaxDescription, SCHEMA_PROPERTY_FILENAME, null); 619 setSchemaFile(syntaxDescription, schemaFile); 620 } 621 catch (DirectoryException de) 622 { 623 logger.traceException(de); 624 625 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get( 626 schemaFile, 627 de.getMessageObject()); 628 reportError(failOnError, de, message); 629 continue; 630 } 631 catch (Exception e) 632 { 633 logger.traceException(e); 634 635 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_LDAP_SYNTAX.get( 636 schemaFile, v + ": " + getExceptionMessage(e)); 637 reportError(failOnError, e, message); 638 continue; 639 } 640 641 // Register it with the schema. We will allow duplicates, with the 642 // later definition overriding any earlier definition, but we want 643 // to trap them and log a warning. 644 try 645 { 646 schema.registerLdapSyntaxDescription(syntaxDescription, failOnError); 647 registerLdapSyntaxInSchemaNG(serverContext, syntaxDescription, failOnError); 648 } 649 catch (DirectoryException de) 650 { 651 logger.traceException(de); 652 653 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_LDAP_SYNTAX, schemaFile, de.getMessageObject()); 654 655 try 656 { 657 schema.registerLdapSyntaxDescription(syntaxDescription, true); 658 registerLdapSyntaxInSchemaNG(serverContext, syntaxDescription, true); 659 } 660 catch (Exception e) 661 { 662 // This should never happen. 663 logger.traceException(e); 664 } 665 } 666 } 667 } 668 } 669 } 670 671 private static void registerLdapSyntaxInSchemaNG(ServerContext serverContext, LDAPSyntaxDescription syntaxDescription, 672 boolean overwrite) 673 { 674 // The server context may be null when this code is reached through non-server code (e.g. gui tools) 675 if (serverContext != null) 676 { 677 SchemaUpdater schemaUpdater = serverContext.getSchemaUpdater(); 678 Syntax.Builder builder = schemaUpdater.getSchemaBuilder().buildSyntax(syntaxDescription.getSyntax()); 679 SchemaBuilder schemaBuilder = overwrite ? builder.addToSchemaOverwrite() : builder.addToSchema(); 680 schemaUpdater.updateSchema(schemaBuilder.toSchema()); 681 } 682 } 683 684 /** Parse the attribute type definitions if there are any. */ 685 private static void parseAttributeTypeDefinitions(Schema schema, 686 String schemaFile, boolean failOnError, List<Attribute> attrList) 687 throws ConfigException 688 { 689 if (attrList != null) 690 { 691 for (Attribute a : attrList) 692 { 693 for (ByteString v : a) 694 { 695 // Parse the attribute type. 696 AttributeType attrType; 697 try 698 { 699 attrType = AttributeTypeSyntax.decodeAttributeType(v, schema, false); 700 setExtraProperty(attrType, SCHEMA_PROPERTY_FILENAME, null); 701 setSchemaFile(attrType, schemaFile); 702 } 703 catch (DirectoryException de) 704 { 705 logger.traceException(de); 706 707 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_ATTR_TYPE.get( 708 schemaFile, de.getMessageObject()); 709 reportError(failOnError, de, message); 710 continue; 711 } 712 catch (Exception e) 713 { 714 logger.traceException(e); 715 716 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_ATTR_TYPE.get( 717 schemaFile, v + ": " + getExceptionMessage(e)); 718 reportError(failOnError, e, message); 719 continue; 720 } 721 722 // Register it with the schema. We will allow duplicates, with the 723 // later definition overriding any earlier definition, but we want 724 // to trap them and log a warning. 725 try 726 { 727 schema.registerAttributeType(attrType, failOnError); 728 } 729 catch (DirectoryException de) 730 { 731 logger.traceException(de); 732 733 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_ATTR_TYPE, schemaFile, de.getMessageObject()); 734 735 try 736 { 737 schema.registerAttributeType(attrType, true); 738 } 739 catch (Exception e) 740 { 741 // This should never happen. 742 logger.traceException(e); 743 } 744 } 745 } 746 } 747 } 748 } 749 750 /** Parse the objectclass definitions if there are any. */ 751 private static void parseObjectclassDefinitions(Schema schema, 752 String schemaFile, boolean failOnError, List<Attribute> ocList) 753 throws ConfigException 754 { 755 if (ocList != null) 756 { 757 for (Attribute a : ocList) 758 { 759 for (ByteString v : a) 760 { 761 // Parse the objectclass. 762 ObjectClass oc; 763 try 764 { 765 oc = ObjectClassSyntax.decodeObjectClass(v, schema, false); 766 setExtraProperty(oc, SCHEMA_PROPERTY_FILENAME, null); 767 setSchemaFile(oc, schemaFile); 768 } 769 catch (DirectoryException de) 770 { 771 logger.traceException(de); 772 773 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_OC.get( 774 schemaFile, 775 de.getMessageObject()); 776 reportError(failOnError, de, message); 777 continue; 778 } 779 catch (Exception e) 780 { 781 logger.traceException(e); 782 783 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_OC.get( 784 schemaFile, v + ": " + getExceptionMessage(e)); 785 reportError(failOnError, e, message); 786 continue; 787 } 788 789 // Register it with the schema. We will allow duplicates, with the 790 // later definition overriding any earlier definition, but we want 791 // to trap them and log a warning. 792 try 793 { 794 schema.registerObjectClass(oc, failOnError); 795 } 796 catch (DirectoryException de) 797 { 798 logger.traceException(de); 799 800 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_OC, schemaFile, de.getMessageObject()); 801 802 try 803 { 804 schema.registerObjectClass(oc, true); 805 } 806 catch (Exception e) 807 { 808 // This should never happen. 809 logger.traceException(e); 810 } 811 } 812 } 813 } 814 } 815 } 816 817 /** Parse the name form definitions if there are any. */ 818 private static void parseNameFormDefinitions(Schema schema, 819 String schemaFile, boolean failOnError, List<Attribute> nfList) 820 throws ConfigException 821 { 822 if (nfList != null) 823 { 824 for (Attribute a : nfList) 825 { 826 for (ByteString v : a) 827 { 828 // Parse the name form. 829 NameForm nf; 830 try 831 { 832 nf = NameFormSyntax.decodeNameForm(v, schema, false); 833 nf.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME); 834 setSchemaFile(nf, schemaFile); 835 } 836 catch (DirectoryException de) 837 { 838 logger.traceException(de); 839 840 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM.get( 841 schemaFile, de.getMessageObject()); 842 reportError(failOnError, de, message); 843 continue; 844 } 845 catch (Exception e) 846 { 847 logger.traceException(e); 848 849 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_NAME_FORM.get( 850 schemaFile, v + ": " + getExceptionMessage(e)); 851 reportError(failOnError, e, message); 852 continue; 853 } 854 855 // Register it with the schema. We will allow duplicates, with the 856 // later definition overriding any earlier definition, but we want 857 // to trap them and log a warning. 858 try 859 { 860 schema.registerNameForm(nf, failOnError); 861 } 862 catch (DirectoryException de) 863 { 864 logger.traceException(de); 865 866 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_NAME_FORM, schemaFile, de.getMessageObject()); 867 868 try 869 { 870 schema.registerNameForm(nf, true); 871 } 872 catch (Exception e) 873 { 874 // This should never happen. 875 logger.traceException(e); 876 } 877 } 878 } 879 } 880 } 881 } 882 883 /** Parse the DIT content rule definitions if there are any. */ 884 private static void parseDITContentRuleDefinitions(Schema schema, 885 String schemaFile, boolean failOnError, List<Attribute> dcrList) 886 throws ConfigException 887 { 888 if (dcrList != null) 889 { 890 for (Attribute a : dcrList) 891 { 892 for (ByteString v : a) 893 { 894 // Parse the DIT content rule. 895 DITContentRule dcr; 896 try 897 { 898 dcr = DITContentRuleSyntax.decodeDITContentRule(v, schema, false); 899 dcr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME); 900 setSchemaFile(dcr, schemaFile); 901 } 902 catch (DirectoryException de) 903 { 904 logger.traceException(de); 905 906 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DCR.get( 907 schemaFile, de.getMessageObject()); 908 reportError(failOnError, de, message); 909 continue; 910 } 911 catch (Exception e) 912 { 913 logger.traceException(e); 914 915 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DCR.get( 916 schemaFile, v + ": " + getExceptionMessage(e)); 917 reportError(failOnError, e, message); 918 continue; 919 } 920 921 // Register it with the schema. We will allow duplicates, with the 922 // later definition overriding any earlier definition, but we want 923 // to trap them and log a warning. 924 try 925 { 926 schema.registerDITContentRule(dcr, failOnError); 927 } 928 catch (DirectoryException de) 929 { 930 logger.traceException(de); 931 932 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_DCR, schemaFile, de.getMessageObject()); 933 934 try 935 { 936 schema.registerDITContentRule(dcr, true); 937 } 938 catch (Exception e) 939 { 940 // This should never happen. 941 logger.traceException(e); 942 } 943 } 944 } 945 } 946 } 947 } 948 949 private static void reportError(boolean failOnError, Exception e, 950 LocalizableMessage message) throws ConfigException 951 { 952 if (failOnError) 953 { 954 throw new ConfigException(message, e); 955 } 956 logger.error(message); 957 } 958 959 /** Parse the DIT structure rule definitions if there are any. */ 960 private static void parseDITStructureRuleDefinitions(Schema schema, 961 String schemaFile, boolean failOnError, List<Attribute> dsrList) 962 throws ConfigException 963 { 964 if (dsrList != null) 965 { 966 for (Attribute a : dsrList) 967 { 968 for (ByteString v : a) 969 { 970 // Parse the DIT content rule. 971 DITStructureRule dsr; 972 try 973 { 974 dsr = DITStructureRuleSyntax.decodeDITStructureRule(v, schema, false); 975 dsr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME); 976 setSchemaFile(dsr, schemaFile); 977 } 978 catch (DirectoryException de) 979 { 980 logger.traceException(de); 981 982 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DSR.get( 983 schemaFile, de.getMessageObject()); 984 reportError(failOnError, de, message); 985 continue; 986 } 987 catch (Exception e) 988 { 989 logger.traceException(e); 990 991 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_DSR.get( 992 schemaFile, v + ": " + getExceptionMessage(e)); 993 reportError(failOnError, e, message); 994 continue; 995 } 996 997 // Register it with the schema. We will allow duplicates, with the 998 // later definition overriding any earlier definition, but we want 999 // to trap them and log a warning. 1000 try 1001 { 1002 schema.registerDITStructureRule(dsr, failOnError); 1003 } 1004 catch (DirectoryException de) 1005 { 1006 logger.traceException(de); 1007 1008 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_DSR, schemaFile, de.getMessageObject()); 1009 1010 try 1011 { 1012 schema.registerDITStructureRule(dsr, true); 1013 } 1014 catch (Exception e) 1015 { 1016 // This should never happen. 1017 logger.traceException(e); 1018 } 1019 } 1020 } 1021 } 1022 } 1023 } 1024 1025 /** Parse the matching rule use definitions if there are any. */ 1026 private static void parseMatchingRuleUseDefinitions(Schema schema, 1027 String schemaFile, boolean failOnError, List<Attribute> mruList) 1028 throws ConfigException 1029 { 1030 if (mruList != null) 1031 { 1032 for (Attribute a : mruList) 1033 { 1034 for (ByteString v : a) 1035 { 1036 // Parse the matching rule use definition. 1037 MatchingRuleUse mru; 1038 try 1039 { 1040 mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(v, schema, false); 1041 mru.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME); 1042 setSchemaFile(mru, schemaFile); 1043 } 1044 catch (DirectoryException de) 1045 { 1046 logger.traceException(de); 1047 1048 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_MRU.get( 1049 schemaFile, de.getMessageObject()); 1050 reportError(failOnError, de, message); 1051 continue; 1052 } 1053 catch (Exception e) 1054 { 1055 logger.traceException(e); 1056 1057 LocalizableMessage message = WARN_CONFIG_SCHEMA_CANNOT_PARSE_MRU.get( 1058 schemaFile, v + ": " + getExceptionMessage(e)); 1059 reportError(failOnError, e, message); 1060 continue; 1061 } 1062 1063 // Register it with the schema. We will allow duplicates, with the 1064 // later definition overriding any earlier definition, but we want 1065 // to trap them and log a warning. 1066 try 1067 { 1068 schema.registerMatchingRuleUse(mru, failOnError); 1069 } 1070 catch (DirectoryException de) 1071 { 1072 logger.traceException(de); 1073 1074 logger.warn(WARN_CONFIG_SCHEMA_CONFLICTING_MRU, schemaFile, de.getMessageObject()); 1075 1076 try 1077 { 1078 schema.registerMatchingRuleUse(mru, true); 1079 } 1080 catch (Exception e) 1081 { 1082 // This should never happen. 1083 logger.traceException(e); 1084 } 1085 } 1086 } 1087 } 1088 } 1089 } 1090 1091 1092 1093 /** 1094 * This method checks if a given attribute is an attribute that 1095 * is used by the definition of the schema. 1096 * 1097 * @param attribute The attribute to be checked. 1098 * @return true if the attribute is part of the schema definition, 1099 * false if the attribute is not part of the schema 1100 * definition. 1101 */ 1102 public static boolean isSchemaAttribute(Attribute attribute) 1103 { 1104 String attributeOid = attribute.getAttributeType().getOID(); 1105 return attributeOid.equals("2.5.21.1") || 1106 attributeOid.equals("2.5.21.2") || 1107 attributeOid.equals("2.5.21.4") || 1108 attributeOid.equals("2.5.21.5") || 1109 attributeOid.equals("2.5.21.6") || 1110 attributeOid.equals("2.5.21.7") || 1111 attributeOid.equals("2.5.21.8") || 1112 attributeOid.equals("2.5.4.3") || 1113 attributeOid.equals("1.3.6.1.4.1.1466.101.120.16") || 1114 attributeOid.equals("cn-oid") || 1115 attributeOid.equals("attributetypes-oid") || 1116 attributeOid.equals("objectclasses-oid") || 1117 attributeOid.equals("matchingrules-oid") || 1118 attributeOid.equals("matchingruleuse-oid") || 1119 attributeOid.equals("nameformdescription-oid") || 1120 attributeOid.equals("ditcontentrules-oid") || 1121 attributeOid.equals("ditstructurerules-oid") || 1122 attributeOid.equals("ldapsyntaxes-oid"); 1123 } 1124} 1125