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

Jean-Noël Rouvignac
25.53.2016 3edfdef912dc5193e9313c82ee851f145b0505fb
OPENDJ-2803 Migrate Attribute

Added AttributeDescription.getNameOrOID() + create() methods to return the user supplied attribute name
2 files modified
454 ■■■■ changed files
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java 232 ●●●●● patch | view | raw | blame | history
opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java 222 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -81,7 +81,6 @@
    private static final class MultiOptionImpl extends Impl {
        private final String[] normalizedOptions;
        private final String[] options;
        private MultiOptionImpl(final String[] options, final String[] normalizedOptions) {
@@ -203,7 +202,6 @@
    private static final class SingleOptionImpl extends Impl {
        private final String normalizedOption;
        private final String option;
        private SingleOptionImpl(final String option, final String normalizedOption) {
@@ -351,9 +349,8 @@
    private static final AttributeDescription OBJECT_CLASS;
    static {
        final AttributeType attributeType = Schema.getCoreSchema().getAttributeType("2.5.4.0");
        OBJECT_CLASS =
                new AttributeDescription(attributeType.getNameOrOID(), attributeType,
                        ZERO_OPTION_IMPL);
        final String attributeName = attributeType.getNameOrOID();
        OBJECT_CLASS = new AttributeDescription(attributeName, attributeName, attributeType, ZERO_OPTION_IMPL);
    }
    /**
@@ -378,21 +375,15 @@
        Reject.ifNull(option);
        final String normalizedOption = toLowerCase(option);
        if (pimpl.hasOption(normalizedOption)) {
        if (optionsPimpl.hasOption(normalizedOption)) {
            return this;
        }
        final String oldAttributeDescription = attributeDescription;
        final StringBuilder builder =
                new StringBuilder(oldAttributeDescription.length() + option.length() + 1);
        builder.append(oldAttributeDescription);
        builder.append(';');
        builder.append(option);
        final String newAttributeDescription = builder.toString();
        final String newAttributeDescription = appendOption(attributeDescription, option);
        final Impl impl = pimpl;
        final Impl impl = optionsPimpl;
        if (impl instanceof ZeroOptionImpl) {
            return new AttributeDescription(newAttributeDescription, attributeType,
            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                    new SingleOptionImpl(option, normalizedOption));
        } else if (impl instanceof SingleOptionImpl) {
            final SingleOptionImpl simpl = (SingleOptionImpl) impl;
@@ -410,7 +401,7 @@
                newNormalizedOptions[1] = normalizedOption;
            }
            return new AttributeDescription(newAttributeDescription, attributeType,
            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                    new MultiOptionImpl(newOptions, newNormalizedOptions));
        } else {
            final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
@@ -441,7 +432,7 @@
                newNormalizedOptions[sz2] = normalizedOption;
            }
            return new AttributeDescription(newAttributeDescription, attributeType,
            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                    new MultiOptionImpl(newOptions, newNormalizedOptions));
        }
    }
@@ -464,7 +455,7 @@
        Reject.ifNull(option);
        final String normalizedOption = toLowerCase(option);
        if (!pimpl.hasOption(normalizedOption)) {
        if (!optionsPimpl.hasOption(normalizedOption)) {
            return this;
        }
@@ -479,11 +470,11 @@
                .length());
        final String newAttributeDescription = builder.toString();
        final Impl impl = pimpl;
        final Impl impl = optionsPimpl;
        if (impl instanceof ZeroOptionImpl) {
            throw new IllegalStateException("ZeroOptionImpl unexpected");
        } else if (impl instanceof SingleOptionImpl) {
            return new AttributeDescription(newAttributeDescription, attributeType,
            return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                    ZERO_OPTION_IMPL);
        } else {
            final MultiOptionImpl mimpl = (MultiOptionImpl) impl;
@@ -503,7 +494,7 @@
                    remainingNormalizedOption = mimpl.normalizedOptions[0];
                }
                return new AttributeDescription(newAttributeDescription, attributeType,
                return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                        new SingleOptionImpl(remainingOption, remainingNormalizedOption));
            } else {
                final String[] newOptions = new String[mimpl.options.length - 1];
@@ -522,15 +513,14 @@
                    }
                }
                return new AttributeDescription(newAttributeDescription, attributeType,
                return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType,
                        new MultiOptionImpl(newOptions, newNormalizedOptions));
            }
        }
    }
    /**
     * Creates an attribute description having the provided attribute type and
     * no options.
     * Creates an attribute description having the provided attribute type and no options.
     *
     * @param attributeType
     *            The attribute type.
@@ -539,21 +529,35 @@
     *             If {@code attributeType} was {@code null}.
     */
    public static AttributeDescription create(final AttributeType attributeType) {
        Reject.ifNull(attributeType);
        // Use object identity in case attribute type does not come from
        // core schema.
        if (attributeType == OBJECT_CLASS.getAttributeType()) {
            return OBJECT_CLASS;
        } else {
            return new AttributeDescription(attributeType.getNameOrOID(), attributeType,
                    ZERO_OPTION_IMPL);
        }
        return create(attributeType.getNameOrOID(), attributeType);
    }
    /**
     * Creates an attribute description having the provided attribute type and
     * single option.
     * Creates an attribute description having the provided attribute name, type and no options.
     *
     * @param attributeName
     *            The attribute name.
     * @param attributeType
     *            The attribute type.
     * @return The attribute description.
     * @throws NullPointerException
     *             If {@code attributeType} was {@code null}.
     * @deprecated This method may be removed at any time
     * @since OPENDJ-2803 Migrate Attribute
     */
    @Deprecated
    public static AttributeDescription create(final String attributeName, final AttributeType attributeType) {
        Reject.ifNull(attributeName, attributeType);
        // Use object identity in case attribute type does not come from core schema.
        if (attributeType == OBJECT_CLASS.getAttributeType()) {
            return OBJECT_CLASS;
        }
        return new AttributeDescription(attributeName, attributeName, attributeType, ZERO_OPTION_IMPL);
    }
    /**
     * Creates an attribute description having the provided attribute type and single option.
     *
     * @param attributeType
     *            The attribute type.
@@ -564,18 +568,64 @@
     *             If {@code attributeType} or {@code option} was {@code null}.
     */
    public static AttributeDescription create(final AttributeType attributeType, final String option) {
        Reject.ifNull(attributeType, option);
        return create(attributeType.getNameOrOID(), attributeType, option);
    }
        final String oid = attributeType.getNameOrOID();
    /**
     * Creates an attribute description having the provided attribute name, type and single option.
     *
     * @param attributeName
     *            The attribute name.
     * @param attributeType
     *            The attribute type.
     * @param option
     *            The attribute option.
     * @return The attribute description.
     * @throws NullPointerException
     *             If {@code attributeType} or {@code option} was {@code null}.
     * @deprecated This method may be removed at any time
     * @since OPENDJ-2803 Migrate Attribute
     */
    @Deprecated
    public static AttributeDescription create(
            final String attributeName, final AttributeType attributeType, final String option) {
        Reject.ifNull(attributeName, attributeType, option);
        final String attributeDescription = appendOption(attributeName, option);
        final String normalizedOption = toLowerCase(option);
        return new AttributeDescription(attributeDescription, attributeName, attributeType,
            new SingleOptionImpl(option, normalizedOption));
    }
    private static String appendOption(final String oid, final String option) {
        final StringBuilder builder = new StringBuilder(oid.length() + option.length() + 1);
        builder.append(oid);
        builder.append(';');
        builder.append(option);
        final String attributeDescription = builder.toString();
        final String normalizedOption = toLowerCase(option);
        return builder.toString();
    }
        return new AttributeDescription(attributeDescription, attributeType, new SingleOptionImpl(
                option, normalizedOption));
    /**
     * Creates an attribute description having the provided attribute name, type and options.
     *
     * @param attributeName
     *            The attribute name.
     * @param attributeType
     *            The attribute type.
     * @param options
     *            The attribute options.
     * @return The attribute description.
     * @throws NullPointerException
     *             If {@code attributeType} or {@code options} was {@code null}.
     * @deprecated This method may be removed at any time
     * @since OPENDJ-2803 Migrate Attribute
     */
    @Deprecated
    public static AttributeDescription create(
            final String attributeName, final AttributeType attributeType, final String... options) {
        Reject.ifNull(options);
        return create(attributeName, attributeType, Arrays.asList(options));
    }
    /**
@@ -591,7 +641,7 @@
     */
    public static AttributeDescription create(final AttributeType attributeType, final String... options) {
        Reject.ifNull(options);
        return create(attributeType, Arrays.asList(options));
        return create(attributeType.getNameOrOID(), attributeType, Arrays.asList(options));
    }
    /**
@@ -606,23 +656,43 @@
     *             If {@code attributeType} or {@code options} was {@code null}.
     */
    public static AttributeDescription create(final AttributeType attributeType, final Collection<String> options) {
        Reject.ifNull(attributeType);
        return create(attributeType.getNameOrOID(), attributeType, options);
    }
    /**
     * Creates an attribute description having the provided attribute name, type and options.
     *
     * @param attributeName
     *            The attribute name.
     * @param attributeType
     *            The attribute type.
     * @param options
     *            The attribute options.
     * @return The attribute description.
     * @throws NullPointerException
     *             If {@code attributeType} or {@code options} was {@code null}.
     * @deprecated This method may be removed at any time
     * @since OPENDJ-2803 Migrate Attribute
     */
    @Deprecated
    public static AttributeDescription create(
            final String attributeName, final AttributeType attributeType, final Collection<String> options) {
        Reject.ifNull(attributeName, attributeType);
        final Collection<String> opts = options != null ? options : Collections.<String> emptySet();
        switch (opts.size()) {
        case 0:
            return create(attributeType);
            return create(attributeName, attributeType);
        case 1:
            return create(attributeType, opts.iterator().next());
            return create(attributeName, attributeType, opts.iterator().next());
        default:
            final String[] optionsList = new String[opts.size()];
            final String[] normalizedOptions = new String[opts.size()];
            final Iterator<String> it = opts.iterator();
            final String oid = attributeType.getNameOrOID();
            final StringBuilder builder =
                    new StringBuilder(oid.length() + it.next().length() + it.next().length() + 2);
            builder.append(oid);
                    new StringBuilder(attributeName.length() + it.next().length() + it.next().length() + 2);
            builder.append(attributeName);
            int i = 0;
            for (final String option : opts) {
@@ -634,10 +704,9 @@
            Arrays.sort(normalizedOptions);
            final String attributeDescription = builder.toString();
            return new AttributeDescription(attributeDescription, attributeType,
            return new AttributeDescription(attributeDescription, attributeName, attributeType,
                    new MultiOptionImpl(optionsList, normalizedOptions));
        }
    }
    /**
@@ -779,7 +848,6 @@
            i++;
            while (i < length) {
                c = attributeDescription.charAt(i);
                if (c == ';' || c == ' ') {
                    break;
                }
@@ -827,8 +895,7 @@
            i = skipTrailingWhiteSpace(attributeDescription, i + 1, length);
        }
        // Determine the portion of the string containing the attribute type
        // name.
        // Determine the portion of the string containing the attribute type name.
        String oid;
        if (attributeTypeStart == 0 && attributeTypeEnd == length) {
            oid = attributeDescription;
@@ -848,15 +915,12 @@
        // If we're already at the end of the attribute description then it
        // does not contain any options.
        if (i == length) {
            // Use object identity in case attribute type does not come from
            // core schema.
            // Use object identity in case attribute type does not come from core schema.
            if (attributeType == OBJECT_CLASS.getAttributeType()
                    && attributeDescription.equals(OBJECT_CLASS.toString())) {
                return OBJECT_CLASS;
            } else {
                return new AttributeDescription(attributeDescription, attributeType,
                        ZERO_OPTION_IMPL);
            }
            return new AttributeDescription(attributeDescription, oid, attributeType, ZERO_OPTION_IMPL);
        }
        // At this point 'i' must point at a semi-colon.
@@ -911,7 +975,7 @@
        // If we're already at the end of the attribute description then it
        // only contains a single option.
        if (i == length) {
            return new AttributeDescription(attributeDescription, attributeType,
            return new AttributeDescription(attributeDescription, oid, attributeType,
                    new SingleOptionImpl(option, normalizedOption));
        }
@@ -977,23 +1041,23 @@
            normalizedOptions.add(normalizedOption);
        }
        return new AttributeDescription(attributeDescription, attributeType, new MultiOptionImpl(
                options.toArray(new String[options.size()]), normalizedOptions
                        .toArray(new String[normalizedOptions.size()])));
        return new AttributeDescription(attributeDescription, oid, attributeType,
                new MultiOptionImpl(options.toArray(new String[options.size()]),
                                    normalizedOptions.toArray(new String[normalizedOptions.size()])));
    }
    private final String attributeDescription;
    private final String nameOrOid;
    private final AttributeType attributeType;
    private final Impl pimpl;
    private final Impl optionsPimpl;
    /** Private constructor. */
    private AttributeDescription(final String attributeDescription,
    private AttributeDescription(final String attributeDescription, final String attributeName,
            final AttributeType attributeType, final Impl pimpl) {
        this.attributeDescription = attributeDescription;
        this.nameOrOid = attributeName;
        this.attributeType = attributeType;
        this.pimpl = pimpl;
        this.optionsPimpl = pimpl;
    }
    /**
@@ -1016,7 +1080,7 @@
            return result;
        } else {
            // Attribute type is the same, so compare options.
            return pimpl.compareTo(other.pimpl);
            return optionsPimpl.compareTo(other.optionsPimpl);
        }
    }
@@ -1033,7 +1097,7 @@
     */
    public boolean hasOption(final String option) {
        final String normalizedOption = toLowerCase(option);
        return pimpl.hasOption(normalizedOption);
        return optionsPimpl.hasOption(normalizedOption);
    }
    /**
@@ -1054,7 +1118,7 @@
            return true;
        } else if (o instanceof AttributeDescription) {
            final AttributeDescription other = (AttributeDescription) o;
            return attributeType.equals(other.attributeType) && pimpl.equals(other.pimpl);
            return attributeType.equals(other.attributeType) && optionsPimpl.equals(other.optionsPimpl);
        } else {
            return false;
        }
@@ -1070,6 +1134,20 @@
    }
    /**
     * Returns the attribute name or the oid provided by the user associated with this attribute
     * description.
     *
     * @return The attribute name or the oid provided by the user associated with this attribute
     *         description.
     * @deprecated This method may be removed at any time
     * @since OPENDJ-2803 Migrate Attribute
     */
    @Deprecated
    public String getNameOrOID() {
        return nameOrOid;
    }
    /**
     * Returns an {@code Iterable} containing the options contained in this
     * attribute description. Attempts to remove options using an iterator's
     * {@code remove()} method are not permitted and will result in an
@@ -1078,7 +1156,7 @@
     * @return An {@code Iterable} containing the options.
     */
    public Iterable<String> getOptions() {
        return pimpl;
        return optionsPimpl;
    }
    /**
@@ -1091,7 +1169,7 @@
    @Override
    public int hashCode() {
        // FIXME: should we cache this?
        return attributeType.hashCode() * 31 + pimpl.hashCode();
        return attributeType.hashCode() * 31 + optionsPimpl.hashCode();
    }
    /**
@@ -1101,7 +1179,7 @@
     *         {@code false} if not.
     */
    public boolean hasOptions() {
        return pimpl.hasOptions();
        return optionsPimpl.hasOptions();
    }
    /**
@@ -1160,7 +1238,7 @@
     */
    public boolean isSubTypeOf(final AttributeDescription other) {
        return attributeType.isSubTypeOf(other.attributeType)
            && pimpl.isSubTypeOf(other.pimpl);
            && optionsPimpl.isSubTypeOf(other.optionsPimpl);
    }
    /**
@@ -1187,7 +1265,7 @@
     */
    public boolean isSuperTypeOf(final AttributeDescription other) {
        return attributeType.isSuperTypeOf(other.attributeType)
            && pimpl.isSuperTypeOf(other.pimpl);
            && optionsPimpl.isSuperTypeOf(other.optionsPimpl);
    }
    /**
@@ -1205,7 +1283,7 @@
        if (this == other) {
            return true;
        } else {
            return attributeType.matches(other.attributeType) && pimpl.equals(other.pimpl);
            return attributeType.matches(other.attributeType) && optionsPimpl.equals(other.optionsPimpl);
        }
    }
opendj-sdk/opendj-core/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
@@ -21,9 +21,11 @@
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;
import java.util.Iterator;
import java.util.Arrays;
import org.assertj.core.api.Assertions;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.forgerock.opendj.ldap.schema.Schema;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -161,7 +163,10 @@
            { "cn;BAR;FOO", "cn", new String[] { "BAR", "FOO" }, true },
            { " cn;BAR;FOO ", "cn", new String[] { "BAR", "FOO" }, true },
            { "  cn;BAR;FOO  ", "cn", new String[] { "BAR", "FOO" }, true },
            { "  CN;BAR;FOO  ", "CN", new String[] { "BAR", "FOO" }, true },
            { "cn;xxx;yyy;zzz", "cn", new String[] { "xxx", "yyy", "zzz" }, false },
            { "cn;zzz;YYY;xxx", "cn", new String[] { "zzz", "YYY", "xxx" }, false },
            { "CN;zzz;YYY;xxx", "CN", new String[] { "zzz", "YYY", "xxx" }, false },
        };
        // @formatter:on
    }
@@ -224,15 +229,14 @@
                AttributeDescription.valueOf(ad, Schema.getCoreSchema());
        assertEquals(attributeDescription.toString(), ad);
        assertEquals(attributeDescription.getNameOrOID(), ad);
        assertEquals(attributeDescription.getAttributeType().getNameOrOID(), at);
        assertEquals(attributeDescription.isObjectClass(), isObjectClass);
        assertFalse(attributeDescription.hasOptions());
        assertFalse(attributeDescription.hasOption("dummy"));
        final Iterator<String> iterator = attributeDescription.getOptions().iterator();
        assertFalse(iterator.hasNext());
        Assertions.assertThat(attributeDescription.getOptions()).isEmpty();
    }
    /** FIXME: none of these pass! The valueOf method is far too lenient. */
@@ -252,8 +256,7 @@
        assertEquals(attributeDescription.getAttributeType().getNameOrOID(), at);
        assertFalse(attributeDescription.isObjectClass());
        assertEquals(attributeDescription.hasOptions(), options.length != 0);
        assertOptions(attributeDescription, options);
        assertFalse(attributeDescription.hasOption("dummy"));
        if (containsFoo) {
            assertTrue(attributeDescription.hasOption("foo"));
@@ -264,28 +267,24 @@
            assertFalse(attributeDescription.hasOption("FOO"));
            assertFalse(attributeDescription.hasOption("FoO"));
        }
    }
    private void assertOptions(final AttributeDescription attributeDescription, final String... options) {
        assertEquals(attributeDescription.hasOptions(), options.length != 0);
        for (final String option : options) {
            assertTrue(attributeDescription.hasOption(option));
        }
        final Iterator<String> iterator = attributeDescription.getOptions().iterator();
        for (final String option : options) {
            assertTrue(iterator.hasNext());
            assertEquals(iterator.next(), option);
        }
        assertFalse(iterator.hasNext());
        Assertions.assertThat(attributeDescription.getOptions()).containsExactly(options);
    }
    @Test
    public void testWithOptionAddFirstOption() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn");
        AttributeDescription ad2 = ad1.withOption("test");
        assertTrue(ad2.hasOptions());
        assertTrue(ad2.hasOption("test"));
        assertOptions(ad2, "test");
        assertFalse(ad2.hasOption("dummy"));
        assertEquals(ad2.toString(), "cn;test");
        assertEquals(ad2.getOptions().iterator().next(), "test");
    }
    @Test
@@ -297,16 +296,20 @@
    @Test
    public void testWithOptionAddSecondOption() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1");
        AttributeDescription ad2 = ad1.withOption("test2");
        assertTrue(ad2.hasOptions());
        assertTrue(ad2.hasOption("test1"));
        assertTrue(ad2.hasOption("test2"));
        testWithOptionAddSecondOption("test1", "test2");
    }
    @Test
    public void testWithOptionAddSecondOption2() {
        testWithOptionAddSecondOption("test2", "test1");
    }
    private void testWithOptionAddSecondOption(String option1, String option2) {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;" + option1);
        AttributeDescription ad2 = ad1.withOption(option2);
        assertOptions(ad2, option1, option2);
        assertFalse(ad2.hasOption("dummy"));
        assertEquals(ad2.toString(), "cn;test1;test2");
        Iterator<String> i = ad2.getOptions().iterator();
        assertEquals(i.next(), "test1");
        assertEquals(i.next(), "test2");
        assertEquals(ad2.toString(), toAttributeDescriptionString("cn", option1, option2));
    }
    @Test
@@ -319,6 +322,24 @@
    }
    @Test
    public void testWithOptionAddMultipleOptions() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
        AttributeDescription ad2 = ad1.withOption("test4").withOption("test3");
        assertOptions(ad2, "test1", "test2", "test4", "test3");
        assertFalse(ad2.hasOption("dummy"));
        assertEquals(ad2.toString(), "cn;test1;test2;test4;test3");
    }
    @Test
    public void testWithOptionAddMultipleOptions2() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
        AttributeDescription ad2 = ad1.withOption("test0");
        assertOptions(ad2, "test1", "test2", "test0");
        assertFalse(ad2.hasOption("dummy"));
        assertEquals(ad2.toString(), "cn;test1;test2;test0");
    }
    @Test
    public void testWithoutOptionEmpty() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn");
        AttributeDescription ad2 = ad1.withoutOption("test");
@@ -329,10 +350,9 @@
    public void testWithoutOptionFirstOption() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test");
        AttributeDescription ad2 = ad1.withoutOption("test");
        assertFalse(ad2.hasOptions());
        assertOptions(ad2);
        assertFalse(ad2.hasOption("test"));
        assertEquals(ad2.toString(), "cn");
        assertFalse(ad2.getOptions().iterator().hasNext());
    }
    @Test
