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