From eeff47209a107e9e81ab8c3eb171be3a9823e1d8 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 28 Feb 2014 15:55:33 +0000
Subject: [PATCH] OPENDJ-1308 (CR-3121) Migrate schema support

---
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java                     |   26 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java                     |   25 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java |   30 --
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java                 |   46 ---
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java                    |   24 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java                       |   19 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java                                           |  153 +++++++++--
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java                                        |   21 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java                 |   13 
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java           |   26 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java               |   58 ----
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java                              |    9 
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java                |   13 
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java                    |   26 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java                    |   25 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java                |   39 --
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java                |   45 ---
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java                 |   12 
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java           |   26 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java                   |   25 -
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java                  |   44 ---
 opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java                 |   45 ---
 22 files changed, 182 insertions(+), 568 deletions(-)

diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
index 43597af..b19e5a5 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/AbstractMatchingRuleImpl.java
@@ -92,13 +92,4 @@
             throws DecodeException {
         return UNDEFINED_ASSERTION;
     }
-
-    static void trimConsecutiveSpaces(StringBuilder buffer) {
-        for (int pos = buffer.length() - 1; pos > 0; pos--) {
-            if (buffer.charAt(pos) == ' '
-                    && buffer.charAt(pos - 1) == ' ') {
-                buffer.delete(pos, pos + 1);
-            }
-        }
-    }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
index 28796a4..6b8fa44 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactEqualityMatchingRuleImpl.java
@@ -26,36 +26,18 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class defines the caseExactMatch matching rule defined in X.520 and
  * referenced in RFC 4519.
  */
 final class CaseExactEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, NO_CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
index 3bafee4..4aa9163 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5EqualityMatchingRuleImpl.java
@@ -26,16 +26,12 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
-
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the caseExactIA5Match matching rule defined in RFC
  * 2252.
