From 2e3744358baf3083a347e070d18f03a48140505d Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 16 Jun 2011 18:00:52 +0000
Subject: [PATCH] Fix OPENDJ-198: RFC 4512 compliance for ldap-toolkit

---
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java                                                 |   31 +
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java                                                 |   96 ++++
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java                        |    4 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java                                          |   47 ++
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java                                |  220 ++++++++++++
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java |    7 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java                                          |    4 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java               |    7 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java                                |   22 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java                             |    7 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java                              |    4 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java                              |   10 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java                                         |  221 +++++++++---
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java                               |   19 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java                               |   14 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java                                        |   34 +
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java                                 |    4 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java                                          |   96 +++-
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java                                |    7 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java                                        |    8 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java                                            |   51 +-
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java                                 |   10 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java                                                   |   19 +
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java                                  |   16 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java                                     |   16 
 opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java                                          |   10 
 26 files changed, 771 insertions(+), 213 deletions(-)

diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java
index 8eb5039..30b471d 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/ASCIICharProp.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package com.forgerock.opendj.util;
@@ -56,6 +57,8 @@
 
   private final boolean isKeyChar;
 
+  private final boolean isCompatKeyChar;
+
   private final boolean isHexChar;
 
   private final int hexValue;
@@ -137,6 +140,7 @@
       this.isDigit = false;
       this.isLetter = true;
       this.isKeyChar = true;
