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