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

Violette Roche-Montane
10.26.2013 0918f144f87f0ffbc650faa77b5593bda27abd83
CR-2688 OPENDJ-1230 SDK Builder for Matching rules
1 files added
5 files modified
1529 ■■■■ changed files
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java 288 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java 211 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java 6 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java 200 ●●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java 754 ●●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java 70 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
@@ -22,6 +22,7 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS.
 */
package org.forgerock.opendj.ldap.schema;
@@ -62,8 +63,8 @@
    private static final Map<String, List<String>> RFC5020_ORIGIN = Collections.singletonMap(
            SCHEMA_PROPERTY_ORIGIN, Collections.singletonList("RFC 5020"));
    static final Map<String, List<String>> OPENDS_ORIGIN = Collections.singletonMap(
            SCHEMA_PROPERTY_ORIGIN, Collections.singletonList("OpenDS Directory Server"));
    static final Map<String, List<String>> OPENDJ_ORIGIN = Collections.singletonMap(
            SCHEMA_PROPERTY_ORIGIN, Collections.singletonList("OpenDJ Directory Server"));
    private static final String EMPTY_STRING = "".intern();
@@ -107,10 +108,11 @@
    private static void addRFC3112(final SchemaBuilder builder) {
        builder.addSyntax(SYNTAX_AUTH_PASSWORD_OID, SYNTAX_AUTH_PASSWORD_DESCRIPTION,
                RFC3112_ORIGIN, new AuthPasswordSyntaxImpl(), false);
        builder.addMatchingRule(EMR_AUTH_PASSWORD_EXACT_OID, Collections
                .singletonList(EMR_AUTH_PASSWORD_EXACT_NAME), EMR_AUTH_PASSWORD_EXACT_DESCRIPTION,
                false, SYNTAX_AUTH_PASSWORD_OID, RFC3112_ORIGIN,
                new AuthPasswordExactEqualityMatchingRuleImpl(), false);
        builder.buildMatchingRule(EMR_AUTH_PASSWORD_EXACT_OID)
                .names(EMR_AUTH_PASSWORD_EXACT_NAME)
                .description(EMR_AUTH_PASSWORD_EXACT_DESCRIPTION).syntaxOID(SYNTAX_AUTH_PASSWORD_OID)
                .extraProperties(RFC3112_ORIGIN).implementation(new AuthPasswordExactEqualityMatchingRuleImpl())
                .addToSchema();
        builder.addAttributeType("1.3.6.1.4.1.4203.1.3.3", Collections
                .singletonList("supportedAuthPasswordSchemes"),
                "supported password storage schemes", false, null, EMR_CASE_EXACT_IA5_OID, null,
@@ -549,14 +551,13 @@
    }
    private static void addRFC4530(final SchemaBuilder builder) {
        builder.addSyntax(SYNTAX_UUID_OID, SYNTAX_UUID_DESCRIPTION, RFC4530_ORIGIN,
                new UUIDSyntaxImpl(), false);
        builder.addMatchingRule(EMR_UUID_OID, Collections.singletonList(EMR_UUID_NAME),
                EMPTY_STRING, false, SYNTAX_UUID_OID, RFC4530_ORIGIN,
                new UUIDEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_UUID_OID, Collections.singletonList(OMR_UUID_NAME),
                EMPTY_STRING, false, SYNTAX_UUID_OID, RFC4530_ORIGIN,
                new UUIDOrderingMatchingRuleImpl(), false);
        builder.addSyntax(SYNTAX_UUID_OID, SYNTAX_UUID_DESCRIPTION, RFC4530_ORIGIN, new UUIDSyntaxImpl(), false);
        builder.buildMatchingRule(EMR_UUID_OID).names(EMR_UUID_NAME).syntaxOID(SYNTAX_UUID_OID)
                .extraProperties(RFC4530_ORIGIN).implementation(new UUIDEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(OMR_UUID_OID).names(OMR_UUID_NAME).syntaxOID(SYNTAX_UUID_OID)
                .extraProperties(RFC4530_ORIGIN).implementation(new UUIDOrderingMatchingRuleImpl())
                .addToSchema();
        builder.addAttributeType("1.3.6.1.1.16.4", Collections.singletonList("entryUUID"),
                "UUID of the entry", false, null, EMR_UUID_OID, OMR_UUID_OID, null, null,
                SYNTAX_UUID_OID, true, false, true, AttributeUsage.DIRECTORY_OPERATION,
@@ -572,16 +573,16 @@
    private static void addSunProprietary(final SchemaBuilder builder) {
        builder.addSyntax(SYNTAX_USER_PASSWORD_OID, SYNTAX_USER_PASSWORD_DESCRIPTION,
                OPENDS_ORIGIN, new UserPasswordSyntaxImpl(), false);
        builder.addMatchingRule(EMR_USER_PASSWORD_EXACT_OID, Collections
                .singletonList(EMR_USER_PASSWORD_EXACT_NAME), EMR_USER_PASSWORD_EXACT_DESCRIPTION,
                false, SYNTAX_USER_PASSWORD_OID, OPENDS_ORIGIN,
                new UserPasswordExactEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(AMR_DOUBLE_METAPHONE_OID, Collections
                .singletonList(AMR_DOUBLE_METAPHONE_NAME), AMR_DOUBLE_METAPHONE_DESCRIPTION, false,
                SYNTAX_DIRECTORY_STRING_OID, OPENDS_ORIGIN,
                new DoubleMetaphoneApproximateMatchingRuleImpl(), false);
                OPENDJ_ORIGIN, new UserPasswordSyntaxImpl(), false);
        builder.buildMatchingRule(EMR_USER_PASSWORD_EXACT_OID)
                .names(Collections.singletonList(EMR_USER_PASSWORD_EXACT_NAME))
                .description(EMR_USER_PASSWORD_EXACT_DESCRIPTION).syntaxOID(SYNTAX_USER_PASSWORD_OID)
                .extraProperties(OPENDJ_ORIGIN).implementation(new UserPasswordExactEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(AMR_DOUBLE_METAPHONE_OID).names(Collections.singletonList(AMR_DOUBLE_METAPHONE_NAME))
                .description(AMR_DOUBLE_METAPHONE_DESCRIPTION).syntaxOID(SYNTAX_DIRECTORY_STRING_OID)
                .extraProperties(OPENDJ_ORIGIN).implementation(new DoubleMetaphoneApproximateMatchingRuleImpl())
                .addToSchema();
    }
    private static void defaultAttributeTypes(final SchemaBuilder builder) {
@@ -699,139 +700,118 @@
    }
    private static void defaultMatchingRules(final SchemaBuilder builder) {
        builder.addMatchingRule(EMR_BIT_STRING_OID, Collections.singletonList(EMR_BIT_STRING_NAME),
                EMPTY_STRING, false, SYNTAX_BIT_STRING_OID, RFC4512_ORIGIN,
                new BitStringEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_BOOLEAN_OID, Collections.singletonList(EMR_BOOLEAN_NAME),
                EMPTY_STRING, false, SYNTAX_BOOLEAN_OID, RFC4512_ORIGIN,
                new BooleanEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_CASE_EXACT_IA5_OID, Collections
                .singletonList(EMR_CASE_EXACT_IA5_NAME), EMPTY_STRING, false,
                SYNTAX_IA5_STRING_OID, RFC4512_ORIGIN, new CaseExactIA5EqualityMatchingRuleImpl(),
                false);
        builder.addMatchingRule(SMR_CASE_EXACT_IA5_OID, Collections
                .singletonList(SMR_CASE_EXACT_IA5_NAME), EMPTY_STRING, false,
                SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new CaseExactIA5SubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_CASE_EXACT_OID, Collections.singletonList(EMR_CASE_EXACT_NAME),
                EMPTY_STRING, false, SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new CaseExactEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_CASE_EXACT_OID, Collections.singletonList(OMR_CASE_EXACT_NAME),
                EMPTY_STRING, false, SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new CaseExactOrderingMatchingRuleImpl(), false);
        builder.addMatchingRule(SMR_CASE_EXACT_OID, Collections.singletonList(SMR_CASE_EXACT_NAME),
                EMPTY_STRING, false, SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new CaseExactSubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_CASE_IGNORE_IA5_OID, Collections
                .singletonList(EMR_CASE_IGNORE_IA5_NAME), EMPTY_STRING, false,
                SYNTAX_IA5_STRING_OID, RFC4512_ORIGIN, new CaseIgnoreIA5EqualityMatchingRuleImpl(),
                false);
        builder.addMatchingRule(SMR_CASE_IGNORE_IA5_OID, Collections
                .singletonList(SMR_CASE_IGNORE_IA5_NAME), EMPTY_STRING, false,
                SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new CaseIgnoreIA5SubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_CASE_IGNORE_LIST_OID, Collections
                .singletonList(EMR_CASE_IGNORE_LIST_NAME), EMPTY_STRING, false,
                SYNTAX_POSTAL_ADDRESS_OID, RFC4512_ORIGIN,
                new CaseIgnoreListEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(SMR_CASE_IGNORE_LIST_OID, Collections
                .singletonList(SMR_CASE_IGNORE_LIST_NAME), EMPTY_STRING, false,
                SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new CaseIgnoreListSubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_CASE_IGNORE_OID, Collections
                .singletonList(EMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
                SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new CaseIgnoreEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_CASE_IGNORE_OID, Collections
                .singletonList(OMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
                SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new CaseIgnoreOrderingMatchingRuleImpl(), false);
        builder.addMatchingRule(SMR_CASE_IGNORE_OID, Collections
                .singletonList(SMR_CASE_IGNORE_NAME), EMPTY_STRING, false,
                SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new CaseIgnoreSubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_DIRECTORY_STRING_FIRST_COMPONENT_OID, Collections
                .singletonList(EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME), EMPTY_STRING, false,
                SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new DirectoryStringFirstComponentEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_DN_OID, Collections.singletonList(EMR_DN_NAME), EMPTY_STRING,
                false, SYNTAX_DN_OID, RFC4512_ORIGIN,
                new DistinguishedNameEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_GENERALIZED_TIME_OID, Collections
                .singletonList(EMR_GENERALIZED_TIME_NAME), EMPTY_STRING, false,
                SYNTAX_GENERALIZED_TIME_OID, RFC4512_ORIGIN,
                new GeneralizedTimeEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_GENERALIZED_TIME_OID, Collections
                .singletonList(OMR_GENERALIZED_TIME_NAME), EMPTY_STRING, false,
                SYNTAX_GENERALIZED_TIME_OID, RFC4512_ORIGIN,
                new GeneralizedTimeOrderingMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_INTEGER_FIRST_COMPONENT_OID, Collections
                .singletonList(EMR_INTEGER_FIRST_COMPONENT_NAME), EMPTY_STRING, false,
                SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
                new IntegerFirstComponentEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_INTEGER_OID, Collections.singletonList(EMR_INTEGER_NAME),
                EMPTY_STRING, false, SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
                new IntegerEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_INTEGER_OID, Collections.singletonList(OMR_INTEGER_NAME),
                EMPTY_STRING, false, SYNTAX_INTEGER_OID, RFC4512_ORIGIN,
                new IntegerOrderingMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_KEYWORD_OID, Collections.singletonList(EMR_KEYWORD_NAME),
                EMPTY_STRING, false, SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new KeywordEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_NUMERIC_STRING_OID, Collections
                .singletonList(EMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_NUMERIC_STRING_OID, RFC4512_ORIGIN,
                new NumericStringEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(OMR_NUMERIC_STRING_OID, Collections
                .singletonList(OMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_NUMERIC_STRING_OID, RFC4512_ORIGIN,
                new NumericStringOrderingMatchingRuleImpl(), false);
        builder.addMatchingRule(SMR_NUMERIC_STRING_OID, Collections
                .singletonList(SMR_NUMERIC_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new NumericStringSubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_OID_FIRST_COMPONENT_OID, Collections
                .singletonList(EMR_OID_FIRST_COMPONENT_NAME), EMPTY_STRING, false, SYNTAX_OID_OID,
                RFC4512_ORIGIN, new ObjectIdentifierFirstComponentEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_OID_OID, Collections.singletonList(EMR_OID_NAME), EMPTY_STRING,
                false, SYNTAX_OID_OID, RFC4512_ORIGIN,
                new ObjectIdentifierEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_OCTET_STRING_OID, Collections
                .singletonList(EMR_OCTET_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_OCTET_STRING_OID, RFC4512_ORIGIN, new OctetStringEqualityMatchingRuleImpl(),
                false);
        builder.addMatchingRule(OMR_OCTET_STRING_OID, Collections
                .singletonList(OMR_OCTET_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_OCTET_STRING_OID, RFC4512_ORIGIN, new OctetStringOrderingMatchingRuleImpl(),
                false);
        builder.buildMatchingRule(EMR_BIT_STRING_OID).names(EMR_BIT_STRING_NAME).syntaxOID(SYNTAX_BIT_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new BitStringEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_BOOLEAN_OID).names(EMR_BOOLEAN_NAME).syntaxOID(SYNTAX_BOOLEAN_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new BooleanEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_CASE_EXACT_IA5_OID).names(EMR_CASE_EXACT_IA5_NAME)
                .syntaxOID(SYNTAX_IA5_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseExactIA5EqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(SMR_CASE_EXACT_IA5_OID).names(SMR_CASE_EXACT_IA5_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseExactIA5SubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_CASE_EXACT_OID).names(EMR_CASE_EXACT_NAME).syntaxOID(SYNTAX_DIRECTORY_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new CaseExactEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(OMR_CASE_EXACT_OID).names(OMR_CASE_EXACT_NAME).syntaxOID(SYNTAX_DIRECTORY_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new CaseExactOrderingMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(SMR_CASE_EXACT_OID).names(SMR_CASE_EXACT_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseExactSubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_CASE_IGNORE_IA5_OID).names(EMR_CASE_IGNORE_IA5_NAME)
                .syntaxOID(SYNTAX_IA5_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreIA5EqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(SMR_CASE_IGNORE_IA5_OID).names(SMR_CASE_IGNORE_IA5_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreIA5SubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_CASE_IGNORE_LIST_OID).names(EMR_CASE_IGNORE_LIST_NAME)
                .syntaxOID(SYNTAX_POSTAL_ADDRESS_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreListEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(SMR_CASE_IGNORE_LIST_OID).names(SMR_CASE_IGNORE_LIST_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreListSubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_CASE_IGNORE_OID).names(EMR_CASE_IGNORE_NAME)
                .syntaxOID(SYNTAX_DIRECTORY_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(OMR_CASE_IGNORE_OID).names(OMR_CASE_IGNORE_NAME)
                .syntaxOID(SYNTAX_DIRECTORY_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreOrderingMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(SMR_CASE_IGNORE_OID).names(SMR_CASE_IGNORE_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new CaseIgnoreSubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_DIRECTORY_STRING_FIRST_COMPONENT_OID)
                .names(Collections.singletonList(EMR_DIRECTORY_STRING_FIRST_COMPONENT_NAME))
                .syntaxOID(SYNTAX_DIRECTORY_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_DN_OID).names(EMR_DN_NAME).syntaxOID(SYNTAX_DN_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new DistinguishedNameEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_GENERALIZED_TIME_OID).names(EMR_GENERALIZED_TIME_NAME)
                .syntaxOID(SYNTAX_GENERALIZED_TIME_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new GeneralizedTimeEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(OMR_GENERALIZED_TIME_OID).names(OMR_GENERALIZED_TIME_NAME)
                .syntaxOID(SYNTAX_GENERALIZED_TIME_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new GeneralizedTimeOrderingMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_INTEGER_FIRST_COMPONENT_OID).names(EMR_INTEGER_FIRST_COMPONENT_NAME)
                .syntaxOID(SYNTAX_INTEGER_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new IntegerFirstComponentEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_INTEGER_OID).names(EMR_INTEGER_NAME).syntaxOID(SYNTAX_INTEGER_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new IntegerEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(OMR_INTEGER_OID).names(OMR_INTEGER_NAME).syntaxOID(SYNTAX_INTEGER_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new IntegerOrderingMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_KEYWORD_OID).names(EMR_KEYWORD_NAME).syntaxOID(SYNTAX_DIRECTORY_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new KeywordEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_NUMERIC_STRING_OID).names(EMR_NUMERIC_STRING_NAME)
                .syntaxOID(SYNTAX_NUMERIC_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new NumericStringEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(OMR_NUMERIC_STRING_OID).names(OMR_NUMERIC_STRING_NAME)
                .syntaxOID(SYNTAX_NUMERIC_STRING_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new NumericStringOrderingMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(SMR_NUMERIC_STRING_OID).names(SMR_NUMERIC_STRING_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new NumericStringSubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_OID_FIRST_COMPONENT_OID).names(EMR_OID_FIRST_COMPONENT_NAME)
                .syntaxOID(SYNTAX_OID_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new ObjectIdentifierFirstComponentEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_OID_OID).names(EMR_OID_NAME).syntaxOID(SYNTAX_OID_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new ObjectIdentifierEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(EMR_OCTET_STRING_OID).names(EMR_OCTET_STRING_NAME).syntaxOID(SYNTAX_OCTET_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new OctetStringEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(OMR_OCTET_STRING_OID).names(OMR_OCTET_STRING_NAME).syntaxOID(SYNTAX_OCTET_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new OctetStringOrderingMatchingRuleImpl())
                .addToSchema();
        // SMR octet string is not in any LDAP RFC and its from X.500
        builder.addMatchingRule(SMR_OCTET_STRING_OID, Collections
                .singletonList(SMR_OCTET_STRING_NAME), EMPTY_STRING, false,
                SYNTAX_OCTET_STRING_OID, X500_ORIGIN, new OctetStringSubstringMatchingRuleImpl(),
                false);
        builder.buildMatchingRule(SMR_OCTET_STRING_OID).names(SMR_OCTET_STRING_NAME).syntaxOID(SYNTAX_OCTET_STRING_OID)
                .extraProperties(X500_ORIGIN).implementation(new OctetStringSubstringMatchingRuleImpl())
                .addToSchema();
        // Depreciated in RFC 4512
        builder.addMatchingRule(EMR_PROTOCOL_INFORMATION_OID, Collections
                .singletonList(EMR_PROTOCOL_INFORMATION_NAME), EMPTY_STRING, false,
                SYNTAX_PROTOCOL_INFORMATION_OID, RFC2252_ORIGIN,
                new ProtocolInformationEqualityMatchingRuleImpl(), false);
        builder.buildMatchingRule(EMR_PROTOCOL_INFORMATION_OID).names(EMR_PROTOCOL_INFORMATION_NAME)
                .syntaxOID(SYNTAX_PROTOCOL_INFORMATION_OID).extraProperties(RFC2252_ORIGIN)
                .implementation(new ProtocolInformationEqualityMatchingRuleImpl()).addToSchema();
        // Depreciated in RFC 4512
        builder.addMatchingRule(EMR_PRESENTATION_ADDRESS_OID, Collections
                .singletonList(EMR_PRESENTATION_ADDRESS_NAME), EMPTY_STRING, false,
                SYNTAX_PRESENTATION_ADDRESS_OID, RFC2252_ORIGIN,
                new PresentationAddressEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_TELEPHONE_OID, Collections.singletonList(EMR_TELEPHONE_NAME),
                EMPTY_STRING, false, SYNTAX_TELEPHONE_OID, RFC4512_ORIGIN,
                new TelephoneNumberEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(SMR_TELEPHONE_OID, Collections.singletonList(SMR_TELEPHONE_NAME),
                EMPTY_STRING, false, SYNTAX_SUBSTRING_ASSERTION_OID, RFC4512_ORIGIN,
                new TelephoneNumberSubstringMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_UNIQUE_MEMBER_OID, Collections
                .singletonList(EMR_UNIQUE_MEMBER_NAME), EMPTY_STRING, false,
                SYNTAX_NAME_AND_OPTIONAL_UID_OID, RFC4512_ORIGIN,
                new UniqueMemberEqualityMatchingRuleImpl(), false);
        builder.addMatchingRule(EMR_WORD_OID, Collections.singletonList(EMR_WORD_NAME),
                EMPTY_STRING, false, SYNTAX_DIRECTORY_STRING_OID, RFC4512_ORIGIN,
                new WordEqualityMatchingRuleImpl(), false);
        builder.buildMatchingRule(EMR_PRESENTATION_ADDRESS_OID).names(EMR_PRESENTATION_ADDRESS_NAME)
                .syntaxOID(SYNTAX_PRESENTATION_ADDRESS_OID).extraProperties(RFC2252_ORIGIN)
                .implementation(new PresentationAddressEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_TELEPHONE_OID).names(EMR_TELEPHONE_NAME).syntaxOID(SYNTAX_TELEPHONE_OID)
                .extraProperties(RFC2252_ORIGIN).implementation(new TelephoneNumberEqualityMatchingRuleImpl())
                .addToSchema();
        builder.buildMatchingRule(SMR_TELEPHONE_OID).names(SMR_TELEPHONE_NAME)
                .syntaxOID(SYNTAX_SUBSTRING_ASSERTION_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new TelephoneNumberSubstringMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_UNIQUE_MEMBER_OID).names(EMR_UNIQUE_MEMBER_NAME)
                .syntaxOID(SYNTAX_NAME_AND_OPTIONAL_UID_OID).extraProperties(RFC4512_ORIGIN)
                .implementation(new UniqueMemberEqualityMatchingRuleImpl()).addToSchema();
        builder.buildMatchingRule(EMR_WORD_OID).names(EMR_WORD_NAME).syntaxOID(SYNTAX_DIRECTORY_STRING_OID)
                .extraProperties(RFC4512_ORIGIN).implementation(new WordEqualityMatchingRuleImpl())
                .addToSchema();
    }
    private static void defaultObjectClasses(final SchemaBuilder builder) {
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
@@ -30,8 +30,11 @@
import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_MR_UNKNOWN_SYNTAX1;
import static com.forgerock.opendj.ldap.CoreMessages.WARN_MATCHING_RULE_NOT_IMPLEMENTED1;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -41,7 +44,6 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import com.forgerock.opendj.util.Validator;
/**
 * This class defines a data structure for storing and interacting with matching
@@ -59,6 +61,175 @@
 * or via the {@link #toString()} methods.
 */
public final class MatchingRule extends SchemaElement {
    /**
     * A fluent API for incrementally constructing matching rules.
     */
    public final static class Builder extends SchemaElementBuilder<Builder> {
        private String oid;
        private final List<String> names = new LinkedList<String>();
        private boolean isObsolete = false;
        private String syntaxOID;
        private MatchingRuleImpl impl;
        Builder(final MatchingRule mr, final SchemaBuilder builder) {
            super(builder, mr);
            this.oid = mr.oid;
            this.names.addAll(mr.names);
            this.isObsolete = mr.isObsolete;
            this.syntaxOID = mr.syntaxOID;
            this.impl = mr.impl;
        }
        Builder(final String oid, final SchemaBuilder builder) {
            super(builder);
            this.oid(oid);
        }
        /**
         * Adds this matching rule to the schema overwriting any existing matching rule with the same numeric OID.
         *
         * @return The parent schema builder.
         */
        public SchemaBuilder addToSchemaOverwrite() {
            return this.getSchemaBuilder().addMatchingRule(new MatchingRule(this), true);
        }
        /**
         * Adds this matching rule to the schema, throwing an {@code  ConflictingSchemaElementException} if there is an
         * existing matching rule with the same numeric OID.
         *
         * @return The parent schema builder.
         * @throws ConflictingSchemaElementException
         *             If there is an existing matching rule with the same numeric OID.
         */
        public SchemaBuilder addToSchema() {
            return this.getSchemaBuilder().addMatchingRule(new MatchingRule(this), false);
        }
        @Override
        public Builder description(final String description) {
            return description0(description);
        }
        @Override
        public Builder extraProperties(final Map<String, List<String>> extraProperties) {
            return extraProperties0(extraProperties);
        }
        @Override
        public Builder extraProperties(final String extensionName, final String... extensionValues) {
            return extraProperties0(extensionName, extensionValues);
        }
        /**
         * Adds the provided user friendly names.
         *
         * @param names
         *            The user friendly names.
         * @return This builder.
         */
        public Builder names(final Collection<String> names) {
            this.names.addAll(names);
            return this;
        }
        /**
         * Adds the provided user friendly names.
         *
         * @param names
         *            The user friendly names.
         * @return This builder.
         */
        public Builder names(final String... names) {
            return names(Arrays.asList(names));
        }
        /**
         * Specifies whether or not this schema element is obsolete.
         *
         * @param isObsolete
         *            {@code true} if this schema element is obsolete (default is {@code false}).
         * @return This builder.
         */
        public Builder obsolete(final boolean isObsolete) {
            this.isObsolete = isObsolete;
            return this;
        }
        /**
         * Sets the numeric OID which uniquely identifies this matching rule.
         *
         * @param oid
         *            The numeric OID.
         * @return This builder.
         */
        public Builder oid(final String oid) {
            this.oid = oid;
            return this;
        }
        /**
         * Sets the syntax OID of this matching rule.
         *
         * @param syntax
         *            The syntax OID.
         * @return This builder.
         */
        public Builder syntaxOID(final String syntax) {
            this.syntaxOID = syntax;
            return this;
        }
        /**
         * Sets the matching rule implementation.
         *
         * @param implementation
         *            The matching rule implementation.
         * @return This builder.
         */
        public Builder implementation(final MatchingRuleImpl implementation) {
            this.impl = implementation;
            return this;
        }
        @Override
        public Builder removeAllExtraProperties() {
            return removeAllExtraProperties0();
        }
        /**
         * Removes all user friendly names.
         *
         * @return This builder.
         */
        public Builder removeAllNames() {
            this.names.clear();
            return this;
        }
        @Override
        public Builder removeExtraProperty(final String extensionName, final String... extensionValues) {
            return removeExtraProperty0(extensionName, extensionValues);
        }
        /**
         * Removes the provided user friendly name.
         *
         * @param name
         *            The user friendly name to be removed.
         * @return This builder.
         */
        public Builder removeName(final String name) {
            names.remove(name);
            return this;
        }
        @Override
        Builder getThis() {
            return this;
        }
    }
    private final String oid;
    private final List<String> names;
    private final boolean isObsolete;
@@ -67,19 +238,22 @@
    private Syntax syntax;
    private Schema schema;
    MatchingRule(final String oid, final List<String> names, final String description,
            final boolean obsolete, final String syntax,
            final Map<String, List<String>> extraProperties, final String definition,
            final MatchingRuleImpl implementation) {
        super(description, extraProperties, definition);
    private MatchingRule(final Builder builder) {
        super(builder);
        Validator.ensureNotNull(oid, names, description, syntax);
        Validator.ensureNotNull(extraProperties);
        this.oid = oid;
        this.names = names;
        this.isObsolete = obsolete;
        this.syntaxOID = syntax;
        this.impl = implementation;
        // Checks for required attributes.
        if (builder.oid == null || builder.oid.isEmpty()) {
            throw new IllegalArgumentException("An OID must be specified.");
        }
        if (builder.syntaxOID == null || builder.syntaxOID.isEmpty()) {
            throw new IllegalArgumentException("Required syntax OID must be specified.");
        }
        oid = builder.oid;
        names = SchemaUtils.unmodifiableCopyOfList(builder.names);
        isObsolete = builder.isObsolete;
        syntaxOID = builder.syntaxOID;
        impl = builder.impl;
    }
    /**
@@ -117,7 +291,7 @@
    /**
     * Returns the normalized form of the provided assertion value, which is
     * best suite for efficiently performing matching operations on that value.
     * The assertion value is guarenteed to be valid against this matching
     * The assertion value is guaranteed to be valid against this matching
     * rule's assertion syntax.
     *
     * @param value
@@ -157,7 +331,7 @@
    /**
     * Returns the normalized form of the provided assertion value, which is
     * best suite for efficiently performing greater than or equal ordering
     * matching operations on that value. The assertion value is guarenteed to
     * matching operations on that value. The assertion value is guaranteed to
     * be valid against this matching rule's assertion syntax.
     *
     * @param value
@@ -173,7 +347,7 @@
    /**
     * Returns the normalized form of the provided assertion value, which is
     * best suite for efficiently performing greater than or equal ordering
     * matching operations on that value. The assertion value is guarenteed to
     * matching operations on that value. The assertion value is guaranteed to
     * be valid against this matching rule's assertion syntax.
     *
     * @param value
@@ -297,11 +471,6 @@
        return impl.normalizeAttributeValue(schema, value);
    }
    MatchingRule duplicate() {
        return new MatchingRule(oid, names, getDescription(), isObsolete, syntaxOID,
                getExtraProperties(), toString(), impl);
    }
    @Override
    void toStringContent(final StringBuilder buffer) {
        buffer.append(oid);
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
@@ -54,7 +54,7 @@
    /**
     * A fluent API for incrementally constructing name forms.
     */
    public static class Builder extends SchemaElementBuilder<Builder> {
    public final static class Builder extends SchemaElementBuilder<Builder> {
        private boolean isObsolete = false;
        private final List<String> names = new LinkedList<String>();
        private String oid;
@@ -83,7 +83,7 @@
         *
         * @return The parent schema builder.
         */
        public SchemaBuilder addToSchema() {
        public SchemaBuilder addToSchemaOverwrite() {
            return this.getSchemaBuilder().addNameForm(new NameForm(this), true);
        }
@@ -97,7 +97,7 @@
         *             If there is an existing name form with the same numeric
         *             OID.
         */
        public SchemaBuilder addToSchemaNoOverwrite() {
        public SchemaBuilder addToSchema() {
            return this.getSchemaBuilder().addNameForm(new NameForm(this), false);
        }
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -900,14 +900,15 @@
        final Syntax enumSyntax =
                new Syntax(oid, description, Collections.singletonMap("X-ENUM", Arrays
                        .asList(enumerations)), null, enumImpl);
        final MatchingRule enumOMR =
                new MatchingRule(enumImpl.getOrderingMatchingRule(), Collections
                        .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
                        CoreSchemaImpl.OPENDS_ORIGIN, null, new EnumOrderingMatchingRule(enumImpl));
        addSyntax(enumSyntax, overwrite);
        try {
            addMatchingRule(enumOMR, overwrite);
            buildMatchingRule(enumImpl.getOrderingMatchingRule())
                    .names(OMR_GENERIC_ENUM_NAME + oid)
                    .syntaxOID(oid)
                    .extraProperties(CoreSchemaImpl.OPENDJ_ORIGIN)
                    .implementation(new EnumOrderingMatchingRule(enumImpl))
                    .addToSchemaOverwrite();
        } catch (final ConflictingSchemaElementException e) {
            removeSyntax(oid);
        }
@@ -965,14 +966,12 @@
            reader.skipWhitespaces();
            // The next set of characters must be the OID.
            final String oid = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
            final MatchingRule.Builder matchingRuleBuilder =
                    new MatchingRule.Builder(
                            SchemaUtils.readOID(reader, allowMalformedNamesAndOptions), this)
                            .definition(definition);
            List<String> names = Collections.emptyList();
            String description = "".intern();
            boolean isObsolete = false;
            String syntax = null;
            Map<String, List<String>> extraProperties = Collections.emptyMap();
            // At this point, we should have a pretty specific syntax that
            // describes what may come next, but some of the components are
            // optional and it would be pretty easy to put something in the
@@ -988,29 +987,29 @@
                    // No more tokens.
                    break;
                } else if (tokenName.equalsIgnoreCase("name")) {
                    names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
                    matchingRuleBuilder.names(SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions));
                } else if (tokenName.equalsIgnoreCase("desc")) {
                    // This specifies the description for the matching rule. It
                    // is an arbitrary string of characters enclosed in single
                    // quotes.
                    description = SchemaUtils.readQuotedString(reader);
                    matchingRuleBuilder.description(SchemaUtils.readQuotedString(reader));
                } else if (tokenName.equalsIgnoreCase("obsolete")) {
                    // This indicates whether the matching rule should be
                    // considered obsolete. We do not need to do any more
                    // parsing for this token.
                    isObsolete = true;
                    matchingRuleBuilder.obsolete(true);
                } else if (tokenName.equalsIgnoreCase("syntax")) {
                    syntax = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
                    matchingRuleBuilder.syntaxOID(syntax);
                } 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);
                    matchingRuleBuilder.extraProperties(tokenName, extensions
                            .toArray(new String[extensions.size()]));
                } else {
                    final LocalizableMessage message =
                            ERR_ATTR_SYNTAX_MR_ILLEGAL_TOKEN1.get(definition, tokenName);
@@ -1023,13 +1022,11 @@
                final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_NO_SYNTAX.get(definition);
                throw new LocalizedIllegalArgumentException(message);
            }
            if (!extraProperties.isEmpty()) {
                extraProperties = Collections.unmodifiableMap(extraProperties);
            if (overwrite) {
                matchingRuleBuilder.addToSchemaOverwrite();
            } else {
                matchingRuleBuilder.addToSchema();
            }
            addMatchingRule(new MatchingRule(oid, names, description, isObsolete, syntax,
                    extraProperties, definition, null), overwrite);
        } catch (final DecodeException e) {
            final LocalizableMessage msg =
                    ERR_ATTR_SYNTAX_MR_INVALID1.get(definition, e.getMessageObject());
@@ -1039,49 +1036,6 @@
    }
    /**
     * Adds the provided matching rule definition to this schema builder.
     *
     * @param oid
     *            The OID of the matching rule definition.
     * @param names
     *            The user-friendly names of the matching rule definition.
     * @param description
     *            The description of the matching rule definition.
     * @param obsolete
     *            {@code true} if the matching rule definition is obsolete,
     *            otherwise {@code false}.
     * @param assertionSyntax
     *            The OID of the assertion syntax definition.
     * @param extraProperties
     *            A map containing additional properties associated with the
     *            matching rule definition.
     * @param implementation
     *            The implementation of the matching rule.
     * @param overwrite
     *            {@code true} if any existing matching rule with the same OID
     *            should be overwritten.
     * @return A reference to this schema builder.
     * @throws ConflictingSchemaElementException
     *             If {@code overwrite} was {@code false} and a conflicting
     *             schema element was found.
     */
    SchemaBuilder addMatchingRule(final String oid, final List<String> names,
            final String description, final boolean obsolete, final String assertionSyntax,
            final Map<String, List<String>> extraProperties, final MatchingRuleImpl implementation,
            final boolean overwrite) {
        Validator.ensureNotNull(implementation);
        lazyInitBuilder();
        final MatchingRule matchingRule =
                new MatchingRule(oid, unmodifiableCopyOfList(names), description, obsolete,
                        assertionSyntax, unmodifiableCopyOfExtraProperties(extraProperties), null,
                        implementation);
        addMatchingRule(matchingRule, overwrite);
        return this;
    }
    /**
     * Adds the provided matching rule use definition to this schema builder.
     *
     * @param definition
@@ -1210,6 +1164,24 @@
    }
    /**
     * Returns a builder which can be used for incrementally constructing a new matching rule before adding it to the
     * schema. Example usage:
     *
     * <pre>
     * SchemaBuilder builder = ...;
     * builder.buildMatchingRule("matchingrule-oid").name("matching rule name").addToSchema();
     * </pre>
     *
     * @param oid
     *            The OID of the matching rule definition.
     * @return A builder to continue building the NameForm.
     */
    public MatchingRule.Builder buildMatchingRule(final String oid) {
        lazyInitBuilder();
        return new MatchingRule.Builder(oid, this);
    }
    /**
     * Adds the provided matching rule use definition to this schema builder.
     *
     * @param oid
@@ -1376,9 +1348,9 @@
            }
            if (overwrite) {
                nameFormBuilder.addToSchema();
                nameFormBuilder.addToSchemaOverwrite();
            } else {
                nameFormBuilder.addToSchemaNoOverwrite();
                nameFormBuilder.addToSchema();
            }
        } catch (final DecodeException e) {
            final LocalizableMessage msg =
@@ -1475,6 +1447,18 @@
    }
    /**
     * Duplicates the matching rule.
     *
     * @param matchingRule
     *            The matching rule to duplicate.
     * @return A matching rule builder.
     */
    public MatchingRule.Builder buildMatchingRule(final MatchingRule matchingRule) {
        lazyInitBuilder();
        return new MatchingRule.Builder(matchingRule, this);
    }
    /**
     * Duplicates the name form.
     *
     * @param nameForm
@@ -2175,14 +2159,14 @@
                    final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, property.getValue());
                    final Syntax enumSyntax =
                            new Syntax(oid, description, extraProperties, definition, enumImpl);
                    final MatchingRule enumOMR =
                            new MatchingRule(enumImpl.getOrderingMatchingRule(), Collections
                                    .singletonList(OMR_GENERIC_ENUM_NAME + oid), "", false, oid,
                                    CoreSchemaImpl.OPENDS_ORIGIN, null,
                                    new EnumOrderingMatchingRule(enumImpl));
                    addSyntax(enumSyntax, overwrite);
                    addMatchingRule(enumOMR, overwrite);
                    buildMatchingRule(enumImpl.getOrderingMatchingRule())
                        .names(OMR_GENERIC_ENUM_NAME + oid)
                        .syntaxOID(oid)
                        .extraProperties(CoreSchemaImpl.OPENDJ_ORIGIN)
                        .implementation(new EnumOrderingMatchingRule(enumImpl))
                        .addToSchemaOverwrite();
                    return this;
                }
            }
@@ -2647,35 +2631,6 @@
        }
    }
    private void addMatchingRule(final MatchingRule rule, final boolean overwrite) {
        MatchingRule conflictingRule;
        if (numericOID2MatchingRules.containsKey(rule.getOID())) {
            conflictingRule = numericOID2MatchingRules.get(rule.getOID());
            if (!overwrite) {
                final LocalizableMessage message =
                        ERR_SCHEMA_CONFLICTING_MR_OID.get(rule.getNameOrOID(), rule.getOID(),
                                conflictingRule.getNameOrOID());
                throw new ConflictingSchemaElementException(message);
            }
            removeMatchingRule(conflictingRule);
        }
        numericOID2MatchingRules.put(rule.getOID(), rule);
        for (final String name : rule.getNames()) {
            final String lowerName = StaticUtils.toLowerCase(name);
            List<MatchingRule> rules;
            if ((rules = name2MatchingRules.get(lowerName)) == null) {
                name2MatchingRules.put(lowerName, Collections.singletonList(rule));
            } else if (rules.size() == 1) {
                rules = new ArrayList<MatchingRule>(rules);
                rules.add(rule);
                name2MatchingRules.put(lowerName, rules);
            } else {
                rules.add(rule);
            }
        }
    }
    private void addMatchingRuleUse(final MatchingRuleUse use, final boolean overwrite) {
        MatchingRuleUse conflictingUse;
        if (numericOID2MatchingRuleUses.containsKey(use.getMatchingRuleOID())) {
@@ -2705,12 +2660,37 @@
        }
    }
    SchemaBuilder addNameForm(final NameForm form, final boolean overwrite) {
        // If schema is not initialized before.
        if (numericOID2NameForms == null || name2NameForms == null) {
            lazyInitBuilder();
    SchemaBuilder addMatchingRule(final MatchingRule rule, final boolean overwrite) {
        MatchingRule conflictingRule;
        if (numericOID2MatchingRules.containsKey(rule.getOID())) {
            conflictingRule = numericOID2MatchingRules.get(rule.getOID());
            if (!overwrite) {
                final LocalizableMessage message =
                        ERR_SCHEMA_CONFLICTING_MR_OID.get(rule.getNameOrOID(), rule.getOID(),
                                conflictingRule.getNameOrOID());
                throw new ConflictingSchemaElementException(message);
            }
            removeMatchingRule(conflictingRule);
        }
        numericOID2MatchingRules.put(rule.getOID(), rule);
        for (final String name : rule.getNames()) {
            final String lowerName = StaticUtils.toLowerCase(name);
            List<MatchingRule> rules;
            if ((rules = name2MatchingRules.get(lowerName)) == null) {
                name2MatchingRules.put(lowerName, Collections.singletonList(rule));
            } else if (rules.size() == 1) {
                rules = new ArrayList<MatchingRule>(rules);
                rules.add(rule);
                name2MatchingRules.put(lowerName, rules);
            } else {
                rules.add(rule);
            }
        }
        return this;
    }
    SchemaBuilder addNameForm(final NameForm form, final boolean overwrite) {
        NameForm conflictingForm;
        if (numericOID2NameForms.containsKey(form.getOID())) {
            conflictingForm = numericOID2NameForms.get(form.getOID());
@@ -2779,7 +2759,7 @@
        }
        for (final MatchingRule matchingRule : schema.getMatchingRules()) {
            addMatchingRule(matchingRule.duplicate(), overwrite);
            addMatchingRule(matchingRule, overwrite);
        }
        for (final MatchingRuleUse matchingRuleUse : schema.getMatchingRuleUses()) {
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java
New file
@@ -0,0 +1,754 @@
/*
 * 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 static org.fest.assertions.Assertions.assertThat;
import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_AUTH_PASSWORD_EXACT_DESCRIPTION;
import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_AUTH_PASSWORD_EXACT_NAME;
import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_AUTH_PASSWORD_EXACT_OID;
import static org.forgerock.opendj.ldap.schema.SchemaConstants.SYNTAX_AUTH_PASSWORD_OID;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.testng.annotations.Test;
/**
 * This class tests the MatchingRule class. The matching rule builder can be only used with the schema builder.
 */
@SuppressWarnings("javadoc")
public class MatchingRuleTestCase extends SchemaTestCase {
    @Test()
    public final void testCreatesBasicMatchingRule() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getDescription()).isEqualTo("Directory String");
        assertThat(mr.getDescription()).isEqualTo("An example of matching rule");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(mr.isObsolete()).isFalse();
    }
    @Test()
    public final void testCreatesOverrideBasicMatchingRule() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule(EMR_AUTH_PASSWORD_EXACT_OID)
            .names(Collections.singletonList(EMR_AUTH_PASSWORD_EXACT_NAME))
            .description(EMR_AUTH_PASSWORD_EXACT_DESCRIPTION)
            .syntaxOID(SYNTAX_AUTH_PASSWORD_OID)
            .extraProperties("New extra propertie")
            .implementation(new AuthPasswordExactEqualityMatchingRuleImpl())
            .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule(EMR_AUTH_PASSWORD_EXACT_OID);
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isTrue();
        assertThat(mr.isObsolete()).isFalse();
    }
    /**
     * The builder requires an OID or throw an exception.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testBuilderDoesntAllowEmptyOid() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule("")
            .names("ExampleMatch")
            .description("An example of matching rule")
            .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
            .extraProperties("LDAP Schema Update Procedures")
            .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
            .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on
    }
    /**
     * The builder requires an OID or throw an exception.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testBuilderDoesntAllowNullOid() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule((String) null)
            .names("ExampleMatch")
            .description("An example of matching rule")
            .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
            .extraProperties("LDAP Schema Update Procedures")
            .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
            .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on
    }
    /**
     * When syntax is missing, the builder sends exception.
     */
    @Test(expectedExceptions = IllegalArgumentException.class)
    public final void testBuilderDoesntAllowNullSyntax() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule("1.1.4.1")
            .names("ExampleMatch")
            .description("An example of matching rule")
            .extraProperties("LDAP Schema Update Procedures")
            .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
            .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on
    }
    /**
     * Matching rule name is optional.
     */
    @Test()
    public final void testBuilderAllowsEmptyName() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule("1.1.4.1")
            .description("An example of matching rule")
            .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
            .extraProperties("LDAP Schema Update Procedures")
            .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
            .addToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("1.1.4.1");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(mr.getNames().size()).isEqualTo(0);
        assertThat(mr.getNameOrOID()).isEqualTo("1.1.4.1");
    }
    /**
     * Multiple names can be set to the matching rule.
     */
    @Test()
    public final void testBuilderAllowsMultipleNames() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("my new matching rule")
                .names("maching rule test")
                .names("exampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("1.1.4.1");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(mr.getNames().size()).isEqualTo(3);
        assertThat(mr.hasName("my new matching rule")).isTrue();
        assertThat(mr.hasName("maching rule test")).isTrue();
        assertThat(mr.hasName("exampleMatch")).isTrue();
    }
    /**
     * Name in optional for a matching rule. (RFC 4512)
     */
    @Test()
    public final void testBuilderRemoveNames() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("my new matching rule")
                .names("maching rule test")
                .names("exampleMatch")
                .removeAllNames()
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("1.1.4.1");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(mr.getNames().size()).isEqualTo(0);
        assertThat(mr.getNameOrOID()).isEqualTo("1.1.4.1");
    }
    /**
     * The builder allows to remove selected name.
     */
    @Test()
    public final void testBuilderRemoveSelectedName() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("my new matching rule")
                .names("maching rule test")
                .names("exampleMatch")
                .removeName("maching rule test")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("1.1.4.1");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(mr.getNames().size()).isEqualTo(2);
        assertThat(mr.hasName("my new matching rule")).isTrue();
        assertThat(mr.hasName("exampleMatch")).isTrue();
    }
    /**
     * The builder allows a missing description.
     */
    @Test()
    public final void testBuilderAllowsNoDescription() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getDescription()).isEmpty();
        assertThat(mr.getDescription()).isEqualTo("");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
    }
    /**
     * The builder allows empty description.
     */
    @Test()
    public final void testBuilderAllowsEmptyDescription() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getDescription()).isEmpty();
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(mr.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
    }
    /**
     * Extra properties is not a mandatory field.
     */
    @Test()
    public final void testBuilderAllowsNoExtraProperties() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("Example match description")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getDescription()).isEqualTo("Example match description");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties()).isEmpty();
    }
    /**
     * Extra properties set to null is not allowed.
     */
    @Test(expectedExceptions = NullPointerException.class)
    public final void testBuilderDoesntAllowNullExtraProperties() {
        // @formatter:off
        new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("Example match description")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15")
                .extraProperties(null)
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
    }
    /**
     * Removes all the extra properties
     */
    @Test()
    public final void testBuilderRemoveExtraProperties() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("exampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .removeAllExtraProperties()
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("1.1.4.1");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(mr.getExtraProperties()).isEmpty();
        assertThat(mr.getNames().size()).isEqualTo(1);
        assertThat(mr.getNames().get(0)).isEqualTo("exampleMatch");
    }
    /**
     * If the implementation is not set, the schema will use the default matching rule for this one.
     */
    @Test()
    public final void testBuilderAllowsNoImplementation() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("Example match description")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isNotEmpty();
        assertThat(schema.getWarnings().contains("The default matching rule \"2.5.13.17\" will be used instead"));
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getDescription()).isEqualTo("Example match description");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
    }
    /**
     * If the implementation is null, the schema will use the default matching rule for this one.
     */
    @Test()
    public final void testBuilderAllowsNullImplementation() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("Example match description")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(null)
                .addToSchemaOverwrite()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isNotEmpty();
        assertThat(
                schema.getWarnings().toString()
                        .contains("The default matching rule \"2.5.13.17\" will be used instead")).isTrue();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr).isNotNull();
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.getDescription()).isEqualTo("Example match description");
        assertThat(mr.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
    }
    /**
     * Sets a matching rule using a string definition.
     */
    @Test()
    public final void testAddingAMatchingRuleDefinitionStringNoOverride() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        final String definition = "( 1.1.4.1 NAME 'ExampleMatch' DESC 'An example of"
                + " Matching Rule' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
        sb.addMatchingRule(definition, false);
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isNotEmpty();
        assertThat(
                schema.getWarnings().toString()
                        .contains("The default matching rule \"2.5.13.17\" will be used instead")).isTrue();
        assertThat(schema.getMatchingRules()).isNotEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr.toString()).isEqualTo(definition);
        assertThat(mr.isObsolete()).isFalse();
    }
    /**
     * Sets a matching rule using a string definition.
     */
    @Test()
    public final void testAddingAMatchingRuleDefinitionStringOverride() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        final String definition = "( 2.5.13.0 NAME 'objectIdentifierMatch'"
                + " OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )";
        sb.addMatchingRule(definition, true);
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        assertThat(schema.getMatchingRules()).isNotEmpty();
        final MatchingRule mr = schema.getMatchingRule("objectIdentifierMatch");
        assertThat(mr.getOID()).isEqualTo("2.5.13.0");
        assertThat(mr.toString()).isEqualTo(definition);
        assertThat(mr.isObsolete()).isTrue();
    }
    /**
     * Duplicates an existing matching rule.
     */
    @Test()
    public final void testDuplicatesExistingMatchingRule() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final MatchingRule.Builder nfb = new MatchingRule.Builder("1.1.4.1", sb);
        nfb.description("This is a new matching rule")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .extraProperties("X-ORIGIN", "NO RFC")
                .implementation(new BooleanEqualityMatchingRuleImpl())
                .addToSchemaOverwrite();
        // @formatter:on
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr.getOID()).isEqualTo("1.1.4.1");
        // @formatter:off
        sb.buildMatchingRule(mr)
            .names("Dolly")
            .oid("2.5.13.0.1")
            .obsolete(true)
            .addToSchemaOverwrite();
        // @formatter:on
        schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule dolly = schema.getMatchingRule("Dolly");
        assertThat(dolly.getOID()).isEqualTo("2.5.13.0.1");
        assertThat(dolly.getSyntax().getDescription()).isEqualTo("Directory String");
        assertThat(dolly.getDescription()).isEqualTo("An example of matching rule");
        assertThat(dolly.getSyntax().getOID()).isEqualTo("1.3.6.1.4.1.1466.115.121.1.15");
        assertThat(dolly.getExtraProperties().containsKey("New extra propertie")).isFalse();
        assertThat(dolly.getExtraProperties().containsKey("LDAP Schema Update Procedures")).isTrue();
        assertThat(dolly.getExtraProperties().containsKey("X-ORIGIN")).isTrue();
        assertThat(dolly.isObsolete()).isTrue();
    }
    /**
     * Equality between matching rules.
     */
    @Test()
    public final void testMatchingRuleEqualsTrue() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        final MatchingRule mr1 = schema.getMatchingRule("ExampleMatch");
        // @formatter:off
        final Schema schema2 = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("Second")
                .description("A second example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        final MatchingRule mr2 = schema2.getMatchingRule("Second");
        assertThat(mr2.equals(mr1)).isTrue();
    }
    /**
     * Equality between matching rules fails.
     */
    @Test()
    public final void testMatchingRuleEqualsFalse() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        final MatchingRule mr1 = schema.getMatchingRule("ExampleMatch");
        // @formatter:off
        final Schema schema2 = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.2")
                .names("Second")
                .description("A second example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        final MatchingRule mr2 = schema2.getMatchingRule("Second");
        assertThat(mr2.equals(mr1)).isFalse();
    }
    /**
     * Verifies the builder definition.
     */
    @Test()
    public final void testVerifyMatchingRuleDefinition() {
        final SchemaBuilder sb = new SchemaBuilder();
        sb.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final MatchingRule.Builder nfb = new MatchingRule.Builder("1.1.4.1", sb);
        nfb.description("This is a new matching rule")
                .names("ExampleMatch")
                .names("MyExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures", "RFC 2252")
                .extraProperties("X-ORIGIN", "NONE")
                .obsolete(true)
                .implementation(new BooleanEqualityMatchingRuleImpl())
                .addToSchemaOverwrite();
        // @formatter:on
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
        final String definition = "( 1.1.4.1 NAME ( 'ExampleMatch' 'MyExampleMatch' ) "
                + "DESC 'An example of matching rule' OBSOLETE " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
                + "LDAP Schema Update Procedures 'RFC 2252' X-ORIGIN 'NONE' )";
        final MatchingRule mr = schema.getMatchingRule("ExampleMatch");
        assertThat(mr.toString()).isEqualTo(definition);
    }
    /**
     * Equality between builder and definition.
     */
    @Test()
    public final void testMatchingRuleEqualityReturnsTrueBetweenBuilderAndDefinition() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr1 = schema.getMatchingRule("ExampleMatch");
        final SchemaBuilder sb2 = new SchemaBuilder();
        sb2.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final String definition = "( 1.1.4.1 NAME 'ExampleMatch2' DESC 'An example of"
                + " Matching Rule' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
        sb2.addMatchingRule(definition, false);
        // @formatter:on
        final MatchingRule mr2 = sb2.toSchema().getMatchingRule("ExampleMatch2");
        assertThat(mr1.equals(mr2)).isTrue();
    }
    /**
     * Equality between builder and definition fails.
     */
    @Test()
    public final void testMatchingRuleEqualityReturnsTrueBetweenBuilderAndDefinitionFails() {
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
                .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .extraProperties("LDAP Schema Update Procedures")
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .addToSchema()
                .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        final MatchingRule mr1 = schema.getMatchingRule("ExampleMatch");
        final SchemaBuilder sb2 = new SchemaBuilder();
        sb2.addSchema(Schema.getCoreSchema(), false);
        // @formatter:off
        final String definition = "( 1.1.4.2 NAME 'ExampleMatch2' DESC 'An example of"
                + " Matching Rule' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )";
        sb2.addMatchingRule(definition, false);
        // @formatter:on
        final MatchingRule mr2 = sb2.toSchema().getMatchingRule("ExampleMatch2");
        assertThat(mr1.equals(mr2)).isFalse();
    }
    /**
     * The builder allows to create chained matching rules.
     */
    @Test()
    public final void testCreatesMatchingRulesUsingChainingMethods() {
        final Map<String, List<String>> extraProperties = new TreeMap<String, List<String>>();
        final List<String> extra = new ArrayList<String>();
        extra.add("Custom");
        extraProperties.put("X-ORIGIN", extra);
        // @formatter:off
        final Schema schema = new SchemaBuilder(Schema.getCoreSchema())
            .buildMatchingRule("1.1.4.1")
                .names("ExampleMatch")
                .description("An example of matching rule")
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15") // DirectoryStringSyntax OID.
                .implementation(new DirectoryStringFirstComponentEqualityMatchingRuleImpl())
                .extraProperties(extraProperties)
                .addToSchema()
            .buildMatchingRule("1.1.4.9999")
                .names("SecondExampleMatch")
                .description("Another example of matching rule")
                .extraProperties(extraProperties)
                .syntaxOID("1.3.6.1.4.1.1466.115.121.1.15")
                .implementation(new BooleanEqualityMatchingRuleImpl())
                .addToSchema()
            .toSchema();
        // @formatter:on
        assertThat(schema.getWarnings()).isEmpty();
        // First
        final MatchingRule mr1 = schema.getMatchingRule("ExampleMatch");
        assertThat(mr1.getOID()).isEqualTo("1.1.4.1");
        assertThat(mr1.getDescription()).isEqualTo("An example of matching rule");
        // Second
        final MatchingRule mr2 = schema.getMatchingRule("SecondExampleMatch");
        assertThat(mr2.getOID()).isEqualTo("1.1.4.9999");
        assertThat(mr2.getDescription()).isEqualTo("Another example of matching rule");
        assertThat(mr1.getExtraProperties()).isEqualTo(mr2.getExtraProperties());
    }
}
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java
@@ -55,7 +55,7 @@
                .buildNameForm("1.3.6.1.4.1.1466.115.121.1.35")
                    .structuralObjectClassOID("person")
                    .requiredAttributes("sn", "cn") // ("cn, sn") is not supported.
                    .addToSchemaNoOverwrite()
                    .addToSchema()
                .toSchema();
        assertThat(schema.getWarnings()).isEmpty();
@@ -81,7 +81,7 @@
                    .structuralObjectClassOID("person")
                    .names("MyNewForm")
                    .requiredAttributes("sn", "cn")
                    .addToSchemaNoOverwrite()
                    .addToSchema()
                .toSchema();
        // @formatter:on
@@ -114,7 +114,7 @@
                .names("MyNewForm")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("owner")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -145,7 +145,7 @@
                .requiredAttributes("sn", "cn")
                .optionalAttributes("owner")
                .extraProperties("X-ORIGIN", "RFC xxx")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -180,7 +180,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .structuralObjectClassOID("person")
                .requiredAttributes("sn, cn")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -201,7 +201,7 @@
                .names("MyNewForm")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn, cn")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -223,7 +223,7 @@
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes()
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -244,7 +244,7 @@
                .names("MyNewForm")
                .structuralObjectClassOID("person")
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -265,7 +265,7 @@
                .structuralObjectClassOID("person")
                .requiredAttributes("sn, cn")
                .requiredAttributes((String[]) null)
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -287,7 +287,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                // .optionalAttributeOIDs("") empty by default.
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
    }
@@ -310,7 +310,7 @@
                .requiredAttributes("sn")
                .removeRequiredAttribute("unknown")
                .removeOptionalAttribute("optionalunknown")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -405,7 +405,7 @@
            .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addToSchemaNoOverwrite();
            .addToSchema();
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
@@ -416,7 +416,7 @@
        sb.buildNameForm(nf)
            .names("Dolly")
            .oid("1.3.6.1.4.1.1466.115.121.1.36")
            .addToSchema();
            .addToSchemaOverwrite();
        schema = sb.toSchema();
        assertThat(schema.getNameForms()).isNotEmpty();
        assertThat(schema.getNameForms().size()).isEqualTo(2);
@@ -451,7 +451,7 @@
            .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addToSchemaNoOverwrite();
            .addToSchema();
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
@@ -463,7 +463,7 @@
            .names("Dolly")
            .oid("1.3.6.1.4.1.1466.115.121.1.36")
            .structuralObjectClassOID("wrongStructuralOID")
            .addToSchema();
            .addToSchemaOverwrite();
        schema = sb.toSchema();
        assertThat(schema.getNameForms().size()).isEqualTo(1); // MyNewForm
        // The duplicate name form is  not created and the schema contains warnings about.
@@ -486,7 +486,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -497,7 +497,7 @@
            .names("MyNewForm")
            .structuralObjectClassOID("person")
            .requiredAttributes("sn", "cn")
            .addToSchemaNoOverwrite().toSchema();
            .addToSchema().toSchema();
        final NameForm nf2 = schema2.getNameForm("MyNewForm");
        assertThat(nf1.equals(nf2)).isTrue();
@@ -519,7 +519,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
        final NameForm nf1 = schema.getNameForms().iterator().next();
@@ -534,7 +534,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -590,7 +590,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -631,7 +631,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -673,7 +673,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -702,7 +702,7 @@
                .extraProperties("X-ORIGIN", "NameFormCheckingTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -735,7 +735,7 @@
                .optionalAttributes("owner")
                .optionalAttributes("l")
                .names("Rock")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -801,7 +801,7 @@
                .extraProperties(extraProperties)
                .requiredAttributes("uid")
                .optionalAttributes("sn")
                .addToSchema()
                .addToSchemaOverwrite()
            .buildNameForm("4.4.4")
                .description("NF2's description")
                .names("theSecondNameForm")
@@ -809,7 +809,7 @@
                .extraProperties(extraProperties)
                .requiredAttributes("uid")
                .requiredAttributes("sn")
                .addToSchema()
                .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on
@@ -854,7 +854,7 @@
                .removeName("nameform2")
                .removeRequiredAttribute("cn")
                .removeOptionalAttribute("l")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -890,7 +890,7 @@
                .extraProperties("FROM", "NameFormTestCase")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .toSchema();
        // @formatter:on
@@ -917,7 +917,7 @@
        // @formatter:on
        sb.addSchema(schema, true);
        sb.addSchema(nfBuilder.addToSchema().toSchema(), true);
        sb.addSchema(nfBuilder.addToSchemaOverwrite().toSchema(), true);
        Schema finalSchema =  sb.toSchema();
        assertThat(finalSchema.getNameForms()).isNotEmpty();
@@ -957,7 +957,7 @@
            .extraProperties("FROM", "NameFormTestCase")
            .requiredAttributes("sn", "cn")
            .optionalAttributes("description", "uid")
            .addToSchemaNoOverwrite();
            .addToSchema();
        Schema schema = sb.toSchema();
        assertThat(schema.getWarnings()).isEmpty();
@@ -978,7 +978,7 @@
            .removeAllExtraProperties()
            .removeAllRequiredAttributes()
            .requiredAttributes("businessCategory")
            .addToSchema();
            .addToSchemaOverwrite();
        schema = sb.toSchema();
        assertThat(schema.getNameForms()).isNotEmpty();
        assertThat(schema.getNameForms().size()).isEqualTo(2);
@@ -1015,7 +1015,7 @@
                .extraProperties("X-ORIGIN", "NameFormTestCase", "Forgerock", "extra")
                .requiredAttributes("sn", "cn")
                .optionalAttributes("description", "uid")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.36")
                .description("Description of the second form")
                .names("SecondForm")
@@ -1023,7 +1023,7 @@
                .extraProperties("X-ORIGIN", "NameFormTestCase2")
                .requiredAttributes("name")
                .optionalAttributes("owner")
                .addToSchemaNoOverwrite()
                .addToSchema()
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.37")
                .description("Description of the third form")
                .names("ThirdForm")
@@ -1032,7 +1032,7 @@
                .requiredAttributes("sn", "l")
                .optionalAttributes("description", "uid")
                .description("Description of the third form")
                .addToSchemaNoOverwrite()
                .addToSchema()
                // we overwritten the third name form.
            .buildNameForm("1.3.6.1.4.1.1466.115.121.1.37")
                .names("ThirdFormOverwritten")
@@ -1040,7 +1040,7 @@
                .extraProperties("X-ORIGIN", "RFC 2252")
                .requiredAttributes("sn", "l")
                .optionalAttributes("description", "uid")
                .addToSchema()
                .addToSchemaOverwrite()
            .toSchema();
        // @formatter:on