@@ -43,40 +39,6 @@
 final class CaseExactIA5EqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
             throws DecodeException {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space and watch out
-        // for non-ASCII characters.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            final char c = buffer.charAt(pos);
-            if (c == ' ') {
-                if (buffer.charAt(pos - 1) == ' ') {
-                    buffer.delete(pos, pos + 1);
-                }
-            } else if ((c & 0x7F) != c) {
-                // This is not a valid character for an IA5 string. If strict
-                // syntax enforcement is enabled, then we'll throw an exception.
-                // Otherwise, we'll get rid of the character.
-                final LocalizableMessage message =
-                        WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(value.toString(), String
-                                .valueOf(c));
-                throw DecodeException.error(message);
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeIA5StringAttributeValue(value, TRIM, NO_CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java
index 15af8a8..9af57d0 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactIA5SubstringMatchingRuleImpl.java
@@ -22,19 +22,16 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2014 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
-
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the caseExactIA5SubstringsMatch matching rule. This
  * matching rule actually isn't defined in any official specification, but some
@@ -42,6 +39,7 @@
  * private namespace.
  */
 final class CaseExactIA5SubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
             throws DecodeException {
         return normalize(TRIM, value);
@@ -55,40 +53,6 @@
 
     private ByteString normalize(final boolean trim, final ByteSequence value)
             throws DecodeException {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, trim, NO_CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space and watch out
-        // for non-ASCII characters.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            final char c = buffer.charAt(pos);
-            if (c == ' ') {
-                if (buffer.charAt(pos - 1) == ' ') {
-                    buffer.delete(pos, pos + 1);
-                }
-            } else if ((c & 0x7F) != c) {
-                // This is not a valid character for an IA5 string. If strict
-                // syntax enforcement is enabled, then we'll throw an exception.
-                // Otherwise, we'll get rid of the character.
-                final LocalizableMessage message =
-                        WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(value.toString(), String
-                                .valueOf(c));
-                throw DecodeException.error(message);
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeIA5StringAttributeValue(value, trim, NO_CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java
index c1ab24d..b96f83a 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactOrderingMatchingRuleImpl.java
@@ -26,36 +26,17 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class defines the caseExactOrderingMatch matching rule defined in X.520
  * and referenced in RFC 4519.
  */
 final class CaseExactOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, NO_CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java
index 7670851..8d16777 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseExactSubstringMatchingRuleImpl.java
@@ -26,14 +26,12 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class defines the caseExactSubstringsMatch matching rule defined in
  * X.520 and referenced in RFC 2252.
@@ -50,23 +48,6 @@
     }
 
     private ByteString normalize(final boolean trim, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, trim, NO_CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, trim, NO_CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
index 0aa5d1d..e90369d 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreEqualityMatchingRuleImpl.java
@@ -26,9 +26,7 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
+import static com.forgerock.opendj.util.StringPrepProfile.*;
 
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
@@ -38,24 +36,8 @@
  * referenced in RFC 2252.
  */
 final class CaseIgnoreEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
index 00fb9dc..5c3f861 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5EqualityMatchingRuleImpl.java
@@ -26,57 +26,20 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
-
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the caseIgnoreIA5Match matching rule defined in RFC
  * 2252.
  */
 final class CaseIgnoreIA5EqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
             throws DecodeException {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space and watch out
-        // for non-ASCII characters.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            final char c = buffer.charAt(pos);
-            if (c == ' ') {
-                if (buffer.charAt(pos - 1) == ' ') {
-                    buffer.delete(pos, pos + 1);
-                }
-            } else if ((c & 0x7F) != c) {
-                // This is not a valid character for an IA5 string. If strict
-                // syntax enforcement is enabled, then we'll throw an exception.
-                // Otherwise, we'll get rid of the character.
-                final LocalizableMessage message =
-                        WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(value.toString(), String
-                                .valueOf(c));
-                throw DecodeException.error(message);
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeIA5StringAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
index 7821da5..8dfe213 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreIA5SubstringMatchingRuleImpl.java
@@ -22,19 +22,16 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2014 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER;
-
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the caseIgnoreIA5SubstringsMatch matching rule defined
  * in RFC 2252.
@@ -53,40 +50,6 @@
 
     private ByteString normalize(final boolean trim, final ByteSequence value)
             throws DecodeException {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, trim, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space and watch out
-        // for non-ASCII characters.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            final char c = buffer.charAt(pos);
-            if (c == ' ') {
-                if (buffer.charAt(pos - 1) == ' ') {
-                    buffer.delete(pos, pos + 1);
-                }
-            } else if ((c & 0x7F) != c) {
-                // This is not a valid character for an IA5 string. If strict
-                // syntax enforcement is enabled, then we'll throw an exception.
-                // Otherwise, we'll get rid of the character.
-                final LocalizableMessage message =
-                        WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(value.toString(), String
-                                .valueOf(c));
-                throw DecodeException.error(message);
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeIA5StringAttributeValue(value, trim, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
index 29d7f2b..55d7809 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListEqualityMatchingRuleImpl.java
@@ -27,50 +27,17 @@
 package org.forgerock.opendj.ldap.schema;
 
 import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the caseIgnoreListMatch matching rule defined in X.520
  * and referenced in RFC 2252.
  */
 final class CaseIgnoreListEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space. Any spaces
-        // around a dollar sign will also be removed.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            if (buffer.charAt(pos) == ' ') {
-                final char c = buffer.charAt(pos - 1);
-                if (c == ' ') {
-                    buffer.delete(pos, pos + 1);
-                } else if (c == '$') {
-                    if (pos <= 1 || buffer.charAt(pos - 2) != '\\') {
-                        buffer.delete(pos, pos + 1);
-                    }
-                } else if (buffer.charAt(pos + 1) == '$') {
-                    buffer.delete(pos, pos + 1);
-                }
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringListAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
index f00bd7e..bf2ebc8 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreListSubstringMatchingRuleImpl.java
@@ -26,14 +26,11 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
-import com.forgerock.opendj.util.StringPrepProfile;
+import static com.forgerock.opendj.util.StringPrepProfile.*;
 
 /**
  * This class implements the caseIgnoreListSubstringsMatch matching rule defined
@@ -41,39 +38,7 @@
  */
 final class CaseIgnoreListSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, StringPrepProfile.TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        // Replace any consecutive spaces with a single space. Any spaces
-        // around a dollar sign will also be removed.
-        for (int pos = bufferLength - 1; pos > 0; pos--) {
-            if (buffer.charAt(pos) == ' ') {
-                final char c = buffer.charAt(pos - 1);
-                if (c == ' ') {
-                    buffer.delete(pos, pos + 1);
-                } else if (c == '$') {
-                    if (pos <= 1 || buffer.charAt(pos - 2) != '\\') {
-                        buffer.delete(pos, pos + 1);
-                    }
-                } else if (buffer.charAt(pos + 1) == '$') {
-                    buffer.delete(pos, pos + 1);
-                }
-            }
-        }
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringListAttributeValue(value, TRIM, CASE_FOLD);
     }
 
     @Override
@@ -82,23 +47,6 @@
         // In this case, the process for normalizing a substring is the same
         // as normalizing a full value with the exception that it may
         // include an opening or trailing space.
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, false, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return value.toByteString();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, false, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java
index 784accf..b295d10 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreOrderingMatchingRuleImpl.java
@@ -26,36 +26,18 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class defines the caseIgnoreOrderingMatch matching rule defined in X.520
  * and referenced in RFC 2252.
  */
 final class CaseIgnoreOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java
index 95bf3b7..aff7f7d 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/CaseIgnoreSubstringMatchingRuleImpl.java
@@ -26,14 +26,11 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
-import com.forgerock.opendj.util.StringPrepProfile;
+import static com.forgerock.opendj.util.StringPrepProfile.*;
 
 /**
  * This class defines the caseIgnoreSubstringsMatch matching rule defined in
@@ -51,24 +48,6 @@
     }
 
     private ByteString normalize(final boolean trim, final ByteSequence value) {
-
-        final StringBuilder buffer = new StringBuilder();
-        StringPrepProfile.prepareUnicode(buffer, value, trim, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return value.toByteString();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, trim, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
index a3b2162..e02293a 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/DirectoryStringFirstComponentEqualityMatchingRuleImpl.java
@@ -28,11 +28,9 @@
 
 import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
 import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
 import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_EMPTY_VALUE;
 import static com.forgerock.opendj.ldap.CoreMessages.ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS;
 
-import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.Assertion;
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
@@ -51,24 +49,7 @@
 final class DirectoryStringFirstComponentEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
     @Override
     public Assertion getAssertion(final Schema schema, final ByteSequence assertionValue) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, assertionValue, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (assertionValue.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return new DefaultEqualityAssertion(SchemaConstants.SINGLE_SPACE_VALUE);
-            } else {
-                // The value is empty, so it is already normalized.
-                return new DefaultEqualityAssertion(ByteString.empty());
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return new DefaultEqualityAssertion(ByteString.valueOf(buffer.toString()));
+        return new DefaultEqualityAssertion(SchemaUtils.normalizeStringAttributeValue(assertionValue, TRIM, CASE_FOLD));
     }
 
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value)
@@ -84,18 +65,15 @@
             // This means that the value was empty or contained only
             // whitespace.
             // That is illegal.
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_EMPTY_VALUE.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_EMPTY_VALUE.get());
         }
 
         // The next character must be an open parenthesis. If it is not,
         // then that is an error.
         final char c = reader.read();
         if (c != '(') {
-            final LocalizableMessage message =
-                    ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS.get(definition, (reader.pos() - 1),
-                            String.valueOf(c));
-            throw DecodeException.error(message);
+            throw DecodeException.error(
+                    ERR_ATTR_SYNTAX_EXPECTED_OPEN_PARENTHESIS.get(definition, reader.pos() - 1, c));
         }
 
         // Skip over any spaces immediately following the opening parenthesis.
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java
index aca1b6b..27814fd 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/EnumSyntaxImpl.java
@@ -28,10 +28,8 @@
 
 import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
 import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
 import static com.forgerock.opendj.ldap.CoreMessages.WARN_ATTR_SYNTAX_LDAPSYNTAX_ENUM_INVALID_VALUE;
 
-import static org.forgerock.opendj.ldap.schema.AbstractMatchingRuleImpl.*;
 import static org.forgerock.opendj.ldap.schema.SchemaConstants.AMR_DOUBLE_METAPHONE_OID;
 import static org.forgerock.opendj.ldap.schema.SchemaConstants.EMR_CASE_IGNORE_OID;
 import static org.forgerock.opendj.ldap.schema.SchemaConstants.OMR_OID_GENERIC_ENUM;
@@ -118,23 +116,6 @@
     }
 
     private String normalize(final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return " ";
-            } else {
-                // The value is empty, so it is already normalized.
-                return "";
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return buffer.toString();
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD).toString();
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
index 02a4c6d..8a33b76 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/KeywordEqualityMatchingRuleImpl.java
@@ -28,7 +28,6 @@
 
 import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
 import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
 
 import org.forgerock.opendj.ldap.Assertion;
 import org.forgerock.opendj.ldap.ByteSequence;
@@ -116,22 +115,6 @@
     }
 
     private String normalize(final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        if (buffer.length() == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return " ";
-            } else {
-                // The value is empty, so it is already normalized.
-                return "";
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return buffer.toString();
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD).toString();
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
index 5a329cd..98f5836 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringEqualityMatchingRuleImpl.java
@@ -26,10 +26,6 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
@@ -40,12 +36,6 @@
  */
 final class NumericStringEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        if (buffer.length() == 0) {
-            return ByteString.empty();
-        }
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeNumericStringAttributeValue(value);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java
index a829417..7152afa 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringOrderingMatchingRuleImpl.java
@@ -22,13 +22,10 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2014 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
@@ -38,12 +35,6 @@
  */
 final class NumericStringOrderingMatchingRuleImpl extends AbstractOrderingMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        if (buffer.length() == 0) {
-            return ByteString.empty();
-        }
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeNumericStringAttributeValue(value);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java
index 57d6d7d..fc3f636 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/NumericStringSubstringMatchingRuleImpl.java
@@ -22,13 +22,10 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2014 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.NO_CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
@@ -38,12 +35,6 @@
  */
 final class NumericStringSubstringMatchingRuleImpl extends AbstractSubstringMatchingRuleImpl {
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
-
-        if (buffer.length() == 0) {
-            return ByteString.empty();
-        }
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeNumericStringAttributeValue(value);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java
index 7cf97c0..026d8f5 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/PresentationAddressEqualityMatchingRuleImpl.java
@@ -26,13 +26,11 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the presentationAddressMatch matching rule defined in
  * X.520 and referenced in RFC 2252. However, since this matching rule and the
@@ -40,24 +38,8 @@
  * like the caseIgnoreMatch rule.
  */
 final class PresentationAddressEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java
index 95f1a22..a5c70ba 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/ProtocolInformationEqualityMatchingRuleImpl.java
@@ -26,13 +26,11 @@
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StringPrepProfile.CASE_FOLD;
-import static com.forgerock.opendj.util.StringPrepProfile.TRIM;
-import static com.forgerock.opendj.util.StringPrepProfile.prepareUnicode;
-
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteString;
 
+import static com.forgerock.opendj.util.StringPrepProfile.*;
+
 /**
  * This class implements the protocolInformationMatch matching rule defined in
  * X.520 and referenced in RFC 2252. However, since this matching rule and the
@@ -40,24 +38,8 @@
  * like the caseIgnoreMatch rule.
  */
 final class ProtocolInformationEqualityMatchingRuleImpl extends AbstractEqualityMatchingRuleImpl {
+    @Override
     public ByteString normalizeAttributeValue(final Schema schema, final ByteSequence value) {
-        final StringBuilder buffer = new StringBuilder();
-        prepareUnicode(buffer, value, TRIM, CASE_FOLD);
-
-        final int bufferLength = buffer.length();
-        if (bufferLength == 0) {
-            if (value.length() > 0) {
-                // This should only happen if the value is composed entirely of
-                // spaces. In that case, the normalized value is a single space.
-                return SchemaConstants.SINGLE_SPACE_VALUE;
-            } else {
-                // The value is empty, so it is already normalized.
-                return ByteString.empty();
-            }
-        }
-
-        trimConsecutiveSpaces(buffer);
-
-        return ByteString.valueOf(buffer.toString());
+        return SchemaUtils.normalizeStringAttributeValue(value, TRIM, CASE_FOLD);
     }
 }
diff --git a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
index 28cb118..1aaf180 100644
--- a/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
+++ b/opendj-sdk/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
@@ -22,14 +22,13 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
- *      Portions copyright 2011 ForgeRock AS
+ *      Portions copyright 2011-2014 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
-import static com.forgerock.opendj.util.StaticUtils.isAlpha;
-import static com.forgerock.opendj.util.StaticUtils.isDigit;
-import static com.forgerock.opendj.util.StaticUtils.isKeyChar;
 import static com.forgerock.opendj.ldap.CoreMessages.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
+import static com.forgerock.opendj.util.StringPrepProfile.*;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -41,6 +40,8 @@
 import java.util.Set;
 
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.ByteSequence;
+import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
 
 import com.forgerock.opendj.util.SubstringReader;
@@ -116,8 +117,7 @@
 
             return values;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -162,8 +162,7 @@
 
             return values;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -279,8 +278,7 @@
         }
 
         if (length == 0) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_OID_NO_VALUE1.get(reader.pos() - 1);
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_OID_NO_VALUE1.get(reader.pos() - 1));
         }
 
         reader.reset();
@@ -336,13 +334,11 @@
                         }
                     } else if (!isDigit(c)) {
                         // Technically, this must be an illegal character.
-                        // However,
-                        // it is possible that someone just got sloppy and did
-                        // not
+                        // However, it is possible that someone just got sloppy
+                        // and did not
                         // include a space between the name/OID and a closing
                         // parenthesis. In that case, we'll assume it's the end
-                        // of
-                        // the value.
+                        // of the value.
                         if (c == ')') {
                             break;
                         }
@@ -421,8 +417,7 @@
 
             return oid;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -452,8 +447,7 @@
 
             return values;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -495,8 +489,7 @@
             reader.read();
             return str;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -536,12 +529,10 @@
             try {
                 return Integer.valueOf(ruleID);
             } catch (final NumberFormatException e) {
-                final LocalizableMessage message = ERR_ATTR_SYNTAX_RULE_ID_INVALID1.get(ruleID);
-                throw DecodeException.error(message);
+                throw DecodeException.error(ERR_ATTR_SYNTAX_RULE_ID_INVALID1.get(ruleID));
             }
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -570,8 +561,7 @@
 
             return values;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -617,8 +607,7 @@
 
             return token;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -725,8 +714,7 @@
             reader.read();
             return descr;
         } catch (final StringIndexOutOfBoundsException e) {
-            final LocalizableMessage message = ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get();
-            throw DecodeException.error(message);
+            throw DecodeException.error(ERR_ATTR_SYNTAX_TRUNCATED_VALUE1.get());
         }
     }
 
@@ -735,4 +723,107 @@
         // Nothing to do.
     }
 
+    private static ByteString singleSpaceOrEmpty(final ByteSequence value) {
+        if (value.length() > 0) {
+            // This should only happen if the value is composed entirely of
+            // spaces. In that case, the normalized value is a single space.
+            return SchemaConstants.SINGLE_SPACE_VALUE;
+        }
+        // The value is empty, so it is already normalized.
+        return ByteString.empty();
+    }
+
+    static ByteString normalizeStringListAttributeValue(final ByteSequence value, boolean trim, boolean foldCase) {
+        final StringBuilder buffer = new StringBuilder();
+        prepareUnicode(buffer, value, trim, foldCase);
+
+        if (buffer.length() == 0) {
+            return singleSpaceOrEmpty(value);
+        }
+        trimConsecutiveSpacesInStringList(buffer);
+        return ByteString.valueOf(buffer.toString());
+    }
+
+    private static void trimConsecutiveSpacesInStringList(StringBuilder buffer) {
+        // Replace any consecutive spaces with a single space. Any spaces
+        // around a dollar sign will also be removed.
+        for (int pos = buffer.length() - 1; pos > 0; pos--) {
+            if (buffer.charAt(pos) == ' ') {
+                final char c = buffer.charAt(pos - 1);
+                if (c == ' ') {
+                    buffer.delete(pos, pos + 1);
+                } else if (c == '$') {
+                    if (pos <= 1 || buffer.charAt(pos - 2) != '\\') {
+                        buffer.delete(pos, pos + 1);
+                    }
+                } else if (buffer.charAt(pos + 1) == '$') {
+                    buffer.delete(pos, pos + 1);
+                }
+            }
+        }
+    }
+
+    static ByteString normalizeStringAttributeValue(final ByteSequence value, final boolean trim,
+            final boolean foldCase) {
+        final StringBuilder buffer = new StringBuilder();
+        prepareUnicode(buffer, value, trim, foldCase);
+
+        if (buffer.length() == 0) {
+            return singleSpaceOrEmpty(value);
+        }
+        trimConsecutiveSpaces(buffer);
+        return ByteString.valueOf(buffer.toString());
+    }
+
+    private static void trimConsecutiveSpaces(StringBuilder buffer) {
+        for (int pos = buffer.length() - 1; pos > 0; pos--) {
+            if (buffer.charAt(pos) == ' '
+                    && buffer.charAt(pos - 1) == ' ') {
+                buffer.delete(pos, pos + 1);
+            }
+        }
+    }
+
+    static ByteString normalizeIA5StringAttributeValue(final ByteSequence value, boolean trim, boolean foldCase)
+            throws DecodeException {
+        final StringBuilder buffer = new StringBuilder();
+        prepareUnicode(buffer, value, trim, foldCase);
+
+        if (buffer.length() == 0) {
+            return singleSpaceOrEmpty(value);
+        }
+        trimConsecutiveSpacesInIA5String(buffer, value);
+        return ByteString.valueOf(buffer.toString());
+    }
+
+    private static void trimConsecutiveSpacesInIA5String(StringBuilder buffer, ByteSequence value)
+            throws DecodeException {
+        // Replace any consecutive spaces with a single space and watch out
+        // for non-ASCII characters.
+        for (int pos = buffer.length() - 1; pos > 0; pos--) {
+            final char c = buffer.charAt(pos);
+            if (c == ' ') {
+                if (buffer.charAt(pos - 1) == ' ') {
+                    buffer.delete(pos, pos + 1);
+                }
+            } else if ((c & 0x7F) != c) {
+                // This is not a valid character for an IA5 string. If strict
+                // syntax enforcement is enabled, then we'll throw an exception.
+                // Otherwise, we'll get rid of the character.
+                throw DecodeException.error(
+                        WARN_ATTR_SYNTAX_IA5_ILLEGAL_CHARACTER.get(value, c));
+            }
+        }
+    }
+
+    static ByteString normalizeNumericStringAttributeValue(final ByteSequence value) {
+        final StringBuilder buffer = new StringBuilder();
+        prepareUnicode(buffer, value, TRIM, NO_CASE_FOLD);
+
+        if (buffer.length() == 0) {
+            return ByteString.empty();
+        }
+        return ByteString.valueOf(buffer.toString());
+    }
+
 }

--
Gitblit v1.10.0