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