mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Gaetan Boismal
28.41.2015 5759eb1a5d28d5b106e04657906ba6a1b20618fc
OPENDJ-1731 CR-5871 Builder for Matching rule use

Adds fluent builder for matching rule use schema element.
1 files added
2 files modified
486 ■■■■ changed files
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUse.java 228 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java 101 ●●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseBuilderTestCase.java 157 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUse.java
@@ -22,16 +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_MRUSE_UNKNOWN_ATTR1;
import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_MRUSE_UNKNOWN_MATCHING_RULE1;
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 +52,202 @@
 * attribute types that may be used for a given matching rule.
 */
public final class MatchingRuleUse extends SchemaElement {
    /** A fluent API for incrementally constructing matching rule uses. */
    public static final class Builder extends SchemaElementBuilder<Builder> {
        private String oid;
        private final List<String> names = new LinkedList<String>();
        private boolean isObsolete;
        private final Set<String> attributeOIDs = new LinkedHashSet<String>();
        Builder(MatchingRuleUse mru, SchemaBuilder builder) {
            super(builder, mru);
            this.oid = mru.oid;
            this.names.addAll(mru.names);
            this.isObsolete = mru.isObsolete;
            this.attributeOIDs.addAll(mru.attributeOIDs);
        }
        Builder(final String oid, final SchemaBuilder builder) {
            super(builder);
            this.oid = oid;
        }
        /**
         * Adds this matching rule use definition to the schema, throwing a
         * {@code  ConflictingSchemaElementException} if there is an existing
         * matching rule definition with the same numeric OID.
         *
         * @return The parent schema builder.
         * @throws ConflictingSchemaElementException
         *             If there is an existing matching rule use definition with
         *             the same numeric OID.
         */
        public SchemaBuilder addToSchema() {
            return getSchemaBuilder().addMatchingRuleUse(new MatchingRuleUse(this), false);
        }
        /**
         * Adds this matching rule use definition to the schema overwriting any
         * existing matching rule use definition with the same numeric OID.
         *
         * @return The parent schema builder.
         */
        public SchemaBuilder addToSchemaOverwrite() {
            return getSchemaBuilder().addMatchingRuleUse(new MatchingRuleUse(this), true);
        }
        /**
         * Adds the provided list of attribute types to the list of attribute
         * type the matching rule applies to.
         *
         * @param attributeOIDs
         *            The list of attribute type numeric OIDs.
         * @return This builder.
         */
        public Builder attributes(Collection<String> attributeOIDs) {
            this.attributeOIDs.addAll(attributeOIDs);
            return this;
        }
        /**
         * Adds the provided list of attribute types to the list of attribute
         * type the matching rule applies to.
         *
         * @param attributeOIDs
         *            The list of attribute type numeric OIDs.
         * @return This builder.
         */
        public Builder attributes(String... attributeOIDs) {
            this.attributeOIDs.addAll(asList(attributeOIDs));
            return this;
        }
        @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 matching rule use
         * definition.
         *
         * @param oid
         *            The numeric OID.
         * @return This builder.
         */
        public Builder oid(final String oid) {
            this.oid = oid;
            return this;
        }
        /**
         * Removes all attribute types the matching rule applies to.
         *
         * @return This builder.
         */
        public Builder removeAllAttributes() {
            this.attributeOIDs.clear();
            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 the provided attribute type.
         *
         * @param attributeOID
         *            The attribute type OID to be removed.
         * @return This builder.
         */
        public Builder removeAttribute(String attributeOID) {
            this.attributeOIDs.remove(attributeOID);
            return this;
        }
        @Override
        public Builder removeExtraProperty(String extensionName, 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(String name) {
            this.names.remove(name);
            return this;
        }
    }
    /**
     * The OID of the matching rule associated with this matching rule
     * use definition.
@@ -66,16 +269,14 @@
    private MatchingRule matchingRule;
    private Set<AttributeType> attributes = Collections.emptySet();
    MatchingRuleUse(final String oid, final List<String> names, final String description,
            final boolean obsolete, final Set<String> attributeOIDs,
            final Map<String, List<String>> extraProperties, final String definition) {
        super(description, extraProperties, definition);
    private MatchingRuleUse(final Builder builder) {
        super(builder);
        Reject.ifNull(builder.oid);
        Reject.ifNull(oid, names, attributeOIDs);
        this.oid = oid;
        this.names = names;
        this.isObsolete = obsolete;
        this.attributeOIDs = attributeOIDs;
        this.oid = builder.oid;
        this.names = unmodifiableCopyOfList(builder.names);
        this.isObsolete = builder.isObsolete;
        this.attributeOIDs = unmodifiableCopyOfSet(builder.attributeOIDs);
    }
    /**
@@ -218,11 +419,6 @@
        return isObsolete;
    }
    MatchingRuleUse duplicate() {
        return new MatchingRuleUse(oid, names, getDescription(), isObsolete, attributeOIDs,
                getExtraProperties(), toString());
    }
    @Override
    void toStringContent(final StringBuilder buffer) {
        buffer.append(oid);
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -820,13 +820,9 @@
            reader.skipWhitespaces();
            // The next set of characters must be the OID.
            final String oid = readOID(reader, allowsMalformedNamesAndOptions());
            List<String> names = Collections.emptyList();
            String description = "".intern();
            boolean isObsolete = false;
            final MatchingRuleUse.Builder useBuilder =
                    buildMatchingRuleUse(readOID(reader, allowsMalformedNamesAndOptions()));
            Set<String> attributes = null;
            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
@@ -843,17 +839,16 @@
                    // No more tokens.
                    break;
                } else if ("name".equalsIgnoreCase(tokenName)) {
                    names = readNameDescriptors(reader, allowsMalformedNamesAndOptions());
                    useBuilder.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);
                    useBuilder.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.
                    useBuilder.obsolete(true);
                } else if ("applies".equalsIgnoreCase(tokenName)) {
                    attributes = readOIDs(reader, allowsMalformedNamesAndOptions());
                } else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -862,10 +857,7 @@
                    // 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));
                    useBuilder.extraProperties(tokenName, readExtensions(reader));
                } else {
                    throw new LocalizedIllegalArgumentException(
                        ERR_ATTR_SYNTAX_MRUSE_ILLEGAL_TOKEN1.get(definition, tokenName));
@@ -876,21 +868,13 @@
            if (attributes == null || attributes.size() == 0) {
                throw new LocalizedIllegalArgumentException(ERR_ATTR_SYNTAX_MRUSE_NO_ATTR.get(definition));
            }
            useBuilder.attributes(attributes);
            if (!extraProperties.isEmpty()) {
                extraProperties = Collections.unmodifiableMap(extraProperties);
            }
            final MatchingRuleUse use =
                    new MatchingRuleUse(oid, names, description, isObsolete, attributes,
                            extraProperties, definition);
            addMatchingRuleUse(use, overwrite);
            return overwrite ? useBuilder.addToSchemaOverwrite() : useBuilder.addToSchema();
        } catch (final DecodeException e) {
            final LocalizableMessage msg =
                    ERR_ATTR_SYNTAX_MRUSE_INVALID1.get(definition, e.getMessageObject());
            final LocalizableMessage msg = ERR_ATTR_SYNTAX_MRUSE_INVALID1.get(definition, e.getMessageObject());
            throw new LocalizedIllegalArgumentException(msg, e.getCause());
        }
        return this;
    }
    /**
@@ -949,41 +933,23 @@
    }
    /**
     * Adds the provided matching rule use definition to this schema builder.
     * Returns a builder which can be used for incrementally constructing a new
     * matching rule use before adding it to the schema. Example usage:
     *
     * <pre>
     * SchemaBuilder builder = ...;
     * builder.buildMatchingRuleUse("matchingrule-oid")
     *        .name("matching rule use name")
     *        .addToSchema();
     * </pre>
     *
     * @param oid
     *            The OID of the matching rule use definition.
     * @param names
     *            The user-friendly names of the matching rule use definition.
     * @param description
     *            The description of the matching rule use definition.
     * @param obsolete
     *            {@code true} if the matching rule use definition is obsolete,
     *            otherwise {@code false}.
     * @param attributeOIDs
     *            The list of attribute types the matching rule applies to.
     * @param extraProperties
     *            A map containing additional properties associated with the
     *            matching rule use definition.
     * @param overwrite
     *            {@code true} if any existing matching rule use 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.
     *            The OID of the matching rule definition.
     * @return A builder to continue building the MatchingRuleUse.
     */
    SchemaBuilder addMatchingRuleUse(final String oid, final List<String> names,
            final String description, final boolean obsolete, final Set<String> attributeOIDs,
            final Map<String, List<String>> extraProperties, final boolean overwrite) {
    public MatchingRuleUse.Builder buildMatchingRuleUse(final String oid) {
        lazyInitBuilder();
        final MatchingRuleUse use =
                new MatchingRuleUse(oid, unmodifiableCopyOfList(names), description, obsolete,
                        unmodifiableCopyOfSet(attributeOIDs),
                        unmodifiableCopyOfExtraProperties(extraProperties), null);
        addMatchingRuleUse(use, overwrite);
        return this;
        return new MatchingRuleUse.Builder(oid, this);
    }
    /**
@@ -1254,6 +1220,21 @@
    }
    /**
     * Returns a matching rule use builder whose fields are initialized to the
     * values of the provided matching rule use object. This method should be used when
     * duplicating matching rule uses from external schemas or when modifying
     * existing matching rule uses.
     *
     * @param matchingRuleUse
     *            The matching rule use source.
     * @return A builder to continue building the MatchingRuleUse.
     */
    public MatchingRuleUse.Builder buildMatchingRuleUse(final MatchingRuleUse matchingRuleUse) {
        lazyInitBuilder();
        return new MatchingRuleUse.Builder(matchingRuleUse, this);
    }
    /**
     * Returns a name form builder whose fields are initialized to the
     * values of the provided name form. This method should be used when
     * duplicating name forms from external schemas or when modifying
@@ -2258,7 +2239,7 @@
        return this;
    }
    private void addMatchingRuleUse(final MatchingRuleUse use, final boolean overwrite) {
    SchemaBuilder addMatchingRuleUse(final MatchingRuleUse use, final boolean overwrite) {
        MatchingRuleUse conflictingUse;
        if (numericOID2MatchingRuleUses.containsKey(use.getMatchingRuleOID())) {
            conflictingUse = numericOID2MatchingRuleUses.get(use.getMatchingRuleOID());
@@ -2285,6 +2266,8 @@
                uses.add(use);
            }
        }
        return this;
    }
    SchemaBuilder addMatchingRule(final MatchingRule rule, final boolean overwrite) {
@@ -2402,7 +2385,7 @@
        }
        for (final MatchingRuleUse matchingRuleUse : schema.getMatchingRuleUses()) {
            addMatchingRuleUse(matchingRuleUse.duplicate(), overwrite);
            addMatchingRuleUse(matchingRuleUse, overwrite);
        }
        for (final AttributeType attributeType : schema.getAttributeTypes()) {
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseBuilderTestCase.java
New file
@@ -0,0 +1,157 @@
/*
 * 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 static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
import org.testng.annotations.Test;
public class MatchingRuleUseBuilderTestCase extends AbstractSchemaTestCase {
    @Test
    public void testValidMatchingRuleUse() {
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse(EMR_CASE_EXACT_OID)
                .names("Matching rule use test")
                .description("Matching rule use description")
                .attributes("2.5.4.40", "2.5.4.52", "2.5.4.53")
                .extraProperties("property name", "property value")
                .addToSchema()
                .toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRuleUse mru = schema.getMatchingRuleUse(EMR_CASE_EXACT_OID);
        assertThat(mru).isNotNull();
        assertThat(mru.getMatchingRuleOID()).isEqualTo(EMR_CASE_EXACT_OID);
        assertThat(mru.getNames()).containsOnly("Matching rule use test");
        assertThat(mru.getDescription()).isEqualTo("Matching rule use description");
        assertThat(mru.getAttributes()).containsOnly(schema.getAttributeType("2.5.4.40"),
                                                     schema.getAttributeType("2.5.4.52"),
                                                     schema.getAttributeType("2.5.4.53"));
        assertThat(mru.getExtraProperties()).includes(entry("property name", singletonList("property value")));
        assertThat(mru.isObsolete()).isFalse();
    }
    @Test
    public void testCopyConstructor() {
        final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse(EMR_BIT_STRING_OID)
                .description("Matching rule use description")
                .names("Matching rule use test")
                .attributes("2.5.4.40")
                .extraProperties("property name", "property value")
                .addToSchema();
        final Schema schema = builder.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final Schema schemaCopy = builder.buildMatchingRuleUse(schema.getMatchingRuleUse(EMR_BIT_STRING_OID))
                .oid(EMR_OCTET_STRING_OID)
                .names("Matching rule use test copy")
                .attributes("2.5.4.53")
                .addToSchema()
                .toSchema();
        assertThat(schemaCopy.getWarnings()).isEmpty();
        final MatchingRuleUse mru = schemaCopy.getMatchingRuleUse(EMR_OCTET_STRING_OID);
        assertThat(mru).isNotNull();
        assertThat(mru.getMatchingRuleOID()).isEqualTo(EMR_OCTET_STRING_OID);
        assertThat(mru.getNames()).containsOnly("Matching rule use test", "Matching rule use test copy");
        assertThat(mru.getDescription()).isEqualTo("Matching rule use description");
        assertThat(mru.getAttributes()).containsOnly(schema.getAttributeType("2.5.4.40"),
                                                     schema.getAttributeType("2.5.4.53"));
        assertThat(mru.getExtraProperties()).includes(entry("property name", singletonList("property value")));
        assertThat(mru.isObsolete()).isFalse();
    }
    @Test(expectedExceptions = ConflictingSchemaElementException.class)
    public void testBuilderDoesNotAllowOverwrite() throws Exception {
        final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse(EMR_BIT_STRING_OID)
                .names("Matching rule use test")
                .attributes("2.5.4.40")
                .addToSchema();
        builder.buildMatchingRuleUse(EMR_BIT_STRING_OID)
               .addToSchema()
               .toSchema();
    }
    @Test(expectedExceptions = NullPointerException.class)
    public void testBuilderDoesNotAllowNullMatchingRuleOID() throws Exception {
        new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse((String) null)
                .addToSchema();
    }
    @Test
    public void testBuilderRemoveAll() throws Exception {
        final MatchingRuleUse.Builder builder = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse(EMR_BIT_STRING_OID)
                .description("Matching rule use description")
                .names("Matching rule use test")
                .attributes("2.5.4.40", "2.5.4.52")
                .extraProperties("property name", "property value");
        final Schema schema = builder.removeAllNames()
                .removeAllAttributes()
                .removeAllExtraProperties()
                .addToSchema()
                .toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRuleUse mru = schema.getMatchingRuleUse(EMR_BIT_STRING_OID);
        assertThat(mru.getNames()).isEmpty();
        assertThat(mru.getAttributes()).isEmpty();
        assertThat(mru.getExtraProperties()).isEmpty();
    }
    @Test
    public void testBuilderRemove() throws Exception {
        final MatchingRuleUse.Builder builder = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRuleUse(EMR_OCTET_STRING_OID)
                .description("Matching rule use description")
                .names("Matching rule use test", "I should not be in the schema")
                .attributes("2.5.4.52", "I should not be in the schema")
                .extraProperties("property name", "property value");
        final Schema schema = builder.removeName("I should not be in the schema")
                .removeAttribute("I should not be in the schema")
                .removeExtraProperty("property name")
                .addToSchema()
                .toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRuleUse mru = schema.getMatchingRuleUse(EMR_OCTET_STRING_OID);
        assertThat(mru.getNames()).containsOnly("Matching rule use test");
        assertThat(mru.getAttributes()).containsOnly(schema.getAttributeType("2.5.4.52"));
        assertThat(mru.getExtraProperties()).isEmpty();
    }
}