+      this.isCompatKeyChar = true;
       this.decimalValue = -1;
       if (c >= 'a' && c <= 'f')
       {
@@ -158,6 +162,7 @@
       this.isDigit = false;
       this.isLetter = true;
       this.isKeyChar = true;
+      this.isCompatKeyChar = true;
       this.decimalValue = -1;
       if (c >= 'A' && c <= 'F')
       {
@@ -179,6 +184,7 @@
       this.isDigit = true;
       this.isLetter = false;
       this.isKeyChar = true;
+      this.isCompatKeyChar = true;
       this.isHexChar = true;
       this.hexValue = c - 48;
       this.decimalValue = c - 48;
@@ -192,6 +198,7 @@
       this.isDigit = false;
       this.isLetter = false;
       this.isKeyChar = c == '-';
+      this.isCompatKeyChar = (c == '-') || (c == '.') || (c == '_');
       this.isHexChar = false;
       this.hexValue = -1;
       this.decimalValue = -1;
@@ -301,16 +308,26 @@
 
 
   /**
-   * Indicates whether or not the char value associated with this {@code
-   * ASCIICharProp} is a {@code keychar} as defined in RFC 4512. A {@code
-   * keychar} is a letter, a digit, or a hyphen.
+   * Indicates whether or not the char value associated with this
+   * {@code ASCIICharProp} is a {@code keychar} as defined in RFC 4512. A
+   * {@code keychar} is a letter, a digit, or a hyphen. When
+   * {@code allowCompatChars} is {@code true} the following illegal characters
+   * will be permitted:
    *
-   * @return {@code true} if the char value associated with this {@code
-   *         ASCIICharProp} is a {@code keychar}.
+   * <pre>
+   * USCORE  = %x5F ; underscore ("_")
+   * DOT     = %x2E ; period (".")
+   * </pre>
+   *
+   * @param allowCompatChars
+   *          {@code true} if certain illegal characters should be allowed for
+   *          compatibility reasons.
+   * @return {@code true} if the char value associated with this
+   *         {@code ASCIICharProp} is a {@code keychar}.
    */
-  public boolean isKeyChar()
+  public boolean isKeyChar(final boolean allowCompatChars)
   {
-    return isKeyChar;
+    return allowCompatChars ? isCompatKeyChar : isKeyChar;
   }
 
 
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
index 734c62e..cbd42f0 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/StaticUtils.java
@@ -1773,6 +1773,25 @@
 
 
   /**
+   * Indicates whether the provided character is a keychar.
+   *
+   * @param c
+   *          The character for which to make the determination.
+   * @param allowCompatChars
+   *          {@code true} if certain illegal characters should be allowed for
+   *          compatibility reasons.
+   * @return <CODE>true</CODE> if the provided character represents a
+   *         keychar, or <CODE>false</CODE> if not.
+   */
+  public static boolean isKeyChar(final char c, final boolean allowCompatChars)
+  {
+    final ASCIICharProp cp = ASCIICharProp.valueOf(c);
+    return cp != null ? cp.isKeyChar(allowCompatChars) : false;
+  }
+
+
+
+  /**
    * Returns a string whose content is the string representation of the objects
    * contained in the provided collection concatenated together using the
    * provided separator.
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
index 1379e95..875da3b 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -884,6 +884,8 @@
       final String attributeDescription, final Schema schema)
       throws LocalizedIllegalArgumentException
   {
+    final boolean allowMalformedNamesAndOptions = schema
+        .allowMalformedNamesAndOptions();
     int i = 0;
     final int length = attributeDescription.length();
     char c = 0;
@@ -933,7 +935,7 @@
         }
 
         cp = ASCIICharProp.valueOf(c);
-        if (!cp.isKeyChar())
+        if (!cp.isKeyChar(allowMalformedNamesAndOptions))
         {
           final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
               .get(attributeDescription, c, i);
@@ -1003,7 +1005,7 @@
     }
 
     // Get the attribute type from the schema.
-    AttributeType attributeType;
+    final AttributeType attributeType;
     try
     {
       attributeType = schema.getAttributeType(oid);
@@ -1046,7 +1048,7 @@
       }
 
       cp = ASCIICharProp.valueOf(c);
-      if (!cp.isKeyChar())
+      if (!cp.isKeyChar(allowMalformedNamesAndOptions))
       {
         final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
             .get(attributeDescription, c, i);
@@ -1125,7 +1127,7 @@
         }
 
         cp = ASCIICharProp.valueOf(c);
-        if (!cp.isKeyChar())
+        if (!cp.isKeyChar(allowMalformedNamesAndOptions))
         {
           final LocalizableMessage message = ERR_ATTRIBUTE_DESCRIPTION_ILLEGAL_CHARACTER
               .get(attributeDescription, c, i);
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java
index ddbc57c..f65f945 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeTypeSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -114,7 +115,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -135,7 +137,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -155,25 +158,29 @@
           // This specifies the name or OID of the superior attribute
           // type from which this attribute type should inherit its
           // properties.
-          SchemaUtils.readOID(reader);
+          SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("equality"))
         {
           // This specifies the name or OID of the equality matching
           // rule to use for this attribute type.
-          SchemaUtils.readOID(reader);
+          SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("ordering"))
         {
           // This specifies the name or OID of the ordering matching
           // rule to use for this attribute type.
-          SchemaUtils.readOID(reader);
+          SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("substr"))
         {
           // This specifies the name or OID of the substring matching
           // rule to use for this attribute type.
-          SchemaUtils.readOID(reader);
+          SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("syntax"))
         {
@@ -185,7 +192,8 @@
           // implementation will ignore any such length because it does
           // not impose any practical limit on the length of attribute
           // values.
-          SchemaUtils.readOIDLen(reader);
+          SchemaUtils.readOIDLen(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("single-definition"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java
index 1b46f9b..8ac4bc5 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -122,7 +123,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      SchemaUtils.readOID(reader);
+      SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -143,7 +145,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -160,19 +163,23 @@
         }
         else if (tokenName.equalsIgnoreCase("aux"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("not"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java
index 1aa4a06..90897e9 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DITStructureRuleSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -143,7 +144,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -160,7 +162,8 @@
         }
         else if (tokenName.equalsIgnoreCase("form"))
         {
-          nameForm = SchemaUtils.readOID(reader);
+          nameForm = SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("sup"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java
new file mode 100644
index 0000000..56c287f
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DefaultSchema.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ * trunk/opendj3/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
+ * trunk/opendj3/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 2011 ForgeRock AS
+ */
+
+package org.forgerock.opendj.ldap.schema;
+
+
+
+/**
+ * This class is used to maintain a reference to the default schema and avoid
+ * having to reference the core schema in the {@link Schema} class since this
+ * can cause initialization errors because the CoreSchema depends on Schema.
+ */
+final class DefaultSchema
+{
+  private DefaultSchema()
+  {
+    // Prevent instantiation.
+  }
+
+
+
+  static volatile Schema schema = Schema.getCoreSchema();
+}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java
index 7cd287b..15409e1 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/EnhancedGuideSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -123,7 +124,8 @@
 
     try
     {
-      SchemaUtils.readOID(new SubstringReader(ocName.substring(ocLength)));
+      SchemaUtils.readOID(new SubstringReader(ocName.substring(ocLength)),
+          schema.allowMalformedNamesAndOptions());
     }
     catch (final DecodeException de)
     {
@@ -176,6 +178,7 @@
       return false;
     }
 
-    return GuideSyntaxImpl.criteriaIsValid(criteria, valueStr, invalidReason);
+    return GuideSyntaxImpl.criteriaIsValid(schema, criteria,
+        valueStr, invalidReason);
   }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java
index e438696..efc4d81 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/GuideSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -54,6 +55,8 @@
    * Determines whether the provided string represents a valid criteria
    * according to the guide syntax.
    *
+   * @param schema
+   *          The schema in which this syntax is defined.
    * @param criteria
    *          The portion of the criteria for which to make the determination.
    * @param valueStr
@@ -64,7 +67,8 @@
    * @return <CODE>true</CODE> if the provided string does contain a valid
    *         criteria, or <CODE>false</CODE> if not.
    */
-  static boolean criteriaIsValid(final String criteria, final String valueStr,
+  static boolean criteriaIsValid(final Schema schema,
+      final String criteria, final String valueStr,
       final LocalizableMessageBuilder invalidReason)
   {
     // See if the criteria starts with a '!'. If so, then just evaluate
@@ -72,7 +76,8 @@
     char c = criteria.charAt(0);
     if (c == '!')
     {
-      return criteriaIsValid(criteria.substring(1), valueStr, invalidReason);
+      return criteriaIsValid(schema, criteria.substring(1), valueStr,
+          invalidReason);
     }
 
     // See if the criteria starts with a '('. If so, then find the
@@ -91,7 +96,7 @@
           if (depth == 0)
           {
             final String subCriteria = criteria.substring(1, i);
-            if (!criteriaIsValid(subCriteria, valueStr, invalidReason))
+            if (!criteriaIsValid(schema, subCriteria, valueStr, invalidReason))
             {
               return false;
             }
@@ -108,7 +113,8 @@
               c = criteria.charAt(i + 1);
               if (c == '|' || c == '&')
               {
-                return criteriaIsValid(criteria.substring(i + 2), valueStr,
+                return criteriaIsValid(schema,
+                    criteria.substring(i + 2), valueStr,
                     invalidReason);
               }
               else
@@ -152,7 +158,7 @@
           c = criteria.charAt(5);
           if (c == '|' || c == '&')
           {
-            return criteriaIsValid(criteria.substring(6), valueStr,
+            return criteriaIsValid(schema, criteria.substring(6), valueStr,
                 invalidReason);
           }
           else
@@ -176,7 +182,7 @@
           c = criteria.charAt(6);
           if (c == '|' || c == '&')
           {
-            return criteriaIsValid(criteria.substring(7), valueStr,
+            return criteriaIsValid(schema, criteria.substring(7), valueStr,
                 invalidReason);
           }
           else
@@ -230,7 +236,8 @@
       try
       {
         SchemaUtils.readOID(new SubstringReader(criteria
-            .substring(0, dollarPos)));
+            .substring(0, dollarPos)),
+            schema.allowMalformedNamesAndOptions());
       }
       catch (final DecodeException de)
       {
@@ -328,8 +335,8 @@
       c = criteria.charAt(endPos);
       if (c == '|' || c == '&')
       {
-        return criteriaIsValid(criteria.substring(endPos + 1), valueStr,
-            invalidReason);
+        return criteriaIsValid(schema,
+            criteria.substring(endPos + 1), valueStr, invalidReason);
       }
       else
       {
@@ -397,7 +404,7 @@
     final int sharpPos = valueStr.indexOf('#');
     if (sharpPos < 0)
     {
-      return criteriaIsValid(valueStr, valueStr, invalidReason);
+      return criteriaIsValid(schema, valueStr, valueStr, invalidReason);
     }
 
     // Get the objectclass and see if it is a valid name or OID.
@@ -412,7 +419,8 @@
 
     try
     {
-      SchemaUtils.readOID(new SubstringReader(ocName.substring(0, ocLength)));
+      SchemaUtils.readOID(new SubstringReader(ocName.substring(0, ocLength)),
+          schema.allowMalformedNamesAndOptions());
     }
     catch (final DecodeException de)
     {
@@ -421,7 +429,7 @@
     }
 
     // The rest of the value must be the criteria.
-    return criteriaIsValid(valueStr.substring(sharpPos + 1), valueStr,
-        invalidReason);
+    return criteriaIsValid(schema, valueStr.substring(sharpPos + 1),
+        valueStr, invalidReason);
   }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java
index a79389b..b319dfb 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/LDAPSyntaxDescriptionSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -120,7 +121,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       Map<String, List<String>> extraProperties = Collections.emptyMap();
       // At this point, we should have a pretty specific syntax that
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java
index af4614e..94d28e0 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -129,7 +130,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      SchemaUtils.readOID(reader);
+      SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
       String syntax = null;
 
       // At this point, we should have a pretty specific syntax that
@@ -151,7 +153,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -168,7 +171,8 @@
         }
         else if (tokenName.equalsIgnoreCase("syntax"))
         {
-          syntax = SchemaUtils.readOID(reader);
+          syntax = SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java
index a988501..88e68ed 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -132,7 +133,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      SchemaUtils.readOID(reader);
+      SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -154,7 +156,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -171,7 +174,8 @@
         }
         else if (tokenName.equalsIgnoreCase("applies"))
         {
-          attributes = SchemaUtils.readOIDs(reader);
+          attributes = SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java
index 7b395b2..2eb90ae 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/NameFormSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -119,7 +120,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      SchemaUtils.readOID(reader);
+      SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       String structuralClass = null;
       Set<String> requiredAttributes = null;
@@ -143,7 +145,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -160,15 +163,18 @@
         }
         else if (tokenName.equalsIgnoreCase("oc"))
         {
-          structuralClass = SchemaUtils.readOID(reader);
+          structuralClass = SchemaUtils.readOID(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          requiredAttributes = SchemaUtils.readOIDs(reader);
+          requiredAttributes = SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java
index b9a66c4..6aa5aa2 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/OIDSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -96,7 +97,8 @@
   {
     try
     {
-      SchemaUtils.readOID(new SubstringReader(value.toString()));
+      SchemaUtils.readOID(new SubstringReader(value.toString()),
+          schema.allowMalformedNamesAndOptions());
       return true;
     }
     catch (final DecodeException de)
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java
index 79d81a6..2121648 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectClassSyntaxImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package org.forgerock.opendj.ldap.schema;
@@ -116,7 +117,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      SchemaUtils.readOID(reader);
+      SchemaUtils.readOID(reader,
+          schema.allowMalformedNamesAndOptions());
 
       // At this point, we should have a pretty specific syntax that
       // describes what may come next, but some of the components are
@@ -137,7 +139,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          SchemaUtils.readNameDescriptors(reader);
+          SchemaUtils.readNameDescriptors(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -154,7 +157,8 @@
         }
         else if (tokenName.equalsIgnoreCase("sup"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("abstract"))
         {
@@ -175,11 +179,13 @@
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          SchemaUtils.readOIDs(reader);
+          SchemaUtils.readOIDs(reader,
+              schema.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
index ae278de..7f59333 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierEqualityMatchingRuleImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -161,7 +162,8 @@
   {
     final String definition = value.toString();
     final SubstringReader reader = new SubstringReader(definition);
-    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader));
+    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader,
+        schema.allowMalformedNamesAndOptions()));
 
     return new OIDAssertion(normalized);
   }
@@ -173,7 +175,8 @@
   {
     final String definition = value.toString();
     final SubstringReader reader = new SubstringReader(definition);
-    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader));
+    final String normalized = resolveNames(schema, SchemaUtils.readOID(reader,
+        schema.allowMalformedNamesAndOptions()));
     return ByteString.valueOf(normalized);
   }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java
index 7a0bc74..c65b3ed 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/ObjectIdentifierFirstComponentEqualityMatchingRuleImpl.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -59,7 +60,8 @@
     final String definition = value.toString();
     final SubstringReader reader = new SubstringReader(definition);
     final String normalized = ObjectIdentifierEqualityMatchingRuleImpl
-        .resolveNames(schema, SchemaUtils.readOID(reader));
+        .resolveNames(schema, SchemaUtils.readOID(reader,
+            schema.allowMalformedNamesAndOptions()));
 
     return new ObjectIdentifierEqualityMatchingRuleImpl.OIDAssertion(normalized);
   }
@@ -100,7 +102,8 @@
 
     // The next set of characters must be the OID.
     final String normalized = ObjectIdentifierEqualityMatchingRuleImpl
-        .resolveNames(schema, SchemaUtils.readOID(reader));
+        .resolveNames(schema, SchemaUtils.readOID(reader,
+            schema.allowMalformedNamesAndOptions()));
     return ByteString.valueOf(normalized);
   }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index 6a2d2b9..9fc4a13 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -46,6 +47,7 @@
 import com.forgerock.opendj.util.FutureResultTransformer;
 import com.forgerock.opendj.util.RecursiveFutureResult;
 import com.forgerock.opendj.util.StaticUtils;
+import com.forgerock.opendj.util.Validator;
 
 
 
@@ -1456,13 +1458,12 @@
   }
 
 
-
-  private static final Schema CORE_SCHEMA = CoreSchemaImpl.getInstance();
+  /*
+   * WARNING: do not reference the core schema in the following declarations.
+   */
 
   private static final Schema EMPTY_SCHEMA = new Schema(new EmptyImpl());
 
-  private static volatile Schema defaultSchema = CoreSchemaImpl.getInstance();
-
   static final String ATTR_ATTRIBUTE_TYPES = "attributeTypes";
 
   static final String ATTR_DIT_CONTENT_RULES = "dITContentRules";
@@ -1482,17 +1483,16 @@
   private static final String ATTR_SUBSCHEMA_SUBENTRY = "subschemaSubentry";
 
   private static final String[] SUBSCHEMA_ATTRS = new String[] {
-      ATTR_LDAP_SYNTAXES.toString(), ATTR_ATTRIBUTE_TYPES.toString(),
-      ATTR_DIT_CONTENT_RULES.toString(), ATTR_DIT_STRUCTURE_RULES.toString(),
-      ATTR_MATCHING_RULE_USE.toString(), ATTR_MATCHING_RULES.toString(),
-      ATTR_NAME_FORMS.toString(), ATTR_OBJECT_CLASSES.toString() };
+      ATTR_LDAP_SYNTAXES, ATTR_ATTRIBUTE_TYPES,
+      ATTR_DIT_CONTENT_RULES, ATTR_DIT_STRUCTURE_RULES,
+      ATTR_MATCHING_RULE_USE, ATTR_MATCHING_RULES,
+      ATTR_NAME_FORMS, ATTR_OBJECT_CLASSES };
 
-  private static final Filter SUBSCHEMA_FILTER = Filter.newEqualityMatchFilter(
-      CoreSchema.getObjectClassAttributeType().getNameOrOID(), CoreSchema
-          .getSubschemaObjectClass().getNameOrOID());
+  private static final Filter SUBSCHEMA_FILTER = Filter
+      .valueOf("(objectClass=subschema)");
 
-  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS = new String[] { ATTR_SUBSCHEMA_SUBENTRY
-      .toString() };
+  private static final String[] SUBSCHEMA_SUBENTRY_ATTRS =
+    new String[] { ATTR_SUBSCHEMA_SUBENTRY };
 
 
 
@@ -1518,7 +1518,7 @@
    */
   public static Schema getCoreSchema()
   {
-    return CORE_SCHEMA;
+    return CoreSchemaImpl.getInstance();
   }
 
 
@@ -1531,7 +1531,7 @@
    */
   public static Schema getDefaultSchema()
   {
-    return defaultSchema;
+    return DefaultSchema.schema;
   }
 
 
@@ -1765,7 +1765,8 @@
    */
   public static void setDefaultSchema(final Schema schema)
   {
-    defaultSchema = schema;
+    Validator.ensureNotNull(schema);
+    DefaultSchema.schema = schema;
   }
 
 
@@ -1896,6 +1897,69 @@
 
 
   /**
+   * Returns {@code true} if this schema allows certain illegal characters
+   * in OIDs and attribute options. When this compatibility option is set to
+   * {@code true} the following illegal characters will be permitted:
+   *
+   * <pre>
+   * USCORE  = %x5F ; underscore ("_")
+   * DOT     = %x2E ; period (".")
+   * </pre>
+   *
+   * By default this compatibility option is set to {@code false}.
+   *
+   * @return {@code true} if this schema allows certain illegal characters
+   *         in OIDs and attribute options.
+   * @see <a href="http://tools.ietf.org/html/rfc4512">RFC 4512 - Lightweight
+   *      Directory Access Protocol (LDAP): Directory Information Models </a>
+   */
+  public boolean allowMalformedNamesAndOptions()
+  {
+    return impl.getSchemaCompatOptions().allowMalformedNamesAndOptions();
+  }
+
+
+
+  /**
+   * Returns {@code true} if the Telephone Number syntax defined for this schema
+   * allows values which do not conform to the E.123 international telephone
+   * number format.
+   * <p>
+   * By default this compatibility option is set to {@code true}.
+   *
+   * @return {@code true} if the Telephone Number syntax defined for this schema
+   *         allows values which do not conform to the E.123 international
+   *         telephone number format.
+   */
+  public boolean allowNonStandardTelephoneNumbers()
+  {
+    return impl.getSchemaCompatOptions()
+        .allowNonStandardTelephoneNumbers();
+  }
+
+
+
+  /**
+   * Returns {@code true} if zero-length values will be allowed by the Directory
+   * String syntax defined for this schema. This is technically forbidden by the
+   * LDAP specification, but it was allowed in earlier versions of the server,
+   * and the discussion of the directory string syntax in RFC 2252 does not
+   * explicitly state that they are not allowed.
+   * <p>
+   * By default this compatibility option is set to {@code false}.
+   *
+   * @return {@code true} if zero-length values will be allowed by the Directory
+   *         String syntax defined for this schema, or {@code false} if not.
+   */
+  public boolean allowZeroLengthDirectoryStrings()
+  {
+    return impl.getSchemaCompatOptions()
+        .allowZeroLengthDirectoryStrings();
+  }
+
+
+
+  /**
    * Returns the attribute type with the specified name or numeric OID.
    *
    * @param name
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index ee2d781..1b5d4ed 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -226,7 +226,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -262,7 +263,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -283,25 +285,29 @@
           // This specifies the name or OID of the superior attribute
           // type from which this attribute type should inherit its
           // properties.
-          superiorType = SchemaUtils.readOID(reader);
+          superiorType = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("equality"))
         {
           // This specifies the name or OID of the equality matching
           // rule to use for this attribute type.
-          equalityMatchingRule = SchemaUtils.readOID(reader);
+          equalityMatchingRule = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("ordering"))
         {
           // This specifies the name or OID of the ordering matching
           // rule to use for this attribute type.
-          orderingMatchingRule = SchemaUtils.readOID(reader);
+          orderingMatchingRule = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("substr"))
         {
           // This specifies the name or OID of the substring matching
           // rule to use for this attribute type.
-          substringMatchingRule = SchemaUtils.readOID(reader);
+          substringMatchingRule = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("syntax"))
         {
@@ -313,7 +319,8 @@
           // implementation will ignore any such length because it does
           // not impose any practical limit on the length of attribute
           // values.
-          syntax = SchemaUtils.readOIDLen(reader);
+          syntax = SchemaUtils.readOIDLen(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("single-definition"))
         {
@@ -569,7 +576,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String structuralClass = SchemaUtils.readOID(reader);
+      final String structuralClass = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -599,7 +607,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -617,19 +626,23 @@
         }
         else if (tokenName.equalsIgnoreCase("aux"))
         {
-          auxiliaryClasses = SchemaUtils.readOIDs(reader);
+          auxiliaryClasses = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          requiredAttributes = SchemaUtils.readOIDs(reader);
+          requiredAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          optionalAttributes = SchemaUtils.readOIDs(reader);
+          optionalAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("not"))
         {
-          prohibitedAttributes = SchemaUtils.readOIDs(reader);
+          prohibitedAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
@@ -857,7 +870,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -875,7 +889,8 @@
         }
         else if (tokenName.equalsIgnoreCase("form"))
         {
-          nameForm = SchemaUtils.readOID(reader);
+          nameForm = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("sup"))
         {
@@ -1030,7 +1045,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -1057,7 +1073,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -1075,7 +1092,8 @@
         }
         else if (tokenName.equalsIgnoreCase("syntax"))
         {
-          syntax = SchemaUtils.readOID(reader);
+          syntax = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
@@ -1223,7 +1241,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -1250,7 +1269,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -1268,7 +1288,8 @@
         }
         else if (tokenName.equalsIgnoreCase("applies"))
         {
-          attributes = SchemaUtils.readOIDs(reader);
+          attributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
@@ -1413,7 +1434,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -1442,7 +1464,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -1460,15 +1483,18 @@
         }
         else if (tokenName.equalsIgnoreCase("oc"))
         {
-          structuralClass = SchemaUtils.readOID(reader);
+          structuralClass = SchemaUtils.readOID(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          requiredAttributes = SchemaUtils.readOIDs(reader);
+          requiredAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          optionalAttributes = SchemaUtils.readOIDs(reader);
+          optionalAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
@@ -1630,7 +1656,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       List<String> names = Collections.emptyList();
       String description = "".intern();
@@ -1660,7 +1687,8 @@
         }
         else if (tokenName.equalsIgnoreCase("name"))
         {
-          names = SchemaUtils.readNameDescriptors(reader);
+          names = SchemaUtils.readNameDescriptors(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("desc"))
         {
@@ -1678,7 +1706,8 @@
         }
         else if (tokenName.equalsIgnoreCase("sup"))
         {
-          superiorClasses = SchemaUtils.readOIDs(reader);
+          superiorClasses = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("abstract"))
         {
@@ -1702,11 +1731,13 @@
         }
         else if (tokenName.equalsIgnoreCase("must"))
         {
-          requiredAttributes = SchemaUtils.readOIDs(reader);
+          requiredAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.equalsIgnoreCase("may"))
         {
-          optionalAttributes = SchemaUtils.readOIDs(reader);
+          optionalAttributes = SchemaUtils.readOIDs(reader,
+              options.allowMalformedNamesAndOptions());
         }
         else if (tokenName.matches("^X-[A-Za-z_-]+$"))
         {
@@ -2163,7 +2194,8 @@
       reader.skipWhitespaces();
 
       // The next set of characters must be the OID.
-      final String oid = SchemaUtils.readOID(reader);
+      final String oid = SchemaUtils.readOID(reader,
+          options.allowMalformedNamesAndOptions());
 
       String description = "".intern();
       Map<String, List<String>> extraProperties = Collections.emptyMap();
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
index 4c398c3..8f8c6b7 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/SchemaUtils.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -30,6 +31,7 @@
 
 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 org.forgerock.opendj.ldap.CoreMessages.*;
 
 import java.util.*;
@@ -137,10 +139,10 @@
 
 
 
-  static List<String> readNameDescriptors(final SubstringReader reader)
+  static List<String> readNameDescriptors(
+      final SubstringReader reader, final boolean allowCompatChars)
       throws DecodeException
   {
-    int length = 0;
     List<String> values;
 
     // Skip over any spaces at the beginning of the value.
@@ -148,18 +150,13 @@
 
     try
     {
+      reader.mark();
       char c = reader.read();
       if (c == '\'')
       {
-        reader.mark();
-        // Parse until the closing quote.
-        while (reader.read() != '\'')
-        {
-          length++;
-        }
-
         reader.reset();
-        values = Collections.singletonList(reader.read(length));
+        values = Collections.singletonList(readQuotedDescriptor(
+            reader, allowCompatChars));
         reader.read();
       }
       else if (c == '(')
@@ -179,7 +176,7 @@
           do
           {
             reader.reset();
-            values.add(readQuotedDescriptor(reader));
+            values.add(readQuotedDescriptor(reader, allowCompatChars));
             reader.skipWhitespaces();
             reader.mark();
           }
@@ -211,11 +208,15 @@
    *
    * @param reader
    *          The string representation of the definition.
+   * @param allowCompatChars
+   *          {@code true} if certain illegal characters should be allowed for
+   *          compatibility reasons.
    * @return The attribute description or numeric OID read from the definition.
    * @throws DecodeException
    *           If a problem is encountered while reading the name or OID.
    */
-  static String readOID(final SubstringReader reader) throws DecodeException
+  static String readOID(final SubstringReader reader,
+      final boolean allowCompatChars) throws DecodeException
   {
     int length = 0;
     boolean enclosingQuote = false;
@@ -305,7 +306,7 @@
             throw DecodeException.error(message);
           }
 
-          if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '.' && c != '_')
+          if (!isKeyChar(c, allowCompatChars))
           {
             // This is an illegal character.
             final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
@@ -355,11 +356,15 @@
    *
    * @param reader
    *          The string representation of the definition.
+   * @param allowCompatChars
+   *          {@code true} if certain illegal characters should be allowed for
+   *          compatibility reasons.
    * @return The OID read from the definition.
    * @throws DecodeException
    *           If a problem is encountered while reading the token name.
    */
-  static String readOIDLen(final SubstringReader reader) throws DecodeException
+  static String readOIDLen(final SubstringReader reader,
+      final boolean allowCompatChars) throws DecodeException
   {
     int length = 1;
     boolean enclosingQuote = false;
@@ -445,7 +450,7 @@
             throw DecodeException.error(message);
           }
 
-          if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '.' && c != '_')
+          if (!isKeyChar(c, allowCompatChars))
           {
             // This is an illegal character.
             final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
@@ -505,8 +510,8 @@
 
 
 
-  static Set<String> readOIDs(final SubstringReader reader)
-      throws DecodeException
+  static Set<String> readOIDs(final SubstringReader reader,
+      final boolean allowCompatChars) throws DecodeException
   {
     Set<String> values;
 
@@ -522,7 +527,7 @@
         values = new LinkedHashSet<String>();
         do
         {
-          values.add(readOID(reader));
+          values.add(readOID(reader, allowCompatChars));
 
           // Skip over any trailing spaces;
           reader.skipWhitespaces();
@@ -533,7 +538,7 @@
       else
       {
         reader.reset();
-        values = Collections.singleton(readOID(reader));
+        values = Collections.singleton(readOID(reader, allowCompatChars));
       }
 
       return values;
@@ -828,11 +833,15 @@
    *
    * @param reader
    *          The string representation of the definition.
+   * @param allowCompatChars
+   *          {@code true} if certain illegal characters should be allowed for
+   *          compatibility reasons.
    * @return The string value read from the definition.
    * @throws DecodeException
    *           If a problem is encountered while reading the quoted string.
    */
-  private static String readQuotedDescriptor(final SubstringReader reader)
+  private static String readQuotedDescriptor(
+      final SubstringReader reader, final boolean allowCompatChars)
       throws DecodeException
   {
     int length = 0;
@@ -863,7 +872,7 @@
           throw DecodeException.error(message);
         }
 
-        if (!isAlpha(c) && !isDigit(c) && c != '-' && c != '_' && c != '.')
+        if (!isKeyChar(c, allowCompatChars))
         {
           // This is an illegal character.
           final LocalizableMessage message = ERR_ATTR_SYNTAX_ILLEGAL_CHAR_IN_STRING_OID
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java
index e7a4a9c..d1a59c8 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/com/forgerock/opendj/util/ASCIICharPropTestCase.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2010 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 
 package com.forgerock.opendj.util;
@@ -30,7 +31,6 @@
 
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
 
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -68,32 +68,140 @@
   @DataProvider(name = "validasciidata")
   public Object[][] createValidASCIIData()
   {
+    // @formatter:off
     return new Object[][] {
-        { (char) 1,/* uppercase */false,/* hex value */0,/* decimal value */0,/*
-                                                                               * is
-                                                                               * letter
-                                                                               */
-        false,/* is digit */false,/* is keychar */false },
-        { '-',/* uppercase */false,/* hex value */-1,/* decimal value */-1,/*
-                                                                            * is
-                                                                            * letter
-                                                                            */
-        false,/* is digit */false,/* is keychar */true },
-        { 'a',/* uppercase */false,/* hex value */10,/* decimal value */-1,/*
-                                                                            * is
-                                                                            * letter
-                                                                            */
-        true,/* is digit */false,/* is keychar */true },
-        { 'A',/* uppercase */true,/* hex value */10,/* decimal value */-1,/*
-                                                                           * is
-                                                                           * letter
-                                                                           */
-        true,/* is digit */false,/* is keychar */true },
-        { '1',/* uppercase */false,/* hex value */1,/* decimal value */1,/*
-                                                                          * is
-                                                                          * letter
-                                                                          */
-        false,/* is digit */true,/* is keychar */true }, };
+        {
+          (char) 1,
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          false, // is letter
+          false, // is digit
+          false, // is key char
+          false  // is compat key char
+        },
+        {
+          '-',
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          false, // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          '_',
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          false, // is letter
+          false, // is digit
+          false, // is key char
+          true   // is compat key char
+        },
+        {
+          '.',
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          false, // is letter
+          false, // is digit
+          false, // is key char
+          true   // is compat key char
+        },
+        {
+          '+',
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          false, // is letter
+          false, // is digit
+          false, // is key char
+          false  // is compat key char
+        },
+        {
+          'a',
+          false, // uppercase
+          10,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          'A',
+          true,  // uppercase
+          10,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          'f',
+          false, // uppercase
+          15,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          'F',
+          true,  // uppercase
+          15,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          'z',
+          false, // uppercase
+          -1,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          'Z',
+          true,  // uppercase
+          -1,    // hex
+          -1,    // decimal
+          true,  // is letter
+          false, // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          '0',
+          false, // uppercase
+          0,     // hex
+          0,     // decimal
+          false, // is letter
+          true,  // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+        {
+          '9',
+          false, // uppercase
+          9,     // hex
+          9,     // decimal
+          false, // is letter
+          true,  // is digit
+          true,  // is key char
+          true   // is compat key char
+        },
+    };
+    // @formatter:on
   }
 
 
@@ -107,7 +215,7 @@
    *           In case of any errors.
    */
   @Test(dataProvider = "invalidasciidata")
-  public void testEncode(final char myChar) throws Exception
+  public void testValueOf(final char myChar) throws Exception
   {
     assertEquals(ASCIICharProp.valueOf(myChar), null);
   }
@@ -131,55 +239,42 @@
    *          Whether the character is a digit
    * @param isKeyChar
    *          Whether the character is a key char.
+   * @param isCompatKeyChar
+   *          Whether the character is a compat key char.
    * @throws Exception
    *           In case of any errors.
    */
   @Test(dataProvider = "validasciidata")
-  public void testEncode(final char myChar, final Boolean isUpper,
-      final Integer hexValue, final Integer decimalValue,
-      final Boolean isLetter, final Boolean isDigit, final Boolean isKeyChar)
+  public void testValueOf(final char myChar, final boolean isUpper,
+      final int hexValue, final int decimalValue,
+      final boolean isLetter, final boolean isDigit,
+      final boolean isKeyChar, final boolean isCompatKeyChar)
       throws Exception
   {
     final ASCIICharProp myProp = ASCIICharProp.valueOf(myChar);
 
     // check letter.
-    if (isLetter)
-    {
-      assertTrue(myProp.isLetter());
-      // Check case.
-      if (isUpper)
-      {
-        assertTrue(myProp.isUpperCase());
-      }
-      else
-      {
-        assertTrue(myProp.isLowerCase());
-      }
-    }
+    assertEquals(isLetter, myProp.isLetter());
+
+    // Check case.
+    assertEquals(isLetter & isUpper, myProp.isUpperCase());
+    assertEquals(isLetter & !isUpper, myProp.isLowerCase());
 
     // check digit.
-    if (isDigit)
-    {
-      assertTrue(myProp.isDigit());
-    }
+    assertEquals(isDigit, myProp.isDigit());
 
-    if (isLetter || isDigit)
-    {
-      // Check hex.
-      final int hex = myProp.hexValue();
-      final int hex1 = hexValue.intValue();
-      assertEquals(myProp.hexValue(), hexValue.intValue());
-      // Decimal value.
-      assertEquals(myProp.decimalValue(), decimalValue.intValue());
-      // Check if it is equal to itself.
-      assertEquals(myProp.charValue(), myChar);
-      assertEquals(myProp.compareTo(ASCIICharProp.valueOf(myChar)), 0);
-    }
+    // Check hex.
+    assertEquals(myProp.hexValue(), hexValue);
+
+    // Decimal value.
+    assertEquals(myProp.decimalValue(), decimalValue);
+
+    // Check if it is equal to itself.
+    assertEquals(myProp.charValue(), myChar);
+    assertEquals(myProp.compareTo(ASCIICharProp.valueOf(myChar)), 0);
 
     // keychar.
-    if (isKeyChar)
-    {
-      assertTrue(myProp.isKeyChar());
-    }
+    assertEquals(isKeyChar, myProp.isKeyChar(false));
+    assertEquals(isCompatKeyChar, myProp.isKeyChar(true));
   }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java
index 392188f..1b0d69a 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/DITContentRuleSyntaxTest.java
@@ -50,31 +50,31 @@
             "( 2.5.6.4 DESC 'content rule for organization' NOT "
                 + "( x121Address $ telexNumber ) )", true },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'rule with all possible fields' "
+            "( 2.5.6.4 NAME 'fullRule' DESC 'rule with all possible fields' "
                 + " OBSOLETE" + " AUX ( posixAccount )" + " MUST ( cn $ sn )"
                 + " MAY ( dc )" + " NOT ( x121Address $ telexNumber ) )", true },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'ommit parenthesis' "
+            "( 2.5.6.4 NAME 'fullRule' DESC 'ommit parenthesis' "
                 + " OBSOLETE" + " AUX posixAccount " + " MUST cn " + " MAY dc "
                 + " NOT x121Address )", true },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'use numeric OIDs' " + " OBSOLETE"
