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