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