+            "( 2.5.6.4 NAME 'fullRule' DESC 'use numeric OIDs' " + " OBSOLETE"
                 + " AUX 1.3.6.1.1.1.2.0" + " MUST cn " + " MAY dc "
                 + " NOT x121Address )", true },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'illegal OIDs' " + " OBSOLETE"
+            "( 2.5.6.4 NAME 'fullRule' DESC 'illegal OIDs' " + " OBSOLETE"
                 + " AUX 2.5.6.." + " MUST cn " + " MAY dc "
                 + " NOT x121Address )", false },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'illegal OIDs' " + " OBSOLETE"
+            "( 2.5.6.4 NAME 'fullRule' DESC 'illegal OIDs' " + " OBSOLETE"
                 + " AUX 2.5.6.x" + " MUST cn " + " MAY dc "
                 + " NOT x121Address )", false },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'missing closing parenthesis' "
+            "( 2.5.6.4 NAME 'fullRule' DESC 'missing closing parenthesis' "
                 + " OBSOLETE" + " AUX posixAccount" + " MUST cn " + " MAY dc "
                 + " NOT x121Address", false },
         {
-            "( 2.5.6.4 NAME 'full rule' DESC 'extra parameterss' "
+            "( 2.5.6.4 NAME 'fullRule' DESC 'extra parameterss' "
                 + " MUST cn " + " X-name ( 'this is an extra parameter' ) )",
             true },
 
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java
index e90f367..487c37e 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleSyntaxTest.java
@@ -50,12 +50,12 @@
   {
     return new Object[][] {
         {
-            "( 1.2.3.4 NAME 'full matching rule' "
+            "( 1.2.3.4 NAME 'fullMatchingRule' "
                 + " DESC 'description of matching rule' OBSOLETE "
                 + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
                 + " X-name ( 'this is an extension' ) )", true },
         {
-            "( 1.2.3.4 NAME 'missing closing parenthesis' "
+            "( 1.2.3.4 NAME 'missingClosingParenthesis' "
                 + " DESC 'description of matching rule' "
                 + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
                 + " X-name ( 'this is an extension' ) ", false }, };
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java
index 2318642..1369047 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/MatchingRuleUseSyntaxTest.java
@@ -50,12 +50,12 @@
   {
     return new Object[][] {
         {
-            "( 2.5.13.10 NAME 'full matching rule' "
+            "( 2.5.13.10 NAME 'fullMatchingRule' "
                 + " DESC 'description of matching rule' OBSOLETE "
                 + " APPLIES 2.5.4.3 " + " X-name 'this is an extension' )",
             true },
         {
-            "( 2.5.13.10 NAME 'missing closing parenthesis' "
+            "( 2.5.13.10 NAME 'missingClosingParenthesis' "
                 + " DESC 'description of matching rule' " + " SYNTAX 2.5.4.3 "
                 + " X-name ( 'this is an extension' ) ", false }, };
   }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
index 6414403..22cbc8e 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaCompatOptionsTest.java
@@ -80,7 +80,7 @@
    *          {@code true} if the attribute description requires the
    *          compatibility option to be set.
    */
-  @Test(enabled = false, dataProvider = "validAttributeDescriptions")
+  @Test(dataProvider = "validAttributeDescriptions")
   public void testValidAttributeDescriptions(String atd,
       boolean allowIllegalCharacters)
   {
@@ -129,9 +129,8 @@
    *          {@code true} if the attribute description requires the
    *          compatibility option to be set.
    */
-  @Test(enabled = false, dataProvider = "invalidAttributeDescriptions",
-      expectedExceptions = LocalizedIllegalArgumentException.class)
-  public void testinvalidAttributeDescriptions(String atd,
+  @Test(dataProvider = "invalidAttributeDescriptions", expectedExceptions = LocalizedIllegalArgumentException.class)
+  public void testInvalidAttributeDescriptions(String atd,
       boolean allowIllegalCharacters)
   {
     SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema())
@@ -140,4 +139,217 @@
     Schema schema = builder.toSchema().nonStrict();
     AttributeDescription.valueOf(atd, schema);
   }
+
+
+
+  private static final Syntax ATD_SYNTAX = CoreSchema
+      .getAttributeTypeDescriptionSyntax();
+  private static final Syntax OCD_SYNTAX = CoreSchema
+      .getObjectClassDescriptionSyntax();
+
+
+
+  /**
+   * Returns test data for invalid schema elements.
+   *
+   * @return The test data.
+   */
+  @DataProvider
+  public Object[][] invalidSchemaElements()
+  {
+    // @formatter:off
+    return new Object[][] {
+        { "(testtype+oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(testtype_oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(testtype.oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(1.2.8.5 NAME 'test+type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(1.2.8.5 NAME 'test.type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(1.2.8.5 NAME 'test_type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(1.2.8.5 NAME 'test+type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          true
+        },
+    };
+    // @formatter:on
+  }
+
+
+
+  /**
+   * Test schema builder schema element parsing with compat chars.
+   *
+   * @param element
+   *          The schema element.
+   * @param syntax
+   *          The type of element.
+   * @param allowIllegalCharacters
+   *          {@code true} if the element requires the compatibility option to
+   *          be set.
+   */
+  @Test(dataProvider = "invalidSchemaElements", expectedExceptions = LocalizedIllegalArgumentException.class)
+  public void testInvalidSchemaBuilderElementParsers(String element,
+      Syntax syntax, boolean allowIllegalCharacters)
+  {
+    SchemaBuilder builder = new SchemaBuilder()
+        .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
+            .allowMalformedNamesAndOptions(allowIllegalCharacters));
+
+    if (syntax == ATD_SYNTAX)
+    {
+      builder.addAttributeType(element, false);
+    }
+    else if (syntax == OCD_SYNTAX)
+    {
+      builder.addObjectClass(element, false);
+    }
+  }
+
+
+
+  /**
+   * Returns test data for valid schema elements.
+   *
+   * @return The test data.
+   */
+  @DataProvider
+  public Object[][] validSchemaElements()
+  {
+    // @formatter:off
+    return new Object[][] {
+        { "(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(testtype-oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(testtype_oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          true
+        },
+        { "(testtype.oid NAME 'testtype' DESC 'full type' OBSOLETE SUP cn "
+                     + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                     + " SUBSTR caseIgnoreSubstringsMatch"
+                     + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                     + " USAGE userApplications )",
+          ATD_SYNTAX,
+          true
+        },
+        { "(1.2.8.5 NAME 'test-type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          false
+        },
+        { "(1.2.8.5 NAME 'test.type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          true
+        },
+        { "(1.2.8.5 NAME 'test_type' DESC 'full type' OBSOLETE SUP cn "
+                + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch"
+                + " SUBSTR caseIgnoreSubstringsMatch"
+                + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE"
+                + " USAGE userApplications )",
+          ATD_SYNTAX,
+          true
+        },
+    };
+    // @formatter:on
+  }
+
+
+
+  /**
+   * Test schema builder schema element parsing with compat chars.
+   *
+   * @param element
+   *          The schema element.
+   * @param syntax
+   *          The type of element.
+   * @param allowIllegalCharacters
+   *          {@code true} if the element requires the compatibility option to
+   *          be set.
+   */
+  @Test(dataProvider = "validSchemaElements")
+  public void testValidSchemaBuilderElementParsers(String element,
+      Syntax syntax, boolean allowIllegalCharacters)
+  {
+    SchemaBuilder builder = new SchemaBuilder()
+        .setSchemaCompatOptions(SchemaCompatOptions.defaultOptions()
+            .allowMalformedNamesAndOptions(allowIllegalCharacters));
+
+    if (syntax == ATD_SYNTAX)
+    {
+      builder.addAttributeType(element, false);
+    }
+    else if (syntax == OCD_SYNTAX)
+    {
+      builder.addObjectClass(element, false);
+    }
+  }
 }
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java
index b78c258..2131dad 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/schema/SchemaUtilsTest.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS
  */
 package org.forgerock.opendj.ldap.schema;
 