@@ -346,22 +366,18 @@
    public void testWithoutOptionSecondOption1() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
        AttributeDescription ad2 = ad1.withoutOption("test1");
        assertTrue(ad2.hasOptions());
        assertOptions(ad2, "test2");
        assertFalse(ad2.hasOption("test1"));
        assertTrue(ad2.hasOption("test2"));
        assertEquals(ad2.toString(), "cn;test2");
        assertEquals(ad2.getOptions().iterator().next(), "test2");
    }
    @Test
    public void testWithoutOptionSecondOption2() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
        AttributeDescription ad2 = ad1.withoutOption("test2");
        assertTrue(ad2.hasOptions());
        assertTrue(ad2.hasOption("test1"));
        assertOptions(ad2, "test1");
        assertFalse(ad2.hasOption("test2"));
        assertEquals(ad2.toString(), "cn;test1");
        assertEquals(ad2.getOptions().iterator().next(), "test1");
    }
    @Test
@@ -375,42 +391,27 @@
    public void testWithoutOptionThirdOption1() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
        AttributeDescription ad2 = ad1.withoutOption("test1");
        assertTrue(ad2.hasOptions());
        assertOptions(ad2, "test2", "test3");
        assertFalse(ad2.hasOption("test1"));
        assertTrue(ad2.hasOption("test2"));
        assertTrue(ad2.hasOption("test3"));
        assertEquals(ad2.toString(), "cn;test2;test3");
        Iterator<String> i = ad2.getOptions().iterator();
        assertEquals(i.next(), "test2");
        assertEquals(i.next(), "test3");
    }
    @Test
    public void testWithoutOptionThirdOption2() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
        AttributeDescription ad2 = ad1.withoutOption("test2");
        assertTrue(ad2.hasOptions());
        assertTrue(ad2.hasOption("test1"));
        assertOptions(ad2, "test1", "test3");
        assertFalse(ad2.hasOption("test2"));
        assertTrue(ad2.hasOption("test3"));
        assertEquals(ad2.toString(), "cn;test1;test3");
        Iterator<String> i = ad2.getOptions().iterator();
        assertEquals(i.next(), "test1");
        assertEquals(i.next(), "test3");
    }
    @Test
    public void testWithoutOptionThirdOption3() {
        AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
        AttributeDescription ad2 = ad1.withoutOption("test3");
        assertTrue(ad2.hasOptions());
        assertTrue(ad2.hasOption("test1"));
        assertTrue(ad2.hasOption("test2"));
        assertOptions(ad2, "test1", "test2");
        assertFalse(ad2.hasOption("test3"));
        assertEquals(ad2.toString(), "cn;test1;test2");
        Iterator<String> i = ad2.getOptions().iterator();
        assertEquals(i.next(), "test1");
        assertEquals(i.next(), "test2");
    }
    @Test
