opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
@@ -22,12 +22,13 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions copyright 2013-2014 ForgeRock AS. * Portions copyright 2013-2015 ForgeRock AS. * Portions copyright 2014 Manuel Gaupp */ package org.forgerock.opendj.ldap.schema; import static org.forgerock.opendj.ldap.schema.CollationMatchingRulesImpl.*; import static org.forgerock.opendj.ldap.schema.ObjectClassType.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; import static org.forgerock.opendj.ldap.schema.TimeBasedMatchingRulesImpl.*; @@ -35,12 +36,10 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; final class CoreSchemaImpl { @@ -73,8 +72,6 @@ private static final String EMPTY_STRING = "".intern(); private static final Set<String> EMPTY_STRING_SET = Collections.emptySet(); private static final Schema SINGLETON; /** @@ -337,10 +334,13 @@ .singletonList("authPassword"), "password authentication information", false, null, EMR_AUTH_PASSWORD_EXACT_OID, null, null, null, SYNTAX_AUTH_PASSWORD_OID, false, false, false, AttributeUsage.USER_APPLICATIONS, RFC3112_ORIGIN, false); builder.addObjectClass("1.3.6.1.4.1.4203.1.4.7", Collections .singletonList("authPasswordObject"), "authentication password mix in class", false, EMPTY_STRING_SET, EMPTY_STRING_SET, Collections.singleton("authPassword"), ObjectClassType.AUXILIARY, RFC3112_ORIGIN, false); builder.buildObjectClass("1.3.6.1.4.1.4203.1.4.7") .names("authPasswordObject") .type(AUXILIARY) .description("authentication password mix in class") .optionalAttributes("authPassword") .extraProperties(RFC3112_ORIGIN) .addToSchema(); } private static void addRFC4519(final SchemaBuilder builder) { @@ -540,229 +540,137 @@ SYNTAX_BIT_STRING_OID, false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4519_ORIGIN, false); Set<String> attrs = new HashSet<String>(); attrs.add("seeAlso"); attrs.add("ou"); attrs.add("l"); attrs.add("description"); builder.buildObjectClass("2.5.6.11") .names("applicationProcess") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("cn") .optionalAttributes("seeAlso", "ou", "l", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.11", Collections.singletonList("applicationProcess"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections .singleton("cn"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.2") .names("country") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("c") .optionalAttributes("searchGuide", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("searchGuide"); attrs.add("description"); builder.buildObjectClass("1.3.6.1.4.1.1466.344") .names("dcObject") .type(AUXILIARY) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("dc") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.2", Collections.singletonList("country"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("c"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.14") .names("device") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("cn") .optionalAttributes("serialNumber", "seeAlso", "owner", "ou", "o", "l", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("1.3.6.1.4.1.1466.344", Collections.singletonList("dcObject"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections .singleton("dc"), EMPTY_STRING_SET, ObjectClassType.AUXILIARY, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.9") .names("groupOfNames") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("member", "cn") .optionalAttributes("businessCategory", "seeAlso", "owner", "ou", "o", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("serialNumber"); attrs.add("seeAlso"); attrs.add("owner"); attrs.add("ou"); attrs.add("o"); attrs.add("l"); attrs.add("description"); builder.buildObjectClass("2.5.6.17") .names("groupOfUniqueNames") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("member", "cn") .optionalAttributes("businessCategory", "seeAlso", "owner", "ou", "o", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.14", Collections.singletonList("device"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.3") .names("locality") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .optionalAttributes("street", "seeAlso", "searchGuide", "st", "l", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); Set<String> must = new HashSet<String>(); must.add("member"); must.add("cn"); builder.buildObjectClass("2.5.6.4") .names("organization") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("o") .optionalAttributes("userPassword", "searchGuide", "seeAlso", "businessCategory", "x121Address", "registeredAddress", "destinationIndicator", "preferredDeliveryMethod", "telexNumber", "teletexTerminalIdentifier", "telephoneNumber", "internationalISDNNumber", "facsimileTelephoneNumber", "street", "postOfficeBox", "postalCode", "postalAddress", "physicalDeliveryOfficeName", "st", "l", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("businessCategory"); attrs.add("seeAlso"); attrs.add("owner"); attrs.add("ou"); attrs.add("o"); attrs.add("description"); builder.buildObjectClass("2.5.6.7") .names("organizationalPerson") .superiorObjectClasses("person") .optionalAttributes("title", "x121Address", "registeredAddress", "destinationIndicator", "preferredDeliveryMethod", "telexNumber", "teletexTerminalIdentifier", "telephoneNumber", "internationalISDNNumber", "facsimileTelephoneNumber", "street", "postOfficeBox", "postalCode", "postalAddress", "physicalDeliveryOfficeName", "ou", "st", "l") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.9", Collections.singletonList("groupOfNames"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), must, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.8") .names("organizationalRole") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("cn") .optionalAttributes("x121Address", "registeredAddress", "destinationIndicator", "preferredDeliveryMethod", "telexNumber", "teletexTerminalIdentifier", "telephoneNumber", "internationalISDNNumber", "facsimileTelephoneNumber", "seeAlso", "roleOccupant", "preferredDeliveryMethod", "street", "postOfficeBox", "postalCode", "postalAddress", "physicalDeliveryOfficeName", "ou", "st", "l", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("businessCategory"); attrs.add("seeAlso"); attrs.add("owner"); attrs.add("ou"); attrs.add("o"); attrs.add("description"); builder.buildObjectClass("2.5.6.5") .names("organizationalUnit") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("ou") .optionalAttributes("businessCategory", "description", "destinationIndicator", "facsimileTelephoneNumber", "internationalISDNNumber", "l", "physicalDeliveryOfficeName", "postalAddress", "postalCode", "postOfficeBox", "preferredDeliveryMethod", "registeredAddress", "searchGuide", "seeAlso", "st", "street", "telephoneNumber", "teletexTerminalIdentifier", "telexNumber", "userPassword", "x121Address") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.17", Collections.singletonList("groupOfUniqueNames"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), must, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.buildObjectClass("2.5.6.6") .names("person") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("sn", "cn") .optionalAttributes("userPassword", "telephoneNumber", "destinationIndicator", "seeAlso", "description") .extraProperties(RFC4519_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("street"); attrs.add("seeAlso"); attrs.add("searchGuide"); attrs.add("st"); attrs.add("l"); attrs.add("description"); builder.buildObjectClass("2.5.6.10") .names("residentialPerson") .superiorObjectClasses("person") .requiredAttributes("l") .optionalAttributes("businessCategory", "x121Address", "registeredAddress", "destinationIndicator", "preferredDeliveryMethod", "telexNumber", "teletexTerminalIdentifier", "telephoneNumber", "internationalISDNNumber", "facsimileTelephoneNumber", "preferredDeliveryMethod", "street", "postOfficeBox", "postalCode", "postalAddress", "physicalDeliveryOfficeName", "st", "l") .extraProperties(RFC4519_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.3", Collections.singletonList("locality"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); attrs = new HashSet<String>(); attrs.add("userPassword"); attrs.add("searchGuide"); attrs.add("seeAlso"); attrs.add("businessCategory"); attrs.add("x121Address"); attrs.add("registeredAddress"); attrs.add("destinationIndicator"); attrs.add("preferredDeliveryMethod"); attrs.add("telexNumber"); attrs.add("teletexTerminalIdentifier"); attrs.add("telephoneNumber"); attrs.add("internationalISDNNumber"); attrs.add("facsimileTelephoneNumber"); attrs.add("street"); attrs.add("postOfficeBox"); attrs.add("postalCode"); attrs.add("postalAddress"); attrs.add("physicalDeliveryOfficeName"); attrs.add("st"); attrs.add("l"); attrs.add("description"); builder.addObjectClass("2.5.6.4", Collections.singletonList("organization"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("o"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); attrs = new HashSet<String>(); attrs.add("title"); attrs.add("x121Address"); attrs.add("registeredAddress"); attrs.add("destinationIndicator"); attrs.add("preferredDeliveryMethod"); attrs.add("telexNumber"); attrs.add("teletexTerminalIdentifier"); attrs.add("telephoneNumber"); attrs.add("internationalISDNNumber"); attrs.add("facsimileTelephoneNumber"); attrs.add("street"); attrs.add("postOfficeBox"); attrs.add("postalCode"); attrs.add("postalAddress"); attrs.add("physicalDeliveryOfficeName"); attrs.add("ou"); attrs.add("st"); attrs.add("l"); builder.addObjectClass("2.5.6.7", Collections.singletonList("organizationalPerson"), EMPTY_STRING, false, Collections.singleton("person"), EMPTY_STRING_SET, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); attrs = new HashSet<String>(); attrs.add("x121Address"); attrs.add("registeredAddress"); attrs.add("destinationIndicator"); attrs.add("preferredDeliveryMethod"); attrs.add("telexNumber"); attrs.add("teletexTerminalIdentifier"); attrs.add("telephoneNumber"); attrs.add("internationalISDNNumber"); attrs.add("facsimileTelephoneNumber"); attrs.add("seeAlso"); attrs.add("roleOccupant"); attrs.add("preferredDeliveryMethod"); attrs.add("street"); attrs.add("postOfficeBox"); attrs.add("postalCode"); attrs.add("postalAddress"); attrs.add("physicalDeliveryOfficeName"); attrs.add("ou"); attrs.add("st"); attrs.add("l"); attrs.add("description"); builder.addObjectClass("2.5.6.8", Collections.singletonList("organizationalRole"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections .singleton("cn"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); attrs = new HashSet<String>(); attrs.add("businessCategory"); attrs.add("description"); attrs.add("destinationIndicator"); attrs.add("facsimileTelephoneNumber"); attrs.add("internationalISDNNumber"); attrs.add("l"); attrs.add("physicalDeliveryOfficeName"); attrs.add("postalAddress"); attrs.add("postalCode"); attrs.add("postOfficeBox"); attrs.add("preferredDeliveryMethod"); attrs.add("registeredAddress"); attrs.add("searchGuide"); attrs.add("seeAlso"); attrs.add("st"); attrs.add("street"); attrs.add("telephoneNumber"); attrs.add("teletexTerminalIdentifier"); attrs.add("telexNumber"); attrs.add("userPassword"); attrs.add("x121Address"); builder.addObjectClass("2.5.6.5", Collections.singletonList("organizationalUnit"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections .singleton("ou"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); must = new HashSet<String>(); must.add("sn"); must.add("cn"); attrs = new HashSet<String>(); attrs.add("userPassword"); attrs.add("telephoneNumber"); attrs.add("destinationIndicator"); attrs.add("seeAlso"); attrs.add("description"); builder.addObjectClass("2.5.6.6", Collections.singletonList("person"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), must, attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); attrs = new HashSet<String>(); attrs.add("businessCategory"); attrs.add("x121Address"); attrs.add("registeredAddress"); attrs.add("destinationIndicator"); attrs.add("preferredDeliveryMethod"); attrs.add("telexNumber"); attrs.add("teletexTerminalIdentifier"); attrs.add("telephoneNumber"); attrs.add("internationalISDNNumber"); attrs.add("facsimileTelephoneNumber"); attrs.add("preferredDeliveryMethod"); attrs.add("street"); attrs.add("postOfficeBox"); attrs.add("postalCode"); attrs.add("postalAddress"); attrs.add("physicalDeliveryOfficeName"); attrs.add("st"); attrs.add("l"); builder.addObjectClass("2.5.6.10", Collections.singletonList("residentialPerson"), EMPTY_STRING, false, Collections.singleton("person"), Collections.singleton("l"), attrs, ObjectClassType.STRUCTURAL, RFC4519_ORIGIN, false); builder.addObjectClass("1.3.6.1.1.3.1", Collections.singletonList("uidObject"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections .singleton("uid"), attrs, ObjectClassType.AUXILIARY, RFC4519_ORIGIN, false); builder.buildObjectClass("1.3.6.1.1.3.1") .names("uidObject") .type(AUXILIARY) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("uid") .optionalAttributes("businessCategory", "x121Address", "registeredAddress", "destinationIndicator", "preferredDeliveryMethod", "telexNumber", "teletexTerminalIdentifier", "telephoneNumber", "internationalISDNNumber", "facsimileTelephoneNumber", "preferredDeliveryMethod", "street", "postOfficeBox", "postalCode", "postalAddress", "physicalDeliveryOfficeName", "st", "l") .extraProperties(RFC4519_ORIGIN) .addToSchema(); } private static void addRFC4523(final SchemaBuilder builder) { @@ -811,53 +719,79 @@ null, null, SYNTAX_CERTLIST_OID, false, false, false, AttributeUsage.USER_APPLICATIONS, RFC4523_ORIGIN, false); builder.addObjectClass("2.5.6.21", Collections.singletonList("pkiUser"), "X.509 PKI User", false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, Collections.singleton("userCertificate"), ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.buildObjectClass("2.5.6.21") .names("pkiUser") .type(AUXILIARY) .description("X.509 PKI User") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .optionalAttributes("userCertificate") .extraProperties(RFC4523_ORIGIN) .addToSchema(); Set<String> attrs = new HashSet<String>(); attrs.add("cACertificate"); attrs.add("certificateRevocationList"); attrs.add("authorityRevocationList"); attrs.add("crossCertificatePair"); builder.buildObjectClass("2.5.6.22") .names("pkiCA") .type(AUXILIARY) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .description("X.509 PKI Certificate Authority") .optionalAttributes("cACertificate", "certificateRevocationList", "authorityRevocationList", "crossCertificatePair") .extraProperties(RFC4523_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.22", Collections.singletonList("pkiCA"), "X.509 PKI Certificate Authority", false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, attrs, ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.buildObjectClass("2.5.6.19") .names("cRLDistributionPoint") .description("X.509 CRL distribution point") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("cn") .optionalAttributes("certificateRevocationList", "authorityRevocationList", "deltaRevocationList") .extraProperties(RFC4523_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("certificateRevocationList"); attrs.add("authorityRevocationList"); attrs.add("deltaRevocationList"); builder.buildObjectClass("2.5.6.23") .names("deltaCRL") .type(AUXILIARY) .description("X.509 delta CRL") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .optionalAttributes("deltaRevocationList") .extraProperties(RFC4523_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.19", Collections.singletonList("cRLDistributionPoint"), "X.509 CRL distribution point", false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs, ObjectClassType.STRUCTURAL, RFC4523_ORIGIN, false); builder.buildObjectClass("2.5.6.15") .names("strongAuthenticationUser") .type(AUXILIARY) .description("X.521 strong authentication user") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("userCertificate") .extraProperties(RFC4523_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.23", Collections.singletonList("deltaCRL"), "X.509 delta CRL", false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, Collections.singleton("deltaRevocationList"), ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.addObjectClass("2.5.6.15", Collections.singletonList("strongAuthenticationUser"), "X.521 strong authentication user", false, Collections.singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("userCertificate"), EMPTY_STRING_SET, ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.addObjectClass("2.5.6.18", Collections.singletonList("userSecurityInformation"), "X.521 user security information", false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, Collections.singleton("supportedAlgorithms"), ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.buildObjectClass("2.5.6.18") .names("userSecurityInformation") .type(AUXILIARY) .description("X.521 user security information") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .optionalAttributes("supportedAlgorithms") .extraProperties(RFC4523_ORIGIN) .addToSchema(); attrs = new HashSet<String>(); attrs.add("authorityRevocationList"); attrs.add("certificateRevocationList"); attrs.add("cACertificate"); builder.buildObjectClass("2.5.6.16") .names("certificationAuthority") .type(AUXILIARY) .description("X.509 certificate authority") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("authorityRevocationList", "certificateRevocationList", "cACertificate") .optionalAttributes("crossCertificatePair") .extraProperties(RFC4523_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.16", Collections.singletonList("certificationAuthority"), "X.509 certificate authority", false, Collections.singleton(TOP_OBJECTCLASS_NAME), attrs, Collections.singleton("crossCertificatePair"), ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.addObjectClass("2.5.6.16.2", Collections.singletonList("certificationAuthority-V2"), "X.509 certificate authority, version 2", false, Collections.singleton("certificationAuthority"), EMPTY_STRING_SET, Collections.singleton("deltaRevocationList"), ObjectClassType.AUXILIARY, RFC4523_ORIGIN, false); builder.buildObjectClass("2.5.6.16.2") .names("certificationAuthority-V2") .type(AUXILIARY) .description("X.509 certificate authority, version 2") .superiorObjectClasses("certificationAuthority") .optionalAttributes("deltaRevocationList") .extraProperties(RFC4523_ORIGIN) .addToSchema(); } private static void addRFC4530(final SchemaBuilder builder) { @@ -1267,32 +1201,36 @@ } private static void defaultObjectClasses(final SchemaBuilder builder) { builder.addObjectClass(TOP_OBJECTCLASS_OID, Collections.singletonList(TOP_OBJECTCLASS_NAME), TOP_OBJECTCLASS_DESCRIPTION, false, EMPTY_STRING_SET, Collections.singleton("objectClass"), EMPTY_STRING_SET, ObjectClassType.ABSTRACT, RFC4512_ORIGIN, false); builder.buildObjectClass(TOP_OBJECTCLASS_OID) .names(TOP_OBJECTCLASS_NAME) .type(ABSTRACT) .description(TOP_OBJECTCLASS_DESCRIPTION) .requiredAttributes("objectClass") .extraProperties(RFC4512_ORIGIN) .addToSchema(); builder.addObjectClass("2.5.6.1", Collections.singletonList("alias"), EMPTY_STRING, false, Collections.singleton("top"), Collections.singleton("aliasedObjectName"), EMPTY_STRING_SET, ObjectClassType.STRUCTURAL, RFC4512_ORIGIN, false); builder.buildObjectClass("2.5.6.1") .names("alias") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("aliasedObjectName") .extraProperties(RFC4512_ORIGIN) .addToSchema(); builder.addObjectClass(EXTENSIBLE_OBJECT_OBJECTCLASS_OID, Collections .singletonList(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, EMPTY_STRING_SET, ObjectClassType.AUXILIARY, RFC4512_ORIGIN, false); builder.buildObjectClass(EXTENSIBLE_OBJECT_OBJECTCLASS_OID) .names(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME) .type(AUXILIARY) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .extraProperties(RFC4512_ORIGIN) .addToSchema(); final Set<String> subschemaAttrs = new HashSet<String>(); subschemaAttrs.add("dITStructureRules"); subschemaAttrs.add("nameForms"); subschemaAttrs.add("ditContentRules"); subschemaAttrs.add("objectClasses"); subschemaAttrs.add("attributeTypes"); subschemaAttrs.add("matchingRules"); subschemaAttrs.add("matchingRuleUse"); builder.addObjectClass("2.5.20.1", Collections.singletonList("subschema"), EMPTY_STRING, false, Collections.singleton(TOP_OBJECTCLASS_NAME), EMPTY_STRING_SET, subschemaAttrs, ObjectClassType.AUXILIARY, RFC4512_ORIGIN, false); builder.buildObjectClass("2.5.20.1") .names("subschema") .type(AUXILIARY) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .optionalAttributes("dITStructureRules", "nameForms", "ditContentRules", "objectClasses", "attributeTypes", "matchingRules", "matchingRuleUse") .extraProperties(RFC4512_ORIGIN) .addToSchema(); } private static void defaultSyntaxes(final SchemaBuilder builder) { opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
@@ -22,24 +22,31 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2015 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; import static com.forgerock.opendj.ldap.CoreMessages.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_NAME; import static org.forgerock.opendj.ldap.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID; import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.util.Reject; import static java.util.Arrays.*; import static java.util.Collections.*; import static org.forgerock.opendj.ldap.schema.ObjectClassType.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; import static com.forgerock.opendj.ldap.CoreMessages.*; /** * This class defines a data structure for storing and interacting with an @@ -51,6 +58,308 @@ * accessed via their getters or via the {@link #toString()} methods. */ public final class ObjectClass extends SchemaElement { /** A fluent API for incrementally constructing object classes. */ public static final class Builder extends SchemaElementBuilder<Builder> { private boolean isObsolete; private final List<String> names = new LinkedList<String>(); private String oid; private final Set<String> optionalAttributes = new LinkedHashSet<String>(); private final Set<String> requiredAttributes = new LinkedHashSet<String>(); private final Set<String> superiorClasses = new LinkedHashSet<String>(); private ObjectClassType type = null; Builder(final ObjectClass oc, final SchemaBuilder builder) { super(builder, oc); this.oid = oc.oid; this.names.addAll(oc.names); this.isObsolete = oc.isObsolete; this.type = oc.objectClassType; this.superiorClasses.addAll(oc.superiorClassOIDs); this.requiredAttributes.addAll(oc.requiredAttributeOIDs); this.optionalAttributes.addAll(optionalAttributes); } Builder(final String oid, final SchemaBuilder builder) { super(builder); oid(oid); } /** * Adds this object class to the schema overwriting any existing object class * with the same numeric OID. * * @return The parent schema builder. */ public SchemaBuilder addToSchemaOverwrite() { return getSchemaBuilder().addObjectClass(new ObjectClass(this), true); } /** * Adds this object class to the schema, throwing an * {@code ConflictingSchemaElementException} if there is an existing * object class with the same numeric OID. * * @return The parent schema builder. * @throws ConflictingSchemaElementException * If there is an existing object class with the same numeric * OID. */ public SchemaBuilder addToSchema() { return getSchemaBuilder().addObjectClass(new ObjectClass(this), false); } @Override public Builder description(final String description) { return description0(description); } @Override public Builder extraProperties(final Map<String, List<String>> extraProperties) { return extraProperties0(extraProperties); } @Override public Builder extraProperties(final String extensionName, final String... extensionValues) { return extraProperties0(extensionName, extensionValues); } @Override Builder getThis() { return this; } /** * Adds the provided user friendly names. * * @param names * The user friendly names. * @return This builder. */ public Builder names(final Collection<String> names) { this.names.addAll(names); return this; } /** * Adds the provided user friendly names. * * @param names * The user friendly names. * @return This builder. */ public Builder names(final String... names) { return names(asList(names)); } /** * Specifies whether this schema element is obsolete. * * @param isObsolete * {@code true} if this schema element is obsolete * (default is {@code false}). * @return This builder. */ public Builder obsolete(final boolean isObsolete) { this.isObsolete = isObsolete; return this; } /** * Sets the numeric OID which uniquely identifies this object class. * * @param oid * The numeric OID. * @return This builder. */ public Builder oid(final String oid) { this.oid = oid; return this; } /** * Adds the provided optional attributes. * * @param attributeNamesOrOIDs * The list of optional attribute names or OIDs. * @return This builder. */ public Builder optionalAttributes(final Collection<String> attributeNamesOrOIDs) { this.optionalAttributes.addAll(attributeNamesOrOIDs); return this; } /** * Adds the provided optional attributes. * * @param attributeNamesOrOIDs * The list of optional attribute names or OIDs. * @return This builder. */ public Builder optionalAttributes(final String... attributeNamesOrOIDs) { this.optionalAttributes.addAll(asList(attributeNamesOrOIDs)); return this; } @Override public Builder removeAllExtraProperties() { return removeAllExtraProperties0(); } @Override public Builder removeExtraProperty(final String extensionName, final String... extensionValues) { return removeExtraProperty0(extensionName, extensionValues); } /** * Removes all user defined names. * * @return This builder. */ public Builder removeAllNames() { this.names.clear(); return this; } /** * Removes all optional attributes. * * @return This builder. */ public Builder removeAllOptionalAttributes() { this.optionalAttributes.clear(); return this; } /** * Removes all required attributes. * * @return This builder. */ public Builder removeAllRequiredAttributes() { this.requiredAttributes.clear(); return this; } /** * Removes all superior object class. * * @return This builder. */ public Builder removeAllSuperiorObjectClass() { this.superiorClasses.clear(); return this; } /** * Removes the provided user defined name. * * @param name * The user defined name to be removed. * @return This builder. */ public Builder removeName(String name) { this.names.remove(name); return this; } /** * Removes the provided optional attribute. * * @param attributeNameOrOID * The optional attribute name or OID to be removed. * @return This builder. */ public Builder removeOptionalAttribute(String attributeNameOrOID) { this.optionalAttributes.remove(attributeNameOrOID); return this; } /** * Removes the provided required attribute. * * @param attributeNameOrOID * The provided required attribute name or OID to be removed. * @return This builder. */ public Builder removeRequiredAttribute(String attributeNameOrOID) { this.optionalAttributes.remove(attributeNameOrOID); return this; } /** * Removes the provided superior object class. * * @param objectClassNameOrOID * The superior object class name or OID to be removed. * @return This builder. */ public Builder removeSuperiorObjectClass(String objectClassNameOrOID) { this.superiorClasses.remove(objectClassNameOrOID); return this; } /** * Adds the provided required attributes. * * @param attributeNamesOrOIDs * The list of required attribute names or OIDs. * @return This builder. */ public Builder requiredAttributes(final Collection<String> attributeNamesOrOIDs) { this.requiredAttributes.addAll(attributeNamesOrOIDs); return this; } /** * Adds the provided required attributes. * * @param attributeNamesOrOIDs * The list of required attribute names or OIDs. * @return This builder. */ public Builder requiredAttributes(final String... attributeNamesOrOIDs) { this.requiredAttributes.addAll(asList(attributeNamesOrOIDs)); return this; } /** * Adds the provided superior object classes. * * @param objectClassNamesOrOIDs * The list of superior object classes names or OIDs. * @return This builder. */ public Builder superiorObjectClasses(final Collection<String> objectClassNamesOrOIDs) { this.superiorClasses.addAll(objectClassNamesOrOIDs); return this; } /** * Adds the provided superior object classes. * * @param objectClassNamesOrOIDs * The list of superior object classes names or OIDs. * @return This builder. */ public Builder superiorObjectClasses(final String... objectClassNamesOrOIDs) { this.superiorClasses.addAll(asList(objectClassNamesOrOIDs)); return this; } /** * Sets the type of this object class. * * @param type * The object class type. * @return This builder. */ public Builder type(final ObjectClassType type) { this.type = type; return this; } } /** The OID that may be used to reference this definition. */ private final String oid; @@ -72,11 +381,11 @@ /** The set of optional attribute types for this objectclass. */ private final Set<String> optionalAttributeOIDs; private Set<ObjectClass> superiorClasses = Collections.emptySet(); private Set<AttributeType> declaredRequiredAttributes = Collections.emptySet(); private Set<AttributeType> requiredAttributes = Collections.emptySet(); private Set<AttributeType> declaredOptionalAttributes = Collections.emptySet(); private Set<AttributeType> optionalAttributes = Collections.emptySet(); private Set<ObjectClass> superiorClasses = emptySet(); private Set<AttributeType> declaredRequiredAttributes = emptySet(); private Set<AttributeType> requiredAttributes = emptySet(); private Set<AttributeType> declaredOptionalAttributes = emptySet(); private Set<AttributeType> optionalAttributes = emptySet(); /** Indicates whether or not validation has been performed. */ private boolean needsValidating = true; @@ -84,23 +393,6 @@ /** The indicates whether or not validation failed. */ private boolean isValid; ObjectClass(final String oid, final List<String> names, final String description, final boolean obsolete, final Set<String> superiorClassOIDs, final Set<String> requiredAttributeOIDs, final Set<String> optionalAttributeOIDs, final ObjectClassType objectClassType, final Map<String, List<String>> extraProperties, final String definition) { super(description, extraProperties, definition); Reject.ifNull(oid, names, superiorClassOIDs, requiredAttributeOIDs, optionalAttributeOIDs, objectClassType); this.oid = oid; this.names = names; this.isObsolete = obsolete; this.superiorClassOIDs = superiorClassOIDs; this.objectClassType = objectClassType; this.requiredAttributeOIDs = requiredAttributeOIDs; this.optionalAttributeOIDs = optionalAttributeOIDs; } /** * Construct a extensibleObject object class where the set of allowed * attribute types of this object class is implicitly the set of all @@ -111,15 +403,31 @@ * @param extraProperties * The map of "extra" properties for this schema definition */ ObjectClass(final String description, final Map<String, List<String>> extraProperties) { super(description, extraProperties, null); this.oid = EXTENSIBLE_OBJECT_OBJECTCLASS_OID; this.names = Collections.singletonList(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME); this.isObsolete = false; this.superiorClassOIDs = Collections.singleton(TOP_OBJECTCLASS_NAME); this.objectClassType = ObjectClassType.AUXILIARY; this.requiredAttributeOIDs = Collections.emptySet(); this.optionalAttributeOIDs = Collections.emptySet(); static ObjectClass newExtensibleObjectObjectClass(final String description, final Map<String, List<String>> extraProperties, final SchemaBuilder builder) { return new ObjectClass(new Builder(EXTENSIBLE_OBJECT_OBJECTCLASS_OID, builder) .description(description) .extraProperties(extraProperties) .names(EXTENSIBLE_OBJECT_OBJECTCLASS_NAME) .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .type(AUXILIARY)); } private ObjectClass(final Builder builder) { super(builder); if (builder.oid == null || builder.oid.isEmpty()) { throw new IllegalArgumentException("An OID must be specified."); } this.oid = builder.oid; this.names = unmodifiableCopyOfList(builder.names); this.isObsolete = builder.isObsolete; this.superiorClassOIDs = unmodifiableCopyOfSet(builder.superiorClasses); this.objectClassType = builder.type; this.requiredAttributeOIDs = unmodifiableCopyOfSet(builder.requiredAttributes); this.optionalAttributeOIDs = unmodifiableCopyOfSet(builder.optionalAttributes); } /** @@ -198,8 +506,7 @@ * @return The objectclass type for this objectclass. */ public ObjectClassType getObjectClassType() { return objectClassType; return objectClassType != null ? objectClassType : STRUCTURAL; } /** @@ -208,7 +515,6 @@ * @return The OID for this schema definition. */ public String getOID() { return oid; } @@ -356,12 +662,6 @@ return isRequired(attributeType) || isOptional(attributeType); } ObjectClass duplicate() { return new ObjectClass(oid, names, getDescription(), isObsolete, superiorClassOIDs, requiredAttributeOIDs, optionalAttributeOIDs, objectClassType, getExtraProperties(), toString()); } @Override void toStringContent(final StringBuilder buffer) { buffer.append(oid); @@ -473,7 +773,7 @@ // Init a flag to check to inheritance from top (only needed for // structural object classes) per RFC 4512 boolean derivesTop = objectClassType != ObjectClassType.STRUCTURAL; boolean derivesTop = getObjectClassType() != ObjectClassType.STRUCTURAL; if (!superiorClassOIDs.isEmpty()) { superiorClasses = new HashSet<ObjectClass>(superiorClassOIDs.size()); @@ -491,14 +791,15 @@ // Make sure that the inheritance configuration is acceptable. final ObjectClassType superiorType = superiorClass.getObjectClassType(); switch (objectClassType) { final ObjectClassType type = getObjectClassType(); switch (type) { case ABSTRACT: // Abstract classes may only inherit from other abstract // classes. if (superiorType != ObjectClassType.ABSTRACT) { final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE1.get( getNameOrOID(), objectClassType.toString(), superiorType getNameOrOID(), type.toString(), superiorType .toString(), superiorClass.getNameOrOID()); failValidation(invalidSchemaElements, warnings, message); return false; @@ -513,7 +814,7 @@ && superiorType != ObjectClassType.AUXILIARY) { final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE1.get( getNameOrOID(), objectClassType.toString(), superiorType getNameOrOID(), type.toString(), superiorType .toString(), superiorClass.getNameOrOID()); failValidation(invalidSchemaElements, warnings, message); return false; @@ -527,7 +828,7 @@ && superiorType != ObjectClassType.STRUCTURAL) { final LocalizableMessage message = WARN_ATTR_SYNTAX_OBJECTCLASS_INVALID_SUPERIOR_TYPE1.get( getNameOrOID(), objectClassType.toString(), superiorType getNameOrOID(), type.toString(), superiorType .toString(), superiorClass.getNameOrOID()); failValidation(invalidSchemaElements, warnings, message); return false; opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -22,7 +22,7 @@ * * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions Copyright 2011-2014 ForgeRock AS * Portions Copyright 2011-2015 ForgeRock AS * Portions Copyright 2014 Manuel Gaupp */ package org.forgerock.opendj.ldap.schema; @@ -66,11 +66,16 @@ import com.forgerock.opendj.util.StaticUtils; import com.forgerock.opendj.util.SubstringReader; import static java.util.Collections.*; import static org.forgerock.opendj.ldap.LdapException.*; import static org.forgerock.opendj.ldap.schema.ObjectClass.*; import static org.forgerock.opendj.ldap.schema.ObjectClassType.*; import static org.forgerock.opendj.ldap.schema.Schema.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; import static org.forgerock.opendj.ldap.schema.SchemaOptions.*; import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; import static com.forgerock.opendj.ldap.CoreMessages.*; import static com.forgerock.opendj.util.StaticUtils.*; @@ -1143,7 +1148,7 @@ * * @param oid * The OID of the matching rule definition. * @return A builder to continue building the NameForm. * @return A builder to continue building the MatchingRule. */ public MatchingRule.Builder buildMatchingRule(final String oid) { lazyInitBuilder(); @@ -1394,6 +1399,39 @@ } /** * Returns an object class builder whose fields are initialized to the * values of the provided object class. This method should be used when * duplicating object classes from external schemas or when modifying * existing object classes. * * @param objectClass * The object class source. * @return A builder to continue building the ObjectClass. */ public ObjectClass.Builder buildObjectClass(final ObjectClass objectClass) { lazyInitBuilder(); return new ObjectClass.Builder(objectClass, this); } /** * Returns a builder which can be used for incrementally constructing a new * object class before adding it to the schema. Example usage: * * <pre> * SchemaBuilder builder = ...; * builder.buildObjectClass("objectclass-oid").name("object class name").addToSchema(); * </pre> * * @param oid * The OID of the object class definition. * @return A builder to continue building the ObjectClass. */ public ObjectClass.Builder buildObjectClass(final String oid) { lazyInitBuilder(); return new ObjectClass.Builder(oid, this); } /** * Duplicates the syntax. * * @param syntax @@ -1470,17 +1508,11 @@ // parenthesis. reader.skipWhitespaces(); // The next set of characters must be the OID. // The next set of characters is the OID. final String oid = readOID(reader, allowsMalformedNamesAndOptions()); List<String> names = Collections.emptyList(); String description = "".intern(); boolean isObsolete = false; Set<String> superiorClasses = Collections.emptySet(); Set<String> requiredAttributes = Collections.emptySet(); Set<String> optionalAttributes = Collections.emptySet(); ObjectClassType objectClassType = ObjectClassType.STRUCTURAL; Map<String, List<String>> extraProperties = Collections.emptyMap(); Set<String> superiorClasses = emptySet(); ObjectClassType ocType = null; ObjectClass.Builder ocBuilder = new ObjectClass.Builder(oid, this).definition(definition); // At this point, we should have a pretty specific syntax that // describes what may come next, but some of the components are @@ -1497,47 +1529,39 @@ // No more tokens. break; } else if ("name".equalsIgnoreCase(tokenName)) { names = readNameDescriptors(reader, allowsMalformedNamesAndOptions()); ocBuilder.names(readNameDescriptors(reader, allowsMalformedNamesAndOptions())); } else if ("desc".equalsIgnoreCase(tokenName)) { // This specifies the description for the attribute type. It // is an arbitrary string of characters enclosed in single // quotes. description = readQuotedString(reader); ocBuilder.description(readQuotedString(reader)); } else if ("obsolete".equalsIgnoreCase(tokenName)) { // This indicates whether the attribute type should be // considered obsolete. We do not need to do any more // parsing for this token. isObsolete = true; // considered obsolete. ocBuilder.obsolete(true); } else if ("sup".equalsIgnoreCase(tokenName)) { superiorClasses = readOIDs(reader, allowsMalformedNamesAndOptions()); } else if ("abstract".equalsIgnoreCase(tokenName)) { // This indicates that entries must not include this // objectclass unless they also include a non-abstract // objectclass that inherits from this class. We do not need // any more parsing for this token. objectClassType = ObjectClassType.ABSTRACT; // objectclass that inherits from this class. ocType = ABSTRACT; } else if ("structural".equalsIgnoreCase(tokenName)) { // This indicates that this is a structural objectclass. We // do not need any more parsing for this token. objectClassType = ObjectClassType.STRUCTURAL; ocType = STRUCTURAL; } else if ("auxiliary".equalsIgnoreCase(tokenName)) { // This indicates that this is an auxiliary objectclass. We // do not need any more parsing for this token. objectClassType = ObjectClassType.AUXILIARY; ocType = AUXILIARY; } else if ("must".equalsIgnoreCase(tokenName)) { requiredAttributes = readOIDs(reader, allowsMalformedNamesAndOptions()); ocBuilder.requiredAttributes(readOIDs(reader, allowsMalformedNamesAndOptions())); } else if ("may".equalsIgnoreCase(tokenName)) { optionalAttributes = readOIDs(reader, allowsMalformedNamesAndOptions()); ocBuilder.optionalAttributes(readOIDs(reader, allowsMalformedNamesAndOptions())); } else if (tokenName.matches("^X-[A-Za-z_-]+$")) { // This must be a non-standard property and it must be // followed by either a single definition in single quotes // or an open parenthesis followed by one or more values in // single quotes separated by spaces followed by a close // parenthesis. if (extraProperties.isEmpty()) { extraProperties = new HashMap<String, List<String>>(); } extraProperties.put(tokenName, readExtensions(reader)); final List<String> extensions = readExtensions(reader); ocBuilder.extraProperties(tokenName, extensions.toArray(new String[extensions.size()])); } else { throw new LocalizedIllegalArgumentException( ERR_ATTR_SYNTAX_OBJECTCLASS_ILLEGAL_TOKEN1.get(definition, tokenName)); @@ -1545,81 +1569,21 @@ } if (EXTENSIBLE_OBJECT_OBJECTCLASS_OID.equals(oid)) { addObjectClass(new ObjectClass(description, extraProperties), overwrite); addObjectClass(newExtensibleObjectObjectClass( ocBuilder.getDescription(), ocBuilder.getExtraProperties(), this), overwrite); return this; } else { if (objectClassType == ObjectClassType.STRUCTURAL && superiorClasses.isEmpty()) { superiorClasses = Collections.singleton(TOP_OBJECTCLASS_NAME); if (ocType == STRUCTURAL && superiorClasses.isEmpty()) { superiorClasses = singleton(TOP_OBJECTCLASS_NAME); } if (!extraProperties.isEmpty()) { extraProperties = Collections.unmodifiableMap(extraProperties); } addObjectClass(new ObjectClass(oid, names, description, isObsolete, superiorClasses, requiredAttributes, optionalAttributes, objectClassType, extraProperties, definition), overwrite); ocBuilder.superiorObjectClasses(superiorClasses) .type(ocType); return overwrite ? ocBuilder.addToSchemaOverwrite() : ocBuilder.addToSchema(); } } catch (final DecodeException e) { final LocalizableMessage msg = ERR_ATTR_SYNTAX_OBJECTCLASS_INVALID1.get(definition, e.getMessageObject()); throw new LocalizedIllegalArgumentException(msg, e.getCause()); throw new LocalizedIllegalArgumentException( ERR_ATTR_SYNTAX_OBJECTCLASS_INVALID1.get(definition, e.getMessageObject()), e.getCause()); } return this; } /** * Adds the provided object class definition to this schema builder. * * @param oid * The OID of the object class definition. * @param names * The user-friendly names of the object class definition. * @param description * The description of the object class definition. * @param obsolete * {@code true} if the object class definition is obsolete, * otherwise {@code false}. * @param superiorClassOIDs * A list of direct superclasses of the object class. * @param requiredAttributeOIDs * A list of attribute types that entries must contain. * @param optionalAttributeOIDs * A list of attribute types that entries may contain. * @param objectClassType * The type of the object class. * @param extraProperties * A map containing additional properties associated with the * object class definition. * @param overwrite * {@code true} if any existing object class with the same OID * should be overwritten. * @return A reference to this schema builder. * @throws ConflictingSchemaElementException * If {@code overwrite} was {@code false} and a conflicting * schema element was found. */ SchemaBuilder addObjectClass(final String oid, final List<String> names, final String description, final boolean obsolete, Set<String> superiorClassOIDs, final Set<String> requiredAttributeOIDs, final Set<String> optionalAttributeOIDs, final ObjectClassType objectClassType, final Map<String, List<String>> extraProperties, final boolean overwrite) { lazyInitBuilder(); if (EXTENSIBLE_OBJECT_OBJECTCLASS_OID.equals(oid)) { addObjectClass(new ObjectClass(description, unmodifiableCopyOfExtraProperties(extraProperties)), overwrite); } else { if (objectClassType == ObjectClassType.STRUCTURAL && superiorClassOIDs.isEmpty()) { superiorClassOIDs = Collections.singleton(TOP_OBJECTCLASS_NAME); } addObjectClass(new ObjectClass(oid, unmodifiableCopyOfList(names), description, obsolete, unmodifiableCopyOfSet(superiorClassOIDs), unmodifiableCopyOfSet(requiredAttributeOIDs), unmodifiableCopyOfSet(optionalAttributeOIDs), objectClassType, unmodifiableCopyOfExtraProperties(extraProperties), null), overwrite); } return this; } /** @@ -2535,7 +2499,7 @@ return this; } private void addObjectClass(final ObjectClass oc, final boolean overwrite) { SchemaBuilder addObjectClass(final ObjectClass oc, final boolean overwrite) { ObjectClass conflictingOC; if (numericOID2ObjectClasses.containsKey(oc.getOID())) { conflictingOC = numericOID2ObjectClasses.get(oc.getOID()); @@ -2562,6 +2526,8 @@ classes.add(oc); } } return this; } private void addSchema0(final Schema schema, final boolean overwrite) { @@ -2594,7 +2560,7 @@ } for (final ObjectClass objectClass : schema.getObjectClasses()) { addObjectClass(objectClass.duplicate(), overwrite); addObjectClass(objectClass, overwrite); } for (final NameForm nameForm : schema.getNameForms()) { opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/ObjectClassBuilderTestCase.java
New file @@ -0,0 +1,208 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2015 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; import java.util.List; import java.util.Set; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.util.Collections.*; import static org.fest.assertions.Assertions.*; import static org.fest.assertions.MapAssert.*; import static org.forgerock.opendj.ldap.schema.ObjectClassType.*; import static org.forgerock.opendj.ldap.schema.Schema.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; public class ObjectClassBuilderTestCase extends AbstractSchemaTestCase { @DataProvider Object[][] validObjectClasses() { // OID, obsolete, names, optional attributes, required attributes, // superior object classes, type, description, // extra property name, extra property values, overwrite return new Object[][] { // Basic object class { "1.2.3.4", false, singletonList("MyObjectClass"), emptySet(), singleton("cn"), singleton(TOP_OBJECTCLASS_NAME), STRUCTURAL, "MyObjectClass description.", "New extra property", "New extra value", false }, // Allowed overrides existing core schema object class groupOfNames { "2.5.6.9", false, singletonList("groupOfFirstNames"), emptySet(), singleton("cn"), singleton(TOP_OBJECTCLASS_NAME), AUXILIARY, "MyObjectClass description.", "New extra property", "New extra value", true }, // No name provided, should be validated { "1.2.3.4", false, emptyList(), singleton("name"), singleton("cn"), singleton(TOP_OBJECTCLASS_NAME), STRUCTURAL, "MyObjectClass description.", "New extra property", "New extra value", false }, // Empty description, should be validated { "1.2.3.4", false, emptyList(), singleton("name"), singleton("cn"), singleton(TOP_OBJECTCLASS_NAME), STRUCTURAL, "", "New extra property", "New extra value", false }, }; } @Test(dataProvider = "validObjectClasses") public void testValidOCBuilder(final String oid, final boolean isObsolete, final List<String> names, final Set<String> optionalAttributeOIDs, final Set<String> requiredAttributesOIDs, final Set<String> superiorClassOIDs, final ObjectClassType type, final String description, final String extraPropertyName, final String extraPropertyValue, final boolean overwrite) throws Exception { final ObjectClass.Builder ocBuilder = new SchemaBuilder(getCoreSchema()) .buildObjectClass(oid) .description(description) .obsolete(isObsolete) .names(names) .superiorObjectClasses(superiorClassOIDs) .requiredAttributes(requiredAttributesOIDs) .optionalAttributes(optionalAttributeOIDs) .type(type) .extraProperties(extraPropertyName, extraPropertyValue); final Schema schema = overwrite ? ocBuilder.addToSchemaOverwrite().toSchema() : ocBuilder.addToSchema().toSchema(); assertThat(schema.getWarnings()).isEmpty(); final ObjectClass oc = schema.getObjectClass(oid); assertThat(oc).isNotNull(); assertThat(oc.getOID()).isEqualTo(oid); assertThat(oc.getDescription()).isEqualTo(description); assertThat(oc.isObsolete()).isEqualTo(isObsolete); assertThat(oc.getNames()).containsOnly(names.toArray()); assertSchemaElementsContainsAll(oc.getSuperiorClasses(), superiorClassOIDs); assertSchemaElementsContainsAll(oc.getRequiredAttributes(), requiredAttributesOIDs); assertSchemaElementsContainsAll(oc.getOptionalAttributes(), optionalAttributeOIDs); assertThat(oc.getObjectClassType()).isEqualTo(type); assertThat(oc.getExtraProperties()).includes(entry(extraPropertyName, singletonList(extraPropertyValue))); } @Test public void testOCBuilderDefaultValues() throws Exception { final SchemaBuilder sb = new SchemaBuilder(getCoreSchema()); final ObjectClass.Builder ocBuilder = sb.buildObjectClass("1.1.1.42") .description("Default object class") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .names("defaultObjectClass"); final Schema schema = ocBuilder.addToSchema().toSchema(); assertThat(schema.getWarnings()).isEmpty(); final ObjectClass oc = schema.getObjectClass("defaultObjectClass"); assertThat(oc).isNotNull(); assertThat(oc.getOID()).isEqualTo("1.1.1.42"); assertThat(oc.getDescription()).isEqualTo("Default object class"); assertThat(oc.isObsolete()).isFalse(); assertThat(oc.getNames()).containsOnly("defaultObjectClass"); assertSchemaElementsContainsAll(oc.getSuperiorClasses(), TOP_OBJECTCLASS_NAME); final Set<AttributeType> topReqAttrs = schema.getObjectClass(TOP_OBJECTCLASS_NAME).getRequiredAttributes(); assertThat(oc.getRequiredAttributes()).containsOnly(topReqAttrs.toArray()); assertThat(oc.getOptionalAttributes()).isEmpty(); assertThat(oc.getObjectClassType()).isEqualTo(STRUCTURAL); assertThat(oc.getExtraProperties()).isEmpty(); } @Test public void testOCBuilderCopyConstructor() throws Exception { final SchemaBuilder sb = new SchemaBuilder(getCoreSchema()); final ObjectClass.Builder ocBuilder = sb.buildObjectClass("1.1.1.42") .description("Object class to duplicate") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .names("ObjectClassToDuplicate") .requiredAttributes("name"); final Schema schema = ocBuilder.addToSchema().toSchema(); assertThat(schema.getWarnings()).isEmpty(); sb.buildObjectClass(schema.getObjectClass("ObjectClassToDuplicate")) .oid("1.1.1.43") .names("Copy") .obsolete(true) .addToSchemaOverwrite(); final Schema schemaCopy = sb.toSchema(); assertThat(schemaCopy.getWarnings()).isEmpty(); final ObjectClass ocCopy = schemaCopy.getObjectClass("Copy"); assertThat(ocCopy).isNotNull(); assertThat(ocCopy.getOID()).isEqualTo("1.1.1.43"); assertThat(ocCopy.getDescription()).isEqualTo("Object class to duplicate"); assertThat(ocCopy.isObsolete()).isTrue(); assertThat(ocCopy.getNames()).containsOnly("ObjectClassToDuplicate", "Copy"); assertSchemaElementsContainsAll(ocCopy.getSuperiorClasses(), TOP_OBJECTCLASS_NAME); assertSchemaElementsContainsAll(ocCopy.getRequiredAttributes(), "name"); assertThat(ocCopy.getOptionalAttributes()).isEmpty(); assertThat(ocCopy.getObjectClassType()).isEqualTo(STRUCTURAL); assertThat(ocCopy.getExtraProperties()).isEmpty(); } @Test(expectedExceptions = ConflictingSchemaElementException.class) public void testOCBuilderDoesNotAllowOverwrite() throws Exception { final ObjectClass.Builder ocBuilder = new SchemaBuilder(getCoreSchema()) .buildObjectClass("2.5.6.9") .description("MyObjectClass description") .names("groupOfFirstNames") .requiredAttributes("cn") .type(AUXILIARY) .extraProperties("New extra property", "New extra value"); ocBuilder.addToSchema().toSchema(); } @Test(expectedExceptions = IllegalArgumentException.class) public void testOCBuilderDoesNotAllowEmptyOID() throws Exception { final ObjectClass.Builder ocBuilder = new SchemaBuilder(getCoreSchema()) .buildObjectClass("") .description("MyObjectClass description") .names("MyObjectClass") .requiredAttributes("cn") .extraProperties("New extra property", "New extra value"); ocBuilder.addToSchema().toSchema(); } private void assertSchemaElementsContainsAll(final Set<? extends SchemaElement> elements, final Set<String> namesOrOIDs) throws Exception { assertSchemaElementsContainsAll(elements, namesOrOIDs.toArray(new String[namesOrOIDs.size()])); } private void assertSchemaElementsContainsAll(final Set<? extends SchemaElement> elements, final String... namesOrOIDs) throws Exception { for (final String nameOrOID : namesOrOIDs) { assertThat(assertSchemaElementsContains(elements, nameOrOID)).isTrue(); } } private boolean assertSchemaElementsContains(final Set<? extends SchemaElement> elements, final String nameOrOID) { for (final SchemaElement element : elements) { final String oid = element instanceof AttributeType ? ((AttributeType) element).getNameOrOID() : ((ObjectClass) element).getNameOrOID(); if (oid.equals(nameOrOID)) { return true; } } return false; } } opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
@@ -21,13 +21,11 @@ * CDDL HEADER END * * * Portions Copyright 2012-2014 ForgeRock AS. * Portions Copyright 2012-2015 ForgeRock AS. */ package org.forgerock.opendj.ldap.schema; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.forgerock.i18n.LocalizedIllegalArgumentException; import org.forgerock.opendj.ldap.ByteString; @@ -46,6 +44,7 @@ import static org.fest.assertions.Assertions.*; import static org.fest.assertions.Fail.*; import static org.forgerock.opendj.ldap.schema.CoreSchema.*; import static org.forgerock.opendj.ldap.schema.Schema.*; import static org.forgerock.opendj.ldap.schema.SchemaConstants.*; import static org.forgerock.opendj.ldap.schema.SchemaOptions.*; import static org.forgerock.opendj.ldap.spi.LdapPromises.*; @@ -1151,18 +1150,15 @@ */ @Test public final void testSchemaBuilderAddObjectClass() throws Exception { final SchemaBuilder scBuild = new SchemaBuilder(Schema.getDefaultSchema()); Set<String> attrs = new HashSet<String>(); attrs.add("seeAlso"); attrs.add("ou"); attrs.add("l"); attrs.add("description"); scBuild.addObjectClass("2.5.6.14", Collections.singletonList("device"), "New description for the new existing Object Class", false, Collections .singleton(TOP_OBJECTCLASS_NAME), Collections.singleton("cn"), attrs, ObjectClassType.STRUCTURAL, Collections.singletonMap(SCHEMA_PROPERTY_ORIGIN, Collections.singletonList("RFC 4519")), true); final SchemaBuilder scBuild = new SchemaBuilder(getDefaultSchema()); scBuild.buildObjectClass("2.5.6.14") .names("device") .description("New description for the new existing Object Class") .superiorObjectClasses(TOP_OBJECTCLASS_NAME) .requiredAttributes("cn") .optionalAttributes("seeAlso", "ou", "l", "description") .extraProperties(SCHEMA_PROPERTY_ORIGIN, "RFC 4519") .addToSchemaOverwrite(); Schema sc = scBuild.toSchema(); assertThat(sc.getWarnings()).isEmpty();