001 /* 002 * Copyright 2007-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2008-2014 UnboundID Corp. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021 package com.unboundid.ldap.sdk.schema; 022 023 024 025 import java.io.File; 026 import java.io.IOException; 027 import java.io.InputStream; 028 import java.io.Serializable; 029 import java.util.ArrayList; 030 import java.util.Arrays; 031 import java.util.Collections; 032 import java.util.LinkedHashMap; 033 import java.util.LinkedHashSet; 034 import java.util.List; 035 import java.util.Map; 036 import java.util.Set; 037 import java.util.concurrent.atomic.AtomicReference; 038 039 import com.unboundid.ldap.sdk.Attribute; 040 import com.unboundid.ldap.sdk.Entry; 041 import com.unboundid.ldap.sdk.LDAPConnection; 042 import com.unboundid.ldap.sdk.LDAPException; 043 import com.unboundid.ldap.sdk.ReadOnlyEntry; 044 import com.unboundid.ldap.sdk.ResultCode; 045 import com.unboundid.ldif.LDIFException; 046 import com.unboundid.ldif.LDIFReader; 047 048 import static com.unboundid.ldap.sdk.schema.SchemaMessages.*; 049 import static com.unboundid.util.Debug.*; 050 import static com.unboundid.util.StaticUtils.*; 051 import static com.unboundid.util.Validator.*; 052 053 054 055 /** 056 * This class provides a data structure for representing a directory server 057 * subschema subentry. This includes information about the attribute syntaxes, 058 * matching rules, attribute types, object classes, name forms, DIT content 059 * rules, DIT structure rules, and matching rule uses defined in the server 060 * schema. 061 */ 062 public final class Schema 063 implements Serializable 064 { 065 /** 066 * The name of the attribute used to hold the attribute syntax definitions. 067 */ 068 public static final String ATTR_ATTRIBUTE_SYNTAX = "ldapSyntaxes"; 069 070 071 072 /** 073 * The name of the attribute used to hold the attribute type definitions. 074 */ 075 public static final String ATTR_ATTRIBUTE_TYPE = "attributeTypes"; 076 077 078 079 /** 080 * The name of the attribute used to hold the DIT content rule definitions. 081 */ 082 public static final String ATTR_DIT_CONTENT_RULE = "dITContentRules"; 083 084 085 086 /** 087 * The name of the attribute used to hold the DIT structure rule definitions. 088 */ 089 public static final String ATTR_DIT_STRUCTURE_RULE = "dITStructureRules"; 090 091 092 093 /** 094 * The name of the attribute used to hold the matching rule definitions. 095 */ 096 public static final String ATTR_MATCHING_RULE = "matchingRules"; 097 098 099 100 /** 101 * The name of the attribute used to hold the matching rule use definitions. 102 */ 103 public static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse"; 104 105 106 107 /** 108 * The name of the attribute used to hold the name form definitions. 109 */ 110 public static final String ATTR_NAME_FORM = "nameForms"; 111 112 113 114 /** 115 * The name of the attribute used to hold the object class definitions. 116 */ 117 public static final String ATTR_OBJECT_CLASS = "objectClasses"; 118 119 120 121 /** 122 * The name of the attribute used to hold the DN of the subschema subentry 123 * with the schema information that governs a specified entry. 124 */ 125 public static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry"; 126 127 128 129 /** 130 * The default standard schema available for use in the LDAP SDK. 131 */ 132 private static final AtomicReference<Schema> DEFAULT_STANDARD_SCHEMA = 133 new AtomicReference<Schema>(); 134 135 136 137 /** 138 * The set of request attributes that will be used when retrieving the server 139 * subschema subentry in order to retrieve all of the schema elements. 140 */ 141 private static final String[] SCHEMA_REQUEST_ATTRS = 142 { 143 ATTR_ATTRIBUTE_SYNTAX, 144 ATTR_ATTRIBUTE_TYPE, 145 ATTR_DIT_CONTENT_RULE, 146 ATTR_DIT_STRUCTURE_RULE, 147 ATTR_MATCHING_RULE, 148 ATTR_MATCHING_RULE_USE, 149 ATTR_NAME_FORM, 150 ATTR_OBJECT_CLASS 151 }; 152 153 154 155 /** 156 * The set of request attributes that will be used when retrieving the 157 * subschema subentry attribute from a specified entry in order to determine 158 * the location of the server schema definitions. 159 */ 160 private static final String[] SUBSCHEMA_SUBENTRY_REQUEST_ATTRS = 161 { 162 ATTR_SUBSCHEMA_SUBENTRY 163 }; 164 165 166 167 /** 168 * Retrieves the resource path that may be used to obtain a file with a number 169 * of standard schema definitions. 170 */ 171 private static final String DEFAULT_SCHEMA_RESOURCE_PATH = 172 "com/unboundid/ldap/sdk/schema/standard-schema.ldif"; 173 174 175 176 /** 177 * The serial version UID for this serializable class. 178 */ 179 private static final long serialVersionUID = 8081839633831517925L; 180 181 182 183 // A map of all subordinate attribute type definitions for each attribute 184 // type definition. 185 private final Map<AttributeTypeDefinition,List<AttributeTypeDefinition>> 186 subordinateAttributeTypes; 187 188 // The set of attribute syntaxes mapped from lowercase name/OID to syntax. 189 private final Map<String,AttributeSyntaxDefinition> asMap; 190 191 // The set of attribute types mapped from lowercase name/OID to type. 192 private final Map<String,AttributeTypeDefinition> atMap; 193 194 // The set of DIT content rules mapped from lowercase name/OID to rule. 195 private final Map<String,DITContentRuleDefinition> dcrMap; 196 197 // The set of DIT structure rules mapped from rule ID to rule. 198 private final Map<Integer,DITStructureRuleDefinition> dsrMapByID; 199 200 // The set of DIT structure rules mapped from lowercase name to rule. 201 private final Map<String,DITStructureRuleDefinition> dsrMapByName; 202 203 // The set of DIT structure rules mapped from lowercase name to rule. 204 private final Map<String,DITStructureRuleDefinition> dsrMapByNameForm; 205 206 // The set of matching rules mapped from lowercase name/OID to rule. 207 private final Map<String,MatchingRuleDefinition> mrMap; 208 209 // The set of matching rule uses mapped from matching rule OID to use. 210 private final Map<String,MatchingRuleUseDefinition> mruMap; 211 212 // The set of name forms mapped from lowercase name/OID to name form. 213 private final Map<String,NameFormDefinition> nfMapByName; 214 215 // The set of name forms mapped from structural class OID to name form. 216 private final Map<String,NameFormDefinition> nfMapByOC; 217 218 // The set of object classes mapped from lowercase name/OID to class. 219 private final Map<String,ObjectClassDefinition> ocMap; 220 221 // The entry used to create this schema object. 222 private final ReadOnlyEntry schemaEntry; 223 224 // The set of attribute syntaxes defined in the schema. 225 private final Set<AttributeSyntaxDefinition> asSet; 226 227 // The set of attribute types defined in the schema. 228 private final Set<AttributeTypeDefinition> atSet; 229 230 // The set of operational attribute types defined in the schema. 231 private final Set<AttributeTypeDefinition> operationalATSet; 232 233 // The set of user attribute types defined in the schema. 234 private final Set<AttributeTypeDefinition> userATSet; 235 236 // The set of DIT content rules defined in the schema. 237 private final Set<DITContentRuleDefinition> dcrSet; 238 239 // The set of DIT structure rules defined in the schema. 240 private final Set<DITStructureRuleDefinition> dsrSet; 241 242 // The set of matching rules defined in the schema. 243 private final Set<MatchingRuleDefinition> mrSet; 244 245 // The set of matching rule uses defined in the schema. 246 private final Set<MatchingRuleUseDefinition> mruSet; 247 248 // The set of name forms defined in the schema. 249 private final Set<NameFormDefinition> nfSet; 250 251 // The set of object classes defined in the schema. 252 private final Set<ObjectClassDefinition> ocSet; 253 254 // The set of abstract object classes defined in the schema. 255 private final Set<ObjectClassDefinition> abstractOCSet; 256 257 // The set of auxiliary object classes defined in the schema. 258 private final Set<ObjectClassDefinition> auxiliaryOCSet; 259 260 // The set of structural object classes defined in the schema. 261 private final Set<ObjectClassDefinition> structuralOCSet; 262 263 264 265 /** 266 * Creates a new schema object by decoding the information in the provided 267 * entry. 268 * 269 * @param schemaEntry The schema entry to decode. 270 */ 271 public Schema(final Entry schemaEntry) 272 { 273 this.schemaEntry = new ReadOnlyEntry(schemaEntry); 274 275 // Decode the attribute syntaxes from the schema entry. 276 String[] defs = schemaEntry.getAttributeValues(ATTR_ATTRIBUTE_SYNTAX); 277 if (defs == null) 278 { 279 asMap = Collections.emptyMap(); 280 asSet = Collections.emptySet(); 281 } 282 else 283 { 284 final LinkedHashMap<String,AttributeSyntaxDefinition> m = 285 new LinkedHashMap<String,AttributeSyntaxDefinition>(defs.length); 286 final LinkedHashSet<AttributeSyntaxDefinition> s = 287 new LinkedHashSet<AttributeSyntaxDefinition>(defs.length); 288 289 for (final String def : defs) 290 { 291 try 292 { 293 final AttributeSyntaxDefinition as = 294 new AttributeSyntaxDefinition(def); 295 s.add(as); 296 m.put(toLowerCase(as.getOID()), as); 297 } 298 catch (final LDAPException le) 299 { 300 debugException(le); 301 } 302 } 303 304 asMap = Collections.unmodifiableMap(m); 305 asSet = Collections.unmodifiableSet(s); 306 } 307 308 309 // Decode the attribute types from the schema entry. 310 defs = schemaEntry.getAttributeValues(ATTR_ATTRIBUTE_TYPE); 311 if (defs == null) 312 { 313 atMap = Collections.emptyMap(); 314 atSet = Collections.emptySet(); 315 operationalATSet = Collections.emptySet(); 316 userATSet = Collections.emptySet(); 317 } 318 else 319 { 320 final LinkedHashMap<String,AttributeTypeDefinition> m = 321 new LinkedHashMap<String,AttributeTypeDefinition>(2*defs.length); 322 final LinkedHashSet<AttributeTypeDefinition> s = 323 new LinkedHashSet<AttributeTypeDefinition>(defs.length); 324 final LinkedHashSet<AttributeTypeDefinition> sUser = 325 new LinkedHashSet<AttributeTypeDefinition>(defs.length); 326 final LinkedHashSet<AttributeTypeDefinition> sOperational = 327 new LinkedHashSet<AttributeTypeDefinition>(defs.length); 328 329 for (final String def : defs) 330 { 331 try 332 { 333 final AttributeTypeDefinition at = new AttributeTypeDefinition(def); 334 s.add(at); 335 m.put(toLowerCase(at.getOID()), at); 336 for (final String name : at.getNames()) 337 { 338 m.put(toLowerCase(name), at); 339 } 340 341 if (at.isOperational()) 342 { 343 sOperational.add(at); 344 } 345 else 346 { 347 sUser.add(at); 348 } 349 } 350 catch (final LDAPException le) 351 { 352 debugException(le); 353 } 354 } 355 356 atMap = Collections.unmodifiableMap(m); 357 atSet = Collections.unmodifiableSet(s); 358 operationalATSet = Collections.unmodifiableSet(sOperational); 359 userATSet = Collections.unmodifiableSet(sUser); 360 } 361 362 363 // Decode the DIT content rules from the schema entry. 364 defs = schemaEntry.getAttributeValues(ATTR_DIT_CONTENT_RULE); 365 if (defs == null) 366 { 367 dcrMap = Collections.emptyMap(); 368 dcrSet = Collections.emptySet(); 369 } 370 else 371 { 372 final LinkedHashMap<String,DITContentRuleDefinition> m = 373 new LinkedHashMap<String,DITContentRuleDefinition>(2*defs.length); 374 final LinkedHashSet<DITContentRuleDefinition> s = 375 new LinkedHashSet<DITContentRuleDefinition>(defs.length); 376 377 for (final String def : defs) 378 { 379 try 380 { 381 final DITContentRuleDefinition dcr = 382 new DITContentRuleDefinition(def); 383 s.add(dcr); 384 m.put(toLowerCase(dcr.getOID()), dcr); 385 for (final String name : dcr.getNames()) 386 { 387 m.put(toLowerCase(name), dcr); 388 } 389 } 390 catch (final LDAPException le) 391 { 392 debugException(le); 393 } 394 } 395 396 dcrMap = Collections.unmodifiableMap(m); 397 dcrSet = Collections.unmodifiableSet(s); 398 } 399 400 401 // Decode the DIT structure rules from the schema entry. 402 defs = schemaEntry.getAttributeValues(ATTR_DIT_STRUCTURE_RULE); 403 if (defs == null) 404 { 405 dsrMapByID = Collections.emptyMap(); 406 dsrMapByName = Collections.emptyMap(); 407 dsrMapByNameForm = Collections.emptyMap(); 408 dsrSet = Collections.emptySet(); 409 } 410 else 411 { 412 final LinkedHashMap<Integer,DITStructureRuleDefinition> mID = 413 new LinkedHashMap<Integer,DITStructureRuleDefinition>(defs.length); 414 final LinkedHashMap<String,DITStructureRuleDefinition> mN = 415 new LinkedHashMap<String,DITStructureRuleDefinition>(defs.length); 416 final LinkedHashMap<String,DITStructureRuleDefinition> mNF = 417 new LinkedHashMap<String,DITStructureRuleDefinition>(defs.length); 418 final LinkedHashSet<DITStructureRuleDefinition> s = 419 new LinkedHashSet<DITStructureRuleDefinition>(defs.length); 420 421 for (final String def : defs) 422 { 423 try 424 { 425 final DITStructureRuleDefinition dsr = 426 new DITStructureRuleDefinition(def); 427 s.add(dsr); 428 mID.put(dsr.getRuleID(), dsr); 429 mNF.put(toLowerCase(dsr.getNameFormID()), dsr); 430 for (final String name : dsr.getNames()) 431 { 432 mN.put(toLowerCase(name), dsr); 433 } 434 } 435 catch (final LDAPException le) 436 { 437 debugException(le); 438 } 439 } 440 441 dsrMapByID = Collections.unmodifiableMap(mID); 442 dsrMapByName = Collections.unmodifiableMap(mN); 443 dsrMapByNameForm = Collections.unmodifiableMap(mNF); 444 dsrSet = Collections.unmodifiableSet(s); 445 } 446 447 448 // Decode the matching rules from the schema entry. 449 defs = schemaEntry.getAttributeValues(ATTR_MATCHING_RULE); 450 if (defs == null) 451 { 452 mrMap = Collections.emptyMap(); 453 mrSet = Collections.emptySet(); 454 } 455 else 456 { 457 final LinkedHashMap<String,MatchingRuleDefinition> m = 458 new LinkedHashMap<String,MatchingRuleDefinition>(2*defs.length); 459 final LinkedHashSet<MatchingRuleDefinition> s = 460 new LinkedHashSet<MatchingRuleDefinition>(defs.length); 461 462 for (final String def : defs) 463 { 464 try 465 { 466 final MatchingRuleDefinition mr = new MatchingRuleDefinition(def); 467 s.add(mr); 468 m.put(toLowerCase(mr.getOID()), mr); 469 for (final String name : mr.getNames()) 470 { 471 m.put(toLowerCase(name), mr); 472 } 473 } 474 catch (final LDAPException le) 475 { 476 debugException(le); 477 } 478 } 479 480 mrMap = Collections.unmodifiableMap(m); 481 mrSet = Collections.unmodifiableSet(s); 482 } 483 484 485 // Decode the matching rule uses from the schema entry. 486 defs = schemaEntry.getAttributeValues(ATTR_MATCHING_RULE_USE); 487 if (defs == null) 488 { 489 mruMap = Collections.emptyMap(); 490 mruSet = Collections.emptySet(); 491 } 492 else 493 { 494 final LinkedHashMap<String,MatchingRuleUseDefinition> m = 495 new LinkedHashMap<String,MatchingRuleUseDefinition>(2*defs.length); 496 final LinkedHashSet<MatchingRuleUseDefinition> s = 497 new LinkedHashSet<MatchingRuleUseDefinition>(defs.length); 498 499 for (final String def : defs) 500 { 501 try 502 { 503 final MatchingRuleUseDefinition mru = 504 new MatchingRuleUseDefinition(def); 505 s.add(mru); 506 m.put(toLowerCase(mru.getOID()), mru); 507 for (final String name : mru.getNames()) 508 { 509 m.put(toLowerCase(name), mru); 510 } 511 } 512 catch (final LDAPException le) 513 { 514 debugException(le); 515 } 516 } 517 518 mruMap = Collections.unmodifiableMap(m); 519 mruSet = Collections.unmodifiableSet(s); 520 } 521 522 523 // Decode the name forms from the schema entry. 524 defs = schemaEntry.getAttributeValues(ATTR_NAME_FORM); 525 if (defs == null) 526 { 527 nfMapByName = Collections.emptyMap(); 528 nfMapByOC = Collections.emptyMap(); 529 nfSet = Collections.emptySet(); 530 } 531 else 532 { 533 final LinkedHashMap<String,NameFormDefinition> mN = 534 new LinkedHashMap<String,NameFormDefinition>(2*defs.length); 535 final LinkedHashMap<String,NameFormDefinition> mOC = 536 new LinkedHashMap<String,NameFormDefinition>(defs.length); 537 final LinkedHashSet<NameFormDefinition> s = 538 new LinkedHashSet<NameFormDefinition>(defs.length); 539 540 for (final String def : defs) 541 { 542 try 543 { 544 final NameFormDefinition nf = new NameFormDefinition(def); 545 s.add(nf); 546 mOC.put(toLowerCase(nf.getStructuralClass()), nf); 547 mN.put(toLowerCase(nf.getOID()), nf); 548 for (final String name : nf.getNames()) 549 { 550 mN.put(toLowerCase(name), nf); 551 } 552 } 553 catch (final LDAPException le) 554 { 555 debugException(le); 556 } 557 } 558 559 nfMapByName = Collections.unmodifiableMap(mN); 560 nfMapByOC = Collections.unmodifiableMap(mOC); 561 nfSet = Collections.unmodifiableSet(s); 562 } 563 564 565 // Decode the object classes from the schema entry. 566 defs = schemaEntry.getAttributeValues(ATTR_OBJECT_CLASS); 567 if (defs == null) 568 { 569 ocMap = Collections.emptyMap(); 570 ocSet = Collections.emptySet(); 571 abstractOCSet = Collections.emptySet(); 572 auxiliaryOCSet = Collections.emptySet(); 573 structuralOCSet = Collections.emptySet(); 574 } 575 else 576 { 577 final LinkedHashMap<String,ObjectClassDefinition> m = 578 new LinkedHashMap<String,ObjectClassDefinition>(2*defs.length); 579 final LinkedHashSet<ObjectClassDefinition> s = 580 new LinkedHashSet<ObjectClassDefinition>(defs.length); 581 final LinkedHashSet<ObjectClassDefinition> sAbstract = 582 new LinkedHashSet<ObjectClassDefinition>(defs.length); 583 final LinkedHashSet<ObjectClassDefinition> sAuxiliary = 584 new LinkedHashSet<ObjectClassDefinition>(defs.length); 585 final LinkedHashSet<ObjectClassDefinition> sStructural = 586 new LinkedHashSet<ObjectClassDefinition>(defs.length); 587 588 for (final String def : defs) 589 { 590 try 591 { 592 final ObjectClassDefinition oc = new ObjectClassDefinition(def); 593 s.add(oc); 594 m.put(toLowerCase(oc.getOID()), oc); 595 for (final String name : oc.getNames()) 596 { 597 m.put(toLowerCase(name), oc); 598 } 599 600 switch (getOCType(oc, m)) 601 { 602 case ABSTRACT: 603 sAbstract.add(oc); 604 break; 605 case AUXILIARY: 606 sAuxiliary.add(oc); 607 break; 608 case STRUCTURAL: 609 sStructural.add(oc); 610 break; 611 } 612 } 613 catch (final LDAPException le) 614 { 615 debugException(le); 616 } 617 } 618 619 ocMap = Collections.unmodifiableMap(m); 620 ocSet = Collections.unmodifiableSet(s); 621 abstractOCSet = Collections.unmodifiableSet(sAbstract); 622 auxiliaryOCSet = Collections.unmodifiableSet(sAuxiliary); 623 structuralOCSet = Collections.unmodifiableSet(sStructural); 624 } 625 626 627 // Populate the map of subordinate attribute types. 628 final LinkedHashMap<AttributeTypeDefinition,List<AttributeTypeDefinition>> 629 subAttrTypes = new LinkedHashMap<AttributeTypeDefinition, 630 List<AttributeTypeDefinition>>(atSet.size()); 631 for (final AttributeTypeDefinition d : atSet) 632 { 633 AttributeTypeDefinition sup = d.getSuperiorType(this); 634 while (sup != null) 635 { 636 List<AttributeTypeDefinition> l = subAttrTypes.get(sup); 637 if (l == null) 638 { 639 l = new ArrayList<AttributeTypeDefinition>(1); 640 subAttrTypes.put(sup, l); 641 } 642 l.add(d); 643 644 sup = sup.getSuperiorType(this); 645 } 646 } 647 subordinateAttributeTypes = Collections.unmodifiableMap(subAttrTypes); 648 } 649 650 651 652 /** 653 * Retrieves the directory server schema over the provided connection. The 654 * root DSE will first be retrieved in order to get its subschemaSubentry DN, 655 * and then that entry will be retrieved from the server and its contents 656 * decoded as schema elements. This should be sufficient for directories that 657 * only provide a single schema, but for directories with multiple schemas it 658 * may be necessary to specify the DN of an entry for which to retrieve the 659 * subschema subentry. 660 * 661 * @param connection The connection to use in order to retrieve the server 662 * schema. It must not be {@code null}. 663 * 664 * @return A decoded representation of the server schema. 665 * 666 * @throws LDAPException If a problem occurs while obtaining the server 667 * schema. 668 */ 669 public static Schema getSchema(final LDAPConnection connection) 670 throws LDAPException 671 { 672 return getSchema(connection, ""); 673 } 674 675 676 677 /** 678 * Retrieves the directory server schema that governs the specified entry. 679 * In some servers, different portions of the DIT may be served by different 680 * schemas, and in such cases it will be necessary to provide the DN of the 681 * target entry in order to ensure that the appropriate schema which governs 682 * that entry is returned. For servers that support only a single schema, 683 * any entry DN (including that of the root DSE) should be sufficient. 684 * 685 * @param connection The connection to use in order to retrieve the server 686 * schema. It must not be {@code null}. 687 * @param entryDN The DN of the entry for which to retrieve the governing 688 * schema. It may be {@code null} or an empty string in 689 * order to retrieve the schema that governs the server's 690 * root DSE. 691 * 692 * @return A decoded representation of the server schema, or {@code null} if 693 * it is not available for some reason (e.g., the client does not 694 * have permission to read the server schema). 695 * 696 * @throws LDAPException If a problem occurs while obtaining the server 697 * schema. 698 */ 699 public static Schema getSchema(final LDAPConnection connection, 700 final String entryDN) 701 throws LDAPException 702 { 703 ensureNotNull(connection); 704 705 final String subschemaSubentryDN; 706 if (entryDN == null) 707 { 708 subschemaSubentryDN = getSubschemaSubentryDN(connection, ""); 709 } 710 else 711 { 712 subschemaSubentryDN = getSubschemaSubentryDN(connection, entryDN); 713 } 714 715 if (subschemaSubentryDN == null) 716 { 717 return null; 718 } 719 720 final Entry schemaEntry = 721 connection.getEntry(subschemaSubentryDN, SCHEMA_REQUEST_ATTRS); 722 if (schemaEntry == null) 723 { 724 return null; 725 } 726 727 return new Schema(schemaEntry); 728 } 729 730 731 732 /** 733 * Reads schema information from one or more files containing the schema 734 * represented in LDIF form, with the definitions represented in the form 735 * described in section 4.1 of RFC 4512. Each file should contain a single 736 * entry. 737 * 738 * @param schemaFiles The paths to the LDIF files containing the schema 739 * information to be read. At least one file must be 740 * specified. If multiple files are specified, then they 741 * will be processed in the order in which they have been 742 * listed. 743 * 744 * @return The schema read from the specified schema files, or {@code null} 745 * if none of the files contains any LDIF data to be read. 746 * 747 * @throws IOException If a problem occurs while attempting to read from 748 * any of the specified files. 749 * 750 * @throws LDIFException If a problem occurs while attempting to parse the 751 * contents of any of the schema files. 752 */ 753 public static Schema getSchema(final String... schemaFiles) 754 throws IOException, LDIFException 755 { 756 ensureNotNull(schemaFiles); 757 ensureFalse(schemaFiles.length == 0); 758 759 final ArrayList<File> files = new ArrayList<File>(schemaFiles.length); 760 for (final String s : schemaFiles) 761 { 762 files.add(new File(s)); 763 } 764 765 return getSchema(files); 766 } 767 768 769 770 /** 771 * Reads schema information from one or more files containing the schema 772 * represented in LDIF form, with the definitions represented in the form 773 * described in section 4.1 of RFC 4512. Each file should contain a single 774 * entry. 775 * 776 * @param schemaFiles The paths to the LDIF files containing the schema 777 * information to be read. At least one file must be 778 * specified. If multiple files are specified, then they 779 * will be processed in the order in which they have been 780 * listed. 781 * 782 * @return The schema read from the specified schema files, or {@code null} 783 * if none of the files contains any LDIF data to be read. 784 * 785 * @throws IOException If a problem occurs while attempting to read from 786 * any of the specified files. 787 * 788 * @throws LDIFException If a problem occurs while attempting to parse the 789 * contents of any of the schema files. 790 */ 791 public static Schema getSchema(final File... schemaFiles) 792 throws IOException, LDIFException 793 { 794 ensureNotNull(schemaFiles); 795 ensureFalse(schemaFiles.length == 0); 796 797 return getSchema(Arrays.asList(schemaFiles)); 798 } 799 800 801 802 /** 803 * Reads schema information from one or more files containing the schema 804 * represented in LDIF form, with the definitions represented in the form 805 * described in section 4.1 of RFC 4512. Each file should contain a single 806 * entry. 807 * 808 * @param schemaFiles The paths to the LDIF files containing the schema 809 * information to be read. At least one file must be 810 * specified. If multiple files are specified, then they 811 * will be processed in the order in which they have been 812 * listed. 813 * 814 * @return The schema read from the specified schema files, or {@code null} 815 * if none of the files contains any LDIF data to be read. 816 * 817 * @throws IOException If a problem occurs while attempting to read from 818 * any of the specified files. 819 * 820 * @throws LDIFException If a problem occurs while attempting to parse the 821 * contents of any of the schema files. 822 */ 823 public static Schema getSchema(final List<File> schemaFiles) 824 throws IOException, LDIFException 825 { 826 ensureNotNull(schemaFiles); 827 ensureFalse(schemaFiles.isEmpty()); 828 829 Entry schemaEntry = null; 830 for (final File f : schemaFiles) 831 { 832 final LDIFReader ldifReader = new LDIFReader(f); 833 834 try 835 { 836 final Entry e = ldifReader.readEntry(); 837 if (e == null) 838 { 839 continue; 840 } 841 842 if (schemaEntry == null) 843 { 844 schemaEntry = e; 845 } 846 else 847 { 848 for (final Attribute a : e.getAttributes()) 849 { 850 schemaEntry.addAttribute(a); 851 } 852 } 853 } 854 finally 855 { 856 ldifReader.close(); 857 } 858 } 859 860 if (schemaEntry == null) 861 { 862 return null; 863 } 864 865 return new Schema(schemaEntry); 866 } 867 868 869 870 /** 871 * Retrieves a schema containing all of the elements of each of the provided 872 * schemas. 873 * 874 * @param schemas The schemas to be merged. It must not be {@code null} or 875 * empty. 876 * 877 * @return A merged representation of the provided schemas. 878 */ 879 public static Schema mergeSchemas(final Schema... schemas) 880 { 881 if ((schemas == null) || (schemas.length == 0)) 882 { 883 return null; 884 } 885 else if (schemas.length == 1) 886 { 887 return schemas[0]; 888 } 889 890 final LinkedHashMap<String,String> asMap = 891 new LinkedHashMap<String,String>(); 892 final LinkedHashMap<String,String> atMap = 893 new LinkedHashMap<String,String>(); 894 final LinkedHashMap<String,String> dcrMap = 895 new LinkedHashMap<String,String>(); 896 final LinkedHashMap<Integer,String> dsrMap = 897 new LinkedHashMap<Integer,String>(); 898 final LinkedHashMap<String,String> mrMap = 899 new LinkedHashMap<String,String>(); 900 final LinkedHashMap<String,String> mruMap = 901 new LinkedHashMap<String,String>(); 902 final LinkedHashMap<String,String> nfMap = 903 new LinkedHashMap<String,String>(); 904 final LinkedHashMap<String,String> ocMap = 905 new LinkedHashMap<String,String>(); 906 907 for (final Schema s : schemas) 908 { 909 for (final AttributeSyntaxDefinition as : s.asSet) 910 { 911 asMap.put(toLowerCase(as.getOID()), as.toString()); 912 } 913 914 for (final AttributeTypeDefinition at : s.atSet) 915 { 916 atMap.put(toLowerCase(at.getOID()), at.toString()); 917 } 918 919 for (final DITContentRuleDefinition dcr : s.dcrSet) 920 { 921 dcrMap.put(toLowerCase(dcr.getOID()), dcr.toString()); 922 } 923 924 for (final DITStructureRuleDefinition dsr : s.dsrSet) 925 { 926 dsrMap.put(dsr.getRuleID(), dsr.toString()); 927 } 928 929 for (final MatchingRuleDefinition mr : s.mrSet) 930 { 931 mrMap.put(toLowerCase(mr.getOID()), mr.toString()); 932 } 933 934 for (final MatchingRuleUseDefinition mru : s.mruSet) 935 { 936 mruMap.put(toLowerCase(mru.getOID()), mru.toString()); 937 } 938 939 for (final NameFormDefinition nf : s.nfSet) 940 { 941 nfMap.put(toLowerCase(nf.getOID()), nf.toString()); 942 } 943 944 for (final ObjectClassDefinition oc : s.ocSet) 945 { 946 ocMap.put(toLowerCase(oc.getOID()), oc.toString()); 947 } 948 } 949 950 final Entry e = new Entry(schemas[0].getSchemaEntry().getDN()); 951 952 final Attribute ocAttr = 953 schemas[0].getSchemaEntry().getObjectClassAttribute(); 954 if (ocAttr == null) 955 { 956 e.addAttribute("objectClass", "top", "ldapSubEntry", "subschema"); 957 } 958 else 959 { 960 e.addAttribute(ocAttr); 961 } 962 963 if (! asMap.isEmpty()) 964 { 965 final String[] values = new String[asMap.size()]; 966 e.addAttribute(ATTR_ATTRIBUTE_SYNTAX, asMap.values().toArray(values)); 967 } 968 969 if (! mrMap.isEmpty()) 970 { 971 final String[] values = new String[mrMap.size()]; 972 e.addAttribute(ATTR_MATCHING_RULE, mrMap.values().toArray(values)); 973 } 974 975 if (! atMap.isEmpty()) 976 { 977 final String[] values = new String[atMap.size()]; 978 e.addAttribute(ATTR_ATTRIBUTE_TYPE, atMap.values().toArray(values)); 979 } 980 981 if (! ocMap.isEmpty()) 982 { 983 final String[] values = new String[ocMap.size()]; 984 e.addAttribute(ATTR_OBJECT_CLASS, ocMap.values().toArray(values)); 985 } 986 987 if (! dcrMap.isEmpty()) 988 { 989 final String[] values = new String[dcrMap.size()]; 990 e.addAttribute(ATTR_DIT_CONTENT_RULE, dcrMap.values().toArray(values)); 991 } 992 993 if (! dsrMap.isEmpty()) 994 { 995 final String[] values = new String[dsrMap.size()]; 996 e.addAttribute(ATTR_DIT_STRUCTURE_RULE, dsrMap.values().toArray(values)); 997 } 998 999 if (! nfMap.isEmpty()) 1000 { 1001 final String[] values = new String[nfMap.size()]; 1002 e.addAttribute(ATTR_NAME_FORM, nfMap.values().toArray(values)); 1003 } 1004 1005 if (! mruMap.isEmpty()) 1006 { 1007 final String[] values = new String[mruMap.size()]; 1008 e.addAttribute(ATTR_MATCHING_RULE_USE, mruMap.values().toArray(values)); 1009 } 1010 1011 return new Schema(e); 1012 } 1013 1014 1015 1016 /** 1017 * Retrieves the entry used to create this schema object. 1018 * 1019 * @return The entry used to create this schema object. 1020 */ 1021 public ReadOnlyEntry getSchemaEntry() 1022 { 1023 return schemaEntry; 1024 } 1025 1026 1027 1028 /** 1029 * Retrieves the object class type for the specified object class, recursively 1030 * checking its parents as needed. 1031 * 1032 * @param oc The object class definition for which to make the 1033 * determination. 1034 * @param m The map of defined object classes. 1035 * 1036 * @return The object class type for the object class. 1037 */ 1038 private static ObjectClassType getOCType(final ObjectClassDefinition oc, 1039 final Map<String,ObjectClassDefinition> m) 1040 { 1041 ObjectClassType t = oc.getObjectClassType(); 1042 if (t != null) 1043 { 1044 return t; 1045 } 1046 1047 for (final String s : oc.getSuperiorClasses()) 1048 { 1049 final ObjectClassDefinition d = m.get(toLowerCase(s)); 1050 if (d != null) 1051 { 1052 t = getOCType(d, m); 1053 if (t != null) 1054 { 1055 return t; 1056 } 1057 } 1058 } 1059 1060 return ObjectClassType.STRUCTURAL; 1061 } 1062 1063 1064 1065 /** 1066 * Retrieves the value of the subschemaSubentry attribute from the specified 1067 * entry using the provided connection. 1068 * 1069 * @param connection The connection to use in order to perform the search. 1070 * It must not be {@code null}. 1071 * @param entryDN The DN of the entry from which to retrieve the 1072 * subschemaSubentry attribute. It may be {@code null} or 1073 * an empty string in order to retrieve the value from the 1074 * server's root DSE. 1075 * 1076 * @return The value of the subschemaSubentry attribute from the specified 1077 * entry, or {@code null} if it is not available for some reason 1078 * (e.g., the client does not have permission to read the target 1079 * entry or the subschemaSubentry attribute). 1080 * 1081 * @throws LDAPException If a problem occurs while attempting to retrieve 1082 * the specified entry. 1083 */ 1084 public static String getSubschemaSubentryDN(final LDAPConnection connection, 1085 final String entryDN) 1086 throws LDAPException 1087 { 1088 ensureNotNull(connection); 1089 1090 final Entry e; 1091 if (entryDN == null) 1092 { 1093 e = connection.getEntry("", SUBSCHEMA_SUBENTRY_REQUEST_ATTRS); 1094 } 1095 else 1096 { 1097 e = connection.getEntry(entryDN, SUBSCHEMA_SUBENTRY_REQUEST_ATTRS); 1098 } 1099 1100 if (e == null) 1101 { 1102 return null; 1103 } 1104 1105 return e.getAttributeValue(ATTR_SUBSCHEMA_SUBENTRY); 1106 } 1107 1108 1109 1110 /** 1111 * Retrieves the set of attribute syntax definitions contained in the server 1112 * schema. 1113 * 1114 * @return The set of attribute syntax definitions contained in the server 1115 * schema. 1116 */ 1117 public Set<AttributeSyntaxDefinition> getAttributeSyntaxes() 1118 { 1119 return asSet; 1120 } 1121 1122 1123 1124 /** 1125 * Retrieves the attribute syntax with the specified OID from the server 1126 * schema. 1127 * 1128 * @param oid The OID of the attribute syntax to retrieve. It must not be 1129 * {@code null}. It may optionally include a minimum upper bound 1130 * (as may appear when the syntax OID is included in an attribute 1131 * type definition), but if it does then that portion will be 1132 * ignored when retrieving the attribute syntax. 1133 * 1134 * @return The requested attribute syntax, or {@code null} if there is no 1135 * such syntax defined in the server schema. 1136 */ 1137 public AttributeSyntaxDefinition getAttributeSyntax(final String oid) 1138 { 1139 ensureNotNull(oid); 1140 1141 final String lowerOID = toLowerCase(oid); 1142 final int curlyPos = lowerOID.indexOf('{'); 1143 1144 if (curlyPos > 0) 1145 { 1146 return asMap.get(lowerOID.substring(0, curlyPos)); 1147 } 1148 else 1149 { 1150 return asMap.get(lowerOID); 1151 } 1152 } 1153 1154 1155 1156 /** 1157 * Retrieves the set of attribute type definitions contained in the server 1158 * schema. 1159 * 1160 * @return The set of attribute type definitions contained in the server 1161 * schema. 1162 */ 1163 public Set<AttributeTypeDefinition> getAttributeTypes() 1164 { 1165 return atSet; 1166 } 1167 1168 1169 1170 /** 1171 * Retrieves the set of operational attribute type definitions (i.e., those 1172 * definitions with a usage of directoryOperation, distributedOperation, or 1173 * dSAOperation) contained in the server schema. 1174 * 1175 * @return The set of operational attribute type definitions contained in the 1176 * server schema. 1177 */ 1178 public Set<AttributeTypeDefinition> getOperationalAttributeTypes() 1179 { 1180 return operationalATSet; 1181 } 1182 1183 1184 1185 /** 1186 * Retrieves the set of user attribute type definitions (i.e., those 1187 * definitions with a usage of userApplications) contained in the server 1188 * schema. 1189 * 1190 * @return The set of user attribute type definitions contained in the server 1191 * schema. 1192 */ 1193 public Set<AttributeTypeDefinition> getUserAttributeTypes() 1194 { 1195 return userATSet; 1196 } 1197 1198 1199 1200 /** 1201 * Retrieves the attribute type with the specified name or OID from the server 1202 * schema. 1203 * 1204 * @param name The name or OID of the attribute type to retrieve. It must 1205 * not be {@code null}. 1206 * 1207 * @return The requested attribute type, or {@code null} if there is no 1208 * such attribute type defined in the server schema. 1209 */ 1210 public AttributeTypeDefinition getAttributeType(final String name) 1211 { 1212 ensureNotNull(name); 1213 1214 return atMap.get(toLowerCase(name)); 1215 } 1216 1217 1218 1219 /** 1220 * Retrieves a list of all subordinate attribute type definitions for the 1221 * provided attribute type definition. 1222 * 1223 * @param d The attribute type definition for which to retrieve all 1224 * subordinate attribute types. It must not be {@code null}. 1225 * 1226 * @return A list of all subordinate attribute type definitions for the 1227 * provided attribute type definition, or an empty list if it does 1228 * not have any subordinate types or the provided attribute type is 1229 * not defined in the schema. 1230 */ 1231 public List<AttributeTypeDefinition> getSubordinateAttributeTypes( 1232 final AttributeTypeDefinition d) 1233 { 1234 ensureNotNull(d); 1235 1236 final List<AttributeTypeDefinition> l = subordinateAttributeTypes.get(d); 1237 if (l == null) 1238 { 1239 return Collections.emptyList(); 1240 } 1241 else 1242 { 1243 return Collections.unmodifiableList(l); 1244 } 1245 } 1246 1247 1248 1249 /** 1250 * Retrieves the set of DIT content rule definitions contained in the server 1251 * schema. 1252 * 1253 * @return The set of DIT content rule definitions contained in the server 1254 * schema. 1255 */ 1256 public Set<DITContentRuleDefinition> getDITContentRules() 1257 { 1258 return dcrSet; 1259 } 1260 1261 1262 1263 /** 1264 * Retrieves the DIT content rule with the specified name or OID from the 1265 * server schema. 1266 * 1267 * @param name The name or OID of the DIT content rule to retrieve. It must 1268 * not be {@code null}. 1269 * 1270 * @return The requested DIT content rule, or {@code null} if there is no 1271 * such rule defined in the server schema. 1272 */ 1273 public DITContentRuleDefinition getDITContentRule(final String name) 1274 { 1275 ensureNotNull(name); 1276 1277 return dcrMap.get(toLowerCase(name)); 1278 } 1279 1280 1281 1282 /** 1283 * Retrieves the set of DIT structure rule definitions contained in the server 1284 * schema. 1285 * 1286 * @return The set of DIT structure rule definitions contained in the server 1287 * schema. 1288 */ 1289 public Set<DITStructureRuleDefinition> getDITStructureRules() 1290 { 1291 return dsrSet; 1292 } 1293 1294 1295 1296 /** 1297 * Retrieves the DIT content rule with the specified rule ID from the server 1298 * schema. 1299 * 1300 * @param ruleID The rule ID for the DIT structure rule to retrieve. 1301 * 1302 * @return The requested DIT structure rule, or {@code null} if there is no 1303 * such rule defined in the server schema. 1304 */ 1305 public DITStructureRuleDefinition getDITStructureRuleByID(final int ruleID) 1306 { 1307 return dsrMapByID.get(ruleID); 1308 } 1309 1310 1311 1312 /** 1313 * Retrieves the DIT content rule with the specified name from the server 1314 * schema. 1315 * 1316 * @param ruleName The name of the DIT structure rule to retrieve. It must 1317 * not be {@code null}. 1318 * 1319 * @return The requested DIT structure rule, or {@code null} if there is no 1320 * such rule defined in the server schema. 1321 */ 1322 public DITStructureRuleDefinition getDITStructureRuleByName( 1323 final String ruleName) 1324 { 1325 ensureNotNull(ruleName); 1326 1327 return dsrMapByName.get(toLowerCase(ruleName)); 1328 } 1329 1330 1331 1332 /** 1333 * Retrieves the DIT content rule associated with the specified name form from 1334 * the server schema. 1335 * 1336 * @param nameForm The name or OID of the name form for which to retrieve 1337 * the associated DIT structure rule. 1338 * 1339 * @return The requested DIT structure rule, or {@code null} if there is no 1340 * such rule defined in the server schema. 1341 */ 1342 public DITStructureRuleDefinition getDITStructureRuleByNameForm( 1343 final String nameForm) 1344 { 1345 ensureNotNull(nameForm); 1346 1347 return dsrMapByNameForm.get(toLowerCase(nameForm)); 1348 } 1349 1350 1351 1352 /** 1353 * Retrieves the set of matching rule definitions contained in the server 1354 * schema. 1355 * 1356 * @return The set of matching rule definitions contained in the server 1357 * schema. 1358 */ 1359 public Set<MatchingRuleDefinition> getMatchingRules() 1360 { 1361 return mrSet; 1362 } 1363 1364 1365 1366 /** 1367 * Retrieves the matching rule with the specified name or OID from the server 1368 * schema. 1369 * 1370 * @param name The name or OID of the matching rule to retrieve. It must 1371 * not be {@code null}. 1372 * 1373 * @return The requested matching rule, or {@code null} if there is no 1374 * such rule defined in the server schema. 1375 */ 1376 public MatchingRuleDefinition getMatchingRule(final String name) 1377 { 1378 ensureNotNull(name); 1379 1380 return mrMap.get(toLowerCase(name)); 1381 } 1382 1383 1384 1385 /** 1386 * Retrieves the set of matching rule use definitions contained in the server 1387 * schema. 1388 * 1389 * @return The set of matching rule use definitions contained in the server 1390 * schema. 1391 */ 1392 public Set<MatchingRuleUseDefinition> getMatchingRuleUses() 1393 { 1394 return mruSet; 1395 } 1396 1397 1398 1399 /** 1400 * Retrieves the matching rule use with the specified name or OID from the 1401 * server schema. 1402 * 1403 * @param name The name or OID of the matching rule use to retrieve. It 1404 * must not be {@code null}. 1405 * 1406 * @return The requested matching rule, or {@code null} if there is no 1407 * such matching rule use defined in the server schema. 1408 */ 1409 public MatchingRuleUseDefinition getMatchingRuleUse(final String name) 1410 { 1411 ensureNotNull(name); 1412 1413 return mruMap.get(toLowerCase(name)); 1414 } 1415 1416 1417 1418 /** 1419 * Retrieves the set of name form definitions contained in the server schema. 1420 * 1421 * @return The set of name form definitions contained in the server schema. 1422 */ 1423 public Set<NameFormDefinition> getNameForms() 1424 { 1425 return nfSet; 1426 } 1427 1428 1429 1430 /** 1431 * Retrieves the name form with the specified name or OID from the server 1432 * schema. 1433 * 1434 * @param name The name or OID of the name form to retrieve. It must not be 1435 * {@code null}. 1436 * 1437 * @return The requested name form, or {@code null} if there is no 1438 * such rule defined in the server schema. 1439 */ 1440 public NameFormDefinition getNameFormByName(final String name) 1441 { 1442 ensureNotNull(name); 1443 1444 return nfMapByName.get(toLowerCase(name)); 1445 } 1446 1447 1448 1449 /** 1450 * Retrieves the name form associated with the specified structural object 1451 * class from the server schema. 1452 * 1453 * @param objectClass The name or OID of the structural object class for 1454 * which to retrieve the associated name form. It must 1455 * not be {@code null}. 1456 * 1457 * @return The requested name form, or {@code null} if there is no 1458 * such rule defined in the server schema. 1459 */ 1460 public NameFormDefinition getNameFormByObjectClass(final String objectClass) 1461 { 1462 ensureNotNull(objectClass); 1463 1464 return nfMapByOC.get(toLowerCase(objectClass)); 1465 } 1466 1467 1468 1469 /** 1470 * Retrieves the set of object class definitions contained in the server 1471 * schema. 1472 * 1473 * @return The set of object class definitions contained in the server 1474 * schema. 1475 */ 1476 public Set<ObjectClassDefinition> getObjectClasses() 1477 { 1478 return ocSet; 1479 } 1480 1481 1482 1483 /** 1484 * Retrieves the set of abstract object class definitions contained in the 1485 * server schema. 1486 * 1487 * @return The set of abstract object class definitions contained in the 1488 * server schema. 1489 */ 1490 public Set<ObjectClassDefinition> getAbstractObjectClasses() 1491 { 1492 return abstractOCSet; 1493 } 1494 1495 1496 1497 /** 1498 * Retrieves the set of auxiliary object class definitions contained in the 1499 * server schema. 1500 * 1501 * @return The set of auxiliary object class definitions contained in the 1502 * server schema. 1503 */ 1504 public Set<ObjectClassDefinition> getAuxiliaryObjectClasses() 1505 { 1506 return auxiliaryOCSet; 1507 } 1508 1509 1510 1511 /** 1512 * Retrieves the set of structural object class definitions contained in the 1513 * server schema. 1514 * 1515 * @return The set of structural object class definitions contained in the 1516 * server schema. 1517 */ 1518 public Set<ObjectClassDefinition> getStructuralObjectClasses() 1519 { 1520 return structuralOCSet; 1521 } 1522 1523 1524 1525 /** 1526 * Retrieves the object class with the specified name or OID from the server 1527 * schema. 1528 * 1529 * @param name The name or OID of the object class to retrieve. It must 1530 * not be {@code null}. 1531 * 1532 * @return The requested object class, or {@code null} if there is no such 1533 * class defined in the server schema. 1534 */ 1535 public ObjectClassDefinition getObjectClass(final String name) 1536 { 1537 ensureNotNull(name); 1538 1539 return ocMap.get(toLowerCase(name)); 1540 } 1541 1542 1543 1544 /** 1545 * Retrieves a hash code for this schema object. 1546 * 1547 * @return A hash code for this schema object. 1548 */ 1549 @Override() 1550 public int hashCode() 1551 { 1552 int hc; 1553 try 1554 { 1555 hc = schemaEntry.getParsedDN().hashCode(); 1556 } 1557 catch (final Exception e) 1558 { 1559 debugException(e); 1560 hc = toLowerCase(schemaEntry.getDN()).hashCode(); 1561 } 1562 1563 Attribute a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_SYNTAX); 1564 if (a != null) 1565 { 1566 hc += a.hashCode(); 1567 } 1568 1569 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE); 1570 if (a != null) 1571 { 1572 hc += a.hashCode(); 1573 } 1574 1575 a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_TYPE); 1576 if (a != null) 1577 { 1578 hc += a.hashCode(); 1579 } 1580 1581 a = schemaEntry.getAttribute(ATTR_OBJECT_CLASS); 1582 if (a != null) 1583 { 1584 hc += a.hashCode(); 1585 } 1586 1587 a = schemaEntry.getAttribute(ATTR_NAME_FORM); 1588 if (a != null) 1589 { 1590 hc += a.hashCode(); 1591 } 1592 1593 a = schemaEntry.getAttribute(ATTR_DIT_CONTENT_RULE); 1594 if (a != null) 1595 { 1596 hc += a.hashCode(); 1597 } 1598 1599 a = schemaEntry.getAttribute(ATTR_DIT_STRUCTURE_RULE); 1600 if (a != null) 1601 { 1602 hc += a.hashCode(); 1603 } 1604 1605 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE_USE); 1606 if (a != null) 1607 { 1608 hc += a.hashCode(); 1609 } 1610 1611 return hc; 1612 } 1613 1614 1615 1616 /** 1617 * Indicates whether the provided object is equal to this schema object. 1618 * 1619 * @param o The object for which to make the determination. 1620 * 1621 * @return {@code true} if the provided object is equal to this schema 1622 * object, or {@code false} if not. 1623 */ 1624 @Override() 1625 public boolean equals(final Object o) 1626 { 1627 if (o == null) 1628 { 1629 return false; 1630 } 1631 1632 if (o == this) 1633 { 1634 return true; 1635 } 1636 1637 if (! (o instanceof Schema)) 1638 { 1639 return false; 1640 } 1641 1642 final Schema s = (Schema) o; 1643 1644 try 1645 { 1646 if (! schemaEntry.getParsedDN().equals(s.schemaEntry.getParsedDN())) 1647 { 1648 return false; 1649 } 1650 } 1651 catch (final Exception e) 1652 { 1653 debugException(e); 1654 if (! schemaEntry.getDN().equalsIgnoreCase(s.schemaEntry.getDN())) 1655 { 1656 return false; 1657 } 1658 } 1659 1660 return (asSet.equals(s.asSet) && 1661 mrSet.equals(s.mrSet) && 1662 atSet.equals(s.atSet) && 1663 ocSet.equals(s.ocSet) && 1664 nfSet.equals(s.nfSet) && 1665 dcrSet.equals(s.dcrSet) && 1666 dsrSet.equals(s.dsrSet) && 1667 mruSet.equals(s.mruSet)); 1668 } 1669 1670 1671 1672 /** 1673 * Retrieves a string representation of the associated schema entry. 1674 * 1675 * @return A string representation of the associated schema entry. 1676 */ 1677 @Override() 1678 public String toString() 1679 { 1680 return schemaEntry.toString(); 1681 } 1682 }