@@ -419,4 +420,125 @@
        AttributeDescription ad2 = ad1.withoutOption("dummy");
        assertSame(ad1, ad2);
    }
    @Test
    public void testCreateAttributeType() {
        Schema schema = Schema.getCoreSchema();
        AttributeType attributeType = schema.getAttributeType("cn");
        String name = attributeType.getNameOrOID();
        assertAttributeDescriptionCreate(
            AttributeDescription.create(attributeType),
            name, attributeType);
    }
    @Test
    public void testCreateAttributeNameAndType() {
        Schema schema = Schema.getCoreSchema();
        String name = "CN";
        AttributeType attributeType = schema.getAttributeType(name);
        assertAttributeDescriptionCreate(
            AttributeDescription.create(name, attributeType),
            name, attributeType);
    }
    @Test
    public void testCreateAttributeTypeAndOption() {
        Schema schema = Schema.getCoreSchema();
        AttributeType attributeType = schema.getAttributeType("cn");
        String name = attributeType.getNameOrOID();
        assertAttributeDescriptionCreate(
            AttributeDescription.create(attributeType, "option"),
            name, attributeType, "option");
    }
    @Test
    public void testCreateAttributeNameTypeAndOption() {
        Schema schema = Schema.getCoreSchema();
        String name = "CN";
        AttributeType attributeType = schema.getAttributeType(name);
        assertAttributeDescriptionCreate(
            AttributeDescription.create(name, attributeType, "option"),
            name, attributeType, "option");
    }
    @Test
    public void testCreateAttributeTypeAndOptionsArray() {
        Schema schema = Schema.getCoreSchema();
        AttributeType attributeType = schema.getAttributeType("cn");
        String name = attributeType.getNameOrOID();
        String[] options = { "option1", "option2" };
        assertAttributeDescriptionCreate(
            AttributeDescription.create(attributeType, options),
            name, attributeType, options);
    }
    @Test
    public void testCreateAttributeNameTypeAndOptionsArray() {
        Schema schema = Schema.getCoreSchema();
        String name = "CN";
        AttributeType attributeType = schema.getAttributeType(name);
        String[] options = { "option1", "option2" };
        assertAttributeDescriptionCreate(
            AttributeDescription.create(name, attributeType, options),
            name, attributeType, options);
    }
    @Test
    public void testCreateAttributeTypeAndOptionsCollection() {
        Schema schema = Schema.getCoreSchema();
        AttributeType attributeType = schema.getAttributeType("cn");
        String name = attributeType.getNameOrOID();
        String[] options = { "option1", "option2" };
        assertAttributeDescriptionCreate(
            AttributeDescription.create(attributeType, Arrays.asList(options)),
            name, attributeType, options);
    }
    @Test
    public void testCreateAttributeNameTypeAndNoOptionsCollection() {
        testCreateAttributeNameTypeAndOptionsCollection();
    }
    @Test
    public void testCreateAttributeNameTypeAndOneOptionCollection() {
        testCreateAttributeNameTypeAndOptionsCollection("option");
    }
    @Test
    public void testCreateAttributeNameTypeAndTwoOptionsCollection() {
        testCreateAttributeNameTypeAndOptionsCollection("option1", "option2");
    }
    private void testCreateAttributeNameTypeAndOptionsCollection(String... options) {
        Schema schema = Schema.getCoreSchema();
        String name = "CN";
        AttributeType attributeType = schema.getAttributeType(name);
        assertAttributeDescriptionCreate(
            AttributeDescription.create(name, attributeType, Arrays.asList(options)),
            name, attributeType, options);
    }
    private void assertAttributeDescriptionCreate(AttributeDescription attrDesc,
            String name, AttributeType attributeType, String... options) {
        assertEquals(attrDesc.getAttributeType(), attributeType);
        assertEquals(attrDesc.getNameOrOID(), name);
        assertOptions(attrDesc, options);
        assertEquals(attrDesc.toString(), toAttributeDescriptionString(name, options));
    }
    private String toAttributeDescriptionString(String name, String... options) {
        StringBuilder sb = new StringBuilder(name);
        for (String option : options) {
            sb.append(";").append(option);
        }
        return sb.toString();
    }
}