From 0918f144f87f0ffbc650faa77b5593bda27abd83 Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Tue, 10 Dec 2013 16:26:21 +0000
Subject: [PATCH] CR-2688 OPENDJ-1230 SDK Builder for Matching rules

---
 opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java     |   70 +-
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java             |    6 
 opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java |  754 +++++++++++++++++++++++++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java       |  288 +++++-----
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java         |  211 +++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java        |  200 +++----
 6 files changed, 1,206 insertions(+), 323 deletions(-)

diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
index 9683d4f..de03341 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CoreSchemaImpl.java
+++ b/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) {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
index 20638e0..6f376b7 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRule.java
+++ b/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);
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
index 1931e6a..3d91229 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NameForm.java
+++ b/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);
         }
 
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index e6ab73b..0b9cbef 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/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()) {
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java
new file mode 100644
index 0000000..48cc59e
--- /dev/null
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleTestCase.java
@@ -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());
+    }
+}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java
index f732e63..19fa12c 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/NameFormTestCase.java
+++ b/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
 

--
Gitblit v1.10.0