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.util.ArrayList; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.Map; 029import java.util.LinkedHashMap; 030 031import com.unboundid.ldap.sdk.LDAPException; 032import com.unboundid.ldap.sdk.ResultCode; 033import com.unboundid.util.NotMutable; 034import com.unboundid.util.ThreadSafety; 035import com.unboundid.util.ThreadSafetyLevel; 036 037import static com.unboundid.ldap.sdk.schema.SchemaMessages.*; 038import static com.unboundid.util.StaticUtils.*; 039import static com.unboundid.util.Validator.*; 040 041 042 043/** 044 * This class provides a data structure that describes an LDAP DIT content rule 045 * schema element. 046 */ 047@NotMutable() 048@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 049public final class DITContentRuleDefinition 050 extends SchemaElement 051{ 052 /** 053 * The serial version UID for this serializable class. 054 */ 055 private static final long serialVersionUID = 3224440505307817586L; 056 057 058 059 // Indicates whether this DIT content rule is declared obsolete. 060 private final boolean isObsolete; 061 062 // The set of extensions for this DIT content rule. 063 private final Map<String,String[]> extensions; 064 065 // The description for this DIT content rule. 066 private final String description; 067 068 // The string representation of this DIT content rule. 069 private final String ditContentRuleString; 070 071 // The OID of the structural object class with which this DIT content rule is 072 // associated. 073 private final String oid; 074 075 // The names/OIDs of the allowed auxiliary classes. 076 private final String[] auxiliaryClasses; 077 078 // The set of names for this DIT content rule. 079 private final String[] names; 080 081 // The names/OIDs of the optional attributes. 082 private final String[] optionalAttributes; 083 084 // The names/OIDs of the prohibited attributes. 085 private final String[] prohibitedAttributes; 086 087 // The names/OIDs of the required attributes. 088 private final String[] requiredAttributes; 089 090 091 092 /** 093 * Creates a new DIT content rule from the provided string representation. 094 * 095 * @param s The string representation of the DIT content rule to create, 096 * using the syntax described in RFC 4512 section 4.1.6. It must 097 * not be {@code null}. 098 * 099 * @throws LDAPException If the provided string cannot be decoded as a DIT 100 * content rule definition. 101 */ 102 public DITContentRuleDefinition(final String s) 103 throws LDAPException 104 { 105 ensureNotNull(s); 106 107 ditContentRuleString = s.trim(); 108 109 // The first character must be an opening parenthesis. 110 final int length = ditContentRuleString.length(); 111 if (length == 0) 112 { 113 throw new LDAPException(ResultCode.DECODING_ERROR, 114 ERR_DCR_DECODE_EMPTY.get()); 115 } 116 else if (ditContentRuleString.charAt(0) != '(') 117 { 118 throw new LDAPException(ResultCode.DECODING_ERROR, 119 ERR_DCR_DECODE_NO_OPENING_PAREN.get( 120 ditContentRuleString)); 121 } 122 123 124 // Skip over any spaces until we reach the start of the OID, then read the 125 // OID until we find the next space. 126 int pos = skipSpaces(ditContentRuleString, 1, length); 127 128 StringBuilder buffer = new StringBuilder(); 129 pos = readOID(ditContentRuleString, pos, length, buffer); 130 oid = buffer.toString(); 131 132 133 // Technically, DIT content elements are supposed to appear in a specific 134 // order, but we'll be lenient and allow remaining elements to come in any 135 // order. 136 final ArrayList<String> nameList = new ArrayList<String>(1); 137 final ArrayList<String> reqAttrs = new ArrayList<String>(); 138 final ArrayList<String> optAttrs = new ArrayList<String>(); 139 final ArrayList<String> notAttrs = new ArrayList<String>(); 140 final ArrayList<String> auxOCs = new ArrayList<String>(); 141 final Map<String,String[]> exts = new LinkedHashMap<String,String[]>(); 142 Boolean obsolete = null; 143 String descr = null; 144 145 while (true) 146 { 147 // Skip over any spaces until we find the next element. 148 pos = skipSpaces(ditContentRuleString, pos, length); 149 150 // Read until we find the next space or the end of the string. Use that 151 // token to figure out what to do next. 152 final int tokenStartPos = pos; 153 while ((pos < length) && (ditContentRuleString.charAt(pos) != ' ')) 154 { 155 pos++; 156 } 157 158 // It's possible that the token could be smashed right up against the 159 // closing parenthesis. If that's the case, then extract just the token 160 // and handle the closing parenthesis the next time through. 161 String token = ditContentRuleString.substring(tokenStartPos, pos); 162 if ((token.length() > 1) && (token.endsWith(")"))) 163 { 164 token = token.substring(0, token.length() - 1); 165 pos--; 166 } 167 168 final String lowerToken = toLowerCase(token); 169 if (lowerToken.equals(")")) 170 { 171 // This indicates that we're at the end of the value. There should not 172 // be any more closing characters. 173 if (pos < length) 174 { 175 throw new LDAPException(ResultCode.DECODING_ERROR, 176 ERR_DCR_DECODE_CLOSE_NOT_AT_END.get( 177 ditContentRuleString)); 178 } 179 break; 180 } 181 else if (lowerToken.equals("name")) 182 { 183 if (nameList.isEmpty()) 184 { 185 pos = skipSpaces(ditContentRuleString, pos, length); 186 pos = readQDStrings(ditContentRuleString, pos, length, nameList); 187 } 188 else 189 { 190 throw new LDAPException(ResultCode.DECODING_ERROR, 191 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 192 ditContentRuleString, "NAME")); 193 } 194 } 195 else if (lowerToken.equals("desc")) 196 { 197 if (descr == null) 198 { 199 pos = skipSpaces(ditContentRuleString, pos, length); 200 201 buffer = new StringBuilder(); 202 pos = readQDString(ditContentRuleString, pos, length, buffer); 203 descr = buffer.toString(); 204 } 205 else 206 { 207 throw new LDAPException(ResultCode.DECODING_ERROR, 208 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 209 ditContentRuleString, "DESC")); 210 } 211 } 212 else if (lowerToken.equals("obsolete")) 213 { 214 if (obsolete == null) 215 { 216 obsolete = true; 217 } 218 else 219 { 220 throw new LDAPException(ResultCode.DECODING_ERROR, 221 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 222 ditContentRuleString, "OBSOLETE")); 223 } 224 } 225 else if (lowerToken.equals("aux")) 226 { 227 if (auxOCs.isEmpty()) 228 { 229 pos = skipSpaces(ditContentRuleString, pos, length); 230 pos = readOIDs(ditContentRuleString, pos, length, auxOCs); 231 } 232 else 233 { 234 throw new LDAPException(ResultCode.DECODING_ERROR, 235 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 236 ditContentRuleString, "AUX")); 237 } 238 } 239 else if (lowerToken.equals("must")) 240 { 241 if (reqAttrs.isEmpty()) 242 { 243 pos = skipSpaces(ditContentRuleString, pos, length); 244 pos = readOIDs(ditContentRuleString, pos, length, reqAttrs); 245 } 246 else 247 { 248 throw new LDAPException(ResultCode.DECODING_ERROR, 249 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 250 ditContentRuleString, "MUST")); 251 } 252 } 253 else if (lowerToken.equals("may")) 254 { 255 if (optAttrs.isEmpty()) 256 { 257 pos = skipSpaces(ditContentRuleString, pos, length); 258 pos = readOIDs(ditContentRuleString, pos, length, optAttrs); 259 } 260 else 261 { 262 throw new LDAPException(ResultCode.DECODING_ERROR, 263 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 264 ditContentRuleString, "MAY")); 265 } 266 } 267 else if (lowerToken.equals("not")) 268 { 269 if (notAttrs.isEmpty()) 270 { 271 pos = skipSpaces(ditContentRuleString, pos, length); 272 pos = readOIDs(ditContentRuleString, pos, length, notAttrs); 273 } 274 else 275 { 276 throw new LDAPException(ResultCode.DECODING_ERROR, 277 ERR_DCR_DECODE_MULTIPLE_ELEMENTS.get( 278 ditContentRuleString, "NOT")); 279 } 280 } 281 else if (lowerToken.startsWith("x-")) 282 { 283 pos = skipSpaces(ditContentRuleString, pos, length); 284 285 final ArrayList<String> valueList = new ArrayList<String>(); 286 pos = readQDStrings(ditContentRuleString, pos, length, valueList); 287 288 final String[] values = new String[valueList.size()]; 289 valueList.toArray(values); 290 291 if (exts.containsKey(token)) 292 { 293 throw new LDAPException(ResultCode.DECODING_ERROR, 294 ERR_DCR_DECODE_DUP_EXT.get( 295 ditContentRuleString, token)); 296 } 297 298 exts.put(token, values); 299 } 300 else 301 { 302 throw new LDAPException(ResultCode.DECODING_ERROR, 303 ERR_DCR_DECODE_DUP_EXT.get( 304 ditContentRuleString, token)); 305 } 306 } 307 308 description = descr; 309 310 names = new String[nameList.size()]; 311 nameList.toArray(names); 312 313 auxiliaryClasses = new String[auxOCs.size()]; 314 auxOCs.toArray(auxiliaryClasses); 315 316 requiredAttributes = new String[reqAttrs.size()]; 317 reqAttrs.toArray(requiredAttributes); 318 319 optionalAttributes = new String[optAttrs.size()]; 320 optAttrs.toArray(optionalAttributes); 321 322 prohibitedAttributes = new String[notAttrs.size()]; 323 notAttrs.toArray(prohibitedAttributes); 324 325 isObsolete = (obsolete != null); 326 327 extensions = Collections.unmodifiableMap(exts); 328 } 329 330 331 332 /** 333 * Creates a new DIT content rule with the provided information. 334 * 335 * @param oid The OID for the structural object class with 336 * which this DIT content rule is associated. 337 * It must not be {@code null}. 338 * @param name The name for this DIT content rule. It may 339 * be {@code null} if the DIT content rule 340 * should only be referenced by OID. 341 * @param description The description for this DIT content rule. 342 * It may be {@code null} if there is no 343 * description. 344 * @param auxiliaryClasses The names/OIDs of the auxiliary object 345 * classes that may be present in entries 346 * containing this DIT content rule. 347 * @param requiredAttributes The names/OIDs of the attributes which must 348 * be present in entries containing this DIT 349 * content rule. 350 * @param optionalAttributes The names/OIDs of the attributes which may be 351 * present in entries containing this DIT 352 * content rule. 353 * @param prohibitedAttributes The names/OIDs of the attributes which may 354 * not be present in entries containing this DIT 355 * content rule. 356 * @param extensions The set of extensions for this DIT content 357 * rule. It may be {@code null} or empty if 358 * there should not be any extensions. 359 */ 360 public DITContentRuleDefinition(final String oid, final String name, 361 final String description, 362 final String[] auxiliaryClasses, 363 final String[] requiredAttributes, 364 final String[] optionalAttributes, 365 final String[] prohibitedAttributes, 366 final Map<String,String[]> extensions) 367 { 368 this(oid, ((name == null) ? null : new String[] { name }), description, 369 false, auxiliaryClasses, requiredAttributes, optionalAttributes, 370 prohibitedAttributes, extensions); 371 } 372 373 374 375 /** 376 * Creates a new DIT content rule with the provided information. 377 * 378 * @param oid The OID for the structural object class with 379 * which this DIT content rule is associated. 380 * It must not be {@code null}. 381 * @param name The name for this DIT content rule. It may 382 * be {@code null} if the DIT content rule 383 * should only be referenced by OID. 384 * @param description The description for this DIT content rule. 385 * It may be {@code null} if there is no 386 * description. 387 * @param auxiliaryClasses The names/OIDs of the auxiliary object 388 * classes that may be present in entries 389 * containing this DIT content rule. 390 * @param requiredAttributes The names/OIDs of the attributes which must 391 * be present in entries containing this DIT 392 * content rule. 393 * @param optionalAttributes The names/OIDs of the attributes which may be 394 * present in entries containing this DIT 395 * content rule. 396 * @param prohibitedAttributes The names/OIDs of the attributes which may 397 * not be present in entries containing this DIT 398 * content rule. 399 * @param extensions The set of extensions for this DIT content 400 * rule. It may be {@code null} or empty if 401 * there should not be any extensions. 402 */ 403 public DITContentRuleDefinition(final String oid, final String name, 404 final String description, 405 final Collection<String> auxiliaryClasses, 406 final Collection<String> requiredAttributes, 407 final Collection<String> optionalAttributes, 408 final Collection<String> prohibitedAttributes, 409 final Map<String,String[]> extensions) 410 { 411 this(oid, ((name == null) ? null : new String[] { name }), description, 412 false, toArray(auxiliaryClasses), toArray(requiredAttributes), 413 toArray(optionalAttributes), toArray(prohibitedAttributes), 414 extensions); 415 } 416 417 418 419 /** 420 * Creates a new DIT content rule with the provided information. 421 * 422 * @param oid The OID for the structural object class with 423 * which this DIT content rule is associated. 424 * It must not be {@code null}. 425 * @param names The set of names for this DIT content rule. 426 * It may be {@code null} or empty if the DIT 427 * content rule should only be referenced by 428 * OID. 429 * @param description The description for this DIT content rule. 430 * It may be {@code null} if there is no 431 * description. 432 * @param isObsolete Indicates whether this DIT content rule is 433 * declared obsolete. 434 * @param auxiliaryClasses The names/OIDs of the auxiliary object 435 * classes that may be present in entries 436 * containing this DIT content rule. 437 * @param requiredAttributes The names/OIDs of the attributes which must 438 * be present in entries containing this DIT 439 * content rule. 440 * @param optionalAttributes The names/OIDs of the attributes which may be 441 * present in entries containing this DIT 442 * content rule. 443 * @param prohibitedAttributes The names/OIDs of the attributes which may 444 * not be present in entries containing this DIT 445 * content rule. 446 * @param extensions The set of extensions for this DIT content 447 * rule. It may be {@code null} or empty if 448 * there should not be any extensions. 449 */ 450 public DITContentRuleDefinition(final String oid, final String[] names, 451 final String description, 452 final boolean isObsolete, 453 final String[] auxiliaryClasses, 454 final String[] requiredAttributes, 455 final String[] optionalAttributes, 456 final String[] prohibitedAttributes, 457 final Map<String,String[]> extensions) 458 { 459 ensureNotNull(oid); 460 461 this.oid = oid; 462 this.isObsolete = isObsolete; 463 this.description = description; 464 465 if (names == null) 466 { 467 this.names = NO_STRINGS; 468 } 469 else 470 { 471 this.names = names; 472 } 473 474 if (auxiliaryClasses == null) 475 { 476 this.auxiliaryClasses = NO_STRINGS; 477 } 478 else 479 { 480 this.auxiliaryClasses = auxiliaryClasses; 481 } 482 483 if (requiredAttributes == null) 484 { 485 this.requiredAttributes = NO_STRINGS; 486 } 487 else 488 { 489 this.requiredAttributes = requiredAttributes; 490 } 491 492 if (optionalAttributes == null) 493 { 494 this.optionalAttributes = NO_STRINGS; 495 } 496 else 497 { 498 this.optionalAttributes = optionalAttributes; 499 } 500 501 if (prohibitedAttributes == null) 502 { 503 this.prohibitedAttributes = NO_STRINGS; 504 } 505 else 506 { 507 this.prohibitedAttributes = prohibitedAttributes; 508 } 509 510 if (extensions == null) 511 { 512 this.extensions = Collections.emptyMap(); 513 } 514 else 515 { 516 this.extensions = Collections.unmodifiableMap(extensions); 517 } 518 519 final StringBuilder buffer = new StringBuilder(); 520 createDefinitionString(buffer); 521 ditContentRuleString = buffer.toString(); 522 } 523 524 525 526 /** 527 * Constructs a string representation of this DIT content rule definition in 528 * the provided buffer. 529 * 530 * @param buffer The buffer in which to construct a string representation of 531 * this DIT content rule definition. 532 */ 533 private void createDefinitionString(final StringBuilder buffer) 534 { 535 buffer.append("( "); 536 buffer.append(oid); 537 538 if (names.length == 1) 539 { 540 buffer.append(" NAME '"); 541 buffer.append(names[0]); 542 buffer.append('\''); 543 } 544 else if (names.length > 1) 545 { 546 buffer.append(" NAME ("); 547 for (final String name : names) 548 { 549 buffer.append(" '"); 550 buffer.append(name); 551 buffer.append('\''); 552 } 553 buffer.append(" )"); 554 } 555 556 if (description != null) 557 { 558 buffer.append(" DESC '"); 559 encodeValue(description, buffer); 560 buffer.append('\''); 561 } 562 563 if (isObsolete) 564 { 565 buffer.append(" OBSOLETE"); 566 } 567 568 if (auxiliaryClasses.length == 1) 569 { 570 buffer.append(" AUX "); 571 buffer.append(auxiliaryClasses[0]); 572 } 573 else if (auxiliaryClasses.length > 1) 574 { 575 buffer.append(" AUX ("); 576 for (int i=0; i < auxiliaryClasses.length; i++) 577 { 578 if (i >0) 579 { 580 buffer.append(" $ "); 581 } 582 else 583 { 584 buffer.append(' '); 585 } 586 buffer.append(auxiliaryClasses[i]); 587 } 588 buffer.append(" )"); 589 } 590 591 if (requiredAttributes.length == 1) 592 { 593 buffer.append(" MUST "); 594 buffer.append(requiredAttributes[0]); 595 } 596 else if (requiredAttributes.length > 1) 597 { 598 buffer.append(" MUST ("); 599 for (int i=0; i < requiredAttributes.length; i++) 600 { 601 if (i >0) 602 { 603 buffer.append(" $ "); 604 } 605 else 606 { 607 buffer.append(' '); 608 } 609 buffer.append(requiredAttributes[i]); 610 } 611 buffer.append(" )"); 612 } 613 614 if (optionalAttributes.length == 1) 615 { 616 buffer.append(" MAY "); 617 buffer.append(optionalAttributes[0]); 618 } 619 else if (optionalAttributes.length > 1) 620 { 621 buffer.append(" MAY ("); 622 for (int i=0; i < optionalAttributes.length; i++) 623 { 624 if (i > 0) 625 { 626 buffer.append(" $ "); 627 } 628 else 629 { 630 buffer.append(' '); 631 } 632 buffer.append(optionalAttributes[i]); 633 } 634 buffer.append(" )"); 635 } 636 637 if (prohibitedAttributes.length == 1) 638 { 639 buffer.append(" NOT "); 640 buffer.append(prohibitedAttributes[0]); 641 } 642 else if (prohibitedAttributes.length > 1) 643 { 644 buffer.append(" NOT ("); 645 for (int i=0; i < prohibitedAttributes.length; i++) 646 { 647 if (i > 0) 648 { 649 buffer.append(" $ "); 650 } 651 else 652 { 653 buffer.append(' '); 654 } 655 buffer.append(prohibitedAttributes[i]); 656 } 657 buffer.append(" )"); 658 } 659 660 for (final Map.Entry<String,String[]> e : extensions.entrySet()) 661 { 662 final String name = e.getKey(); 663 final String[] values = e.getValue(); 664 if (values.length == 1) 665 { 666 buffer.append(' '); 667 buffer.append(name); 668 buffer.append(" '"); 669 encodeValue(values[0], buffer); 670 buffer.append('\''); 671 } 672 else 673 { 674 buffer.append(' '); 675 buffer.append(name); 676 buffer.append(" ("); 677 for (final String value : values) 678 { 679 buffer.append(" '"); 680 encodeValue(value, buffer); 681 buffer.append('\''); 682 } 683 buffer.append(" )"); 684 } 685 } 686 687 buffer.append(" )"); 688 } 689 690 691 692 /** 693 * Retrieves the OID for the structural object class associated with this 694 * DIT content rule. 695 * 696 * @return The OID for the structural object class associated with this DIT 697 * content rule. 698 */ 699 public String getOID() 700 { 701 return oid; 702 } 703 704 705 706 /** 707 * Retrieves the set of names for this DIT content rule. 708 * 709 * @return The set of names for this DIT content rule, or an empty array if 710 * it does not have any names. 711 */ 712 public String[] getNames() 713 { 714 return names; 715 } 716 717 718 719 /** 720 * Retrieves the primary name that can be used to reference this DIT content 721 * rule. If one or more names are defined, then the first name will be used. 722 * Otherwise, the structural object class OID will be returned. 723 * 724 * @return The primary name that can be used to reference this DIT content 725 * rule. 726 */ 727 public String getNameOrOID() 728 { 729 if (names.length == 0) 730 { 731 return oid; 732 } 733 else 734 { 735 return names[0]; 736 } 737 } 738 739 740 741 /** 742 * Indicates whether the provided string matches the OID or any of the names 743 * for this DIT content rule. 744 * 745 * @param s The string for which to make the determination. It must not be 746 * {@code null}. 747 * 748 * @return {@code true} if the provided string matches the OID or any of the 749 * names for this DIT content rule, or {@code false} if not. 750 */ 751 public boolean hasNameOrOID(final String s) 752 { 753 for (final String name : names) 754 { 755 if (s.equalsIgnoreCase(name)) 756 { 757 return true; 758 } 759 } 760 761 return s.equalsIgnoreCase(oid); 762 } 763 764 765 766 /** 767 * Retrieves the description for this DIT content rule, if available. 768 * 769 * @return The description for this DIT content rule, or {@code null} if 770 * there is no description defined. 771 */ 772 public String getDescription() 773 { 774 return description; 775 } 776 777 778 779 /** 780 * Indicates whether this DIT content rule is declared obsolete. 781 * 782 * @return {@code true} if this DIT content rule is declared obsolete, or 783 * {@code false} if it is not. 784 */ 785 public boolean isObsolete() 786 { 787 return isObsolete; 788 } 789 790 791 792 /** 793 * Retrieves the names or OIDs of the auxiliary object classes that may be 794 * present in entries containing the structural class for this DIT content 795 * rule. 796 * 797 * @return The names or OIDs of the auxiliary object classes that may be 798 * present in entries containing the structural class for this DIT 799 * content rule. 800 */ 801 public String[] getAuxiliaryClasses() 802 { 803 return auxiliaryClasses; 804 } 805 806 807 808 /** 809 * Retrieves the names or OIDs of the attributes that are required to be 810 * present in entries containing the structural object class for this DIT 811 * content rule. 812 * 813 * @return The names or OIDs of the attributes that are required to be 814 * present in entries containing the structural object class for this 815 * DIT content rule, or an empty array if there are no required 816 * attributes. 817 */ 818 public String[] getRequiredAttributes() 819 { 820 return requiredAttributes; 821 } 822 823 824 825 /** 826 * Retrieves the names or OIDs of the attributes that are optionally allowed 827 * to be present in entries containing the structural object class for this 828 * DIT content rule. 829 * 830 * @return The names or OIDs of the attributes that are optionally allowed to 831 * be present in entries containing the structural object class for 832 * this DIT content rule, or an empty array if there are no required 833 * attributes. 834 */ 835 public String[] getOptionalAttributes() 836 { 837 return optionalAttributes; 838 } 839 840 841 842 /** 843 * Retrieves the names or OIDs of the attributes that are not allowed to be 844 * present in entries containing the structural object class for this DIT 845 * content rule. 846 * 847 * @return The names or OIDs of the attributes that are not allowed to be 848 * present in entries containing the structural object class for this 849 * DIT content rule, or an empty array if there are no required 850 * attributes. 851 */ 852 public String[] getProhibitedAttributes() 853 { 854 return prohibitedAttributes; 855 } 856 857 858 859 /** 860 * Retrieves the set of extensions for this DIT content rule. They will be 861 * mapped from the extension name (which should start with "X-") to the set of 862 * values for that extension. 863 * 864 * @return The set of extensions for this DIT content rule. 865 */ 866 public Map<String,String[]> getExtensions() 867 { 868 return extensions; 869 } 870 871 872 873 /** 874 * {@inheritDoc} 875 */ 876 @Override() 877 public int hashCode() 878 { 879 return oid.hashCode(); 880 } 881 882 883 884 /** 885 * {@inheritDoc} 886 */ 887 @Override() 888 public boolean equals(final Object o) 889 { 890 if (o == null) 891 { 892 return false; 893 } 894 895 if (o == this) 896 { 897 return true; 898 } 899 900 if (! (o instanceof DITContentRuleDefinition)) 901 { 902 return false; 903 } 904 905 final DITContentRuleDefinition d = (DITContentRuleDefinition) o; 906 return (oid.equals(d.oid) && 907 stringsEqualIgnoreCaseOrderIndependent(names, d.names) && 908 stringsEqualIgnoreCaseOrderIndependent(auxiliaryClasses, 909 d.auxiliaryClasses) && 910 stringsEqualIgnoreCaseOrderIndependent(requiredAttributes, 911 d.requiredAttributes) && 912 stringsEqualIgnoreCaseOrderIndependent(optionalAttributes, 913 d.optionalAttributes) && 914 stringsEqualIgnoreCaseOrderIndependent(prohibitedAttributes, 915 d.prohibitedAttributes) && 916 bothNullOrEqualIgnoreCase(description, d.description) && 917 (isObsolete == d.isObsolete) && 918 extensionsEqual(extensions, d.extensions)); 919 } 920 921 922 923 /** 924 * Retrieves a string representation of this DIT content rule definition, in 925 * the format described in RFC 4512 section 4.1.6. 926 * 927 * @return A string representation of this DIT content rule definition. 928 */ 929 @Override() 930 public String toString() 931 { 932 return ditContentRuleString; 933 } 934}