@@ -49,6 +50,7 @@
   {
     return new Object[][] { { "" }, { ".0" }, { "0." }, { "100." }, { ".999" },
         { "1one" }, { "one+two+three" },
+        { "one.two.three" },
         // AD puts quotes around OIDs - test mismatched quotes.
         { "'0" }, { "'10" }, { "999'" }, { "0.0'" }, };
   }
@@ -86,7 +88,7 @@
         // Not strictly legal, but we'll be lenient with what we accept.
         { "0" }, { "1" }, { "2" }, { "3" }, { "4" }, { "5" }, { "6" }, { "7" },
         { "8" }, { "9" }, { "00" }, { "01" }, { "01.0" }, { "0.01" },
-        { "one.two.three" }, };
+      };
   }
 
 
@@ -95,7 +97,7 @@
   public void testReadOIDInvalid(final String oid) throws DecodeException
   {
     final SubstringReader reader = new SubstringReader(oid);
-    SchemaUtils.readOID(reader);
+    SchemaUtils.readOID(reader, false);
   }
 
 
@@ -110,6 +112,6 @@
     }
 
     final SubstringReader reader = new SubstringReader(oid);
-    Assert.assertEquals(SchemaUtils.readOID(reader), expected);
+    Assert.assertEquals(SchemaUtils.readOID(reader, false), expected);
   }
 }

--
Gitblit v1.10.0