001/* 002 * Copyright 2007-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2018 Ping Identity Corporation 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 (oc.getObjectClassType(null)) 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 * Reads schema information from the provided input stream. The information 884 * should be in LDIF form, with the definitions represented in the form 885 * described in section 4.1 of RFC 4512. Only a single entry will be read 886 * from the input stream, and it will be closed at the end of this method. 887 * 888 * @param inputStream The input stream from which the schema entry will be 889 * read. It must not be {@code null}, and it will be 890 * closed when this method returns. 891 * 892 * @return The schema read from the provided input stream, or {@code null} if 893 * the end of the input stream is reached without reading any data. 894 * 895 * @throws IOException If a problem is encountered while attempting to read 896 * from the provided input stream. 897 * 898 * @throws LDIFException If a problem occurs while attempting to parse the 899 * data read as LDIF. 900 */ 901 public static Schema getSchema(final InputStream inputStream) 902 throws IOException, LDIFException 903 { 904 ensureNotNull(inputStream); 905 906 final LDIFReader ldifReader = new LDIFReader(inputStream); 907 908 try 909 { 910 final Entry e = ldifReader.readEntry(); 911 if (e == null) 912 { 913 return null; 914 } 915 else 916 { 917 return new Schema(e); 918 } 919 } 920 finally 921 { 922 ldifReader.close(); 923 } 924 } 925 926 927 928 /** 929 * Retrieves a schema object that contains definitions for a number of 930 * standard attribute types and object classes from LDAP-related RFCs and 931 * Internet Drafts. 932 * 933 * @return A schema object that contains definitions for a number of standard 934 * attribute types and object classes from LDAP-related RFCs and 935 * Internet Drafts. 936 * 937 * @throws LDAPException If a problem occurs while attempting to obtain or 938 * parse the default standard schema definitions. 939 */ 940 public static Schema getDefaultStandardSchema() 941 throws LDAPException 942 { 943 final Schema s = DEFAULT_STANDARD_SCHEMA.get(); 944 if (s != null) 945 { 946 return s; 947 } 948 949 synchronized (DEFAULT_STANDARD_SCHEMA) 950 { 951 try 952 { 953 final ClassLoader classLoader = Schema.class.getClassLoader(); 954 final InputStream inputStream = 955 classLoader.getResourceAsStream(DEFAULT_SCHEMA_RESOURCE_PATH); 956 final LDIFReader ldifReader = new LDIFReader(inputStream); 957 final Entry schemaEntry = ldifReader.readEntry(); 958 ldifReader.close(); 959 960 final Schema schema = new Schema(schemaEntry); 961 DEFAULT_STANDARD_SCHEMA.set(schema); 962 return schema; 963 } 964 catch (final Exception e) 965 { 966 debugException(e); 967 throw new LDAPException(ResultCode.LOCAL_ERROR, 968 ERR_SCHEMA_CANNOT_LOAD_DEFAULT_DEFINITIONS.get( 969 getExceptionMessage(e)), 970 e); 971 } 972 } 973 } 974 975 976 977 /** 978 * Retrieves a schema containing all of the elements of each of the provided 979 * schemas. 980 * 981 * @param schemas The schemas to be merged. It must not be {@code null} or 982 * empty. 983 * 984 * @return A merged representation of the provided schemas. 985 */ 986 public static Schema mergeSchemas(final Schema... schemas) 987 { 988 if ((schemas == null) || (schemas.length == 0)) 989 { 990 return null; 991 } 992 else if (schemas.length == 1) 993 { 994 return schemas[0]; 995 } 996 997 final LinkedHashMap<String,String> asMap = 998 new LinkedHashMap<String,String>(); 999 final LinkedHashMap<String,String> atMap = 1000 new LinkedHashMap<String,String>(); 1001 final LinkedHashMap<String,String> dcrMap = 1002 new LinkedHashMap<String,String>(); 1003 final LinkedHashMap<Integer,String> dsrMap = 1004 new LinkedHashMap<Integer,String>(); 1005 final LinkedHashMap<String,String> mrMap = 1006 new LinkedHashMap<String,String>(); 1007 final LinkedHashMap<String,String> mruMap = 1008 new LinkedHashMap<String,String>(); 1009 final LinkedHashMap<String,String> nfMap = 1010 new LinkedHashMap<String,String>(); 1011 final LinkedHashMap<String,String> ocMap = 1012 new LinkedHashMap<String,String>(); 1013 1014 for (final Schema s : schemas) 1015 { 1016 for (final AttributeSyntaxDefinition as : s.asSet) 1017 { 1018 asMap.put(toLowerCase(as.getOID()), as.toString()); 1019 } 1020 1021 for (final AttributeTypeDefinition at : s.atSet) 1022 { 1023 atMap.put(toLowerCase(at.getOID()), at.toString()); 1024 } 1025 1026 for (final DITContentRuleDefinition dcr : s.dcrSet) 1027 { 1028 dcrMap.put(toLowerCase(dcr.getOID()), dcr.toString()); 1029 } 1030 1031 for (final DITStructureRuleDefinition dsr : s.dsrSet) 1032 { 1033 dsrMap.put(dsr.getRuleID(), dsr.toString()); 1034 } 1035 1036 for (final MatchingRuleDefinition mr : s.mrSet) 1037 { 1038 mrMap.put(toLowerCase(mr.getOID()), mr.toString()); 1039 } 1040 1041 for (final MatchingRuleUseDefinition mru : s.mruSet) 1042 { 1043 mruMap.put(toLowerCase(mru.getOID()), mru.toString()); 1044 } 1045 1046 for (final NameFormDefinition nf : s.nfSet) 1047 { 1048 nfMap.put(toLowerCase(nf.getOID()), nf.toString()); 1049 } 1050 1051 for (final ObjectClassDefinition oc : s.ocSet) 1052 { 1053 ocMap.put(toLowerCase(oc.getOID()), oc.toString()); 1054 } 1055 } 1056 1057 final Entry e = new Entry(schemas[0].getSchemaEntry().getDN()); 1058 1059 final Attribute ocAttr = 1060 schemas[0].getSchemaEntry().getObjectClassAttribute(); 1061 if (ocAttr == null) 1062 { 1063 e.addAttribute("objectClass", "top", "ldapSubEntry", "subschema"); 1064 } 1065 else 1066 { 1067 e.addAttribute(ocAttr); 1068 } 1069 1070 if (! asMap.isEmpty()) 1071 { 1072 final String[] values = new String[asMap.size()]; 1073 e.addAttribute(ATTR_ATTRIBUTE_SYNTAX, asMap.values().toArray(values)); 1074 } 1075 1076 if (! mrMap.isEmpty()) 1077 { 1078 final String[] values = new String[mrMap.size()]; 1079 e.addAttribute(ATTR_MATCHING_RULE, mrMap.values().toArray(values)); 1080 } 1081 1082 if (! atMap.isEmpty()) 1083 { 1084 final String[] values = new String[atMap.size()]; 1085 e.addAttribute(ATTR_ATTRIBUTE_TYPE, atMap.values().toArray(values)); 1086 } 1087 1088 if (! ocMap.isEmpty()) 1089 { 1090 final String[] values = new String[ocMap.size()]; 1091 e.addAttribute(ATTR_OBJECT_CLASS, ocMap.values().toArray(values)); 1092 } 1093 1094 if (! dcrMap.isEmpty()) 1095 { 1096 final String[] values = new String[dcrMap.size()]; 1097 e.addAttribute(ATTR_DIT_CONTENT_RULE, dcrMap.values().toArray(values)); 1098 } 1099 1100 if (! dsrMap.isEmpty()) 1101 { 1102 final String[] values = new String[dsrMap.size()]; 1103 e.addAttribute(ATTR_DIT_STRUCTURE_RULE, dsrMap.values().toArray(values)); 1104 } 1105 1106 if (! nfMap.isEmpty()) 1107 { 1108 final String[] values = new String[nfMap.size()]; 1109 e.addAttribute(ATTR_NAME_FORM, nfMap.values().toArray(values)); 1110 } 1111 1112 if (! mruMap.isEmpty()) 1113 { 1114 final String[] values = new String[mruMap.size()]; 1115 e.addAttribute(ATTR_MATCHING_RULE_USE, mruMap.values().toArray(values)); 1116 } 1117 1118 return new Schema(e); 1119 } 1120 1121 1122 1123 /** 1124 * Retrieves the entry used to create this schema object. 1125 * 1126 * @return The entry used to create this schema object. 1127 */ 1128 public ReadOnlyEntry getSchemaEntry() 1129 { 1130 return schemaEntry; 1131 } 1132 1133 1134 1135 /** 1136 * Retrieves the value of the subschemaSubentry attribute from the specified 1137 * entry using the provided connection. 1138 * 1139 * @param connection The connection to use in order to perform the search. 1140 * It must not be {@code null}. 1141 * @param entryDN The DN of the entry from which to retrieve the 1142 * subschemaSubentry attribute. It may be {@code null} or 1143 * an empty string in order to retrieve the value from the 1144 * server's root DSE. 1145 * 1146 * @return The value of the subschemaSubentry attribute from the specified 1147 * entry, or {@code null} if it is not available for some reason 1148 * (e.g., the client does not have permission to read the target 1149 * entry or the subschemaSubentry attribute). 1150 * 1151 * @throws LDAPException If a problem occurs while attempting to retrieve 1152 * the specified entry. 1153 */ 1154 public static String getSubschemaSubentryDN(final LDAPConnection connection, 1155 final String entryDN) 1156 throws LDAPException 1157 { 1158 ensureNotNull(connection); 1159 1160 final Entry e; 1161 if (entryDN == null) 1162 { 1163 e = connection.getEntry("", SUBSCHEMA_SUBENTRY_REQUEST_ATTRS); 1164 } 1165 else 1166 { 1167 e = connection.getEntry(entryDN, SUBSCHEMA_SUBENTRY_REQUEST_ATTRS); 1168 } 1169 1170 if (e == null) 1171 { 1172 return null; 1173 } 1174 1175 return e.getAttributeValue(ATTR_SUBSCHEMA_SUBENTRY); 1176 } 1177 1178 1179 1180 /** 1181 * Retrieves the set of attribute syntax definitions contained in the server 1182 * schema. 1183 * 1184 * @return The set of attribute syntax definitions contained in the server 1185 * schema. 1186 */ 1187 public Set<AttributeSyntaxDefinition> getAttributeSyntaxes() 1188 { 1189 return asSet; 1190 } 1191 1192 1193 1194 /** 1195 * Retrieves the attribute syntax with the specified OID from the server 1196 * schema. 1197 * 1198 * @param oid The OID of the attribute syntax to retrieve. It must not be 1199 * {@code null}. It may optionally include a minimum upper bound 1200 * (as may appear when the syntax OID is included in an attribute 1201 * type definition), but if it does then that portion will be 1202 * ignored when retrieving the attribute syntax. 1203 * 1204 * @return The requested attribute syntax, or {@code null} if there is no 1205 * such syntax defined in the server schema. 1206 */ 1207 public AttributeSyntaxDefinition getAttributeSyntax(final String oid) 1208 { 1209 ensureNotNull(oid); 1210 1211 final String lowerOID = toLowerCase(oid); 1212 final int curlyPos = lowerOID.indexOf('{'); 1213 1214 if (curlyPos > 0) 1215 { 1216 return asMap.get(lowerOID.substring(0, curlyPos)); 1217 } 1218 else 1219 { 1220 return asMap.get(lowerOID); 1221 } 1222 } 1223 1224 1225 1226 /** 1227 * Retrieves the set of attribute type definitions contained in the server 1228 * schema. 1229 * 1230 * @return The set of attribute type definitions contained in the server 1231 * schema. 1232 */ 1233 public Set<AttributeTypeDefinition> getAttributeTypes() 1234 { 1235 return atSet; 1236 } 1237 1238 1239 1240 /** 1241 * Retrieves the set of operational attribute type definitions (i.e., those 1242 * definitions with a usage of directoryOperation, distributedOperation, or 1243 * dSAOperation) contained in the server schema. 1244 * 1245 * @return The set of operational attribute type definitions contained in the 1246 * server schema. 1247 */ 1248 public Set<AttributeTypeDefinition> getOperationalAttributeTypes() 1249 { 1250 return operationalATSet; 1251 } 1252 1253 1254 1255 /** 1256 * Retrieves the set of user attribute type definitions (i.e., those 1257 * definitions with a usage of userApplications) contained in the server 1258 * schema. 1259 * 1260 * @return The set of user attribute type definitions contained in the server 1261 * schema. 1262 */ 1263 public Set<AttributeTypeDefinition> getUserAttributeTypes() 1264 { 1265 return userATSet; 1266 } 1267 1268 1269 1270 /** 1271 * Retrieves the attribute type with the specified name or OID from the server 1272 * schema. 1273 * 1274 * @param name The name or OID of the attribute type to retrieve. It must 1275 * not be {@code null}. 1276 * 1277 * @return The requested attribute type, or {@code null} if there is no 1278 * such attribute type defined in the server schema. 1279 */ 1280 public AttributeTypeDefinition getAttributeType(final String name) 1281 { 1282 ensureNotNull(name); 1283 1284 return atMap.get(toLowerCase(name)); 1285 } 1286 1287 1288 1289 /** 1290 * Retrieves a list of all subordinate attribute type definitions for the 1291 * provided attribute type definition. 1292 * 1293 * @param d The attribute type definition for which to retrieve all 1294 * subordinate attribute types. It must not be {@code null}. 1295 * 1296 * @return A list of all subordinate attribute type definitions for the 1297 * provided attribute type definition, or an empty list if it does 1298 * not have any subordinate types or the provided attribute type is 1299 * not defined in the schema. 1300 */ 1301 public List<AttributeTypeDefinition> getSubordinateAttributeTypes( 1302 final AttributeTypeDefinition d) 1303 { 1304 ensureNotNull(d); 1305 1306 final List<AttributeTypeDefinition> l = subordinateAttributeTypes.get(d); 1307 if (l == null) 1308 { 1309 return Collections.emptyList(); 1310 } 1311 else 1312 { 1313 return Collections.unmodifiableList(l); 1314 } 1315 } 1316 1317 1318 1319 /** 1320 * Retrieves the set of DIT content rule definitions contained in the server 1321 * schema. 1322 * 1323 * @return The set of DIT content rule definitions contained in the server 1324 * schema. 1325 */ 1326 public Set<DITContentRuleDefinition> getDITContentRules() 1327 { 1328 return dcrSet; 1329 } 1330 1331 1332 1333 /** 1334 * Retrieves the DIT content rule with the specified name or OID from the 1335 * server schema. 1336 * 1337 * @param name The name or OID of the DIT content rule to retrieve. It must 1338 * not be {@code null}. 1339 * 1340 * @return The requested DIT content rule, or {@code null} if there is no 1341 * such rule defined in the server schema. 1342 */ 1343 public DITContentRuleDefinition getDITContentRule(final String name) 1344 { 1345 ensureNotNull(name); 1346 1347 return dcrMap.get(toLowerCase(name)); 1348 } 1349 1350 1351 1352 /** 1353 * Retrieves the set of DIT structure rule definitions contained in the server 1354 * schema. 1355 * 1356 * @return The set of DIT structure rule definitions contained in the server 1357 * schema. 1358 */ 1359 public Set<DITStructureRuleDefinition> getDITStructureRules() 1360 { 1361 return dsrSet; 1362 } 1363 1364 1365 1366 /** 1367 * Retrieves the DIT content rule with the specified rule ID from the server 1368 * schema. 1369 * 1370 * @param ruleID The rule ID for the DIT structure rule to retrieve. 1371 * 1372 * @return The requested DIT structure rule, or {@code null} if there is no 1373 * such rule defined in the server schema. 1374 */ 1375 public DITStructureRuleDefinition getDITStructureRuleByID(final int ruleID) 1376 { 1377 return dsrMapByID.get(ruleID); 1378 } 1379 1380 1381 1382 /** 1383 * Retrieves the DIT content rule with the specified name from the server 1384 * schema. 1385 * 1386 * @param ruleName The name of the DIT structure rule to retrieve. It must 1387 * not be {@code null}. 1388 * 1389 * @return The requested DIT structure rule, or {@code null} if there is no 1390 * such rule defined in the server schema. 1391 */ 1392 public DITStructureRuleDefinition getDITStructureRuleByName( 1393 final String ruleName) 1394 { 1395 ensureNotNull(ruleName); 1396 1397 return dsrMapByName.get(toLowerCase(ruleName)); 1398 } 1399 1400 1401 1402 /** 1403 * Retrieves the DIT content rule associated with the specified name form from 1404 * the server schema. 1405 * 1406 * @param nameForm The name or OID of the name form for which to retrieve 1407 * the associated DIT structure rule. 1408 * 1409 * @return The requested DIT structure rule, or {@code null} if there is no 1410 * such rule defined in the server schema. 1411 */ 1412 public DITStructureRuleDefinition getDITStructureRuleByNameForm( 1413 final String nameForm) 1414 { 1415 ensureNotNull(nameForm); 1416 1417 return dsrMapByNameForm.get(toLowerCase(nameForm)); 1418 } 1419 1420 1421 1422 /** 1423 * Retrieves the set of matching rule definitions contained in the server 1424 * schema. 1425 * 1426 * @return The set of matching rule definitions contained in the server 1427 * schema. 1428 */ 1429 public Set<MatchingRuleDefinition> getMatchingRules() 1430 { 1431 return mrSet; 1432 } 1433 1434 1435 1436 /** 1437 * Retrieves the matching rule with the specified name or OID from the server 1438 * schema. 1439 * 1440 * @param name The name or OID of the matching rule to retrieve. It must 1441 * not be {@code null}. 1442 * 1443 * @return The requested matching rule, or {@code null} if there is no 1444 * such rule defined in the server schema. 1445 */ 1446 public MatchingRuleDefinition getMatchingRule(final String name) 1447 { 1448 ensureNotNull(name); 1449 1450 return mrMap.get(toLowerCase(name)); 1451 } 1452 1453 1454 1455 /** 1456 * Retrieves the set of matching rule use definitions contained in the server 1457 * schema. 1458 * 1459 * @return The set of matching rule use definitions contained in the server 1460 * schema. 1461 */ 1462 public Set<MatchingRuleUseDefinition> getMatchingRuleUses() 1463 { 1464 return mruSet; 1465 } 1466 1467 1468 1469 /** 1470 * Retrieves the matching rule use with the specified name or OID from the 1471 * server schema. 1472 * 1473 * @param name The name or OID of the matching rule use to retrieve. It 1474 * must not be {@code null}. 1475 * 1476 * @return The requested matching rule, or {@code null} if there is no 1477 * such matching rule use defined in the server schema. 1478 */ 1479 public MatchingRuleUseDefinition getMatchingRuleUse(final String name) 1480 { 1481 ensureNotNull(name); 1482 1483 return mruMap.get(toLowerCase(name)); 1484 } 1485 1486 1487 1488 /** 1489 * Retrieves the set of name form definitions contained in the server schema. 1490 * 1491 * @return The set of name form definitions contained in the server schema. 1492 */ 1493 public Set<NameFormDefinition> getNameForms() 1494 { 1495 return nfSet; 1496 } 1497 1498 1499 1500 /** 1501 * Retrieves the name form with the specified name or OID from the server 1502 * schema. 1503 * 1504 * @param name The name or OID of the name form to retrieve. It must not be 1505 * {@code null}. 1506 * 1507 * @return The requested name form, or {@code null} if there is no 1508 * such rule defined in the server schema. 1509 */ 1510 public NameFormDefinition getNameFormByName(final String name) 1511 { 1512 ensureNotNull(name); 1513 1514 return nfMapByName.get(toLowerCase(name)); 1515 } 1516 1517 1518 1519 /** 1520 * Retrieves the name form associated with the specified structural object 1521 * class from the server schema. 1522 * 1523 * @param objectClass The name or OID of the structural object class for 1524 * which to retrieve the associated name form. It must 1525 * not be {@code null}. 1526 * 1527 * @return The requested name form, or {@code null} if there is no 1528 * such rule defined in the server schema. 1529 */ 1530 public NameFormDefinition getNameFormByObjectClass(final String objectClass) 1531 { 1532 ensureNotNull(objectClass); 1533 1534 return nfMapByOC.get(toLowerCase(objectClass)); 1535 } 1536 1537 1538 1539 /** 1540 * Retrieves the set of object class definitions contained in the server 1541 * schema. 1542 * 1543 * @return The set of object class definitions contained in the server 1544 * schema. 1545 */ 1546 public Set<ObjectClassDefinition> getObjectClasses() 1547 { 1548 return ocSet; 1549 } 1550 1551 1552 1553 /** 1554 * Retrieves the set of abstract object class definitions contained in the 1555 * server schema. 1556 * 1557 * @return The set of abstract object class definitions contained in the 1558 * server schema. 1559 */ 1560 public Set<ObjectClassDefinition> getAbstractObjectClasses() 1561 { 1562 return abstractOCSet; 1563 } 1564 1565 1566 1567 /** 1568 * Retrieves the set of auxiliary object class definitions contained in the 1569 * server schema. 1570 * 1571 * @return The set of auxiliary object class definitions contained in the 1572 * server schema. 1573 */ 1574 public Set<ObjectClassDefinition> getAuxiliaryObjectClasses() 1575 { 1576 return auxiliaryOCSet; 1577 } 1578 1579 1580 1581 /** 1582 * Retrieves the set of structural object class definitions contained in the 1583 * server schema. 1584 * 1585 * @return The set of structural object class definitions contained in the 1586 * server schema. 1587 */ 1588 public Set<ObjectClassDefinition> getStructuralObjectClasses() 1589 { 1590 return structuralOCSet; 1591 } 1592 1593 1594 1595 /** 1596 * Retrieves the object class with the specified name or OID from the server 1597 * schema. 1598 * 1599 * @param name The name or OID of the object class to retrieve. It must 1600 * not be {@code null}. 1601 * 1602 * @return The requested object class, or {@code null} if there is no such 1603 * class defined in the server schema. 1604 */ 1605 public ObjectClassDefinition getObjectClass(final String name) 1606 { 1607 ensureNotNull(name); 1608 1609 return ocMap.get(toLowerCase(name)); 1610 } 1611 1612 1613 1614 /** 1615 * Retrieves a hash code for this schema object. 1616 * 1617 * @return A hash code for this schema object. 1618 */ 1619 @Override() 1620 public int hashCode() 1621 { 1622 int hc; 1623 try 1624 { 1625 hc = schemaEntry.getParsedDN().hashCode(); 1626 } 1627 catch (final Exception e) 1628 { 1629 debugException(e); 1630 hc = toLowerCase(schemaEntry.getDN()).hashCode(); 1631 } 1632 1633 Attribute a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_SYNTAX); 1634 if (a != null) 1635 { 1636 hc += a.hashCode(); 1637 } 1638 1639 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE); 1640 if (a != null) 1641 { 1642 hc += a.hashCode(); 1643 } 1644 1645 a = schemaEntry.getAttribute(ATTR_ATTRIBUTE_TYPE); 1646 if (a != null) 1647 { 1648 hc += a.hashCode(); 1649 } 1650 1651 a = schemaEntry.getAttribute(ATTR_OBJECT_CLASS); 1652 if (a != null) 1653 { 1654 hc += a.hashCode(); 1655 } 1656 1657 a = schemaEntry.getAttribute(ATTR_NAME_FORM); 1658 if (a != null) 1659 { 1660 hc += a.hashCode(); 1661 } 1662 1663 a = schemaEntry.getAttribute(ATTR_DIT_CONTENT_RULE); 1664 if (a != null) 1665 { 1666 hc += a.hashCode(); 1667 } 1668 1669 a = schemaEntry.getAttribute(ATTR_DIT_STRUCTURE_RULE); 1670 if (a != null) 1671 { 1672 hc += a.hashCode(); 1673 } 1674 1675 a = schemaEntry.getAttribute(ATTR_MATCHING_RULE_USE); 1676 if (a != null) 1677 { 1678 hc += a.hashCode(); 1679 } 1680 1681 return hc; 1682 } 1683 1684 1685 1686 /** 1687 * Indicates whether the provided object is equal to this schema object. 1688 * 1689 * @param o The object for which to make the determination. 1690 * 1691 * @return {@code true} if the provided object is equal to this schema 1692 * object, or {@code false} if not. 1693 */ 1694 @Override() 1695 public boolean equals(final Object o) 1696 { 1697 if (o == null) 1698 { 1699 return false; 1700 } 1701 1702 if (o == this) 1703 { 1704 return true; 1705 } 1706 1707 if (! (o instanceof Schema)) 1708 { 1709 return false; 1710 } 1711 1712 final Schema s = (Schema) o; 1713 1714 try 1715 { 1716 if (! schemaEntry.getParsedDN().equals(s.schemaEntry.getParsedDN())) 1717 { 1718 return false; 1719 } 1720 } 1721 catch (final Exception e) 1722 { 1723 debugException(e); 1724 if (! schemaEntry.getDN().equalsIgnoreCase(s.schemaEntry.getDN())) 1725 { 1726 return false; 1727 } 1728 } 1729 1730 return (asSet.equals(s.asSet) && 1731 mrSet.equals(s.mrSet) && 1732 atSet.equals(s.atSet) && 1733 ocSet.equals(s.ocSet) && 1734 nfSet.equals(s.nfSet) && 1735 dcrSet.equals(s.dcrSet) && 1736 dsrSet.equals(s.dsrSet) && 1737 mruSet.equals(s.mruSet)); 1738 } 1739 1740 1741 1742 /** 1743 * Retrieves a string representation of the associated schema entry. 1744 * 1745 * @return A string representation of the associated schema entry. 1746 */ 1747 @Override() 1748 public String toString() 1749 { 1750 return schemaEntry.toString(); 1751 } 1752}