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

Violette Roche-Montane
22.57.2013 b32944ba175d472abb27afac48b4d6dcff57f511
CR-2262 SDK Name Form Builder
1 files added
3 files modified
2064 ■■■■■ changed files
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java 344 ●●●●● patch | view | raw | blame | history
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java 125 ●●●● patch | view | raw | blame | history
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaElementBuilder.java 157 ●●●●● patch | view | raw | blame | history
opendj3/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java 1438 ●●●●● patch | view | raw | blame | history
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
@@ -22,7 +22,7 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      Portions copyright 2011-2013 ForgeRock AS
 */
package org.forgerock.opendj.ldap.schema;
@@ -32,23 +32,28 @@
import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_REQUIRED_ATTR1;
import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_NAME_FORM_UNKNOWN_STRUCTURAL_CLASS1;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
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 com.forgerock.opendj.util.Validator;
/**
 * This class defines a data structure for storing and interacting with a name
 * form, which defines the attribute type(s) that must and/or may be used in the
 * RDN of an entry with a given structural objectclass.
 */
public final class NameForm extends SchemaElement {
    // The OID that may be used to reference this definition.
    private final String oid;
@@ -74,27 +79,317 @@
    private Set<AttributeType> optionalAttributes = Collections.emptySet();
    private Set<AttributeType> requiredAttributes = Collections.emptySet();
    NameForm(final String oid, final List<String> names, final String description,
            final boolean obsolete, final String structuralClassOID,
            final Set<String> requiredAttributeOIDs, final Set<String> optionalAttributeOIDs,
            final Map<String, List<String>> extraProperties, final String definition) {
        super(description, extraProperties);
    /**
     * The name form builder.
     */
    public static class Builder extends SchemaElementBuilder<Builder> {
        Validator.ensureNotNull(oid, names);
        Validator.ensureNotNull(structuralClassOID, requiredAttributeOIDs, optionalAttributeOIDs);
        Validator.ensureTrue(requiredAttributeOIDs.size() > 0, "required attribute is empty");
        this.oid = oid;
        this.names = names;
        this.isObsolete = obsolete;
        this.structuralClassOID = structuralClassOID;
        this.requiredAttributeOIDs = requiredAttributeOIDs;
        this.optionalAttributeOIDs = optionalAttributeOIDs;
        // Required attributes
        private String oid;
        private String structuralObjectClassOID;
        private Set<String> requiredAttribute = new LinkedHashSet<String>();
        if (definition != null) {
            this.definition = definition;
        } else {
            this.definition = buildDefinition();
        // Optional attributes - initialized to default values.
        private List<String> names = new LinkedList<String>();
        private Set<String> optionalAttributes = new LinkedHashSet<String>();
        private String definition;
        private boolean isObsolete = false;
        /**
         * Sets the OID of the name form definition.
         * <p>
         * RFC 4512 : numericoid ; object identifier.
         *
         * @param oid
         *            Like 1.3.6.1.4.1.1466.115.121.1.35.
         * @return This name form builder.
         */
        public Builder oid(final String oid) {
            this.oid = oid;
            return this;
        }
        /**
         * Sets the structural object class OID.
         * <p>
         * e.g : OC person.
         *
         * @param oid
         *            = SP "OC" SP oid (RFC 4512).
         * @return This name form builder.
         */
        public Builder structuralObjectClassOID(final String oid) {
            this.structuralObjectClassOID = oid;
            return this;
        }
        /**
         * Sets the user defined names for this definition.
         * <p>
         * RFC 4512 : [ SP "NAME" SP qdescrs ] ; short names (descriptors).
         *
         * @param names
         *            Contains a collection of strings.
         * @return This name form builder.
         */
        public Builder names(final Collection<String> names) {
            this.names.addAll(names);
            return this;
        }
        /**
         * Sets the user defined names for this definition.
         * <p>
         * RFC 4512 : [ SP "NAME" SP qdescrs ] ; short names (descriptors).
         *
         * @param names
         *            Contains a series of strings.
         * @return This name form builder.
         */
        public Builder names(final String... names) {
            return names(Arrays.asList(names));
        }
        /**
         * Erases all the names.
         *
         * @return This name form builder.
         */
        public Builder removeAllNames() {
            this.names.clear();
            return this;
        }
        /**
         * Removes the defined name.
         *
         * @param name
         *            The name to remove.
         * @return This name form builder.
         */
        public Builder removeName(String name) {
            names.remove(name);
            return this;
        }
        /**
         * Specifies which attributes are required by this name form.
         * <p>
         * RFC 4512 : SP "MUST" SP oids ; attribute types.
         *
         * @param oids
         *            The OIDs of the required attributes.
         * @return This name form builder.
         */
        public Builder requiredAttributes(final String... oids) {
            return requiredAttributes(Arrays.asList(oids));
        }
        /**
         * Specifies which attributes are required by this name form.
         * <p>
         * RFC 4512 : SP "MUST" SP oids ; attribute types.
         *
         * @param oids
         *            The OIDs of the required attributes.
         * @return This name form builder.
         */
        public Builder requiredAttributes(final Collection<String> oids) {
            this.requiredAttribute.addAll(oids);
            return this;
        }
        /**
         * Removes the specified required attribute.
         *
         * @param oid
         *            The OID of the required attributes.
         * @return This name form builder.
         */
        public Builder removeRequiredAttribute(final String oid) {
            this.requiredAttribute.remove(oid);
            return this;
        }
        /**
         * Removes all the required attributes.
         *
         * @return This name form builder.
         */
        public Builder removeAllRequiredAttributes() {
            this.requiredAttribute.clear();
            return this;
        }
        /**
         * Sets the optional attribute OIDs.
         * <p>
         * RFC 4512 : [ SP "MAY" SP oids ] ; attribute types.
         *
         * @param oids
         *            The OIDs of the optional attributes.
         * @return This name form builder.
         */
        public Builder optionalAttributes(final String... oids) {
            return optionalAttributes(Arrays.asList(oids));
        }
        /**
         * Sets the optional attributes.
         * <p>
         * RFC 4512 : [ SP "MAY" SP oids ] ; attribute types.
         *
         * @param oids
         *            The OIDs of the optional attributes.
         * @return This name form builder.
         */
        public Builder optionalAttributes(final Collection<String> oids) {
            this.optionalAttributes.addAll(oids);
            return this;
        }
        /**
         * Removes the specified attributes.
         *
         * @param oid
         *            The OID of the optional attributes.
         * @return This name form builder.
         */
        public Builder removeOptionalAttribute(final String oid) {
            this.optionalAttributes.remove(oid);
            return this;
        }
        /**
         * Removes all the optional attributes.
         *
         * @return This name form builder.
         */
        public Builder removeAllOptionalAttributes() {
            this.optionalAttributes.clear();
            return this;
        }
        /**
         * {@code true} if the object class definition is obsolete, otherwise
         * {@code false}.
         * <p>
         * RFC 4512 : [ SP "OBSOLETE" ] ; not active.
         *
         * @param isObsolete
         *            default is {@code false}.
         * @return This name form builder.
         */
        public Builder obsolete(final boolean isObsolete) {
            this.isObsolete = isObsolete;
            return this;
        }
        /**
         * Sets the definition string used to create this object class.
         *
         * @param definition
         *            The definition to set.
         * @return This name form builder.
         */
        Builder definition(final String definition) {
            this.definition = definition;
            return this;
        }
        /**
         * Returns the builder.
         *
         * @return This name form builder.
         */
        @Override
        Builder getThis() {
            return this;
        }
        /**
         * Creates a new name form builder implementation.
         *
         * @param oid
         *            The OID of the name form definition.
         * @param builder
         *            The schema builder linked.
         */
        Builder(final String oid, final SchemaBuilder builder) {
            this.oid(oid);
            this.schemaBuilder(builder);
        }
        /**
         * Duplicates an existing name form builder.
         *
         * @param nf
         *            The name form to duplicate.
         * @param builder
         *            The schema builder where to adds this new name form
         * @throws ConflictingSchemaElementException
         *             If {@code overwrite} was {@code false} and a conflicting
         *             schema element was found.
         */
        Builder(final NameForm nf, final SchemaBuilder builder) {
            this.oid = nf.oid;
            this.definition = nf.buildDefinition();
            this.description(nf.description);
            this.structuralObjectClassOID = nf.structuralClassOID;
            this.isObsolete = nf.isObsolete;
            this.names = new ArrayList<String>(nf.names);
            this.extraProperties(new LinkedHashMap<String, List<String>>(nf.extraProperties));
            this.requiredAttribute = new LinkedHashSet<String>(nf.requiredAttributeOIDs);
            this.optionalAttributes = new LinkedHashSet<String>(nf.optionalAttributeOIDs);
            this.schemaBuilder(builder);
        }
        /**
         * Adds the name form to the builder overwriting any existing name form
         * with the same OID.
         *
         * @return A schema builder.
         */
        public SchemaBuilder addToSchema() {
            return this.getSchemaBuilder().addNameForm(new NameForm(this), true);
        }
        /**
         * Adds the name form to the builder throwing an
         * ConflictingSchemaElementException if there is an existing name form
         * with the same OID.
         *
         * @return A schema builder.
         * @throws ConflictingSchemaElementException
         *             If there is an existing name form with the same OID.
         */
        public SchemaBuilder addNoOverwriteToSchema() {
            return this.getSchemaBuilder().addNameForm(new NameForm(this), false);
        }
    }
    private NameForm(final Builder builder) {
        super(builder.description, builder.extraProperties);
        // Checks for required attributes.
        if (builder.oid == null || builder.oid.isEmpty()) {
            throw new IllegalArgumentException("An OID must be specified.");
        }
        if (builder.structuralObjectClassOID == null || builder.structuralObjectClassOID.isEmpty()) {
            throw new IllegalArgumentException("A structural class OID must be specified.");
        }
        if (builder.requiredAttribute == null || builder.requiredAttribute.isEmpty()) {
            throw new IllegalArgumentException("Required attribute must be specified.");
        }
        oid = builder.oid;
        structuralClassOID = builder.structuralObjectClassOID;
        names = SchemaUtils.unmodifiableCopyOfList(builder.names);
        requiredAttributeOIDs = SchemaUtils.unmodifiableCopyOfSet(builder.requiredAttribute);
        optionalAttributeOIDs = SchemaUtils.unmodifiableCopyOfSet(builder.optionalAttributes);
        isObsolete = builder.isObsolete;
        definition = buildDefinition();
    }
    /**
@@ -286,11 +581,6 @@
        return definition;
    }
    NameForm duplicate() {
        return new NameForm(oid, names, description, isObsolete, structuralClassOID,
                requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, definition);
    }
    @Override
    void toStringContent(final StringBuilder buffer) {
        buffer.append(oid);
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -41,6 +41,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
@@ -1317,15 +1318,14 @@
            reader.skipWhitespaces();
            // The next set of characters must be the OID.
            final String oid = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
            final NameForm.Builder nameFormBuilder =
                    new NameForm.Builder(
                            SchemaUtils.readOID(reader, allowMalformedNamesAndOptions), this);
            List<String> names = Collections.emptyList();
            String description = "".intern();
            boolean isObsolete = false;
            String structuralClass = null;
            Set<String> optionalAttributes = Collections.emptySet();
            Set<String> requiredAttributes = null;
            Map<String, List<String>> extraProperties = Collections.emptyMap();
            // Required properties :
            String structuralOID = null;
            Collection<String> requiredAttributes = Collections.emptyList();
            // At this point, we should have a pretty specific syntax that
            // describes what may come next, but some of the components are
@@ -1342,35 +1342,37 @@
                    // No more tokens.
                    break;
                } else if (tokenName.equalsIgnoreCase("name")) {
                    names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
                    nameFormBuilder.names(SchemaUtils.readNameDescriptors(reader,
                            allowMalformedNamesAndOptions));
                } else if (tokenName.equalsIgnoreCase("desc")) {
                    // This specifies the description for the attribute type. It
                    // is an arbitrary string of characters enclosed in single
                    // quotes.
                    description = SchemaUtils.readQuotedString(reader);
                    nameFormBuilder.description(SchemaUtils.readQuotedString(reader));
                } else if (tokenName.equalsIgnoreCase("obsolete")) {
                    // This indicates whether the attribute type should be
                    // considered obsolete. We do not need to do any more
                    // parsing for this token.
                    isObsolete = true;
                    nameFormBuilder.obsolete(true);
                } else if (tokenName.equalsIgnoreCase("oc")) {
                    structuralClass = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
                    structuralOID = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
                    nameFormBuilder.structuralObjectClassOID(structuralOID);
                } else if (tokenName.equalsIgnoreCase("must")) {
                    requiredAttributes =
                            SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
                    nameFormBuilder.requiredAttributes(requiredAttributes);
                } else if (tokenName.equalsIgnoreCase("may")) {
                    optionalAttributes =
                            SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
                    nameFormBuilder.optionalAttributes(SchemaUtils.readOIDs(reader,
                            allowMalformedNamesAndOptions));
                } 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, SchemaUtils.readExtensions(reader));
                    final List<String> extensions = SchemaUtils.readExtensions(reader);
                    nameFormBuilder.extraProperties(tokenName, extensions
                            .toArray(new String[extensions.size()]));
                } else {
                    final LocalizableMessage message =
                            ERR_ATTR_SYNTAX_NAME_FORM_ILLEGAL_TOKEN1.get(definition, tokenName);
@@ -1378,28 +1380,27 @@
                }
            }
            nameFormBuilder.definition(definition);
            // Make sure that a structural class was specified. If not, then
            // it cannot be valid.
            if (structuralClass == null) {
            // it cannot be valid and the name form cannot be build.
            if (structuralOID == null) {
                final LocalizableMessage message =
                        ERR_ATTR_SYNTAX_NAME_FORM_NO_STRUCTURAL_CLASS1.get(definition);
                throw new LocalizedIllegalArgumentException(message);
            }
            if (requiredAttributes == null || requiredAttributes.size() == 0) {
            if (requiredAttributes.isEmpty()) {
                final LocalizableMessage message =
                        ERR_ATTR_SYNTAX_NAME_FORM_NO_REQUIRED_ATTR.get(definition);
                throw new LocalizedIllegalArgumentException(message);
            }
            if (!extraProperties.isEmpty()) {
                extraProperties = Collections.unmodifiableMap(extraProperties);
            if (overwrite) {
                nameFormBuilder.addToSchema();
            } else {
                nameFormBuilder.addNoOverwriteToSchema();
            }
            final NameForm nameForm =
                    new NameForm(oid, names, description, isObsolete, structuralClass,
                            requiredAttributes, optionalAttributes, extraProperties, definition);
            addNameForm(nameForm, overwrite);
        } catch (final DecodeException e) {
            final LocalizableMessage msg =
                    ERR_ATTR_SYNTAX_NAME_FORM_INVALID1.get(definition, e.getMessageObject());
@@ -1409,49 +1410,33 @@
    }
    /**
     * Adds the provided name form definition to this schema builder.
     * Returns a builder which can be used for incrementally constructing a new
     * name form before adding it to the schema. Example usage:
     *
     * <pre>
     * SchemaBuilder builder = ...;
     * builder.buildNameForm("1.2.3.4").name("myNameform").addToSchema();
     * </pre>
     *
     * @param oid
     *            The OID of the name form definition.
     * @param names
     *            The user-friendly names of the name form definition.
     * @param description
     *            The description of the name form definition.
     * @param obsolete
     *            {@code true} if the name form definition is obsolete,
     *            otherwise {@code false}.
     * @param structuralClass
     *            The structural object class this rule applies to.
     * @param requiredAttributes
     *            A list of naming attribute types that entries subject to the
     *            name form must contain.
     * @param optionalAttributes
     *            A list of naming attribute types that entries subject to the
     *            name form may contain.
     * @param extraProperties
     *            A map containing additional properties associated with the
     *            name form definition.
     * @param overwrite
     *            {@code true} if any existing name form 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.
     * @return A builder to continue building the NameForm.
     */
    SchemaBuilder addNameForm(final String oid, final List<String> names,
            final String description, final boolean obsolete, final String structuralClass,
            final Set<String> requiredAttributes, final Set<String> optionalAttributes,
            final Map<String, List<String>> extraProperties, final boolean overwrite) {
    public NameForm.Builder buildNameForm(final String oid) {
        lazyInitBuilder();
        return new NameForm.Builder(oid, this);
    }
        final NameForm nameForm =
                new NameForm(oid, unmodifiableCopyOfList(names), description, obsolete,
                        structuralClass, unmodifiableCopyOfSet(requiredAttributes),
                        unmodifiableCopyOfSet(optionalAttributes),
                        unmodifiableCopyOfExtraProperties(extraProperties), null);
        addNameForm(nameForm, overwrite);
        return this;
    /**
     * Duplicates the name form.
     *
     * @param nameForm
     *            The name form to duplicate.
     * @return A name form builder.
     */
    public NameForm.Builder buildNameForm(final NameForm nameForm) {
        lazyInitBuilder();
        return new NameForm.Builder(nameForm, this);
    }
    /**
@@ -2664,7 +2649,12 @@
        }
    }
    private void addNameForm(final NameForm form, final boolean overwrite) {
    SchemaBuilder addNameForm(final NameForm form, final boolean overwrite) {
        // If schema is not initialized before.
        if (numericOID2NameForms == null || name2NameForms == null) {
            lazyInitBuilder();
        }
        NameForm conflictingForm;
        if (numericOID2NameForms.containsKey(form.getOID())) {
            conflictingForm = numericOID2NameForms.get(form.getOID());
@@ -2691,6 +2681,7 @@
                forms.add(form);
            }
        }
        return this;
    }
    private void addObjectClass(final ObjectClass oc, final boolean overwrite) {
@@ -2748,7 +2739,7 @@
        }
        for (final NameForm nameForm : schema.getNameForms()) {
            addNameForm(nameForm.duplicate(), overwrite);
            addNameForm(nameForm, overwrite);
        }
        for (final DITContentRule contentRule : schema.getDITContentRules()) {
opendj3/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaElementBuilder.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 2013 ForgeRock AS
 */
package org.forgerock.opendj.ldap.schema;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
 * This class defines the set of methods and structures that must be implemented
 * to define a schema element builder.
 *
 * @param <T>
 *            Builder could be : AttributeTypeBuilder, NameFormBuilder,
 *            DITContentRuleBuilder, DITStructureRuleBuilder,
 *            MatchingRuleBuilder, ObjectClassBuilder, ...
 */
abstract class SchemaElementBuilder<T extends SchemaElementBuilder<T>> {
    // List of attributes in common / required attributes used by builders.
    String description = "";
    Map<String, List<String>> extraProperties;
    private SchemaBuilder schemaBuilder = null;
    /**
     * Creates a new abstract schema element builder implementation.
     */
    SchemaElementBuilder() {
        extraProperties = new LinkedHashMap<String, List<String>>();
    }
    /**
     * Defines the schemThe builder.
     *
     * @param sc
     *            The schemThe builder.
     * @return A builder
     */
    T schemaBuilder(final SchemaBuilder sc) {
        this.schemaBuilder = sc;
        return getThis();
    }
    /**
     * Returns the schemThe builder.
     *
     * @return The schemThe builder.
     */
    SchemaBuilder getSchemaBuilder() {
        return schemaBuilder;
    }
    abstract T getThis();
    /**
     * The description of the schema element.
     *
     * @param description
     *            a string containing the description of the schema element.
     * @return <T> The builder.
     */
    public T description(final String description) {
        this.description = description;
        return getThis();
    }
    /**
     * A map containing additional properties associated with the schema element
     * definition.
     * <p>
     * cf. RFC 4512 : extensions WSP RPAREN ; extensions
     *
     * @param extraProperties
     *            Additional properties.
     * @return The builder.
     */
    public T extraProperties(final Map<String, List<String>> extraProperties) {
        this.extraProperties.putAll(extraProperties);
        return getThis();
    }
    /**
     * Additional properties associated with the schema element definition.
     * <p>
     * cf. RFC 4512 : extensions WSP RPAREN ; extensions
     *
     * @param key
     *            like X-ORIGIN
     * @param extensions
     *            e.g : 'RFC 2252'
     * @return The builder.
     */
    public T extraProperties(final String key, final String... extensions) {
        if (this.extraProperties.get(key) != null) {
            List<String> tempExtraProperties = new ArrayList<String>(this.extraProperties.get(key));
            tempExtraProperties.addAll(Arrays.asList(extensions));
            this.extraProperties.put(key, tempExtraProperties);
        } else {
            this.extraProperties.put(key, Arrays.asList(extensions));
        }
        return getThis();
    }
    /**
     * Removes an extra property.
     *
     * @param key
     *            The key to remove.
     * @param extensions
     *            The extension to remove. Can be null.
     * @return The builder.
     */
    public T removeExtraProperties(final String key, final String extensions) {
        if (this.extraProperties.get(key) != null && extensions != null) {
            List<String> tempExtraProperties = new ArrayList<String>(this.extraProperties.get(key));
            tempExtraProperties.remove(tempExtraProperties.indexOf(extensions));
            this.extraProperties.put(key, tempExtraProperties);
        } else if (this.extraProperties.get(key) != null) {
            this.extraProperties.remove(key);
        }
        return getThis();
    }
    /**
     * Clears all extra properties.
     *
     * @return The builder.
     */
    public T clearExtraProperties() {
        this.extraProperties.clear();
        return getThis();
    }
}
opendj3/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java
@@ -21,663 +21,1043 @@
 * CDDL HEADER END
 *
 *
 *      Portions copyright 2012 ForgeRock AS.
 *      Copyright 2013 ForgeRock AS.
 */
package org.forgerock.opendj.ldap.schema;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import static org.fest.assertions.Assertions.assertThat;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.schema.NameForm.Builder;
import org.testng.annotations.Test;
/**
 * This class tests the NameForm class.
 * This class tests the NameForm class. The name form builder can be only used
 * with the schema builder.
 */
@SuppressWarnings("javadoc")
public class NameFormTestCase extends SchemaTestCase {
    /**
     * NameForm doesn't allow null OID.
     * Creates a new form using the required parameters only (oid, structural
     * OID and required attributes).
     */
    @Test(expectedExceptions = NullPointerException.class)
    public final void testCreateFormDoesntAllowNullOid() {
    @Test()
    public final void testCreatesANewFormWithOnlyRequiredParameters() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                    .structuralObjectClassOID("person")
                    .requiredAttributes("sn", "cn") // ("cn, sn") is not supported.
                    .addNoOverwriteToSchema()
                .toSchema();
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().size()).isGreaterThan(0);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        // @formatter:off
        new NameForm(null, names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        // @formatter:on
        for (final NameForm nf : schema.getNameForms()) {
            assertThat(nf.hasName("hasAName ?")).isFalse();
            assertThat(nf.getNameOrOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
            assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
            assertThat(nf.toString()).isEqualTo("( 1.3.6.1.4.1.1466.115.121.1.35 OC person MUST ( sn $ cn ) )");
        }
    }
    /**
     * NameForm doesn't allow null structuralClassOID.
     * Creates a new form with a name.
     */
    @Test(expectedExceptions = NullPointerException.class)
    public final void testCreateFormDoesntAllowNullStructuralClassOID() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        names.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
    @Test()
    public final void testCreatesANewFormWithAName() {
        // @formatter:off
        new NameForm("mynewform-oid", names, "Description of the new form", false,
                null, requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                    .structuralObjectClassOID("person")
                    .names("MyNewForm")
                    .requiredAttributes("sn", "cn")
                    .addNoOverwriteToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().size()).isGreaterThan(0);
        for (final NameForm nf : schema.getNameForms()) {
            assertThat(nf.hasName("hasAName ?")).isFalse();
            assertThat(nf.getNameOrOID()).isEqualTo("MyNewForm");
            assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
            assertThat(nf.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' OC person MUST ( sn $ cn ) )");
        }
    }
    /**
     * NameForm doesn't allow null requiredAttributeOIDs.
     * Creates a new form with optional attributes OID.
     */
    @Test(expectedExceptions = NullPointerException.class)
    public final void testCreateFormDoesntAllowNullRequiredAttributeOIDs() {
    @Test()
    public final void testCreatesANewFormWithOptionalAttributesOid() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", null, Collections.<String> emptySet(), extraProperties, null);
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .structuralObjectClassOID("person")
                .names("MyNewForm")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("owner")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().size()).isGreaterThan(0);
        for (final NameForm nf : schema.getNameForms()) {
            assertThat(nf.hasName("hasAName ?")).isFalse();
            assertThat(nf.getNameOrOID()).isEqualTo("MyNewForm");
            assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
            assertThat(nf.getOptionalAttributes().toString()).contains("owner");
            assertThat(nf.toString()).isEqualTo(
                    "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' OC person MUST ( sn $ cn ) MAY owner )");
        }
    }
    /**
     * NameForm doesn't allow null requiredAttributeOIDs.
     * Creates a new form with ExtraProperties.
     */
    @Test()
    public final void testCreatesANewNameFormWithExtraProperties() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .structuralObjectClassOID("person")
                .names("MyNewForm")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("owner")
                .extraProperties("X-ORIGIN", "RFC xxx")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().size()).isGreaterThan(0);
        for (final NameForm nf : schema.getNameForms()) {
            assertThat(nf.hasName("hasAName ?")).isFalse();
            assertThat(nf.getNameOrOID()).isEqualTo("MyNewForm");
            assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
            assertThat(nf.getExtraProperty("X-ORIGIN").get(0)).isEqualTo("RFC xxx");
            assertThat(nf.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' OC person "
                + "MUST ( sn $ cn ) MAY owner X-ORIGIN 'RFC xxx' )");
        }
    }
    /**
     * When required attributes are absents, the builder sends exception. Here,
     * the OID is missing. An exception is expected.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testCreateFormDoesntAllowEmptyRequiredAttributeOIDs() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
    public final void testBuilderDoesntAllowNullOid() {
        // @formatter:off
        new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm((String) null)
                .description("This is a description")
                .names("name1")
                .names("name2", "name3")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .structuralObjectClassOID("person")
                .requiredAttributes("sn, cn")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
    /**
     * NameForm doesn't allow null requiredAttributeOIDs.
     * When required attributes are absents, the builder sends an exception.
     * Here, the structural class OID is missing.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testBuilderDoesntAllowNullStructuralClassOid() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn, cn")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
    /**
     * When required attributes are absents, the builder sends an exception.
     * Here, the required attributes OID is missing.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = java.lang.IllegalArgumentException.class)
    public final void testBuilderDoesntAllowEmptyRequiredAttributes() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes()
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
    /**
     * When required attributes are absents, the builder sends an exception.
     * Here, the required attribute is missing.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testBuilderDoesntAllowNullRequiredAttributes() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
    /**
     * Optional attributes shouldn't be equals to null. Exception expected.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = NullPointerException.class)
    public final void testCreateFormDoesntAllowNullOptionalAttributeOIDs() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
    public final void testBuilderDoesntAllowNullOptionalAttributes() {
        // @formatter:off
        new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, null, extraProperties, null);
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .structuralObjectClassOID("person")
                .requiredAttributes("sn, cn")
                .requiredAttributes((String[]) null)
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
    /**
     * Create a new form and compare the result as string with the expected
     * usual form.
     * By default optional attributes are empty.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testCreateNewFormWithUniqueName() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
    public final void testBuilderAllowsEmptyOptionalAttributes() {
        // @formatter:off
        NameForm nf = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                // .optionalAttributeOIDs("") empty by default.
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
    }
        assertThat(nf.hasName("MyNewForm")).isTrue();
        assertThat(nf.getOID().toString()).isEqualTo("mynewform-oid");
    /**
     * Allows removing non-existent attributes without errors.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testBuilderAllowRemovingNonexistentAttributes() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("This is a description")
                .names("MyNewForm")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .structuralObjectClassOID("person")
                .requiredAttributes("sn")
                .removeRequiredAttribute("unknown")
                .removeOptionalAttribute("optionalunknown")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.getRequiredAttributes().size()).isEqualTo(1);
        assertThat(nf.getRequiredAttributes().iterator().next().getNameOrOID()).isEqualTo("sn");
        assertThat(nf.getOptionalAttributes()).isEmpty();
    }
    /**
     * Verifying the schema builder allows to add directly a definition. The
     * name form is created as well.
     */
    @Test()
    public final void testNameFormDefinition() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final String nameFormDefinition = "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' "
                + "DESC 'Description of the new form' "
                + "OC person MUST ( sn $ cn ) "
                + "MAY ( description $ uid ) "
                + "X-SCHEMA-FILE 'NameFormCheckingTestCase' "
                + "X-ORIGIN 'NameFormCheckingTestCase' )";
        // @formatter:on
        // Add the nameForm to the schemaBuilder.
        sb.addNameForm(nameFormDefinition, false);
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.getExtraPropertyNames()).isNotEmpty();
        // @formatter:off
        assertThat(nf.toString()).isEqualTo(
                "( mynewform-oid NAME 'MyNewForm' DESC 'Description of the new form'"
                + " OC mynewform-oid MUST ( cn $ sn ) X-ORIGIN 'EntrySchemaCheckingTestCase' )");
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' "
                + "DESC 'Description of the new form' "
                + "OC person MUST ( sn $ cn ) "
                + "MAY ( description $ uid ) "
                + "X-SCHEMA-FILE 'NameFormCheckingTestCase' "
                + "X-ORIGIN 'NameFormCheckingTestCase' )");
        // @formatter:on
    }
    /**
     * Create a new form without name(s).
     * Required attributes are missing in the following definition.
     */
    @Test()
    public final void testCreateNewFormWithOnlyOid() {
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testNameFormDefinitionDoesntAllowMissingAttributes() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        NameForm nf = new NameForm("1.3.6.1.4.1.1466.115.121.1.35", new ArrayList<String>(),
                "Description of the new form", false, "mynewform-oid", requiredAttributeOIDs,
                Collections.<String> emptySet(), extraProperties, null);
        final String nameFormDefinition = "( 1.3.6.1.4.1.1466.115.121.1.35 NAME 'MyNewForm' "
                + "DESC 'Description of the new form' "
                + "OC person "
                + "MAY ( description $ uid ) "
                + "X-SCHEMA-FILE 'NameFormCheckingTestCase' "
                + "X-ORIGIN 'EntrySchemaCheckingTestCase' "
                + "X-ORIGIN 'NameFormCheckingTestCase' )";
        // @formatter:on
        assertThat(nf.hasName("hasAName ?")).isFalse();
        assertThat(nf.getNameOrOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        // Add the nameForm to the schemaBuilder.
        sb.addNameForm(nameFormDefinition, false);
        final Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
    }
    /**
     * Duplicates a name form using the schema builder.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testDuplicatesTheNameForm() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final Builder nfb = new Builder("1.3.6.1.4.1.1466.115.121.1.35", sb);
        nfb.description("Description of the new form")
            .names("MyNewForm")
            .structuralObjectClassOID("person")
            .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addNoOverwriteToSchema();
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Description of the new form'"
                + " OC mynewform-oid MUST ( cn $ sn ) X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
        sb.buildNameForm(nf)
            .names("Dolly")
            .oid("1.3.6.1.4.1.1466.115.121.1.36")
            .addToSchema();
        schema = sb.toSchema();
        assertThat(schema.getNameForms()).isNotEmpty();
        assertThat(schema.getNameForms().size()).isEqualTo(2);
        assertThat(schema.getWarnings()).isEmpty();
        final Iterator<NameForm> i = schema.getNameForms().iterator();
        i.next(); // Jump the first element (== nf)
        final NameForm dolly = i.next(); // Our new cloned NameForm.
        assertThat(dolly.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.36"); // With the new OID !
        assertThat(dolly.getNames().size()).isEqualTo(2);
    }
    /**
     * Create a new form and compare the result as string with the expected
     * usual form.
     */
    @Test()
    public final void testCreateNewForm() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        // @formatter:off
        NameForm nf = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(),
                extraProperties, null);
        assertThat(nf.toString()).isEqualTo(
                "( mynewform-oid NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form' OC mynewform-oid"
                + " MUST ( cn $ sn ) X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
    }
    /**
     * Create a new form and compare the result as string with the expected
     * usual form.
     */
    @Test()
    public final void testCreateNewFormWithOptionalAttributesOid() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        // @formatter:off
        NameForm nf = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        assertThat(nf.toString()).isEqualTo(
                "( mynewform-oid NAME 'MyNewForm' DESC 'Description of the new form'"
                + " OC mynewform-oid MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
    }
    /**
     * Adds a new form which is containing an OID not provided by the schema.
     * Exception expected : The name form description "MyNewForm" is associated
     * with a structural object class "mynewform-oid" which is not defined in
     * the schema.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = SchemaException.class)
    public final void testNameFormValidateDoesntAllowUnknowNewStructuralObject()
            throws SchemaException {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        // @formatter:off
        NameForm nf1 = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        assertThat(nf1.toString()).isEqualTo(
                "( mynewform-oid NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form'"
                + " OC mynewform-oid"
                + " MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
        List<LocalizableMessage> warnings = new ArrayList<LocalizableMessage>();
        nf1.validate(Schema.getDefaultSchema(), warnings);
    }
    /**
     * Validate a nameForm using an abstract object class instead of an
     * structural object class throws an error.
     *
     * @throws SchemaException
     */
    @Test(expectedExceptions = SchemaException.class)
    public final void testNameFormValidateDoesntAllowAbstractObjectClass() throws SchemaException {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        // @formatter:off
        NameForm nf1 = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "top", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        assertThat(nf1.toString()).isEqualTo(
                "( mynewform-oid NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form'"
                + " OC top"
                + " MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
        List<LocalizableMessage> warnings = new ArrayList<LocalizableMessage>();
        nf1.validate(Schema.getDefaultSchema(), warnings);
    }
    /**
     * Validate a new form without warnings.
     * Duplicates a name form using the schema builder.
     * The duplicate name form contains an inappropriate structural class OID which made the build fails.
     * <p>Warning from schema is : <pre>
     * "The name form description "MyNewForm" is associated with a structural object class
     * "wrongStructuralOID" which is not defined in the schema".</pre>
     *
     * @throws SchemaException
     */
    @Test()
    public final void testNameFormValidate() throws SchemaException {
    public final void testDuplicatesTheNameFormFails() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        NameForm nf1 = new NameForm("1.3.6.1.4.1.1466.115.121.1.35", names, "Description of the new form", false,
                "person", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        final Builder nfb = new Builder("1.3.6.1.4.1.1466.115.121.1.35", sb);
        nfb.description("Description of the new form")
            .names("MyNewForm")
            .structuralObjectClassOID("person")
            .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addNoOverwriteToSchema();
        assertThat(nf1.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form'"
                // Structural Object class, contained in the core schema:
                + " OC person"
                + " MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        List<LocalizableMessage> warnings = new ArrayList<LocalizableMessage>();
        nf1.validate(Schema.getCoreSchema(), warnings);
        assertThat(warnings).isEmpty();
        sb.buildNameForm(nf)
            .names("Dolly")
            .oid("1.3.6.1.4.1.1466.115.121.1.36")
            .structuralObjectClassOID("wrongStructuralOID")
            .addToSchema();
        schema = sb.toSchema();
        assertThat(schema.getNameForms().size()).isEqualTo(1); // MyNewForm
        // The duplicate name form is  not created and the schema contains warnings about.
        assertThat(schema.getWarnings()).isNotEmpty();
    }
    /**
     * Compare two same nameForm using the equal function.
     * Compare two same name forms using the equal function.
     */
    @Test()
    public final void testNameFormEqualsTrue() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        // @formatter:off
        NameForm nf1 = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        NameForm nf2 = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .names("TheNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        final NameForm nf1 = schema.getNameForms().iterator().next();
        final Schema schema2 = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
            .names("MyNewForm")
            .structuralObjectClassOID("person")
            .requiredAttributes("sn", "cn")
            .addNoOverwriteToSchema().toSchema();
        final NameForm nf2 = schema2.getNameForm("MyNewForm");
        assertThat(nf1.equals(nf2)).isTrue();
    }
    /**
     * Equals between two 'nameforms' fails.
     * Equals between two name forms fails.
     */
    @Test()
    public final void testNameFormEqualsFalse() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .names("TheNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        final NameForm nf1 = schema.getNameForms().iterator().next();
        // @formatter:off
        NameForm nf1 = new NameForm("mynewform-oid", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        NameForm nf2 = new NameForm("mynewform-oid2", names, "Description of the new form", false,
                "mynewform-oid", requiredAttributeOIDs, Collections.<String> emptySet(), extraProperties, null);
        final Schema schema2 = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.36")
                .description("Description of the new form")
                .names("MyNewForm")
                .names("TheNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(nf1.getOID()).isEqualTo("mynewform-oid");
        assertThat(nf2.getOID()).isEqualTo("mynewform-oid2");
        // fails if oid is different.
        assertThat(nf1.equals(nf2)).isFalse();
        assertThat(nf1.equals(schema2.getNameForms().iterator().next())).isFalse();
    }
    /**
     * Duplicating a form without validating it doesn't copy OptionalAttributes
     * and RequiredAttributes.
     */
    @Test()
    public final void testNameFormDuplicateDoesntDuplicateAllAttributeWithoutValidateIt() {
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        // The set of optional attribute types
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        // @formatter:off
        NameForm nf1 = new NameForm("1.3.6.1.4.1.1466.115.121.1.35", names, "Description of the new form", false,
                "person", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        assertThat(nf1.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form'"
                // Structural Object class, contained in the core schema:
                + " OC person"
                + " MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        // @formatter:on
        // Duplicating the 'nameform'.
        NameForm nf2 = nf1.duplicate();
        // Checking if the attributes are the same :
        assertThat(nf2.getDescription()).isEqualTo(nf1.getDescription());
        assertThat(nf2.getDescription()).isEqualTo("Description of the new form");
        assertThat(nf2.getExtraPropertyNames()).isEqualTo(nf1.getExtraPropertyNames());
        assertThat(nf2.getExtraPropertyNames().iterator().next()).isEqualTo("X-ORIGIN");
        assertThat(nf2.getNameOrOID()).isEqualTo(nf1.getNameOrOID());
        assertThat(nf2.getNameOrOID()).isEqualTo("MyNewForm");
        assertThat(nf2.getOID()).isEqualTo(nf1.getOID());
        assertThat(nf2.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        // Required and optional attributes are empty.
        assertThat(nf2.getOptionalAttributes()).isEmpty();
        assertThat(nf2.getOptionalAttributes()).isEqualTo(nf1.getOptionalAttributes());
        assertThat(nf2.getRequiredAttributes()).isEmpty();
        assertThat(nf2.getRequiredAttributes()).isEqualTo(nf1.getRequiredAttributes());
        assertThat(nf2.getStructuralClass()).isEqualTo(nf1.getStructuralClass());
    }
    /**
     * Duplicating a form succeeds after a schema validation.
     * Testing to add a name form using the definition.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testNameFormDuplicateSucceedAfterValidation() throws SchemaException {
    public final void testCreateFormUsingDefinitionAndSchemaBuilder() {
        final SchemaBuilder sb = new SchemaBuilder();
        // The set of user defined names for this definition.
        List<String> names = new ArrayList<String>();
        names.add("MyNewForm");
        names.add("TheNewForm");
        // @formatter:off
        sb.addSchema(Schema.getCoreSchema(), false)
            .addObjectClass(
                "( mycustomobjectclass-oid NAME 'myCustomObjectClassOC' SUP top "
                + "STRUCTURAL MUST cn X-ORIGIN 'NameFormTestCase')", false)
            .addNameForm(
                "( mycustomnameform-oid NAME 'myCustomNameForm' OC myCustomObjectClassOC "
                + "MUST cn X-ORIGIN 'NameFormTestCase' )",
                false)
            .toSchema();
        // @formatter:on
        // An optional set of extensions for the name form ( X-ORIGIN / X-SCHEMA-FILE)
        Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        List<String> extra = new ArrayList<String>();
        final Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameFormsWithName("mycustomnameform")).isNotNull();
        for (final NameForm o : schema.getNameForms()) {
            assertThat(o.getNameOrOID()).isEqualTo("myCustomNameForm");
            assertThat(o.getOID()).isEqualTo("mycustomnameform-oid");
            assertThat(o.getStructuralClass().getOID().toString()).isEqualTo(
                    "mycustomobjectclass-oid");
        }
    }
    /**
     * Compare two same name forms using the equal function. One created by the
     * name form builder, the other by the schema builder directly using the
     * definition.
     */
    @Test()
    public final void testNameFormEqualityReturnsTrueBetweenBuilderAndDefinition() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final NameForm nf1 = schema.getNameForms().iterator().next();
        final SchemaBuilder sb2 = new SchemaBuilder();
        sb2.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        sb2.addNameForm(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME ( 'MyNewForm' ) "
                + "DESC 'Description of the new form' "
                + "OC person MUST ( sn $ cn ) "
                + "MAY ( description $ uid ) "
                + "X-ORIGIN 'NameFormCheckingTestCase' )", false);
        // @formatter:on
        final NameForm nf2 = sb2.toSchema().getNameForm("MyNewForm");
        assertThat(nf1.equals(nf2)).isTrue();
    }
    /**
     * Compare two same name forms using the equal function. One created by the
     * name form builder, the other by the schema builder directly using the
     * definition with different OID.
     */
    @Test()
    public final void testNameFormEqualityReturnsFalseBetweenBuilderAndDefinition() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final NameForm nf1 = schema.getNameForms().iterator().next();
        final SchemaBuilder sb2 = new SchemaBuilder();
        sb2.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        sb2.addNameForm(
                "( 1.3.6.1.4.1.1466.115.121.1.36 NAME ( 'MyNewForm' ) " // OID changed.
                + "DESC 'Description of the new form' "
                + "OC person MUST ( sn $ cn ) "
                + "MAY ( description $ uid ) "
                + "X-ORIGIN 'NameFormCheckingTestCase' )", false);
        // @formatter:on
        final NameForm nf2 = sb2.toSchema().getNameForm("MyNewForm");
        // Equals is only based on the OID.
        assertThat(nf1.equals(nf2)).isFalse();
    }
    /**
     * Validates a name form using an abstract object class instead of an
     * structural object class and throws an error.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testNameFormValidateDoesntAllowAbstractObjectClass() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("mynewform-oid")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("top")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getNameForms()).isEmpty();
        assertThat(schema.getWarnings()).isNotEmpty();
        assertThat(schema.getWarnings().toString()).contains(
                "This object class exists in the schema but is defined as ABSTRACT rather than structural");
        // output is : The name form description "MyNewForm" is associated with the "top" object class.
        // This object class exists in the schema but is defined as ABSTRACT rather than structural
    }
    /**
     * Creates a name form using the appropriate structural object class.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testNameFormValidateAllowsStructuralObjectClass() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("mynewform-oid")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getNameForms()).isNotEmpty();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().iterator().next().getOID()).isEqualTo("mynewform-oid");
        assertThat(schema.getNameForms().iterator().next().getNames().get(0)).isEqualTo("MyNewForm");
    }
    /**
     * Adds multiple attributes... e.g : name form containing multiple
     * extra-properties, requiredAttributes, optional attributes, names...
     *
     * @throws SchemaException
     */
    @Test()
    public final void testBuildsANewFormWithMultipleAttributes() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("0.0.1.2.3")
                .description("multipleAttributes Test description")
                .names("multipleAttributes")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase2")
                .requiredAttributes("sn", "cn") // ("cn, sn") is not supported.
                .requiredAttributes("uid")
                .optionalAttributes("owner")
                .optionalAttributes("l")
                .names("Rock")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        for (final NameForm nf : schema.getNameForms()) {
            assertThat(nf.getDescription()).isEqualTo("multipleAttributes Test description");
            assertThat(nf.getOID()).isEqualTo("0.0.1.2.3");
            assertThat(nf.getNames().get(0)).isEqualTo("multipleAttributes");
            assertThat(nf.getNames().get(1)).isEqualTo("Rock");
            assertThat(nf.getExtraProperty("X-ORIGIN").get(0))
                    .isEqualTo("NameFormCheckingTestCase");
            assertThat(nf.getExtraProperty("X-ORIGIN").get(1)).isEqualTo(
                    "NameFormCheckingTestCase2");
            assertThat(nf.getStructuralClass().getNameOrOID()).isEqualTo("person");
            // RequiredAttributes is accessible only after validate
            for (final AttributeType att : nf.getRequiredAttributes()) {
                assertThat(
                        att.getNameOrOID().contains("cn") || att.getNameOrOID().contains("sn")
                                || att.getNameOrOID().contains("uid")).isTrue();
            }
            // OptionalAttributes is accessible only after validate
            for (final AttributeType att : nf.getOptionalAttributes()) {
                assertThat(att.getNameOrOID().contains("owner") || att.getNameOrOID().contains("l"))
                        .isTrue();
            }
        }
    }
    /**
     * Using the schema builder for adding new name forms. Allows methods
     * chaining.
     * <p>
     * e.g : (SchemaBuilder) <code>
     * scb.addNameForm("1.2.3").build(true).addAttributeType
     * (...).build(false).addNameForm(...)...etc.
     * </code>
     * <p>
     * N.B : NameForm is validated when the SchemaBuilder is building a Schema.
     * If the NameForm is not valid, the SchemaBuilder just remove the invalid
     * NameForm.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testCreatesANewFormUsingChainingMethods() {
        final Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        final List<String> extra = new ArrayList<String>();
        extra.add("EntrySchemaCheckingTestCase");
        extraProperties.put("X-ORIGIN", extra);
        // The set of required attribute types for this name form.
        Set<String> requiredAttributeOIDs = new TreeSet<String>();
        requiredAttributeOIDs.add("sn");
        requiredAttributeOIDs.add("cn");
        Set<String> optionalAttributeOIDs = new TreeSet<String>();
        optionalAttributeOIDs.add("description");
        optionalAttributeOIDs.add("uid");
        // @formatter:off
        NameForm nf1 = new NameForm("1.3.6.1.4.1.1466.115.121.1.35", names, "Description of the new form", false,
                "person", requiredAttributeOIDs, optionalAttributeOIDs, extraProperties, null);
        assertThat(nf1.toString()).isEqualTo(
                "( 1.3.6.1.4.1.1466.115.121.1.35 NAME ( 'MyNewForm' 'TheNewForm' )"
                + " DESC 'Description of the new form'"
                // Structural Object class, contained in the core schema:
                + " OC person"
                + " MUST ( cn $ sn )"
                + " MAY ( description $ uid )"
                + " X-ORIGIN 'EntrySchemaCheckingTestCase' )");
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.2.3")
                .description("NF1's description")
                .names("theFirstNameForm")
                .structuralObjectClassOID("person")
                .extraProperties(extraProperties)
                .requiredAttributes("uid")
                .optionalAttributes("sn")
                .addToSchema()
            .buildNameForm("4.4.4")
                .description("NF2's description")
                .names("theSecondNameForm")
                .structuralObjectClassOID("person")
                .extraProperties(extraProperties)
                .requiredAttributes("uid")
                .requiredAttributes("sn")
                .addToSchema()
            .toSchema();
        // @formatter:on
        List<LocalizableMessage> warnings1 = new ArrayList<LocalizableMessage>();
        nf1.validate(Schema.getCoreSchema(), warnings1);
        // First name form
        final NameForm first = schema.getNameForm("theFirstNameForm");
        assertThat(first.getOID()).isEqualTo("1.2.3");
        assertThat(first.getDescription()).isEqualTo("NF1's description");
        assertThat(first.getRequiredAttributes()).isNotEmpty();
        assertThat(first.getOptionalAttributes()).isNotEmpty();
        assertThat(first.getStructuralClass().getNameOrOID()).isEqualTo("person");
        // Duplicating the 'nameform'.
        NameForm nf2 = nf1.duplicate();
        // Second name form
        final NameForm second = schema.getNameForm("theSecondNameForm");
        assertThat(second.getOID()).isEqualTo("4.4.4");
        assertThat(second.getDescription()).isEqualTo("NF2's description");
        assertThat(second.getRequiredAttributes()).isNotEmpty();
        assertThat(second.getOptionalAttributes()).isEmpty();
    }
        // Required and optional attributes are empty :
        assertThat(nf2.getOptionalAttributes()).isEmpty();
        assertThat(nf2.getRequiredAttributes()).isEmpty();
    /**
     * Remove functions uses on names / required attribute /
     *
     * @throws SchemaException
     */
    @Test()
    public final void testCreatesNewFormAndRemovesAttributes() {
        List<LocalizableMessage> warnings2 = new ArrayList<LocalizableMessage>();
        nf2.validate(Schema.getCoreSchema(), warnings2);
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("0.0.1.2.3")
                .description("multipleAttributes Test description")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase2")
                .requiredAttributes("sn", "cn")
                .requiredAttributes("uid")
                .optionalAttributes("givenName")
                .optionalAttributes("l")
                .names("nameform1")
                .names("nameform2")
                .names("nameform3")
                .removeName("nameform2")
                .removeRequiredAttribute("cn")
                .removeOptionalAttribute("l")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        // Checking if the attributes are the same :
        assertThat(nf2.getDescription()).isEqualTo(nf1.getDescription());
        assertThat(nf2.getDescription()).isEqualTo("Description of the new form");
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf2.getExtraPropertyNames()).isEqualTo(nf1.getExtraPropertyNames());
        assertThat(nf2.getExtraPropertyNames().iterator().next()).isEqualTo("X-ORIGIN");
        assertThat(nf.getNames()).hasSize(2);
        assertThat(nf.getNames()).contains("nameform1");
        assertThat(nf.getNames()).contains("nameform3");
        assertThat(nf2.getNameOrOID()).isEqualTo(nf1.getNameOrOID());
        assertThat(nf2.getNameOrOID()).isEqualTo("MyNewForm");
        assertThat(nf.getRequiredAttributes().size()).isEqualTo(2);
        assertThat(nf.getRequiredAttributes().toString()).contains("'sn'");
        assertThat(nf.getRequiredAttributes().toString()).contains("uid");
        assertThat(nf2.getOID()).isEqualTo(nf1.getOID());
        assertThat(nf2.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.getOptionalAttributes().size()).isEqualTo(1);
    }
        // Required and optional attributes are not empty :
        assertThat(nf2.getOptionalAttributes()).isNotEmpty();
        assertThat(nf2.getOptionalAttributes()).isEqualTo(nf1.getOptionalAttributes());
    /**
     * Trying to remove attributes from a duplicated name form.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testDuplicatesNameFormAndRemovesAttributes() {
        assertThat(nf2.getRequiredAttributes()).isNotEmpty();
        assertThat(nf2.getRequiredAttributes()).isEqualTo(nf1.getRequiredAttributes());
        // @formatter:off
        Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormTestCase", "Forgerock", "extra")
                .extraProperties("FROM", "NameFormTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .toSchema();
        // @formatter:on
        assertThat(nf2.getStructuralClass()).isEqualTo(nf1.getStructuralClass());
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.getRequiredAttributes().size()).isEqualTo(2);
        assertThat(nf.getOptionalAttributes().size()).isEqualTo(2);
        // @formatter:off.
        SchemaBuilder sb = new SchemaBuilder(Schema.getCoreSchema());
        Builder nfBuilder = new Builder(nf, sb)
                    .names("Dolly")
                    .oid("1.3.6.1.4.1.1466.115.121.1.36")
                    .removeOptionalAttribute("uid")
                    .removeOptionalAttribute("nonExistentUid")
                    .requiredAttributes("street")
                    .removeRequiredAttribute("sn")
                    .removeExtraProperties("X-ORIGIN", "extra")
                    .removeExtraProperties("X-ORIGIN", "Forgerock")
                    .removeExtraProperties("FROM", null);
        // @formatter:on
        sb.addSchema(schema, true);
        sb.addSchema(nfBuilder.addToSchema().toSchema(), true);
        Schema finalSchema =  sb.toSchema();
        assertThat(finalSchema.getNameForms()).isNotEmpty();
        assertThat(finalSchema.getNameForms().size()).isEqualTo(2);
        assertThat(finalSchema.getWarnings()).isEmpty();
        final Iterator<NameForm> i = finalSchema.getNameForms().iterator();
        i.next(); // Jump the first element (== nf)
        final NameForm dolly = i.next();
        assertThat(dolly.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.36");
        assertThat(dolly.getRequiredAttributes().size()).isEqualTo(2);
        assertThat(dolly.getRequiredAttributes().toString()).contains("street");
        assertThat(dolly.getRequiredAttributes().toString()).contains("cn");
        assertThat(dolly.getOptionalAttributes().size()).isEqualTo(1);
        assertThat(dolly.getExtraProperty("X-ORIGIN").size()).isEqualTo(1);
        assertThat(dolly.getExtraProperty("FROM")).isEmpty();
    }
    /**
     * Clears attributes from a duplicated name form.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testDuplicatesNameFormAndClears() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final Builder nfb = new Builder("1.3.6.1.4.1.1466.115.121.1.35", sb);
        nfb.description("Description of the new form")
            .names("MyNewForm")
            .structuralObjectClassOID("person")
            .extraProperties("X-ORIGIN", "NameFormTestCase", "Forgerock", "extra")
            .extraProperties("FROM", "NameFormTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addNoOverwriteToSchema();
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms()).isNotEmpty();
        final NameForm nf = schema.getNameForms().iterator().next();
        assertThat(nf.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(nf.getRequiredAttributes().size()).isEqualTo(2);
        assertThat(nf.getOptionalAttributes().size()).isEqualTo(2);
        assertThat(nf.getExtraPropertyNames().size()).isEqualTo(2);
        sb.buildNameForm(nf)
            .removeAllNames()
            .names("Dolly")
            .removeName("thisOneDoesntExist")
            .oid("1.3.6.1.4.1.1466.115.121.1.36")
            .removeAllOptionalAttributes()
            .clearExtraProperties()
            .removeAllRequiredAttributes()
            .requiredAttributes("businessCategory")
            .addToSchema();
        schema = sb.toSchema();
        assertThat(schema.getNameForms()).isNotEmpty();
        assertThat(schema.getNameForms().size()).isEqualTo(2);
        assertThat(schema.getWarnings()).isEmpty();
        final Iterator<NameForm> i = schema.getNameForms().iterator();
        i.next(); // Jump the first element (== nf)
        final NameForm dolly = i.next();
        assertThat(dolly.getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.36");
        assertThat(dolly.getNames().size()).isEqualTo(1);
        assertThat(dolly.getNames().get(0)).isEqualTo("Dolly");
        assertThat(dolly.getRequiredAttributes().size()).isEqualTo(1);
        assertThat(dolly.getRequiredAttributes().iterator().next().getOID()).isEqualTo("2.5.4.15");
        assertThat(dolly.getRequiredAttributes().iterator().next().getNameOrOID()).isEqualTo("businessCategory");
        assertThat(dolly.getOptionalAttributes().size()).isEqualTo(0);
        assertThat(dolly.getExtraPropertyNames().size()).isEqualTo(0);
    }
    /**
     * Adds several name forms to the same schema builder.
     *
     * @throws SchemaException
     */
    @Test()
    public final void testAddsSeveralFormsToSchemaBuilder() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                .description("Description of the new form")
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormTestCase", "Forgerock", "extra")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addNoOverwriteToSchema()
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.36")
                .description("Description of the second form")
                .names("SecondForm")
                .structuralObjectClassOID("organization")
                .extraProperties("X-ORIGIN", "NameFormTestCase2")
                .requiredAttributes("name")
                .optionalAttributes("owner")
                .addNoOverwriteToSchema()
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.37")
                .description("Description of the third form")
                .names("ThirdForm")
                .structuralObjectClassOID("groupOfNames")
                .extraProperties("X-ORIGIN", "NameFormTestCase3", "ForgeRock")
                .requiredAttributes("sn", "l")
                .optionalAttributes("description", "uid")
                .description("Description of the third form")
                .addNoOverwriteToSchema()
                // we overwritten the third name form.
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.37")
                .names("ThirdFormOverwritten")
                .structuralObjectClassOID("groupOfNames")
                .extraProperties("X-ORIGIN", "RFC 2252")
                .requiredAttributes("sn", "l")
                .optionalAttributes("description", "uid")
                .addToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getNameForms().size()).isEqualTo(3);
        assertThat(schema.getNameForm("MyNewForm").getOID()).isEqualTo(
                "1.3.6.1.4.1.1466.115.121.1.35");
        assertThat(schema.getNameForm("SecondForm").getOID()).isEqualTo(
                "1.3.6.1.4.1.1466.115.121.1.36");
        // The third form is completely overwritten.
        assertThat(schema.getNameForm("ThirdFormOverwritten").getOID()).isEqualTo(
                "1.3.6.1.4.1.1466.115.121.1.37");
        assertThat(schema.getNameForm("ThirdFormOverwritten").getDescription()).isEmpty();
        assertThat(schema.getNameForm("ThirdFormOverwritten").getExtraProperty("X-ORIGIN").get(0))
                .isEqualTo("RFC 2252");
    }
}