| opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRule.java | ●●●●● patch | view | raw | blame | history | |
| opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | ●●●●● patch | view | raw | blame | history | |
| opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/DITStructureRuleTestCase.java | ●●●●● patch | view | raw | blame | history |
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRule.java
@@ -22,17 +22,23 @@ * * * Copyright 2009 Sun Microsystems, Inc. * Portions copyright 2015 ForgeRock AS */ package org.forgerock.opendj.ldap.schema; import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_DSR_UNKNOWN_NAME_FORM; import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_DSR_UNKNOWN_RULE_ID; import static com.forgerock.opendj.ldap.CoreMessages.ERR_DSR_VALIDATION_FAIL; import static java.util.Arrays.*; import static org.forgerock.opendj.ldap.schema.SchemaUtils.*; import static com.forgerock.opendj.ldap.CoreMessages.*; 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; @@ -45,6 +51,208 @@ * of children that entries may have. */ public final class DITStructureRule extends SchemaElement { /** A fluent API for incrementally constructing DIT structure rules. */ public static final class Builder extends SchemaElementBuilder<Builder> { private int ruleID; private final List<String> names = new LinkedList<String>(); private boolean isObsolete; private String nameFormOID; private final Set<Integer> superiorRuleIDs = new LinkedHashSet<Integer>(); Builder(final DITStructureRule structureRule, final SchemaBuilder builder) { super(builder); this.ruleID = structureRule.ruleID; this.names.addAll(structureRule.names); this.isObsolete = structureRule.isObsolete; this.nameFormOID = structureRule.nameFormOID; this.superiorRuleIDs.addAll(structureRule.superiorRuleIDs); } Builder(final Integer ruleID, final SchemaBuilder schemaBuilder) { super(schemaBuilder); this.ruleID = ruleID; } /** * Adds this DIT structure rule to the schema overwriting any existing * DIT structure rule with the same numeric ID. * * @return The parent schema builder. */ public SchemaBuilder addToSchemaOverwrite() { return getSchemaBuilder().addDITStructureRule(new DITStructureRule(this), true); } /** * Adds this DIT structure rule to the schema, throwing an * {@code ConflictingSchemaElementException} if there is an existing DIT * structure rule with the same numeric ID. * * @return The parent schema builder. * @throws ConflictingSchemaElementException * If there is an existing structure rule with the same * numeric ID. */ public SchemaBuilder addToSchema() { return getSchemaBuilder().addDITStructureRule(new DITStructureRule(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; } /** * Sets the name form associated with the DIT structure rule. * * @param nameFormOID * The name form numeric OID. * @return This builder. */ public Builder nameForm(final String nameFormOID) { this.nameFormOID = nameFormOID; 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; } @Override public Builder removeAllExtraProperties() { return removeAllExtraProperties0(); } /** * Removes all user defined names. * * @return This builder. */ public Builder removeAllNames() { this.names.clear(); return this; } /** * Removes all superior rules. * * @return This builder. */ public Builder removeAllSuperiorRules() { this.superiorRuleIDs.clear(); return this; } @Override public Builder removeExtraProperty(final String extensionName, final String... extensionValues) { return removeExtraProperty0(extensionName, extensionValues); } /** * Removes the provided user defined name. * * @param name * The user defined name to be removed. * @return This builder. */ public Builder removeName(final String name) { this.names.remove(name); return this; } /** * Removes the provided superior rule. * * @param superiorRuleID * The superior rule ID to be removed. * @return This builder. */ public Builder removeSuperiorRule(final int superiorRuleID) { this.superiorRuleIDs.remove(superiorRuleID); return this; } /** * Sets the the numeric ID which uniquely identifies this structure rule. * * @param ruleID * The numeric ID. * @return This builder. */ public Builder ruleID(final int ruleID) { this.ruleID = ruleID; return this; } /** * Adds the provided superior rule identifiers. * * @param superiorRuleIDs * Structure rule identifiers. * @return This builder. */ public Builder superiorRules(final int... superiorRuleIDs) { for (int ruleID : superiorRuleIDs) { this.superiorRuleIDs.add(ruleID); } return this; } Builder superiorRules(final Collection<Integer> superiorRuleIDs) { this.superiorRuleIDs.addAll(superiorRuleIDs); return this; } } /** The rule ID for this DIT structure rule. */ private final Integer ruleID; @@ -69,17 +277,15 @@ /** The indicates whether or not validation failed. */ private boolean isValid; DITStructureRule(final Integer ruleID, final List<String> names, final String description, final boolean obsolete, final String nameFormOID, final Set<Integer> superiorRuleIDs, final Map<String, List<String>> extraProperties, final String definition) { super(description, extraProperties, definition); DITStructureRule(final Builder builder) { super(builder); Reject.ifNull(builder.nameFormOID); Reject.ifNull(ruleID, nameFormOID, superiorRuleIDs); this.ruleID = ruleID; this.names = names; this.isObsolete = obsolete; this.nameFormOID = nameFormOID; this.superiorRuleIDs = superiorRuleIDs; this.ruleID = builder.ruleID; this.names = unmodifiableCopyOfList(builder.names); this.isObsolete = builder.isObsolete; this.nameFormOID = builder.nameFormOID; this.superiorRuleIDs = unmodifiableCopyOfSet(builder.superiorRuleIDs); } /** @@ -195,11 +401,6 @@ return isObsolete; } DITStructureRule duplicate() { return new DITStructureRule(ruleID, names, getDescription(), isObsolete, nameFormOID, superiorRuleIDs, getExtraProperties(), toString()); } @Override void toStringContent(final StringBuilder buffer) { buffer.append(ruleID); opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -507,47 +507,6 @@ /** * Adds the provided DIT structure rule definition to this schema builder. * * @param ruleID * The rule identifier of the DIT structure rule. * @param names * The user-friendly names of the DIT structure rule definition. * @param description * The description of the DIT structure rule definition. * @param obsolete * {@code true} if the DIT structure rule definition is obsolete, * otherwise {@code false}. * @param nameForm * The name form associated with the DIT structure rule. * @param superiorRules * A list of superior rules (by rule id). * @param extraProperties * A map containing additional properties associated with the DIT * structure rule definition. * @param overwrite * {@code true} if any existing DIT structure rule 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 addDITStructureRule(final Integer ruleID, final List<String> names, final String description, final boolean obsolete, final String nameForm, final Set<Integer> superiorRules, final Map<String, List<String>> extraProperties, final boolean overwrite) { lazyInitBuilder(); final DITStructureRule rule = new DITStructureRule(ruleID, unmodifiableCopyOfList(names), description, obsolete, nameForm, unmodifiableCopyOfSet(superiorRules), unmodifiableCopyOfExtraProperties(extraProperties), null); addDITStructureRule(rule, overwrite); return this; } /** * Adds the provided DIT structure rule definition to this schema builder. * * @param definition * The DIT structure rule definition. * @param overwrite @@ -595,14 +554,8 @@ reader.skipWhitespaces(); // The next set of characters must be the OID. final Integer ruleID = readRuleID(reader); List<String> names = Collections.emptyList(); String description = "".intern(); boolean isObsolete = false; final DITStructureRule.Builder ruleBuilder = new DITStructureRule.Builder(readRuleID(reader), this); String nameForm = null; Set<Integer> superiorRules = Collections.emptySet(); Map<String, List<String>> extraProperties = Collections.emptyMap(); // At this point, we should have a pretty specific syntax that // describes what may come next, but some of the components are @@ -619,31 +572,27 @@ // No more tokens. break; } else if ("name".equalsIgnoreCase(tokenName)) { names = readNameDescriptors(reader, allowsMalformedNamesAndOptions()); ruleBuilder.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); ruleBuilder.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. ruleBuilder.obsolete(true); } else if ("form".equalsIgnoreCase(tokenName)) { nameForm = readOID(reader, allowsMalformedNamesAndOptions()); } else if ("sup".equalsIgnoreCase(tokenName)) { superiorRules = readRuleIDs(reader); ruleBuilder.superiorRules(readRuleIDs(reader)); } 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)); ruleBuilder.extraProperties(tokenName, readExtensions(reader)); } else { throw new LocalizedIllegalArgumentException( ERR_ATTR_SYNTAX_DSR_ILLEGAL_TOKEN1.get(definition, tokenName)); @@ -653,20 +602,13 @@ if (nameForm == null) { throw new LocalizedIllegalArgumentException(ERR_ATTR_SYNTAX_DSR_NO_NAME_FORM.get(definition)); } ruleBuilder.nameForm(nameForm); if (!extraProperties.isEmpty()) { extraProperties = Collections.unmodifiableMap(extraProperties); } final DITStructureRule rule = new DITStructureRule(ruleID, names, description, isObsolete, nameForm, superiorRules, extraProperties, definition); addDITStructureRule(rule, overwrite); return overwrite ? ruleBuilder.addToSchemaOverwrite() : ruleBuilder.addToSchema(); } catch (final DecodeException e) { final LocalizableMessage msg = ERR_ATTR_SYNTAX_DSR_INVALID1.get(definition, e.getMessageObject()); throw new LocalizedIllegalArgumentException(msg, e.getCause()); } return this; } /** @@ -970,6 +912,25 @@ } /** * Returns a builder which can be used for incrementally constructing a new * DIT structure rule before adding it to the schema. Example usage: * * <pre> * SchemaBuilder builder = ...; * final int myRuleID = ...; * builder.buildDITStructureRule(myRuleID).name("DIT structure rule name").addToSchema(); * </pre> * * @param ruleID * The ID of the DIT structure rule. * @return A builder to continue building the DITStructureRule. */ public DITStructureRule.Builder buildDITStructureRule(final int ruleID) { lazyInitBuilder(); return new DITStructureRule.Builder(ruleID, this); } /** * Returns a builder which can be used for incrementally constructing a new matching rule before adding it to the * schema. Example usage: * @@ -1257,6 +1218,21 @@ } /** * Returns an DIT structure rule builder whose fields are initialized to the * values of the provided rule. This method should be used when duplicating * structure rules from external schemas or when modifying existing * structure rules. * * @param structureRule * The DIT structure rule source. * @return A builder to continue building the DITStructureRule. */ public DITStructureRule.Builder buildDITStructureRule(final DITStructureRule structureRule) { lazyInitBuilder(); return new DITStructureRule.Builder(structureRule, this); } /** * Returns a matching rule builder whose fields are initialized to the * values of the provided matching rule. This method should be used when * duplicating matching rules from external schemas or when modifying @@ -2251,7 +2227,7 @@ return this; } private void addDITStructureRule(final DITStructureRule rule, final boolean overwrite) { SchemaBuilder addDITStructureRule(final DITStructureRule rule, final boolean overwrite) { DITStructureRule conflictingRule; if (id2StructureRules.containsKey(rule.getRuleID())) { conflictingRule = id2StructureRules.get(rule.getRuleID()); @@ -2278,6 +2254,8 @@ rules.add(rule); } } return this; } private void addMatchingRuleUse(final MatchingRuleUse use, final boolean overwrite) { @@ -2444,7 +2422,7 @@ } for (final DITStructureRule structureRule : schema.getDITStuctureRules()) { addDITStructureRule(structureRule.duplicate(), overwrite); addDITStructureRule(structureRule, overwrite); } } opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/DITStructureRuleTestCase.java
New file @@ -0,0 +1,181 @@ /* * 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 static java.util.Collections.*; import static org.fest.assertions.Assertions.*; import static org.fest.assertions.MapAssert.*; import org.testng.annotations.Test; public class DITStructureRuleTestCase extends AbstractSchemaTestCase { private static final String NAME_FORM_TEST_OID = "1.2.3.4"; /** Adds a valid DIT structure rule on the "" name form. */ @Test public void testValidDITStructureRule() { final SchemaBuilder builder = getTestSchema() .buildDITStructureRule(42) .names("DIT structure rule test", "DIT structure rule for person") .nameForm(NAME_FORM_TEST_OID) .description("My DIT structure rule") .extraProperties("property name", "property value") .addToSchema(); final Schema schema = builder.buildDITStructureRule(43) .names("DIT structure rule child test") .nameForm(NAME_FORM_TEST_OID) .superiorRules(42) .description("My DIT structure rule child") .extraProperties("property name", "property value") .addToSchema() .toSchema(); assertThat(schema.getWarnings()).isEmpty(); final DITStructureRule sr = schema.getDITStructureRule(42); assertThat(sr).isNotNull(); assertThat(sr.getRuleID()).isEqualTo(42); assertThat(sr.getNames()).containsOnly("DIT structure rule test", "DIT structure rule for person"); assertThat(sr.getDescription()).isEqualTo("My DIT structure rule"); assertThat(sr.getNameForm().getOID()).isEqualTo(NAME_FORM_TEST_OID); assertThat(sr.getExtraProperties()).includes(entry("property name", singletonList("property value"))); assertThat(sr.getSuperiorRules()).isEmpty(); assertThat(sr.isObsolete()).isFalse(); final DITStructureRule srChild = schema.getDITStructureRule(43); assertThat(srChild).isNotNull(); assertThat(srChild.getRuleID()).isEqualTo(43); assertThat(srChild.getNames()).containsOnly("DIT structure rule child test"); assertThat(srChild.getDescription()).isEqualTo("My DIT structure rule child"); assertThat(srChild.getNameForm().getOID()).isEqualTo(NAME_FORM_TEST_OID); assertThat(srChild.getExtraProperties()).includes(entry("property name", singletonList("property value"))); assertThat(srChild.getSuperiorRules()).containsOnly(sr); assertThat(srChild.isObsolete()).isFalse(); } @Test public void testCopyConstructor() throws Exception { final Schema schema = getTestSchema() .buildDITStructureRule(42) .names("DIT structure rule test") .nameForm(NAME_FORM_TEST_OID) .description("My DIT structure rule") .addToSchema() .toSchema(); final Schema schemaCopy = getTestSchema() .buildDITStructureRule(schema.getDITStructureRule(42)) .ruleID(43) .names("DIT structure rule test - copy") .addToSchema() .toSchema(); assertThat(schema.getWarnings()).isEmpty(); assertThat(schemaCopy.getWarnings()).isEmpty(); final DITStructureRule srCopy = schemaCopy.getDITStructureRule(43); assertThat(srCopy).isNotNull(); assertThat(srCopy.getRuleID()).isEqualTo(43); assertThat(srCopy.getNames()).containsOnly("DIT structure rule test", "DIT structure rule test - copy"); assertThat(srCopy.getNameForm().getOID()).isEqualTo(NAME_FORM_TEST_OID); assertThat(srCopy.getDescription()).isEmpty(); assertThat(srCopy.isObsolete()).isFalse(); } @Test(expectedExceptions = ConflictingSchemaElementException.class) public void testBuilderDoesNotAllowOverwrite() throws Exception { final SchemaBuilder builder = getTestSchema() .buildDITStructureRule(42) .nameForm(NAME_FORM_TEST_OID) .addToSchema(); builder.buildDITStructureRule(42) .nameForm(NAME_FORM_TEST_OID) .addToSchema() .toSchema(); } @Test(expectedExceptions = NullPointerException.class) public void testBuilderDoesNotAllowNullNameForm() throws Exception { getTestSchema().buildDITStructureRule(42) .nameForm(null) .addToSchema(); } @Test public void testBuilderRemoveAll() throws Exception { DITStructureRule.Builder srBuilder = getTestSchema() .buildDITStructureRule(42) .names("DIT structure rule test", "DIT structure rule for person") .nameForm(NAME_FORM_TEST_OID) .description("My DIT structure rule") .superiorRules(1, 2, 3, 4) .extraProperties("property name", "property value"); Schema schema = srBuilder.removeAllNames() .removeAllSuperiorRules() .removeAllExtraProperties() .addToSchema() .toSchema(); assertThat(schema.getWarnings()).isEmpty(); DITStructureRule sr = schema.getDITStructureRule(42); assertThat(sr.getNames()).isEmpty(); assertThat(sr.getExtraProperties()).isEmpty(); assertThat(sr.getSuperiorRules()).isEmpty(); } @Test public void testBuilderRemove() throws Exception { DITStructureRule.Builder srBuilder = getTestSchema() .buildDITStructureRule(42) .names("DIT structure rule test", "should be removed") .nameForm(NAME_FORM_TEST_OID) .description("My DIT structure rule") .superiorRules(1) .extraProperties("property name", "property value"); Schema schema = srBuilder.removeName("should be removed") .removeSuperiorRule(1) .addToSchema() .toSchema(); assertThat(schema.getWarnings()).isEmpty(); DITStructureRule sr = schema.getDITStructureRule(42); assertThat(sr.getNames()).containsOnly("DIT structure rule test"); assertThat(sr.getSuperiorRules()).isEmpty(); } private SchemaBuilder getTestSchema() { return new SchemaBuilder(Schema.getCoreSchema()) .buildNameForm(NAME_FORM_TEST_OID) .structuralObjectClassOID("person") .requiredAttributes("sn", "cn") .addToSchema(); } }