From cc1f99dc6bf00e63e6a1df0c6f39d9e37d176b04 Mon Sep 17 00:00:00 2001
From: Gaetan Boismal <gaetan.boismal@forgerock.com>
Date: Wed, 14 Jan 2015 10:33:13 +0000
Subject: [PATCH] OPENDJ-1652 (CR-5591) Add fluent builder for object class
---
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/ObjectClassBuilderTestCase.java | 208 +++++++++
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java | 502 ++++++++++------------
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java | 26
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java | 403 ++++++++++++++++--
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | 174 +++----
5 files changed, 861 insertions(+), 452 deletions(-)
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
index ba8d86a..9e3bbc3 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
+++ b/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) {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
index cd48852..82563d3 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClass.java
+++ b/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;
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 14a431f..d9653ca 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/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()) {
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/ObjectClassBuilderTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/ObjectClassBuilderTestCase.java
new file mode 100644
index 0000000..37ad0a0
--- /dev/null
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/ObjectClassBuilderTestCase.java
@@ -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;
+ }
+
+}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
index 4982cdc..fe509c9 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
+++ b/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();
--
Gitblit v1.10.0