From 8d87254b4576d48cc6cbd69765f9f3d7df95e32c Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 28 Jun 2011 16:46:41 +0000
Subject: [PATCH] Fix OPENDJ-220: Make sure that SchemaBuilder is re-usable after calling toSchema
---
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java | 117 ++++++++++++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | 345 +++++++++++++++++++++++++++++++-----------
2 files changed, 369 insertions(+), 93 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 187aaea..6535580 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -171,9 +171,12 @@
private boolean allowMalformedNamesAndOptions;
+ // A schema which should be copied into this builder on any mutation.
+ private Schema copyOnWriteSchema = null;
+
// A unique ID which can be used to uniquely identify schemas
// constructed without a name.
- private final AtomicInteger nextSchemaID = new AtomicInteger();
+ private static final AtomicInteger NEXT_SCHEMA_ID = new AtomicInteger();
@@ -183,7 +186,7 @@
*/
public SchemaBuilder()
{
- initBuilder(null);
+ preLazyInitBuilder(null, null);
}
@@ -201,8 +204,7 @@
*/
public SchemaBuilder(final Entry entry) throws NullPointerException
{
- initBuilder(entry.getName().toString());
-
+ preLazyInitBuilder(entry.getName().toString(), null);
addSchema(entry, true);
}
@@ -219,8 +221,7 @@
*/
public SchemaBuilder(final Schema schema) throws NullPointerException
{
- initBuilder(schema.getSchemaName());
- addSchema(schema, true);
+ preLazyInitBuilder(schema.getSchemaName(), schema);
}
@@ -235,7 +236,7 @@
*/
public SchemaBuilder(final String schemaName)
{
- initBuilder(schemaName);
+ preLazyInitBuilder(schemaName, null);
}
@@ -262,6 +263,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -586,6 +590,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
final AttributeType attrType = new AttributeType(oid,
unmodifiableCopyOfList(names), description, obsolete, superiorType,
equalityMatchingRule, orderingMatchingRule, substringMatchingRule,
@@ -620,6 +626,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -807,6 +816,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
final DITContentRule rule = new DITContentRule(structuralClass,
unmodifiableCopyOfList(names), description, obsolete,
unmodifiableCopyOfSet(auxiliaryClasses),
@@ -854,6 +865,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
final DITStructureRule rule = new DITStructureRule(ruleID,
unmodifiableCopyOfList(names), description, obsolete, nameForm,
unmodifiableCopyOfSet(superiorRules),
@@ -887,6 +900,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -1045,6 +1061,8 @@
{
Validator.ensureNotNull((Object) enumerations);
+ lazyInitBuilder();
+
final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid,
Arrays.asList(enumerations));
final Syntax enumSyntax = new Syntax(oid, description,
@@ -1092,6 +1110,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -1256,6 +1277,9 @@
throws ConflictingSchemaElementException
{
Validator.ensureNotNull(implementation);
+
+ lazyInitBuilder();
+
final MatchingRule matchingRule = new MatchingRule(oid,
unmodifiableCopyOfList(names), description, obsolete, assertionSyntax,
unmodifiableCopyOfExtraProperties(extraProperties), null,
@@ -1288,6 +1312,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -1450,6 +1477,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
final MatchingRuleUse use = new MatchingRuleUse(oid,
unmodifiableCopyOfList(names), description, obsolete,
unmodifiableCopyOfSet(attributeOIDs),
@@ -1482,6 +1511,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -1672,6 +1704,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
final NameForm nameForm = new NameForm(oid, unmodifiableCopyOfList(names),
description, obsolete, structuralClass,
unmodifiableCopyOfSet(requiredAttributes),
@@ -1705,6 +1739,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -1914,6 +1951,8 @@
final Map<String, List<String>> extraProperties, final boolean overwrite)
throws ConflictingSchemaElementException
{
+ lazyInitBuilder();
+
if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID))
{
addObjectClass(new ObjectClass(description,
@@ -1962,6 +2001,8 @@
{
Validator.ensureNotNull(pattern);
+ lazyInitBuilder();
+
addSyntax(
new Syntax(oid, description, Collections.singletonMap("X-PATTERN",
Collections.singletonList(pattern.toString())), null, null),
@@ -2003,6 +2044,7 @@
final boolean overwrite) throws UnsupportedOperationException,
IllegalStateException, NullPointerException
{
+ // The call to addSchema will perform copyOnWrite.
final SearchRequest request = getReadSchemaSearchRequest(name);
final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
@@ -2060,6 +2102,7 @@
InterruptedException, UnsupportedOperationException,
IllegalStateException, NullPointerException
{
+ // The call to addSchema will perform copyOnWrite.
final SearchRequest request = getReadSchemaSearchRequest(name);
final Entry entry = connection.searchSingleEntry(request);
return addSchema(entry, overwrite);
@@ -2087,6 +2130,8 @@
{
Validator.ensureNotNull(entry);
+ lazyInitBuilder();
+
Attribute attr = entry.getAttribute(Schema.ATTR_LDAP_SYNTAXES);
if (attr != null)
{
@@ -2241,50 +2286,9 @@
{
Validator.ensureNotNull(schema);
- // All of the schema elements must be duplicated because validation will
- // cause them to update all their internal references which, although
- // unlikely, may be different in the new schema.
+ lazyInitBuilder();
- for (final Syntax syntax : schema.getSyntaxes())
- {
- addSyntax(syntax.duplicate(), overwrite);
- }
-
- for (final MatchingRule matchingRule : schema.getMatchingRules())
- {
- addMatchingRule(matchingRule.duplicate(), overwrite);
- }
-
- for (final MatchingRuleUse matchingRuleUse : schema.getMatchingRuleUses())
- {
- addMatchingRuleUse(matchingRuleUse.duplicate(), overwrite);
- }
-
- for (final AttributeType attributeType : schema.getAttributeTypes())
- {
- addAttributeType(attributeType.duplicate(), overwrite);
- }
-
- for (final ObjectClass objectClass : schema.getObjectClasses())
- {
- addObjectClass(objectClass.duplicate(), overwrite);
- }
-
- for (final NameForm nameForm : schema.getNameForms())
- {
- addNameForm(nameForm.duplicate(), overwrite);
- }
-
- for (final DITContentRule contentRule : schema.getDITContentRules())
- {
- addDITContentRule(contentRule.duplicate(), overwrite);
- }
-
- for (final DITStructureRule structureRule : schema.getDITStuctureRules())
- {
- addDITStructureRule(structureRule.duplicate(), overwrite);
- }
-
+ addSchema0(schema, overwrite);
return this;
}
@@ -2328,6 +2332,7 @@
final boolean overwrite) throws UnsupportedOperationException,
IllegalStateException, NullPointerException
{
+ // The call to addSchema will perform copyOnWrite.
final RecursiveFutureResult<SearchResultEntry, SchemaBuilder> future =
new RecursiveFutureResult<SearchResultEntry, SchemaBuilder>(handler)
{
@@ -2391,6 +2396,7 @@
InterruptedException, UnsupportedOperationException,
IllegalStateException, NullPointerException
{
+ // The call to addSchema will perform copyOnWrite.
final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
final Entry entry = connection.searchSingleEntry(request);
final DN subschemaDN = getSubschemaSubentryDN(name, entry);
@@ -2422,6 +2428,8 @@
{
Validator.ensureNotNull(substituteSyntax);
+ lazyInitBuilder();
+
addSyntax(
new Syntax(oid, description, Collections.singletonMap("X-SUBST",
Collections.singletonList(substituteSyntax)), null, null),
@@ -2453,6 +2461,9 @@
LocalizedIllegalArgumentException, NullPointerException
{
Validator.ensureNotNull(definition);
+
+ lazyInitBuilder();
+
try
{
final SubstringReader reader = new SubstringReader(definition);
@@ -2604,6 +2615,8 @@
final SyntaxImpl implementation, final boolean overwrite)
throws ConflictingSchemaElementException, NullPointerException
{
+ lazyInitBuilder();
+
addSyntax(new Syntax(oid, description,
unmodifiableCopyOfExtraProperties(extraProperties), null,
implementation), overwrite);
@@ -2636,6 +2649,8 @@
public SchemaBuilder allowMalformedNamesAndOptions(
final boolean allowMalformedNamesAndOptions)
{
+ lazyInitBuilder();
+
this.allowMalformedNamesAndOptions = allowMalformedNamesAndOptions;
return this;
}
@@ -2657,6 +2672,8 @@
public SchemaBuilder allowNonStandardTelephoneNumbers(
final boolean allowNonStandardTelephoneNumbers)
{
+ lazyInitBuilder();
+
this.allowNonStandardTelephoneNumbers = allowNonStandardTelephoneNumbers;
return this;
}
@@ -2680,6 +2697,8 @@
public SchemaBuilder allowZeroLengthDirectoryStrings(
final boolean allowZeroLengthDirectoryStrings)
{
+ lazyInitBuilder();
+
this.allowZeroLengthDirectoryStrings = allowZeroLengthDirectoryStrings;
return this;
}
@@ -2695,6 +2714,8 @@
*/
public boolean removeAttributeType(final String name)
{
+ lazyInitBuilder();
+
final AttributeType element = numericOID2AttributeTypes.get(name);
if (element != null)
{
@@ -2725,6 +2746,8 @@
*/
public boolean removeDITContentRule(final String name)
{
+ lazyInitBuilder();
+
final DITContentRule element = numericOID2ContentRules.get(name);
if (element != null)
{
@@ -2755,6 +2778,8 @@
*/
public boolean removeDITStructureRule(final int ruleID)
{
+ lazyInitBuilder();
+
final DITStructureRule element = id2StructureRules.get(ruleID);
if (element != null)
{
@@ -2775,6 +2800,8 @@
*/
public boolean removeMatchingRule(final String name)
{
+ lazyInitBuilder();
+
final MatchingRule element = numericOID2MatchingRules.get(name);
if (element != null)
{
@@ -2805,6 +2832,8 @@
*/
public boolean removeMatchingRuleUse(final String name)
{
+ lazyInitBuilder();
+
final MatchingRuleUse element = numericOID2MatchingRuleUses.get(name);
if (element != null)
{
@@ -2835,6 +2864,8 @@
*/
public boolean removeNameForm(final String name)
{
+ lazyInitBuilder();
+
final NameForm element = numericOID2NameForms.get(name);
if (element != null)
{
@@ -2864,6 +2895,8 @@
*/
public boolean removeObjectClass(final String name)
{
+ lazyInitBuilder();
+
final ObjectClass element = numericOID2ObjectClasses.get(name);
if (element != null)
{
@@ -2894,6 +2927,8 @@
*/
public boolean removeSyntax(final String numericOID)
{
+ lazyInitBuilder();
+
final Syntax element = numericOID2Syntaxes.get(numericOID);
if (element != null)
{
@@ -2910,8 +2945,7 @@
* contained in this schema builder as well as the same set of schema
* compatibility options.
* <p>
- * When this method returns this schema builder is empty and contains a
- * default set of compatibility options.
+ * This method does not alter the contents of this schema builder.
*
* @return A {@code Schema} containing all of the schema elements contained in
* this schema builder as well as the same set of schema compatibility
@@ -2919,18 +2953,45 @@
*/
public Schema toSchema()
{
- final Schema schema = new Schema(schemaName, allowMalformedNamesAndOptions,
- allowNonStandardTelephoneNumbers, allowZeroLengthDirectoryStrings,
- numericOID2Syntaxes, numericOID2MatchingRules,
- numericOID2MatchingRuleUses, numericOID2AttributeTypes,
- numericOID2ObjectClasses, numericOID2NameForms,
- numericOID2ContentRules, id2StructureRules, name2MatchingRules,
- name2MatchingRuleUses, name2AttributeTypes, name2ObjectClasses,
- name2NameForms, name2ContentRules, name2StructureRules,
- objectClass2NameForms, nameForm2StructureRules, warnings);
+ // If this schema builder was initialized from another schema and no
+ // modifications have been made since then we can simply return the original
+ // schema.
+ if (copyOnWriteSchema != null)
+ {
+ return copyOnWriteSchema;
+ }
+
+ // We still need to ensure that this builder has been initialized (otherwise
+ // some fields may still be null).
+ lazyInitBuilder();
+
+ final String localSchemaName;
+ if (schemaName != null)
+ {
+ localSchemaName = schemaName;
+ }
+ else
+ {
+ localSchemaName = String.format("Schema#%d",
+ NEXT_SCHEMA_ID.getAndIncrement());
+ }
+
+ final Schema schema = new Schema(localSchemaName,
+ allowMalformedNamesAndOptions, allowNonStandardTelephoneNumbers,
+ allowZeroLengthDirectoryStrings, numericOID2Syntaxes,
+ numericOID2MatchingRules, numericOID2MatchingRuleUses,
+ numericOID2AttributeTypes, numericOID2ObjectClasses,
+ numericOID2NameForms, numericOID2ContentRules, id2StructureRules,
+ name2MatchingRules, name2MatchingRuleUses, name2AttributeTypes,
+ name2ObjectClasses, name2NameForms, name2ContentRules,
+ name2StructureRules, objectClass2NameForms, nameForm2StructureRules,
+ warnings);
validate(schema);
- initBuilder(null);
+
+ // Re-init this builder so that it can continue to be used afterwards.
+ preLazyInitBuilder(schemaName, schema);
+
return schema;
}
@@ -3224,6 +3285,55 @@
+ private void addSchema0(final Schema schema, final boolean overwrite)
+ {
+ // All of the schema elements must be duplicated because validation will
+ // cause them to update all their internal references which, although
+ // unlikely, may be different in the new schema.
+
+ for (final Syntax syntax : schema.getSyntaxes())
+ {
+ addSyntax(syntax.duplicate(), overwrite);
+ }
+
+ for (final MatchingRule matchingRule : schema.getMatchingRules())
+ {
+ addMatchingRule(matchingRule.duplicate(), overwrite);
+ }
+
+ for (final MatchingRuleUse matchingRuleUse : schema.getMatchingRuleUses())
+ {
+ addMatchingRuleUse(matchingRuleUse.duplicate(), overwrite);
+ }
+
+ for (final AttributeType attributeType : schema.getAttributeTypes())
+ {
+ addAttributeType(attributeType.duplicate(), overwrite);
+ }
+
+ for (final ObjectClass objectClass : schema.getObjectClasses())
+ {
+ addObjectClass(objectClass.duplicate(), overwrite);
+ }
+
+ for (final NameForm nameForm : schema.getNameForms())
+ {
+ addNameForm(nameForm.duplicate(), overwrite);
+ }
+
+ for (final DITContentRule contentRule : schema.getDITContentRules())
+ {
+ addDITContentRule(contentRule.duplicate(), overwrite);
+ }
+
+ for (final DITStructureRule structureRule : schema.getDITStuctureRules())
+ {
+ addDITStructureRule(structureRule.duplicate(), overwrite);
+ }
+ }
+
+
+
private void addSyntax(final Syntax syntax, final boolean overwrite)
throws ConflictingSchemaElementException
{
@@ -3244,37 +3354,85 @@
- private void initBuilder(String schemaName)
+ private void lazyInitBuilder()
{
- if (schemaName == null)
+ // Lazy initialization.
+ if (numericOID2Syntaxes == null)
{
- schemaName = String.format("Schema#%d", nextSchemaID.getAndIncrement());
+ allowMalformedNamesAndOptions = true;
+ allowNonStandardTelephoneNumbers = true;
+ allowZeroLengthDirectoryStrings = false;
+
+ numericOID2Syntaxes = new LinkedHashMap<String, Syntax>();
+ numericOID2MatchingRules = new LinkedHashMap<String, MatchingRule>();
+ numericOID2MatchingRuleUses = new LinkedHashMap<String, MatchingRuleUse>();
+ numericOID2AttributeTypes = new LinkedHashMap<String, AttributeType>();
+ numericOID2ObjectClasses = new LinkedHashMap<String, ObjectClass>();
+ numericOID2NameForms = new LinkedHashMap<String, NameForm>();
+ numericOID2ContentRules = new LinkedHashMap<String, DITContentRule>();
+ id2StructureRules = new LinkedHashMap<Integer, DITStructureRule>();
+
+ name2MatchingRules = new LinkedHashMap<String, List<MatchingRule>>();
+ name2MatchingRuleUses = new LinkedHashMap<String, List<MatchingRuleUse>>();
+ name2AttributeTypes = new LinkedHashMap<String, List<AttributeType>>();
+ name2ObjectClasses = new LinkedHashMap<String, List<ObjectClass>>();
+ name2NameForms = new LinkedHashMap<String, List<NameForm>>();
+ name2ContentRules = new LinkedHashMap<String, List<DITContentRule>>();
+ name2StructureRules = new LinkedHashMap<String, List<DITStructureRule>>();
+
+ objectClass2NameForms = new HashMap<String, List<NameForm>>();
+ nameForm2StructureRules = new HashMap<String, List<DITStructureRule>>();
+ warnings = new LinkedList<LocalizableMessage>();
}
+
+ if (copyOnWriteSchema != null)
+ {
+ // Copy the schema.
+ addSchema0(copyOnWriteSchema, true);
+
+ allowMalformedNamesAndOptions = copyOnWriteSchema
+ .allowMalformedNamesAndOptions();
+ allowNonStandardTelephoneNumbers = copyOnWriteSchema
+ .allowNonStandardTelephoneNumbers();
+ allowZeroLengthDirectoryStrings = copyOnWriteSchema
+ .allowZeroLengthDirectoryStrings();
+
+ copyOnWriteSchema = null;
+ }
+ }
+
+
+
+ private void preLazyInitBuilder(final String schemaName,
+ final Schema copyOnWriteSchema)
+ {
this.schemaName = schemaName;
+ this.copyOnWriteSchema = copyOnWriteSchema;
- allowMalformedNamesAndOptions = true;
- allowNonStandardTelephoneNumbers = true;
- allowZeroLengthDirectoryStrings = false;
- numericOID2Syntaxes = new LinkedHashMap<String, Syntax>();
- numericOID2MatchingRules = new LinkedHashMap<String, MatchingRule>();
- numericOID2MatchingRuleUses = new LinkedHashMap<String, MatchingRuleUse>();
- numericOID2AttributeTypes = new LinkedHashMap<String, AttributeType>();
- numericOID2ObjectClasses = new LinkedHashMap<String, ObjectClass>();
- numericOID2NameForms = new LinkedHashMap<String, NameForm>();
- numericOID2ContentRules = new LinkedHashMap<String, DITContentRule>();
- id2StructureRules = new LinkedHashMap<Integer, DITStructureRule>();
+ this.allowMalformedNamesAndOptions = true;
+ this.allowNonStandardTelephoneNumbers = true;
+ this.allowZeroLengthDirectoryStrings = false;
- name2MatchingRules = new LinkedHashMap<String, List<MatchingRule>>();
- name2MatchingRuleUses = new LinkedHashMap<String, List<MatchingRuleUse>>();
- name2AttributeTypes = new LinkedHashMap<String, List<AttributeType>>();
- name2ObjectClasses = new LinkedHashMap<String, List<ObjectClass>>();
- name2NameForms = new LinkedHashMap<String, List<NameForm>>();
- name2ContentRules = new LinkedHashMap<String, List<DITContentRule>>();
- name2StructureRules = new LinkedHashMap<String, List<DITStructureRule>>();
+ this.numericOID2Syntaxes = null;
+ this.numericOID2MatchingRules = null;
+ this.numericOID2MatchingRuleUses = null;
+ this.numericOID2AttributeTypes = null;
+ this.numericOID2ObjectClasses = null;
+ this.numericOID2NameForms = null;
+ this.numericOID2ContentRules = null;
+ this.id2StructureRules = null;
- objectClass2NameForms = new HashMap<String, List<NameForm>>();
- nameForm2StructureRules = new HashMap<String, List<DITStructureRule>>();
- warnings = new LinkedList<LocalizableMessage>();
+ this.name2MatchingRules = null;
+ this.name2MatchingRuleUses = null;
+ this.name2AttributeTypes = null;
+ this.name2ObjectClasses = null;
+ this.name2NameForms = null;
+ this.name2ContentRules = null;
+ this.name2StructureRules = null;
+
+ this.objectClass2NameForms = null;
+ this.nameForm2StructureRules = null;
+ this.warnings = null;
}
@@ -3484,26 +3642,26 @@
// Attribute types need special processing because they have hierarchical
// dependencies.
- List<AttributeType> invalidAttributeTypes = new LinkedList<AttributeType>();
+ final List<AttributeType> invalidAttributeTypes = new LinkedList<AttributeType>();
for (final AttributeType attributeType : numericOID2AttributeTypes.values())
{
attributeType.validate(schema, invalidAttributeTypes, warnings);
}
- for (AttributeType attributeType : invalidAttributeTypes)
+ for (final AttributeType attributeType : invalidAttributeTypes)
{
removeAttributeType(attributeType);
}
// Object classes need special processing because they have hierarchical
// dependencies.
- List<ObjectClass> invalidObjectClasses = new LinkedList<ObjectClass>();
+ final List<ObjectClass> invalidObjectClasses = new LinkedList<ObjectClass>();
for (final ObjectClass objectClass : numericOID2ObjectClasses.values())
{
objectClass.validate(schema, invalidObjectClasses, warnings);
}
- for (ObjectClass objectClass : invalidObjectClasses)
+ for (final ObjectClass objectClass : invalidObjectClasses)
{
removeObjectClass(objectClass);
}
@@ -3572,15 +3730,16 @@
}
}
- // DIT structure rules need special processing because they have hierarchical
+ // DIT structure rules need special processing because they have
+ // hierarchical
// dependencies.
- List<DITStructureRule> invalidStructureRules = new LinkedList<DITStructureRule>();
+ final List<DITStructureRule> invalidStructureRules = new LinkedList<DITStructureRule>();
for (final DITStructureRule rule : id2StructureRules.values())
{
rule.validate(schema, invalidStructureRules, warnings);
}
- for (DITStructureRule rule : invalidStructureRules)
+ for (final DITStructureRule rule : invalidStructureRules)
{
removeDITStructureRule(rule);
}
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
index e2374cb..3b6125c 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTest.java
@@ -182,6 +182,98 @@
/**
+ * Tests that it is possible to create a schema which is an exact copy of
+ * another and take advantage of copy on write.
+ */
+ @Test
+ public void testCopyOnWriteNoChanges()
+ {
+ final Schema baseSchema = Schema.getCoreSchema();
+ final Schema schema = new SchemaBuilder(baseSchema).toSchema();
+
+ assertThat(schema).isSameAs(baseSchema);
+ }
+
+
+
+ /**
+ * Tests that it is possible to create a schema which is based on another.
+ */
+ @Test
+ public void testCopyOnWriteWithChanges()
+ {
+ final Schema baseSchema = Schema.getCoreSchema();
+ final Schema schema = new SchemaBuilder(baseSchema).addAttributeType(
+ "( testtype-oid NAME 'testtype' SUP name )", false).toSchema();
+ assertThat(schema).isNotSameAs(baseSchema);
+ assertThat(schema.getObjectClasses().containsAll(
+ baseSchema.getObjectClasses()));
+ assertThat(schema.getObjectClasses().size()).isEqualTo(
+ baseSchema.getObjectClasses().size());
+ assertThat(schema.getAttributeTypes().containsAll(
+ baseSchema.getAttributeTypes()));
+ assertThat(schema.getAttributeType("testtype")).isNotNull();
+ assertThat(schema.getSchemaName()).isEqualTo(baseSchema.getSchemaName());
+ assertThat(schema.allowMalformedNamesAndOptions()).isEqualTo(
+ baseSchema.allowMalformedNamesAndOptions());
+ }
+
+
+
+ /**
+ * Tests that it is possible to create an empty schema.
+ */
+ @Test
+ public void testCreateEmptySchema()
+ {
+ final Schema schema = new SchemaBuilder().toSchema();
+ assertThat(schema.getAttributeTypes()).isEmpty();
+ assertThat(schema.getObjectClasses()).isEmpty();
+ assertThat(schema.getSyntaxes()).isEmpty();
+ assertThat(schema.getWarnings()).isEmpty();
+ // Could go on...
+ }
+
+
+
+ /**
+ * Tests that multiple consecutive invocations of toSchema return the exact
+ * same schema.
+ */
+ @Test
+ public void testMultipleToSchema1()
+ {
+ final Schema baseSchema = Schema.getCoreSchema();
+ final SchemaBuilder builder = new SchemaBuilder(baseSchema);
+ final Schema schema1 = builder.toSchema();
+ final Schema schema2 = builder.toSchema();
+ assertThat(schema1).isSameAs(baseSchema);
+ assertThat(schema1).isSameAs(schema2);
+ }
+
+
+
+ /**
+ * Tests that multiple consecutive invocations of toSchema return the exact
+ * same schema.
+ */
+ @Test
+ public void testMultipleToSchema2()
+ {
+ final SchemaBuilder builder = new SchemaBuilder()
+ .addAttributeType(
+ "( testtype-oid NAME 'testtype' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+ false);
+ final Schema schema1 = builder.toSchema();
+ final Schema schema2 = builder.toSchema();
+ assertThat(schema1).isSameAs(schema2);
+ assertThat(schema1.getAttributeType("testtype")).isNotNull();
+ assertThat(schema2.getAttributeType("testtype")).isNotNull();
+ }
+
+
+
+ /**
* Tests that schema validation resolves dependencies between parent/child
* object classes regardless of the order in which they were added.
*/
@@ -302,4 +394,29 @@
// Expected.
}
}
+
+
+
+ /**
+ * Tests that a schema builder can be re-used after toSchema has been called.
+ */
+ @Test
+ public void testReuseSchemaBuilder()
+ {
+ final SchemaBuilder builder = new SchemaBuilder();
+ final Schema schema1 = builder
+ .addAttributeType(
+ "( testtype1-oid NAME 'testtype1' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+ false).toSchema();
+
+ final Schema schema2 = builder
+ .addAttributeType(
+ "( testtype2-oid NAME 'testtype2' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
+ false).toSchema();
+ assertThat(schema1).isNotSameAs(schema2);
+ assertThat(schema1.getAttributeType("testtype1")).isNotNull();
+ assertThat(schema1.hasAttributeType("testtype2")).isFalse();
+ assertThat(schema2.getAttributeType("testtype1")).isNotNull();
+ assertThat(schema2.getAttributeType("testtype2")).isNotNull();
+ }
}
--
Gitblit v1.10.0