001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2009 Sun Microsystems, Inc. 015 * Portions copyright 2011-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.ldap.schema; 018 019import static com.forgerock.opendj.ldap.CoreMessages.*; 020import static java.util.Arrays.*; 021 022import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; 023 024import java.util.Collection; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.LinkedHashSet; 029import java.util.LinkedList; 030import java.util.List; 031import java.util.Map; 032import java.util.Set; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2; 036import org.forgerock.util.Reject; 037 038/** 039 * This class defines a DIT content rule, which defines the set of allowed, 040 * required, and prohibited attributes for entries with a given structural 041 * objectclass, and also indicates which auxiliary classes may be included in 042 * the entry. 043 */ 044public final class DITContentRule extends AbstractSchemaElement { 045 046 /** A fluent API for incrementally constructing DIT content rule. */ 047 public static final class Builder extends SchemaElementBuilder<Builder> { 048 private String structuralClassOID; 049 private final List<String> names = new LinkedList<>(); 050 private boolean isObsolete; 051 private final Set<String> auxiliaryClassOIDs = new LinkedHashSet<>(); 052 private final Set<String> optionalAttributeOIDs = new LinkedHashSet<>(); 053 private final Set<String> prohibitedAttributeOIDs = new LinkedHashSet<>(); 054 private final Set<String> requiredAttributeOIDs = new LinkedHashSet<>(); 055 056 Builder(final DITContentRule contentRule, final SchemaBuilder schemaBuilder) { 057 super(schemaBuilder, contentRule); 058 structuralClassOID = contentRule.structuralClassOID; 059 names.addAll(contentRule.getNames()); 060 isObsolete = contentRule.isObsolete; 061 auxiliaryClassOIDs.addAll(contentRule.auxiliaryClassOIDs); 062 optionalAttributeOIDs.addAll(contentRule.optionalAttributeOIDs); 063 prohibitedAttributeOIDs.addAll(contentRule.prohibitedAttributeOIDs); 064 requiredAttributeOIDs.addAll(contentRule.requiredAttributeOIDs); 065 } 066 067 Builder(final String structuralClassOID, final SchemaBuilder builder) { 068 super(builder); 069 this.structuralClassOID = structuralClassOID; 070 } 071 072 /** 073 * Adds this DIT content rule to the schema, throwing a 074 * {@code ConflictingSchemaElementException} if there is an existing DIT 075 * content rule with the same structural object class OID. 076 * 077 * @return The parent schema builder. 078 * @throws ConflictingSchemaElementException 079 * If there is an existing DIT content rule with the same 080 * structural object class OID. 081 */ 082 public SchemaBuilder addToSchema() { 083 return getSchemaBuilder().addDITContentRule(new DITContentRule(this), false); 084 } 085 086 /** 087 * Adds this DIT content rule to the schema overwriting any existing 088 * content rule with the same structural class OID. 089 * 090 * @return The parent schema builder. 091 */ 092 public SchemaBuilder addToSchemaOverwrite() { 093 return getSchemaBuilder().addDITContentRule(new DITContentRule(this), true); 094 } 095 096 /** 097 * Adds this DIT content rule to the schema, overwriting any existing DIT content rule 098 * with the same numeric OID if the overwrite parameter is set to {@code true}. 099 * 100 * @param overwrite 101 * {@code true} if any DIT content rule with the same OID should be overwritten. 102 * @return The parent schema builder. 103 */ 104 SchemaBuilder addToSchema(final boolean overwrite) { 105 return overwrite ? addToSchemaOverwrite() : addToSchema(); 106 } 107 108 /** 109 * Adds the provided auxiliary classes to the list of auxiliary object 110 * classes that entries subject to this DIT content rule may belong to. 111 * 112 * @param objectClassNamesOrOIDs 113 * The list of auxiliary class names or OIDs. 114 * @return This builder. 115 */ 116 public Builder auxiliaryObjectClasses(final Collection<String> objectClassNamesOrOIDs) { 117 this.auxiliaryClassOIDs.addAll(objectClassNamesOrOIDs); 118 return this; 119 } 120 121 /** 122 * Adds the provided auxiliary classes to the list of auxiliary object 123 * classes that entries subject to this DIT content rule may belong to. 124 * 125 * @param objectClassNamesOrOIDs 126 * The list of auxiliary class names or OIDs. 127 * @return This builder. 128 */ 129 public Builder auxiliaryObjectClasses(String... objectClassNamesOrOIDs) { 130 this.auxiliaryClassOIDs.addAll(asList(objectClassNamesOrOIDs)); 131 return this; 132 } 133 134 @Override 135 public Builder description(final String description) { 136 return description0(description); 137 } 138 139 @Override 140 public Builder extraProperties(final Map<String, List<String>> extraProperties) { 141 return extraProperties0(extraProperties); 142 } 143 144 @Override 145 public Builder extraProperties(final String extensionName, final String... extensionValues) { 146 return extraProperties0(extensionName, extensionValues); 147 } 148 149 @Override 150 Builder getThis() { 151 return this; 152 } 153 154 /** 155 * Adds the provided user friendly names. 156 * 157 * @param names 158 * The user friendly names. 159 * @return This builder. 160 */ 161 public Builder names(final Collection<String> names) { 162 this.names.addAll(names); 163 return this; 164 } 165 166 /** 167 * Adds the provided user friendly names. 168 * 169 * @param names 170 * The user friendly names. 171 * @return This builder. 172 */ 173 public Builder names(final String... names) { 174 return names(asList(names)); 175 } 176 177 /** 178 * Specifies whether this schema element is obsolete. 179 * 180 * @param isObsolete 181 * {@code true} if this schema element is obsolete (default 182 * is {@code false}). 183 * @return This builder. 184 */ 185 public Builder obsolete(final boolean isObsolete) { 186 this.isObsolete = isObsolete; 187 return this; 188 } 189 190 /** 191 * Adds the provided optional attributes to the list of attribute types 192 * that entries subject to this DIT content rule may contain. 193 * 194 * @param attributeNamesOrOIDs 195 * The list of optional attribute names or OIDs. 196 * @return This builder. 197 */ 198 public Builder optionalAttributes(final Collection<String> attributeNamesOrOIDs) { 199 this.optionalAttributeOIDs.addAll(attributeNamesOrOIDs); 200 return this; 201 } 202 203 /** 204 * Adds the provided optional attributes to the list of attribute types 205 * that entries subject to this DIT content rule may contain. 206 * 207 * @param attributeNamesOrOIDs 208 * The list of optional attribute names or OIDs. 209 * @return This builder. 210 */ 211 public Builder optionalAttributes(final String... attributeNamesOrOIDs) { 212 this.optionalAttributeOIDs.addAll(asList(attributeNamesOrOIDs)); 213 return this; 214 } 215 216 /** 217 * Adds the provided prohibited attributes to the list of attribute types 218 * that entries subject to this DIT content rule must not contain. 219 * 220 * @param attributeNamesOrOIDs 221 * The list of prohibited attribute names or OIDs. 222 * @return This builder. 223 */ 224 public Builder prohibitedAttributes(final Collection<String> attributeNamesOrOIDs) { 225 this.prohibitedAttributeOIDs.addAll(attributeNamesOrOIDs); 226 return this; 227 } 228 229 /** 230 * Adds the provided prohibited attributes to the list of attribute types 231 * that entries subject to this DIT content rule must not contain. 232 * 233 * @param attributeNamesOrOIDs 234 * The list of prohibited attribute names or OIDs. 235 * @return This builder. 236 */ 237 public Builder prohibitedAttributes(final String... attributeNamesOrOIDs) { 238 this.prohibitedAttributeOIDs.addAll(asList(attributeNamesOrOIDs)); 239 return this; 240 } 241 242 /** 243 * Clears the list of auxiliary object classes that entries subject to 244 * this DIT content rule may belong to. 245 * 246 * @return This builder. 247 */ 248 public Builder removeAllAuxiliaryObjectClasses() { 249 this.auxiliaryClassOIDs.clear(); 250 return this; 251 } 252 253 @Override 254 public Builder removeAllExtraProperties() { 255 return removeAllExtraProperties0(); 256 } 257 258 /** 259 * Removes all user defined names. 260 * 261 * @return This builder. 262 */ 263 public Builder removeAllNames() { 264 this.names.clear(); 265 return this; 266 } 267 268 /** 269 * Clears the list of attribute types that entries subject to this DIT 270 * content rule may contain. 271 * 272 * @return This builder. 273 */ 274 public Builder removeAllOptionalAttributes() { 275 this.optionalAttributeOIDs.clear(); 276 return this; 277 } 278 279 /** 280 * Clears the list of attribute types that entries subject to this DIT 281 * content rule must not contain. 282 * 283 * @return This builder. 284 */ 285 public Builder removeAllProhibitedAttributes() { 286 this.prohibitedAttributeOIDs.clear(); 287 return this; 288 } 289 290 /** 291 * Clears the list of attribute types that entries subject to this DIT 292 * content rule must contain. 293 * 294 * @return This builder. 295 */ 296 public Builder removeAllRequiredAttributes() { 297 this.requiredAttributeOIDs.clear(); 298 return this; 299 } 300 301 /** 302 * Removes the provided object class in the list of auxiliary object classes that entries subject to 303 * this DIT content rule may belong to. 304 * 305 * @param objectClassNameOrOID 306 * The auxiliary object class name or OID to be removed. 307 * @return This builder. 308 */ 309 public Builder removeAuxiliaryObjectClass(String objectClassNameOrOID) { 310 this.auxiliaryClassOIDs.remove(objectClassNameOrOID); 311 return this; 312 } 313 314 @Override 315 public Builder removeExtraProperty(String extensionName, String... extensionValues) { 316 return removeExtraProperty0(extensionName, extensionValues); 317 } 318 319 /** 320 * Removes the provided user defined name. 321 * 322 * @param name 323 * The user defined name to be removed. 324 * @return This builder. 325 */ 326 public Builder removeName(String name) { 327 this.names.remove(name); 328 return this; 329 } 330 331 /** 332 * Removes the provided optional attribute in the list of attribute 333 * types that entries subject to this DIT content rule may contain. 334 * 335 * @param attributeNameOrOID 336 * The optional attribute name or OID to be removed. 337 * @return This builder. 338 */ 339 public Builder removeOptionalAttribute(String attributeNameOrOID) { 340 this.optionalAttributeOIDs.remove(attributeNameOrOID); 341 return this; 342 } 343 344 /** 345 * Removes the provided prohibited attribute in the list of attribute 346 * types that entries subject to this DIT content rule must not contain. 347 * 348 * @param attributeNameOrOID 349 * The prohibited attribute name or OID to be removed. 350 * @return This builder. 351 */ 352 public Builder removeProhibitedAttribute(String attributeNameOrOID) { 353 this.prohibitedAttributeOIDs.remove(attributeNameOrOID); 354 return this; 355 } 356 357 /** 358 * Removes the provided required attribute in the list of attribute 359 * types that entries subject to this DIT content rule must contain. 360 * 361 * @param attributeNameOrOID 362 * The provided required attribute name or OID to be removed. 363 * @return This builder. 364 */ 365 public Builder removeRequiredAttribute(String attributeNameOrOID) { 366 this.requiredAttributeOIDs.remove(attributeNameOrOID); 367 return this; 368 } 369 370 /** 371 * Adds the provided attribute to the list of attribute types that 372 * entries subject to this DIT content rule must contain. 373 * 374 * @param attributeNamesOrOIDs 375 * The list of required attribute names or OIDs. 376 * @return This builder. 377 */ 378 public Builder requiredAttributes(final Collection<String> attributeNamesOrOIDs) { 379 this.requiredAttributeOIDs.addAll(attributeNamesOrOIDs); 380 return this; 381 } 382 383 /** 384 * Adds the provided attribute to the list of attribute types that 385 * entries subject to this DIT content rule must contain. 386 * 387 * @param attributeNamesOrOIDs 388 * The list of required attribute names or OIDs. 389 * @return This builder. 390 */ 391 public Builder requiredAttributes(final String... attributeNamesOrOIDs) { 392 this.requiredAttributeOIDs.addAll(asList(attributeNamesOrOIDs)); 393 return this; 394 } 395 396 /** 397 * Sets the structural class OID which uniquely identifies this DIT 398 * content rule. 399 * 400 * @param strucuralClassOID 401 * The numeric OID. 402 * @return This builder. 403 */ 404 public Builder structuralClassOID(String strucuralClassOID) { 405 this.structuralClassOID = strucuralClassOID; 406 return this; 407 } 408 409 } 410 411 /** The structural objectclass for this DIT content rule. */ 412 private final String structuralClassOID; 413 414 /** The set of user defined names for this definition. */ 415 private final List<String> names; 416 417 /** Indicates whether this definition is declared "obsolete". */ 418 private final boolean isObsolete; 419 420 /** 421 * The set of auxiliary objectclasses that entries with this content 422 * rule may contain, in a mapping between the objectclass and the 423 * user-defined name for that class. 424 */ 425 private final Set<String> auxiliaryClassOIDs; 426 427 /** The set of optional attribute types for this DIT content rule. */ 428 private final Set<String> optionalAttributeOIDs; 429 430 /** The set of prohibited attribute types for this DIT content rule. */ 431 private final Set<String> prohibitedAttributeOIDs; 432 433 /** The set of required attribute types for this DIT content rule. */ 434 private final Set<String> requiredAttributeOIDs; 435 436 private ObjectClass structuralClass; 437 private Set<ObjectClass> auxiliaryClasses = Collections.emptySet(); 438 private Set<AttributeType> optionalAttributes = Collections.emptySet(); 439 private Set<AttributeType> prohibitedAttributes = Collections.emptySet(); 440 private Set<AttributeType> requiredAttributes = Collections.emptySet(); 441 442 private DITContentRule(final Builder builder) { 443 super(builder); 444 Reject.ifNull(builder.structuralClassOID); 445 446 structuralClassOID = builder.structuralClassOID; 447 names = unmodifiableCopyOfList(builder.names); 448 isObsolete = builder.isObsolete; 449 auxiliaryClassOIDs = unmodifiableCopyOfSet(builder.auxiliaryClassOIDs); 450 optionalAttributeOIDs = unmodifiableCopyOfSet(builder.optionalAttributeOIDs); 451 prohibitedAttributeOIDs = unmodifiableCopyOfSet(builder.prohibitedAttributeOIDs); 452 requiredAttributeOIDs = unmodifiableCopyOfSet(builder.requiredAttributeOIDs); 453 } 454 455 /** 456 * Returns {@code true} if the provided object is a DIT content rule having 457 * the same structural object class OID as this DIT content rule. 458 * 459 * @param o 460 * The object to be compared. 461 * @return {@code true} if the provided object is a DIT content rule having 462 * the same numeric OID as this DIT content rule. 463 */ 464 @Override 465 public boolean equals(final Object o) { 466 if (this == o) { 467 return true; 468 } else if (o instanceof DITContentRule) { 469 final DITContentRule other = (DITContentRule) o; 470 return structuralClassOID.equals(other.structuralClassOID); 471 } else { 472 return false; 473 } 474 } 475 476 /** 477 * Returns an unmodifiable set containing the auxiliary objectclasses that 478 * may be used for entries associated with this DIT content rule. 479 * 480 * @return An unmodifiable set containing the auxiliary objectclasses that 481 * may be used for entries associated with this DIT content rule. 482 */ 483 public Set<ObjectClass> getAuxiliaryClasses() { 484 return auxiliaryClasses; 485 } 486 487 /** 488 * Returns the name or structural class OID for this schema definition. If 489 * it has one or more names, then the primary name will be returned. If it 490 * does not have any names, then the OID will be returned. 491 * 492 * @return The name or OID for this schema definition. 493 */ 494 public String getNameOrOID() { 495 if (names.isEmpty()) { 496 return structuralClassOID; 497 } 498 return names.get(0); 499 } 500 501 /** 502 * Returns an unmodifiable list containing the user-defined names that may 503 * be used to reference this schema definition. 504 * 505 * @return Returns an unmodifiable list containing the user-defined names 506 * that may be used to reference this schema definition. 507 */ 508 public List<String> getNames() { 509 return names; 510 } 511 512 /** 513 * Returns an unmodifiable set containing the optional attributes for this 514 * DIT content rule. 515 * 516 * @return An unmodifiable set containing the optional attributes for this 517 * DIT content rule. 518 */ 519 public Set<AttributeType> getOptionalAttributes() { 520 return optionalAttributes; 521 } 522 523 /** 524 * Returns an unmodifiable set containing the prohibited attributes for this 525 * DIT content rule. 526 * 527 * @return An unmodifiable set containing the prohibited attributes for this 528 * DIT content rule. 529 */ 530 public Set<AttributeType> getProhibitedAttributes() { 531 return prohibitedAttributes; 532 } 533 534 /** 535 * Returns an unmodifiable set containing the required attributes for this 536 * DIT content rule. 537 * 538 * @return An unmodifiable set containing the required attributes for this 539 * DIT content rule. 540 */ 541 public Set<AttributeType> getRequiredAttributes() { 542 return requiredAttributes; 543 } 544 545 /** 546 * Returns the structural objectclass for this DIT content rule. 547 * 548 * @return The structural objectclass for this DIT content rule. 549 */ 550 public ObjectClass getStructuralClass() { 551 return structuralClass; 552 } 553 554 /** 555 * Returns the structural class OID for this schema definition. 556 * 557 * @return The structural class OID for this schema definition. 558 */ 559 public String getStructuralClassOID() { 560 return structuralClassOID; 561 } 562 563 /** 564 * Returns the hash code for this DIT content rule. It will be calculated as 565 * the hash code of the structural object class OID. 566 * 567 * @return The hash code for this DIT content rule. 568 */ 569 @Override 570 public int hashCode() { 571 return structuralClassOID.hashCode(); 572 } 573 574 /** 575 * Indicates whether this schema definition has the specified name. 576 * 577 * @param name 578 * The name for which to make the determination. 579 * @return <code>true</code> if the specified name is assigned to this 580 * schema definition, or <code>false</code> if not. 581 */ 582 public boolean hasName(final String name) { 583 for (final String n : names) { 584 if (n.equalsIgnoreCase(name)) { 585 return true; 586 } 587 } 588 return false; 589 } 590 591 /** 592 * Indicates whether this schema definition has the specified name or 593 * structural class OID. 594 * 595 * @param value 596 * The value for which to make the determination. 597 * @return <code>true</code> if the provided value matches the OID or one of 598 * the names assigned to this schema definition, or 599 * <code>false</code> if not. 600 */ 601 public boolean hasNameOrOID(final String value) { 602 return hasName(value) || structuralClassOID.equals(value); 603 } 604 605 /** 606 * Indicates whether this schema definition is declared "obsolete". 607 * 608 * @return <code>true</code> if this schema definition is declared 609 * "obsolete", or <code>false</code> if not. 610 */ 611 public boolean isObsolete() { 612 return isObsolete; 613 } 614 615 /** 616 * Indicates whether the provided attribute type is included in the optional 617 * attribute list for this DIT content rule. 618 * 619 * @param attributeType 620 * The attribute type for which to make the determination. 621 * @return <code>true</code> if the provided attribute type is optional for 622 * this DIT content rule, or <code>false</code> if not. 623 */ 624 public boolean isOptional(final AttributeType attributeType) { 625 return optionalAttributes.contains(attributeType); 626 } 627 628 /** 629 * Indicates whether the provided attribute type is included in the required 630 * attribute list for this DIT content rule. 631 * 632 * @param attributeType 633 * The attribute type for which to make the determination. 634 * @return <code>true</code> if the provided attribute type is required by 635 * this DIT content rule, or <code>false</code> if not. 636 */ 637 public boolean isRequired(final AttributeType attributeType) { 638 return requiredAttributes.contains(attributeType); 639 } 640 641 /** 642 * Indicates whether the provided attribute type is in the list of required 643 * or optional attributes for this DIT content rule. 644 * 645 * @param attributeType 646 * The attribute type for which to make the determination. 647 * @return <code>true</code> if the provided attribute type is required or 648 * allowed for this DIT content rule, or <code>false</code> if it is 649 * not. 650 */ 651 public boolean isRequiredOrOptional(final AttributeType attributeType) { 652 return isRequired(attributeType) || isOptional(attributeType); 653 } 654 655 @Override 656 void toStringContent(final StringBuilder buffer) { 657 buffer.append(structuralClassOID); 658 659 if (!names.isEmpty()) { 660 final Iterator<String> iterator = names.iterator(); 661 662 final String firstName = iterator.next(); 663 if (iterator.hasNext()) { 664 buffer.append(" NAME ( '"); 665 buffer.append(firstName); 666 667 while (iterator.hasNext()) { 668 buffer.append("' '"); 669 buffer.append(iterator.next()); 670 } 671 672 buffer.append("' )"); 673 } else { 674 buffer.append(" NAME '"); 675 buffer.append(firstName); 676 buffer.append("'"); 677 } 678 } 679 680 appendDescription(buffer); 681 682 if (isObsolete) { 683 buffer.append(" OBSOLETE"); 684 } 685 686 if (!auxiliaryClassOIDs.isEmpty()) { 687 final Iterator<String> iterator = auxiliaryClassOIDs.iterator(); 688 689 final String firstClass = iterator.next(); 690 if (iterator.hasNext()) { 691 buffer.append(" AUX ("); 692 buffer.append(firstClass); 693 694 while (iterator.hasNext()) { 695 buffer.append(" $ "); 696 buffer.append(iterator.next()); 697 } 698 699 buffer.append(" )"); 700 } else { 701 buffer.append(" AUX "); 702 buffer.append(firstClass); 703 } 704 } 705 706 if (!requiredAttributeOIDs.isEmpty()) { 707 final Iterator<String> iterator = requiredAttributeOIDs.iterator(); 708 709 final String firstName = iterator.next(); 710 if (iterator.hasNext()) { 711 buffer.append(" MUST ( "); 712 buffer.append(firstName); 713 714 while (iterator.hasNext()) { 715 buffer.append(" $ "); 716 buffer.append(iterator.next()); 717 } 718 719 buffer.append(" )"); 720 } else { 721 buffer.append(" MUST "); 722 buffer.append(firstName); 723 } 724 } 725 726 if (!optionalAttributeOIDs.isEmpty()) { 727 final Iterator<String> iterator = optionalAttributeOIDs.iterator(); 728 729 final String firstName = iterator.next(); 730 if (iterator.hasNext()) { 731 buffer.append(" MAY ( "); 732 buffer.append(firstName); 733 734 while (iterator.hasNext()) { 735 buffer.append(" $ "); 736 buffer.append(iterator.next()); 737 } 738 739 buffer.append(" )"); 740 } else { 741 buffer.append(" MAY "); 742 buffer.append(firstName); 743 } 744 } 745 746 if (!prohibitedAttributeOIDs.isEmpty()) { 747 final Iterator<String> iterator = prohibitedAttributeOIDs.iterator(); 748 749 final String firstName = iterator.next(); 750 if (iterator.hasNext()) { 751 buffer.append(" NOT ( "); 752 buffer.append(firstName); 753 754 while (iterator.hasNext()) { 755 buffer.append(" $ "); 756 buffer.append(iterator.next()); 757 } 758 759 buffer.append(" )"); 760 } else { 761 buffer.append(" NOT "); 762 buffer.append(firstName); 763 } 764 } 765 } 766 767 void validate(final Schema schema, final List<LocalizableMessage> warnings) 768 throws SchemaException { 769 // Get the objectclass with the specified OID. If it does not exist 770 // or is not structural, then fail. 771 if (structuralClassOID != null) { 772 try { 773 structuralClass = schema.getObjectClass(structuralClassOID); 774 } catch (final UnknownSchemaElementException e) { 775 final LocalizableMessage message = 776 ERR_ATTR_SYNTAX_DCR_UNKNOWN_STRUCTURAL_CLASS1.get(getNameOrOID(), 777 structuralClassOID); 778 throw new SchemaException(message, e); 779 } 780 if (structuralClass.getObjectClassType() != ObjectClassType.STRUCTURAL) { 781 final LocalizableMessage message = 782 ERR_ATTR_SYNTAX_DCR_STRUCTURAL_CLASS_NOT_STRUCTURAL1.get(getNameOrOID(), 783 structuralClass.getNameOrOID(), structuralClass 784 .getObjectClassType().toString()); 785 warnings.add(message); 786 } 787 } 788 789 if (!auxiliaryClassOIDs.isEmpty()) { 790 auxiliaryClasses = new HashSet<>(auxiliaryClassOIDs.size()); 791 ObjectClass objectClass; 792 for (final String oid : auxiliaryClassOIDs) { 793 try { 794 objectClass = schema.getObjectClass(oid); 795 } catch (final UnknownSchemaElementException e) { 796 // This isn't good because it is an unknown auxiliary class. 797 final LocalizableMessage message = 798 ERR_ATTR_SYNTAX_DCR_UNKNOWN_AUXILIARY_CLASS1.get(getNameOrOID(), oid); 799 throw new SchemaException(message, e); 800 } 801 if (objectClass.getObjectClassType() != ObjectClassType.AUXILIARY) { 802 // This isn't good because it isn't an auxiliary class. 803 final LocalizableMessage message = 804 ERR_ATTR_SYNTAX_DCR_AUXILIARY_CLASS_NOT_AUXILIARY1.get(getNameOrOID(), 805 structuralClass.getOID(), structuralClass.getObjectClassType() 806 .toString()); 807 throw new SchemaException(message); 808 } 809 auxiliaryClasses.add(objectClass); 810 } 811 } 812 813 if (!requiredAttributeOIDs.isEmpty()) { 814 requiredAttributes = 815 getAttributeTypes(schema, requiredAttributeOIDs, ERR_ATTR_SYNTAX_DCR_UNKNOWN_REQUIRED_ATTR1); 816 } 817 818 if (!optionalAttributeOIDs.isEmpty()) { 819 optionalAttributes = 820 getAttributeTypes(schema, optionalAttributeOIDs, ERR_ATTR_SYNTAX_DCR_UNKNOWN_OPTIONAL_ATTR1); 821 } 822 823 if (!prohibitedAttributeOIDs.isEmpty()) { 824 prohibitedAttributes = 825 getAttributeTypes(schema, prohibitedAttributeOIDs, ERR_ATTR_SYNTAX_DCR_UNKNOWN_PROHIBITED_ATTR1); 826 } 827 828 // Make sure that none of the prohibited attributes is required by 829 // the structural or any of the auxiliary classes. 830 for (final AttributeType t : prohibitedAttributes) { 831 if (structuralClass.isRequired(t)) { 832 final LocalizableMessage message = 833 ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_STRUCTURAL.get(getNameOrOID(), t 834 .getNameOrOID(), structuralClass.getNameOrOID()); 835 throw new SchemaException(message); 836 } 837 838 for (final ObjectClass oc : auxiliaryClasses) { 839 if (oc.isRequired(t)) { 840 final LocalizableMessage message = 841 ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY.get( 842 getNameOrOID(), t.getNameOrOID(), oc.getNameOrOID()); 843 throw new SchemaException(message); 844 } 845 } 846 } 847 848 auxiliaryClasses = Collections.unmodifiableSet(auxiliaryClasses); 849 optionalAttributes = Collections.unmodifiableSet(optionalAttributes); 850 prohibitedAttributes = Collections.unmodifiableSet(prohibitedAttributes); 851 requiredAttributes = Collections.unmodifiableSet(requiredAttributes); 852 } 853 854 private Set<AttributeType> getAttributeTypes(final Schema schema, Set<String> oids, Arg2<Object, Object> errorMsg) 855 throws SchemaException { 856 Set<AttributeType> attrTypes = new HashSet<>(oids.size()); 857 for (final String oid : oids) { 858 try { 859 attrTypes.add(schema.getAttributeType(oid)); 860 } catch (final UnknownSchemaElementException e) { 861 // This isn't good because it means that the DIT content rule 862 // requires an attribute type that we don't know anything about. 863 throw new SchemaException(errorMsg.get(getNameOrOID(), oid), e); 864 } 865 } 866 return attrTypes; 867 } 868}