From 09fcb137f6d46e0c32f03b0313ac445a2ee7ecc3 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 25 Sep 2006 09:03:39 +0000
Subject: [PATCH] Implement test suite for org.opends.server.types.AttributeType and make it immutable (it's still not 100% immutable - the constructors do not perform deep copies of the extra properties).

---
 opends/src/server/org/opends/server/core/DirectoryServer.java                            |   25 
 opends/src/server/org/opends/server/types/RDNComparator.java                             |    4 
 opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java                      |   25 
 opends/src/server/org/opends/server/types/AttributeType.java                             |  787 ++++++--------------
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java | 1288 ++++++++++++++++++++++++++++++++++
 opends/src/server/org/opends/server/core/SchemaConfigManager.java                        |    2 
 opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java                         |   22 
 opends/src/server/org/opends/server/core/Schema.java                                     |    6 
 opends/src/server/org/opends/server/synchronization/Historical.java                      |   11 
 9 files changed, 1,570 insertions(+), 600 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/DirectoryServer.java b/opends/src/server/org/opends/server/core/DirectoryServer.java
index 36b23e3..4dfa929 100644
--- a/opends/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -29,6 +29,7 @@
 
 import java.net.InetAddress;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Properties;
@@ -3078,10 +3079,6 @@
 
       if (directoryServer.objectClassAttributeType == null)
       {
-        ConcurrentHashMap<String,String> typeNames =
-             new ConcurrentHashMap<String,String>();
-        typeNames.put(OBJECTCLASS_ATTRIBUTE_TYPE_NAME, "objectClass");
-
         AttributeSyntax oidSyntax =
              directoryServer.schema.getSyntax(SYNTAX_OID_NAME);
         if (oidSyntax == null)
@@ -3099,7 +3096,8 @@
         }
 
         directoryServer.objectClassAttributeType =
-             new AttributeType("objectClass", typeNames,
+             new AttributeType("objectClass",
+                               Collections.singleton("objectClass"),
                                OBJECTCLASS_ATTRIBUTE_TYPE_OID, null, null,
                                oidSyntax, AttributeUsage.USER_APPLICATIONS,
                                false, false, false, false);
@@ -3137,15 +3135,7 @@
                       String.valueOf(name));
 
 
-    String lowerName = toLowerCase(name);
-    ConcurrentHashMap<String,String> names =
-         new ConcurrentHashMap<String,String>(1);
-    names.put(lowerName, name);
-
-    return new AttributeType(name, names, lowerName, null, null,
-                             getDefaultAttributeSyntax(),
-                             AttributeUsage.USER_APPLICATIONS, false, false,
-                             false, false);
+    return getDefaultAttributeType(name, getDefaultAttributeSyntax());
   }
 
 
@@ -3169,11 +3159,8 @@
 
 
     String lowerName = toLowerCase(name);
-    ConcurrentHashMap<String,String> names =
-         new ConcurrentHashMap<String,String>(1);
-    names.put(lowerName, name);
-
-    return new AttributeType(name, names, lowerName, null, null, syntax,
+    return new AttributeType(name, Collections.singleton(name),
+                             lowerName, null, null, syntax,
                              AttributeUsage.USER_APPLICATIONS, false, false,
                              false, false);
   }
diff --git a/opends/src/server/org/opends/server/core/Schema.java b/opends/src/server/org/opends/server/core/Schema.java
index 20ff805..f38350b 100644
--- a/opends/src/server/org/opends/server/core/Schema.java
+++ b/opends/src/server/org/opends/server/core/Schema.java
@@ -296,7 +296,7 @@
                                        msgID);
         }
 
-        for (String name : attributeType.getNames().keySet())
+        for (String name : attributeType.getNormalizedNames())
         {
           if (attributeTypes.containsKey(name))
           {
@@ -313,7 +313,7 @@
 
       attributeTypes.put(toLowerCase(attributeType.getOID()), attributeType);
 
-      for (String name : attributeType.getNames().keySet())
+      for (String name : attributeType.getNormalizedNames())
       {
         attributeTypes.put(name, attributeType);
       }
@@ -344,7 +344,7 @@
     {
       attributeTypes.remove(toLowerCase(attributeType.getOID()), attributeType);
 
-      for (String name : attributeType.getNames().keySet())
+      for (String name : attributeType.getNormalizedNames())
       {
         attributeTypes.remove(name, attributeType);
       }
diff --git a/opends/src/server/org/opends/server/core/SchemaConfigManager.java b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
index e030556..9b48df6 100644
--- a/opends/src/server/org/opends/server/core/SchemaConfigManager.java
+++ b/opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -933,8 +933,6 @@
             {
               attrType = attrTypeSyntax.decodeAttributeType(v.getValue(),
                                                             schema);
-              attrType.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
-              attrType.setSchemaFile(schemaFile);
             }
             catch (DirectoryException de)
             {
diff --git a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
index 4afdccb..9c35138 100644
--- a/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
+++ b/opends/src/server/org/opends/server/plugins/EntryUUIDPlugin.java
@@ -29,6 +29,7 @@
 
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -74,6 +75,13 @@
 
 
 
+  /**
+   * The name of the entryUUID attribute type.
+   */
+  private static final String ENTRYUUID = "entryuuid";
+
+
+
   // The attribute type for the "entryUUID" attribute.
   private AttributeType entryUUIDType;
 
@@ -144,13 +152,17 @@
 
 
     // Get the entryUUID attribute type.
-    entryUUIDType = DirectoryServer.getAttributeType("entryuuid");
+    entryUUIDType = DirectoryServer.getAttributeType(ENTRYUUID);
     if (entryUUIDType == null)
     {
-      entryUUIDType = DirectoryServer.getDefaultAttributeType("entryUUID");
-      entryUUIDType.setUsage(AttributeUsage.DIRECTORY_OPERATION);
-      entryUUIDType.setNoUserModification(true);
-      entryUUIDType.setSingleValue(true);
+      entryUUIDType = new AttributeType(ENTRYUUID,
+          Collections.singleton(ENTRYUUID),
+          ENTRYUUID,
+          null,
+          null,
+          DirectoryServer.getDefaultAttributeSyntax(),
+          AttributeUsage.DIRECTORY_OPERATION,
+          false, true, false, true);
     }
   }
 
diff --git a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java b/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
index 5cee389..2ad1981 100644
--- a/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
+++ b/opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
@@ -28,9 +28,10 @@
 
 
 
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.api.EqualityMatchingRule;
@@ -476,8 +477,7 @@
     // we get to the end of the value.  But before we start, set default values
     // for everything else we might need to know.
     String  primaryName = oid;
-    ConcurrentHashMap<String,String> typeNames =
-         new ConcurrentHashMap<String,String>();
+    List<String> typeNames = new LinkedList<String>();
     String description = null;
     AttributeType superiorType = null;
     AttributeSyntax syntax = DirectoryServer.getDefaultAttributeSyntax();
@@ -490,8 +490,8 @@
     boolean isNoUserModification = false;
     boolean isObsolete = false;
     boolean isSingleValue = false;
-    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
-         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
+    HashMap<String,List<String>> extraProperties =
+         new HashMap<String,List<String>>();
 
 
     while (true)
@@ -526,7 +526,7 @@
           pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer,
                                  (pos-1));
           primaryName = userBuffer.toString();
-          typeNames.put(lowerBuffer.toString(), primaryName);
+          typeNames.add(primaryName);
         }
         else if (c == '(')
         {
@@ -535,7 +535,7 @@
           pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer,
                                  pos);
           primaryName = userBuffer.toString();
-          typeNames.put(lowerBuffer.toString(), primaryName);
+          typeNames.add(primaryName);
 
 
           while (true)
@@ -558,7 +558,7 @@
 
               pos = readQuotedString(valueStr, lowerStr, userBuffer,
                                      lowerBuffer, pos);
-              typeNames.put(lowerBuffer.toString(), userBuffer.toString());
+              typeNames.add(userBuffer.toString());
             }
           }
         }
@@ -918,8 +918,7 @@
         // either a single value in single quotes or an open parenthesis
         // followed by one or more values in single quotes separated by spaces
         // followed by a close parenthesis.
-        CopyOnWriteArrayList<String> valueList =
-             new CopyOnWriteArrayList<String>();
+        List<String> valueList = new ArrayList<String>();
         pos = readExtraParameterValues(valueStr, valueList, pos);
         extraProperties.put(tokenName, valueList);
       }
@@ -1350,7 +1349,7 @@
    *                              the value.
    */
   private static int readExtraParameterValues(String valueStr,
-                          CopyOnWriteArrayList<String> valueList, int startPos)
+                          List<String> valueList, int startPos)
           throws DirectoryException
   {
     assert debugEnter(CLASS_NAME, "readExtraParameterValues",
diff --git a/opends/src/server/org/opends/server/synchronization/Historical.java b/opends/src/server/org/opends/server/synchronization/Historical.java
index 834e905..9b017fe 100644
--- a/opends/src/server/org/opends/server/synchronization/Historical.java
+++ b/opends/src/server/org/opends/server/synchronization/Historical.java
@@ -345,7 +345,7 @@
           String strValue;
           if (valInfo.getValueDeleteTime() != null)
           {
-            strValue = type.getLowerName() + optionsString + ":" +
+            strValue = type.getNormalizedPrimaryName() + optionsString + ":" +
             valInfo.getValueDeleteTime().toString() +
             ":del:" + valInfo.getValue().toString();
             AttributeValue val = new AttributeValue(historicalAttrType,
@@ -356,14 +356,14 @@
           {
             if (delAttr && valInfo.getValueUpdateTime() == deleteTime)
             {
-              strValue = type.getLowerName() + optionsString + ":" +
+              strValue = type.getNormalizedPrimaryName() + optionsString + ":" +
               valInfo.getValueUpdateTime().toString() +  ":repl:" +
               valInfo.getValue().toString();
               delAttr = false;
             }
             else
             {
-              strValue = type.getLowerName() + optionsString + ":" +
+              strValue = type.getNormalizedPrimaryName() + optionsString + ":" +
               valInfo.getValueUpdateTime().toString() +
               ":add:" + valInfo.getValue().toString();
             }
@@ -376,8 +376,9 @@
 
         if (delAttr)
         {
-          String strValue = type.getLowerName() + optionsString + ":"
-          + deleteTime.toString() + ":attrDel";
+          String strValue = type.getNormalizedPrimaryName()
+              + optionsString + ":" + deleteTime.toString()
+              + ":attrDel";
           delAttr = false;
           AttributeValue val = new AttributeValue(historicalAttrType, strValue);
           hist.add(val);
diff --git a/opends/src/server/org/opends/server/types/AttributeType.java b/opends/src/server/org/opends/server/types/AttributeType.java
index d2fc1e9..2e1e145 100644
--- a/opends/src/server/org/opends/server/types/AttributeType.java
+++ b/opends/src/server/org/opends/server/types/AttributeType.java
@@ -28,10 +28,12 @@
 
 
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
+import java.util.List;
+import java.util.Map;
 import org.opends.server.api.ApproximateMatchingRule;
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.api.EqualityMatchingRule;
@@ -55,7 +57,7 @@
  * of an attribute and the syntax and matching rules that should be
  * used when interacting with it.
  */
-public class AttributeType
+public final class AttributeType
 {
   /**
    * The fully-qualified name of this class for debugging purposes.
@@ -66,99 +68,105 @@
 
 
   // The approximate matching rule for this attribute type.
-  private ApproximateMatchingRule approximateMatchingRule;
+  private final ApproximateMatchingRule approximateMatchingRule;
 
   // The syntax for this attribute type.
-  private AttributeSyntax syntax;
+  private final AttributeSyntax syntax;
 
   // The superior attribute type from which this attribute type
   // inherits.
-  private AttributeType superiorType;
+  private final AttributeType superiorType;
 
   // The attribute usage for this attribute type.
-  private AttributeUsage attributeUsage;
+  private final AttributeUsage attributeUsage;
 
   // Indicates whether this attribute type is declared "collective".
-  private boolean isCollective;
+  private final boolean isCollective;
 
   // Indicates whether this attribute type is declared
   // "no-user-modification".
-  private boolean isNoUserModification;
+  private final boolean isNoUserModification;
 
   // Indicates whether this attribute type is the objectclass type.
-  private boolean isObjectClassType;
+  private final boolean isObjectClassType;
 
   // Indicates whether this attribute type is declared "obsolete".
-  private boolean isObsolete;
+  private final boolean isObsolete;
 
   // Indicates whether this attribute type is declared "single-value".
-  private boolean isSingleValue;
+  private final boolean isSingleValue;
 
   // The set of additional name-value pairs associated with this
   // attribute type definition.
-  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
-               extraProperties;
+  private final Map<String,List<String>> extraProperties;
 
   // The set of names for this attribute type, in a mapping between
   // the all-lowercase form and the user-defined form.
-  private ConcurrentHashMap<String,String> typeNames;
+  private final Map<String,String> typeNames;
 
   // The equality matching rule for this attribute type.
-  private EqualityMatchingRule equalityMatchingRule;
+  private final EqualityMatchingRule equalityMatchingRule;
 
   // The ordering matching rule for this attribute type.
-  private OrderingMatchingRule orderingMatchingRule;
+  private final OrderingMatchingRule orderingMatchingRule;
 
   // The description for this attribute type.
-  private String description;
+  private final String description;
 
   // The OID that may be used to reference this attribute type.
-  private String oid;
+  private final String oid;
 
   // The primary name to use for this attribute type.
-  private String primaryName;
+  private final String primaryName;
 
   // The lower case name for this attribute type.
-  private String lowerName;
-
-  // The path to the schema configuration file that contains this
-  // attribute type definition.
-  private String schemaFile;
+  private final String lowerName;
 
   // The substring matching rule for this attribute type.
-  private SubstringMatchingRule substringMatchingRule;
+  private final SubstringMatchingRule substringMatchingRule;
 
 
 
   /**
    * Creates a new attribute type with the provided information.
    *
-   * @param  primaryName           The primary name for this attribute
-   *                               type.
-   * @param  typeNames             The full set of names for this
-   *                               attribute type, mapping the
-   *                               lowercase names with the
-   *                               user-defined values.
-   * @param  oid                   The OID for this attribute type.
-   * @param  description           The description for the attribute
-   *                               type.
-   * @param  superiorType          The reference to the superior type
-   *                               for this attribute type.
-   * @param  syntax                The syntax for this attribute type.
-   * @param  attributeUsage        The attribute usage for this
-   *                               attribute type.
-   * @param  isCollective          Indicates whether this attribute
-   *                               type is declared "collective".
-   * @param  isNoUserModification  Indicates whether this attribute
-   *                               type is declared
-   *                               "no-user-modification".
-   * @param  isObsolete            Indicates whether this attribute
-   *                               type is declared "obsolete".
-   * @param  isSingleValue         Indicates whether this attribute
-   *                               type is declared "single-value".
+   * @param primaryName
+   *          The primary name for this attribute type, or
+   *          <code>null</code> if there is no primary name.
+   * @param typeNames
+   *          The full set of names for this attribute type, or
+   *          <code>null</code> if there are no names.
+   * @param oid
+   *          The OID for this attribute type (must not be
+   *          <code>null</code>).
+   * @param description
+   *          The description for the attribute type, or
+   *          <code>null</code> if there is no description.
+   * @param superiorType
+   *          The reference to the superior type for this attribute
+   *          type, or <code>null</code> if there is no superior
+   *          type.
+   * @param syntax
+   *          The syntax for this attribute type, or <code>null</code>
+   *          if there is no syntax.
+   * @param attributeUsage
+   *          The attribute usage for this attribute type, or
+   *          <code>null</code> to default to user applications.
+   * @param isCollective
+   *          Indicates whether this attribute type is declared
+   *          "collective".
+   * @param isNoUserModification
+   *          Indicates whether this attribute type is declared
+   *          "no-user-modification".
+   * @param isObsolete
+   *          Indicates whether this attribute type is declared
+   *          "obsolete".
+   * @param isSingleValue
+   *          Indicates whether this attribute type is declared
+   *          "single-value".
    */
   public AttributeType(String primaryName,
-                       ConcurrentHashMap<String,String> typeNames,
+                       Collection<String> typeNames,
                        String oid, String description,
                        AttributeType superiorType,
                        AttributeSyntax syntax,
@@ -167,60 +175,10 @@
                        boolean isNoUserModification,
                        boolean isObsolete, boolean isSingleValue)
   {
-    assert debugConstructor(CLASS_NAME,
-                            new String[]
-                            {
-                              String.valueOf(primaryName),
-                              String.valueOf(typeNames),
-                              String.valueOf(oid),
-                              String.valueOf(description),
-                              String.valueOf(superiorType),
-                              String.valueOf(syntax),
-                              String.valueOf(attributeUsage),
-                              String.valueOf(isCollective),
-                              String.valueOf(isNoUserModification),
-                              String.valueOf(isObsolete),
-                              String.valueOf(isSingleValue),
-                            });
-
-
-    this.primaryName             = primaryName;
-    this.lowerName               = toLowerCase(primaryName);
-    this.typeNames               = typeNames;
-    this.oid                     = oid;
-    this.description             = description;
-    this.superiorType            = superiorType;
-    this.syntax                  = syntax;
-    this.approximateMatchingRule =
-         syntax.getApproximateMatchingRule();
-    this.equalityMatchingRule    = syntax.getEqualityMatchingRule();
-    this.orderingMatchingRule    = syntax.getOrderingMatchingRule();
-    this.substringMatchingRule   = syntax.getSubstringMatchingRule();
-    this.attributeUsage          = attributeUsage;
-    this.isCollective            = isCollective;
-    this.isNoUserModification    = isNoUserModification;
-    this.isObsolete              = isObsolete;
-    this.isSingleValue           = isSingleValue;
-    this.schemaFile              = null;
-    this.extraProperties         =
-         new ConcurrentHashMap<String,
-                               CopyOnWriteArrayList<String>>(0);
-
-    isObjectClassType = false;
-    if ((oid != null) && oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID))
-    {
-      isObjectClassType = true;
-    }
-    else
-    {
-      for (String lowerName : typeNames.keySet())
-      {
-        if (lowerName.equals(OBJECTCLASS_ATTRIBUTE_TYPE_NAME))
-        {
-          isObjectClassType = true;
-        }
-      }
-    }
+    this(primaryName, typeNames, oid, description,
+        superiorType, syntax, null, null, null,
+        null, attributeUsage, isCollective,
+        isNoUserModification, isObsolete, isSingleValue, null);
   }
 
 
@@ -228,43 +186,58 @@
   /**
    * Creates a new attribute type with the provided information.
    *
-   * @param  primaryName              The primary name for this
-   *                                  attribute type.
-   * @param  typeNames                The full set of names for this
-   *                                  attribute type, mapping the
-   *                                  lowercase names with the
-   *                                  user-defined values.
-   * @param  oid                      The OID for this attribute type.
-   * @param  description              The description for the
-   *                                  attribute type.
-   * @param  superiorType             The reference to the superior
-   *                                  type for this attribute type.
-   * @param  syntax                   The syntax for this attribute
-   *                                  type.
-   * @param  approximateMatchingRule  The approximate matching rule
-   *                                  for this attribute type.
-   * @param  equalityMatchingRule     The equality matching rule for
-   *                                  this attribute type.
-   * @param  orderingMatchingRule     The ordering matching rule for
-   *                                  this attribute type.
-   * @param  substringMatchingRule    The substring matching rule for
-   *                                  this attribute type.
-   * @param  attributeUsage           The attribute usage for this
-   *                                  attribute type.
-   * @param  isCollective             Indicates whether this attribute
-   *                                  type is declared "collective".
-   * @param  isNoUserModification     Indicates whether this attribute
-   *                                  type is declared
-   *                                  "no-user-modification".
-   * @param  isObsolete               Indicates whether this attribute
-   *                                  type is declared "obsolete".
-   * @param  isSingleValue            Indicates whether this attribute
-   *                                  type is declared "single-value".
-   * @param  extraProperties          A set of extra properties for
-   *                                  this attribute type.
+   * @param primaryName
+   *          The primary name for this attribute type, or
+   *          <code>null</code> if there is no primary name.
+   * @param typeNames
+   *          The full set of names for this attribute type, or
+   *          <code>null</code> if there are no names.
+   * @param oid
+   *          The OID for this attribute type (must not be
+   *          <code>null</code>).
+   * @param description
+   *          The description for the attribute type, or
+   *          <code>null</code> if there is no description.
+   * @param superiorType
+   *          The reference to the superior type for this attribute
+   *          type, or <code>null</code> if there is no superior
+   *          type.
+   * @param syntax
+   *          The syntax for this attribute type, or <code>null</code>
+   *          if there is no syntax.
+   * @param approximateMatchingRule
+   *          The approximate matching rule for this attribute type,
+   *          or <code>null</code> if there is no rule.
+   * @param equalityMatchingRule
+   *          The equality matching rule for this attribute type, or
+   *          <code>null</code> if there is no rule.
+   * @param orderingMatchingRule
+   *          The ordering matching rule for this attribute type, or
+   *          <code>null</code> if there is no rule.
+   * @param substringMatchingRule
+   *          The substring matching rule for this attribute type, or
+   *          <code>null</code> if there is no rule.
+   * @param attributeUsage
+   *          The attribute usage for this attribute type, or
+   *          <code>null</code> to default to user applications.
+   * @param isCollective
+   *          Indicates whether this attribute type is declared
+   *          "collective".
+   * @param isNoUserModification
+   *          Indicates whether this attribute type is declared
+   *          "no-user-modification".
+   * @param isObsolete
+   *          Indicates whether this attribute type is declared
+   *          "obsolete".
+   * @param isSingleValue
+   *          Indicates whether this attribute type is declared
+   *          "single-value".
+   * @param extraProperties
+   *          A set of extra properties for this attribute type, or
+   *          <code>null</code> if there is no rule.
    */
   public AttributeType(String primaryName,
-                       ConcurrentHashMap<String,String> typeNames,
+                       Collection<String> typeNames,
                        String oid, String description,
                        AttributeType superiorType,
                        AttributeSyntax syntax,
@@ -277,14 +250,9 @@
                        boolean isCollective,
                        boolean isNoUserModification,
                        boolean isObsolete, boolean isSingleValue,
-                       ConcurrentHashMap<String,
-                                         CopyOnWriteArrayList<String>>
-                            extraProperties)
+                       Map<String,List<String>> extraProperties)
   {
-    assert debugConstructor(CLASS_NAME,
-                            new String[]
-                            {
-                              String.valueOf(primaryName),
+    assert debugConstructor(CLASS_NAME,String.valueOf(primaryName),
                               String.valueOf(typeNames),
                               String.valueOf(oid),
                               String.valueOf(description),
@@ -299,33 +267,44 @@
                               String.valueOf(isNoUserModification),
                               String.valueOf(isObsolete),
                               String.valueOf(isSingleValue),
-                              String.valueOf(extraProperties)
-                            });
+                              String.valueOf(extraProperties));
 
-
-    this.primaryName             = primaryName;
-    this.lowerName               = toLowerCase(primaryName);
-    this.typeNames               = typeNames;
-    this.oid                     = oid;
-    this.description             = description;
-    this.superiorType            = superiorType;
-    this.isCollective            = isCollective;
-    this.isNoUserModification    = isNoUserModification;
-    this.isObsolete              = isObsolete;
-    this.isSingleValue           = isSingleValue;
-    this.extraProperties         = extraProperties;
-    this.schemaFile              = null;
-
-
-    if (attributeUsage == null)
+    // Make sure mandatory parameters are specified.
+    if (oid == null)
     {
-      this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
+      throw new NullPointerException(
+          "No oid specified in constructor");
+    }
+
+    this.primaryName = primaryName;
+    this.lowerName = toLowerCase(primaryName);
+    this.oid = oid;
+    this.description = description;
+    this.superiorType = superiorType;
+    this.isCollective = isCollective;
+    this.isNoUserModification = isNoUserModification;
+    this.isObsolete = isObsolete;
+    this.isSingleValue = isSingleValue;
+
+    // Construct the normalized attribute name mapping.
+    if (typeNames != null)
+    {
+      this.typeNames = new HashMap<String, String>(typeNames.size());
+      for (String name : typeNames)
+      {
+        this.typeNames.put(toLowerCase(name), name);
+      }
     }
     else
     {
-      this.attributeUsage = attributeUsage;
+      this.typeNames = new HashMap<String, String>();
     }
 
+    // Add the primary name to the type names if it is not present.
+    if (lowerName != null && !this.typeNames.containsKey(lowerName))
+    {
+      this.typeNames.put(lowerName, this.primaryName);
+    }
 
     if (syntax == null)
     {
@@ -335,7 +314,7 @@
       }
       else
       {
-        syntax = DirectoryServer.getDefaultAttributeSyntax();
+        this.syntax = DirectoryServer.getDefaultAttributeSyntax();
       }
     }
     else
@@ -346,11 +325,8 @@
 
     if (approximateMatchingRule == null)
     {
-      if (syntax != null)
-      {
-        this.approximateMatchingRule =
-             syntax.getApproximateMatchingRule();
-      }
+      this.approximateMatchingRule =
+             this.syntax.getApproximateMatchingRule();
     }
     else
     {
@@ -360,10 +336,8 @@
 
     if (equalityMatchingRule == null)
     {
-      if (syntax != null)
-      {
-        this.equalityMatchingRule = syntax.getEqualityMatchingRule();
-      }
+      this.equalityMatchingRule =
+        this.syntax.getEqualityMatchingRule();
     }
     else
     {
@@ -373,10 +347,8 @@
 
     if (orderingMatchingRule == null)
     {
-      if (syntax != null)
-      {
-        this.orderingMatchingRule = syntax.getOrderingMatchingRule();
-      }
+      this.orderingMatchingRule =
+        this.syntax.getOrderingMatchingRule();
     }
     else
     {
@@ -386,31 +358,41 @@
 
     if (substringMatchingRule == null)
     {
-      if (syntax != null)
-      {
-        this.substringMatchingRule =
-             syntax.getSubstringMatchingRule();
-      }
+      this.substringMatchingRule =
+        this.syntax.getSubstringMatchingRule();
     }
     else
     {
       this.substringMatchingRule = substringMatchingRule;
     }
 
-    isObjectClassType = false;
-    if ((oid != null) && oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID))
+    if (attributeUsage != null)
+    {
+      this.attributeUsage = attributeUsage;
+    }
+    else
+    {
+      this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
+    }
+
+    if (oid.equals(OBJECTCLASS_ATTRIBUTE_TYPE_OID))
     {
       isObjectClassType = true;
     }
     else
     {
-      for (String lowerName : typeNames.keySet())
-      {
-        if (lowerName.equals(OBJECTCLASS_ATTRIBUTE_TYPE_NAME))
-        {
-          isObjectClassType = true;
-        }
-      }
+      isObjectClassType =
+        this.typeNames.containsKey(OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
+    }
+
+    if (extraProperties != null)
+    {
+      this.extraProperties =
+        new HashMap<String, List<String>>(extraProperties);
+    }
+    else
+    {
+      this.extraProperties = Collections.emptyMap();
     }
   }
 
@@ -419,7 +401,8 @@
   /**
    * Retrieves the primary name for this attribute type.
    *
-   * @return  The primary name for this attribute type.
+   * @return The primary name for this attribute type, or
+   *         <code>null</code> if there is no primary name.
    */
   public String getPrimaryName()
   {
@@ -431,67 +414,50 @@
 
 
   /**
-   * Retrieve the lower case name for this attribute type.
+   * Retrieve the normalized primary name for this attribute type.
    *
-   * @return The lower case name for this attribute type.
+   * @return Returns the normalized primary name for this attribute
+   *         type, or <code>null</code> if there is no primary name.
    */
-  public String getLowerName()
+  public String getNormalizedPrimaryName()
   {
+    assert debugEnter(CLASS_NAME, "getNormalizedPrimaryName");
+
     return lowerName;
   }
 
 
 
   /**
-   * Specifies the primary name for this attribute type.
+   * Retrieves an iterable over the set of normalized names that may
+   * be used to reference this attribute type. The normalized form of
+   * an attribute name is defined as the user-defined name converted
+   * to lower-case.
    *
-   * @param  primaryName  The primary name for this attribute type.
+   * @return Returns an iterable over the set of normalized names that
+   *         may be used to reference this attribute type.
    */
-  public void setPrimaryName(String primaryName)
+  public Iterable<String> getNormalizedNames()
   {
-    assert debugEnter(CLASS_NAME, "setPrimaryName",
-                      String.valueOf(primaryName));
+    assert debugEnter(CLASS_NAME, "getNormalizedNames");
 
-    this.primaryName = primaryName;
-
-    this.lowerName = toLowerCase(primaryName);
-    typeNames.put(this.lowerName, primaryName);
+    return typeNames.keySet();
   }
 
 
 
   /**
-   * Retrieves the set of names that may be used to reference this
-   * attribute type.  The returned mapping will be between an all
-   * lower-case form of the name and a name in the user-defined form
-   * (which may include mixed capitalization).
+   * Retrieves an iterable over the set of user-defined names that may
+   * be used to reference this attribute type.
    *
-   * @return  The set of names that may be used to reference this
-   *          attribute type.
+   * @return Returns an iterable over the set of user-defined names
+   *         that may be used to reference this attribute type.
    */
-  public ConcurrentHashMap<String,String> getNames()
+  public Iterable<String> getUserDefinedNames()
   {
-    assert debugEnter(CLASS_NAME, "getNames");
+    assert debugEnter(CLASS_NAME, "getUserDefinedNames");
 
-    return typeNames;
-  }
-
-
-
-  /**
-   * Specifies the set of names that may be used to reference this
-   * attribute type.  The provided set must contain a mapping between
-   * each name in all lowercase characters and the name in a
-   * user-defined form (which may include mixed capitalization).
-   *
-   * @param  names  The set of names that may be used to reference
-   *                this attribute type.
-   */
-  public void setNames(ConcurrentHashMap<String,String> names)
-  {
-    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
-
-    this.typeNames = names;
+    return typeNames.values();
   }
 
 
@@ -516,52 +482,6 @@
 
 
   /**
-   * Adds the specified name to the set of names for this attribute
-   * type.
-   *
-   * @param  name  The name to add to the set of names for this
-   *               attribute type.
-   */
-  public void addName(String name)
-  {
-    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
-
-    String lowerName = toLowerCase(name);
-    typeNames.put(lowerName, name);
-  }
-
-
-
-  /**
-   * Removes the specified name from the set of names for this
-   * attribute type.  This will have no effect if the specified name
-   * is not associated with this attribute type.
-   *
-   * @param  lowerName  The lowercase name to remove from the set of
-   *                    names for this attribute type.
-   */
-  public void removeName(String lowerName)
-  {
-    assert debugEnter(CLASS_NAME, "removeName",
-                      String.valueOf(lowerName));
-
-    typeNames.remove(lowerName);
-    if (lowerName.equalsIgnoreCase(primaryName))
-    {
-      if (typeNames.isEmpty())
-      {
-        primaryName = null;
-      }
-      else
-      {
-        primaryName = typeNames.values().iterator().next();
-      }
-    }
-  }
-
-
-
-  /**
    * Retrieves the OID for this attribute type.
    *
    * @return  The OID for this attribute type.
@@ -576,20 +496,6 @@
 
 
   /**
-   * Specifies the OID for this attribute type.
-   *
-   * @param  oid  The OID for this attribute type.
-   */
-  public void setOID(String oid)
-  {
-    assert debugEnter(CLASS_NAME, "setOID", String.valueOf(oid));
-
-    this.oid = toLowerCase(oid);
-  }
-
-
-
-  /**
    * Retrieves the name or OID for this attribute type.  If it has one
    * or more names, then the primary name will be returned.  If it
    * does not have any names, then the OID will be returned.
@@ -655,24 +561,13 @@
   {
     assert debugEnter(CLASS_NAME, "getSchemaFile");
 
-    return schemaFile;
-  }
+    List<String> values =
+      extraProperties.get(SCHEMA_PROPERTY_FILENAME);
+    if (values != null && !values.isEmpty()) {
+      return values.get(0);
+    }
 
-
-
-  /**
-   * Specifies the path to the schema file that contains the
-   * definition for this attribute type.
-   *
-   * @param  schemaFile  The path to the schema file that contains the
-   *                     definition for this attribute type.
-   */
-  public void setSchemaFile(String schemaFile)
-  {
-    assert debugEnter(CLASS_NAME, "setSchemaFile",
-                      String.valueOf(schemaFile));
-
-    this.schemaFile = schemaFile;
+    return null;
   }
 
 
@@ -680,7 +575,8 @@
   /**
    * Retrieves the description for this attribute type.
    *
-   * @return  The description for this attribute type.
+   * @return  The description for this attribute type, or
+   *         <code>null</code> if there is no description.
    */
   public String getDescription()
   {
@@ -692,20 +588,6 @@
 
 
   /**
-   * Specifies the description for this attribute type.
-   *
-   * @param  description  The description for this attribute type.
-   */
-  public void setDescription(String description)
-  {
-    assert debugEnter(CLASS_NAME, "setDescription", description);
-
-    this.description = description;
-  }
-
-
-
-  /**
    * Retrieves the superior type for this attribute type.
    *
    * @return  The superior type for this attribute type, or
@@ -721,22 +603,6 @@
 
 
   /**
-   * Specifies the superior type to use for this attribute type.  It
-   * may be <CODE>null</CODE> if it should not have a superior type.
-   *
-   * @param  superiorType  The superior type for this attribute type.
-   */
-  public void setSuperiorType(AttributeType superiorType)
-  {
-    assert debugEnter(CLASS_NAME, "setSuperiorType",
-                      String.valueOf(superiorType));
-
-    this.superiorType = superiorType;
-  }
-
-
-
-  /**
    * Retrieves the syntax for this attribute type.
    *
    * @return  The syntax for this attribute type.
@@ -767,21 +633,6 @@
 
 
   /**
-   * Specifies the syntax for this attribute type.
-   *
-   * @param  syntax  The syntax for this attribute type.
-   */
-  public void setSyntax(AttributeSyntax syntax)
-  {
-    assert debugEnter(CLASS_NAME, "setSyntax",
-                      String.valueOf(syntax));
-
-    this.syntax = syntax;
-  }
-
-
-
-  /**
    * Retrieves the matching rule that should be used for approximate
    * matching with this attribute type.
    *
@@ -798,25 +649,6 @@
 
 
   /**
-   * Specifies the matching rule that should be used for approximate
-   * matching with this attribute type.
-   *
-   * @param  approximateMatchingRule  The matching rule that should be
-   *                                  used for approximate matching
-   *                                  with this attribute type.
-   */
-  public void setApproximateMatchingRule(ApproximateMatchingRule
-                                              approximateMatchingRule)
-  {
-    assert debugEnter(CLASS_NAME, "setApproximateMatchingRule",
-                      String.valueOf(approximateMatchingRule));
-
-    this.approximateMatchingRule = approximateMatchingRule;
-  }
-
-
-
-  /**
    * Retrieves the matching rule that should be used for equality
    * matching with this attribute type.
    *
@@ -833,25 +665,6 @@
 
 
   /**
-   * Specifies the matching rule that should be used for equality
-   * matching with this attribute type.
-   *
-   * @param  equalityMatchingRule  The matching rule that should be
-   *                               used for equality matching with
-   *                               this attribute type.
-   */
-  public void setEqualityMatchingRule(EqualityMatchingRule
-                                           equalityMatchingRule)
-  {
-    assert debugEnter(CLASS_NAME, "setEqualityMatchingRule",
-                      String.valueOf(equalityMatchingRule));
-
-    this.equalityMatchingRule = equalityMatchingRule;
-  }
-
-
-
-  /**
    * Retrieves the matching rule that should be used for ordering with
    * this attribute type.
    *
@@ -868,25 +681,6 @@
 
 
   /**
-   * Specifies the matching rule that should be used for ordering with
-   * this attribute type.
-   *
-   * @param  orderingMatchingRule  The matching rule that should be
-   *                               used for ordering with this
-   *                               attribute type.
-   */
-  public void setOrderingMatchingRule(OrderingMatchingRule
-                                           orderingMatchingRule)
-  {
-    assert debugEnter(CLASS_NAME, "setOrderingMatchingRule",
-                      String.valueOf(orderingMatchingRule));
-
-    this.orderingMatchingRule = orderingMatchingRule;
-  }
-
-
-
-  /**
    * Retrieves the matching rule that should be used for substring
    * matching with this attribute type.
    *
@@ -903,25 +697,6 @@
 
 
   /**
-   * Specifies the matching rule that should be used for substring
-   * matching with this attribute type.
-   *
-   * @param  substringMatchingRule  The matching rule that should be
-   *                                used for substring matching with
-   *                                this attribute type.
-   */
-  public void setSubstringMatchingRule(SubstringMatchingRule
-                                            substringMatchingRule)
-  {
-    assert debugEnter(CLASS_NAME, "setSubstringMatchingRule",
-                      String.valueOf(substringMatchingRule));
-
-    this.substringMatchingRule = substringMatchingRule;
-  }
-
-
-
-  /**
    * Retrieves the usage indicator for this attribute type.
    *
    * @return  The usage indicator for this attribute type.
@@ -936,22 +711,6 @@
 
 
   /**
-   * Specifies the usage indicator for this attribute type.
-   *
-   * @param  attributeUsage  The usage indicator for this attribute
-   *                         type.
-   */
-  public void setUsage(AttributeUsage attributeUsage)
-  {
-    assert debugEnter(CLASS_NAME, "setUsage",
-                      String.valueOf(attributeUsage));
-
-    this.attributeUsage = attributeUsage;
-  }
-
-
-
-  /**
    * Indicates whether this is an operational attribute.  An
    * operational attribute is one with a usage of
    * "directoryOperation", "distributedOperation", or "dSAOperation"
@@ -1000,22 +759,6 @@
 
 
   /**
-   * Specifies whether this attribute type is declared "collective".
-   *
-   * @param  isCollective  Specifies whether this attribute type is
-   *                       declared "collective".
-   */
-  public void setCollective(boolean isCollective)
-  {
-    assert debugEnter(CLASS_NAME, "setCollective",
-                      String.valueOf(isCollective));
-
-    this.isCollective = isCollective;
-  }
-
-
-
-  /**
    * Indicates whether this attribute type is declared
    * "no-user-modification".
    *
@@ -1032,24 +775,6 @@
 
 
   /**
-   * Specifies whether this attribute type is declared
-   * "no-user-modification".
-   *
-   * @param  isNoUserModification  Specifies whether this attribute
-   *                               type is declared
-   *                               "no-user-modification".
-   */
-  public void setNoUserModification(boolean isNoUserModification)
-  {
-    assert debugEnter(CLASS_NAME, "setNoUserModification",
-                      String.valueOf(isNoUserModification));
-
-    this.isNoUserModification = isNoUserModification;
-  }
-
-
-
-  /**
    * Indicates whether this attribute type is declared "obsolete".
    *
    * @return  <CODE>true</CODE> if this attribute type is declared
@@ -1065,22 +790,6 @@
 
 
   /**
-   * Specifies whether this attribute type is declared "obsolete".
-   *
-   * @param  isObsolete  Specifies whether this attribute type is
-   *                     declared "obsolete".
-   */
-  public void setObsolete(boolean isObsolete)
-  {
-    assert debugEnter(CLASS_NAME, "setObsolete",
-                      String.valueOf(isObsolete));
-
-    this.isObsolete = isObsolete;
-  }
-
-
-
-  /**
    * Indicates whether this attribute type is declared "single-value".
    *
    * @return  <CODE>true</CODE> if this attribute type is declared
@@ -1096,54 +805,33 @@
 
 
   /**
-   * Specifies whether this attribute type is declared "single-value".
+   * Retrieves an iterable over the names of "extra" properties
+   * associated with this attribute type.
    *
-   * @param  isSingleValue  Specifies whether this attribute type is
-   *                        declared "single-value".
+   * @return Returns an iterable over the names of "extra" properties
+   *         associated with this attribute type.
    */
-  public void setSingleValue(boolean isSingleValue)
+  public Iterable<String> getExtraPropertyNames()
   {
-    assert debugEnter(CLASS_NAME, "setSingleValue",
-                      String.valueOf(isSingleValue));
+    assert debugEnter(CLASS_NAME, "getExtraPropertyNames");
 
-    this.isSingleValue = isSingleValue;
+    return extraProperties.keySet();
   }
 
 
 
   /**
-   * Retrieves a mapping between the names of any extra non-standard
-   * properties that may be associated with this attribute type and
-   * the value for that property.  The caller may alter the contents
-   * of this mapping.
+   * Retrieves an iterable over the value(s) of the specified "extra"
+   * property for this attribute type.
    *
-   * @return  A mapping between the names of any extra non-standard
-   *          properties that may be associated with this attribute
-   *          type and the value for that property.
+   * @param propertyName
+   *          The name of the "extra" property for which to retrieve
+   *          the value(s).
+   * @return Returns an iterable over the value(s) of the specified
+   *         "extra" property for this attribute type, or
+   *         <CODE>null</CODE> if no such property is defined.
    */
-  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
-              getExtraProperties()
-  {
-    assert debugEnter(CLASS_NAME, "getExtraProperties");
-
-    return extraProperties;
-  }
-
-
-
-  /**
-   * Retrieves the value of the specified "extra" property for this
-   * attribute type.
-   *
-   * @param  propertyName  The name of the "extra" property for which
-   *                       to retrieve the value.
-   *
-   * @return  The value of the specified "extra" property for this
-   *          attribute type, or <CODE>null</CODE> if no such property
-   *          is defined.
-   */
-  public CopyOnWriteArrayList<String>
-              getExtraProperty(String propertyName)
+  public Iterable<String> getExtraProperty(String propertyName)
   {
     assert debugEnter(CLASS_NAME, "getExtraProperty",
                       String.valueOf(propertyName));
@@ -1445,10 +1133,17 @@
 
     if (! extraProperties.isEmpty())
     {
-      for (String property : extraProperties.keySet())
-      {
-        CopyOnWriteArrayList<String> valueList =
-             extraProperties.get(property);
+      for (Map.Entry<String, List<String>> e :
+        extraProperties.entrySet()) {
+
+        String property = e.getKey();
+        if (!includeFileElement
+            && property.equals(SCHEMA_PROPERTY_FILENAME)) {
+          // Don't include the schema file if it was not requested.
+          continue;
+        }
+
+        List<String> valueList = e.getValue();
 
         buffer.append(" ");
         buffer.append(property);
@@ -1475,16 +1170,6 @@
       }
     }
 
-    if (includeFileElement && (schemaFile != null) &&
-        (! extraProperties.containsKey(SCHEMA_PROPERTY_FILENAME)))
-    {
-      buffer.append(" ");
-      buffer.append(SCHEMA_PROPERTY_FILENAME);
-      buffer.append(" '");
-      buffer.append(schemaFile);
-      buffer.append("'");
-    }
-
     buffer.append(" )");
   }
 }
diff --git a/opends/src/server/org/opends/server/types/RDNComparator.java b/opends/src/server/org/opends/server/types/RDNComparator.java
index 15fe524..e95842f 100644
--- a/opends/src/server/org/opends/server/types/RDNComparator.java
+++ b/opends/src/server/org/opends/server/types/RDNComparator.java
@@ -107,8 +107,8 @@
           }
           else
           {
-            return types1[index].getLowerName().compareTo(
-                        types2[index].getLowerName());
+            return types1[index].getNormalizedPrimaryName().compareTo(
+                        types2[index].getNormalizedPrimaryName());
           }
         }
         else
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
new file mode 100644
index 0000000..6e5def2
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
@@ -0,0 +1,1288 @@
+/*
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * 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/opends/resource/legal-notices/OpenDS.LICENSE.  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
+ *
+ *
+ *      Portions Copyright 2006 Sun Microsystems, Inc.
+ */
+package org.opends.server.types;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.opends.server.TestCaseUtils;
+import org.opends.server.api.ApproximateMatchingRule;
+import org.opends.server.api.AttributeSyntax;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.protocols.asn1.ASN1OctetString;
+import org.opends.server.util.ServerConstants;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * This class defines a set of tests for the
+ * {@link org.opends.server.types.AttributeType} class.
+ */
+public final class TestAttributeType extends TypesTestCase {
+  /**
+   * Internal class to simplify construction of attribute types.
+   */
+  private static final class AttributeTypeBuilder {
+    // The primary name to use for this attribute type.
+    private String primaryName;
+
+    // The set of names for this attribute type.
+    private List<String> typeNames;
+
+    // The OID that may be used to reference this attribute type.
+    private String oid;
+
+    // The description for this attribute type.
+    private String description;
+
+    // The superior attribute type from which this attribute type
+    // inherits.
+    private AttributeType superiorType;
+
+    // The syntax for this attribute type.
+    private AttributeSyntax syntax;
+
+    // The approximate matching rule for this attribute type.
+    private ApproximateMatchingRule approximateMatchingRule;
+
+    // The equality matching rule for this attribute type.
+    private EqualityMatchingRule equalityMatchingRule;
+
+    // The ordering matching rule for this attribute type.
+    private OrderingMatchingRule orderingMatchingRule;
+
+    // The substring matching rule for this attribute type.
+    private SubstringMatchingRule substringMatchingRule;
+
+    // The attribute usage for this attribute type.
+    private AttributeUsage attributeUsage;
+
+    // Indicates whether this attribute type is declared "collective".
+    private boolean isCollective;
+
+    // Indicates whether this attribute type is declared
+    // "no-user-modification".
+    private boolean isNoUserModification;
+
+    // Indicates whether this attribute type is declared "obsolete".
+    private boolean isObsolete;
+
+    // Indicates whether this attribute type is declared
+    // "single-value".
+    private boolean isSingleValue;
+
+    // The set of additional name-value pairs associated with this
+    // attribute type definition.
+    private Map<String, List<String>> extraProperties;
+
+    // Reset the builder to its initial state.
+    private void reset() {
+      this.primaryName = null;
+      this.typeNames = null;
+      this.oid = null;
+      this.description = null;
+      this.superiorType = null;
+      this.syntax = null;
+      this.approximateMatchingRule = null;
+      this.equalityMatchingRule = null;
+      this.orderingMatchingRule = null;
+      this.substringMatchingRule = null;
+      this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
+      this.isCollective = false;
+      this.isNoUserModification = false;
+      this.isObsolete = false;
+      this.isSingleValue = false;
+      this.extraProperties = null;
+    }
+
+    /**
+     * Create a new attribute type builder.
+     */
+    public AttributeTypeBuilder() {
+      reset();
+    }
+
+    /**
+     * Create a new attribute type builder.
+     * 
+     * @param primaryName
+     *          The attribute type primary name.
+     * @param oid
+     *          The attribute type OID.
+     */
+    public AttributeTypeBuilder(String primaryName, String oid) {
+      reset();
+
+      this.primaryName = primaryName;
+      this.oid = oid;
+    }
+
+    /**
+     * Construct an attribute type based on the properties of the
+     * builder.
+     * 
+     * @return The new attribute type.
+     */
+    public AttributeType getAttributeType() {
+      if (oid == null) {
+        throw new IllegalStateException("Null OID.");
+      }
+
+      AttributeType type = new AttributeType(primaryName, typeNames,
+          oid, description, superiorType, syntax,
+          approximateMatchingRule, equalityMatchingRule,
+          orderingMatchingRule, substringMatchingRule,
+          attributeUsage, isCollective, isNoUserModification,
+          isObsolete, isSingleValue, extraProperties);
+
+      // Reset the internal state.
+      reset();
+
+      return type;
+    }
+
+    /**
+     * Set the approximateMatchingRule.
+     * 
+     * @param approximateMatchingRule
+     *          The approximateMatchingRule.
+     */
+    public void setApproximateMatchingRule(
+        ApproximateMatchingRule approximateMatchingRule) {
+      this.approximateMatchingRule = approximateMatchingRule;
+    }
+
+    /**
+     * Set the attributeUsage.
+     * 
+     * @param attributeUsage
+     *          The attributeUsage.
+     */
+    public void setAttributeUsage(AttributeUsage attributeUsage) {
+      this.attributeUsage = attributeUsage;
+    }
+
+    /**
+     * Set the description.
+     * 
+     * @param description
+     *          The description.
+     */
+    public void setDescription(String description) {
+      this.description = description;
+    }
+
+    /**
+     * Set the equalityMatchingRule.
+     * 
+     * @param equalityMatchingRule
+     *          The equalityMatchingRule.
+     */
+    public void setEqualityMatchingRule(
+        EqualityMatchingRule equalityMatchingRule) {
+      this.equalityMatchingRule = equalityMatchingRule;
+    }
+
+    /**
+     * Add extra property value(s).
+     * 
+     * @param name
+     *          The name of the extra property.
+     * @param values
+     *          The value(s) of the extra property.
+     */
+    public void addExtraProperty(String name, String... values) {
+      if (name == null) {
+        throw new NullPointerException("Null extra property name");
+      }
+
+      if (values == null) {
+        throw new NullPointerException("Null extra property values");
+      }
+
+      if (extraProperties == null) {
+        extraProperties = new HashMap<String, List<String>>();
+      }
+
+      List<String> l = extraProperties.get(name);
+      if (l == null) {
+        l = new ArrayList<String>();
+        extraProperties.put(name, l);
+      }
+      l.addAll(Arrays.asList(values));
+    }
+
+    /**
+     * Set the isCollective.
+     * 
+     * @param isCollective
+     *          The isCollective.
+     */
+    public void setCollective(boolean isCollective) {
+      this.isCollective = isCollective;
+    }
+
+    /**
+     * Set the isNoUserModification.
+     * 
+     * @param isNoUserModification
+     *          The isNoUserModification.
+     */
+    public void setNoUserModification(boolean isNoUserModification) {
+      this.isNoUserModification = isNoUserModification;
+    }
+
+    /**
+     * Set the isObsolete.
+     * 
+     * @param isObsolete
+     *          The isObsolete.
+     */
+    public void setObsolete(boolean isObsolete) {
+      this.isObsolete = isObsolete;
+    }
+
+    /**
+     * Set the isSingleValue.
+     * 
+     * @param isSingleValue
+     *          The isSingleValue.
+     */
+    public void setSingleValue(boolean isSingleValue) {
+      this.isSingleValue = isSingleValue;
+    }
+
+    /**
+     * Set the oid.
+     * 
+     * @param oid
+     *          The oid.
+     */
+    public void setOid(String oid) {
+      if (oid == null) {
+        throw new NullPointerException("Null OID");
+      }
+
+      this.oid = oid;
+    }
+
+    /**
+     * Set the orderingMatchingRule.
+     * 
+     * @param orderingMatchingRule
+     *          The orderingMatchingRule.
+     */
+    public void setOrderingMatchingRule(
+        OrderingMatchingRule orderingMatchingRule) {
+      this.orderingMatchingRule = orderingMatchingRule;
+    }
+
+    /**
+     * Set the primaryName.
+     * 
+     * @param primaryName
+     *          The primaryName.
+     */
+    public void setPrimaryName(String primaryName) {
+      this.primaryName = primaryName;
+    }
+
+    /**
+     * Set the substringMatchingRule.
+     * 
+     * @param substringMatchingRule
+     *          The substringMatchingRule.
+     */
+    public void setSubstringMatchingRule(
+        SubstringMatchingRule substringMatchingRule) {
+      this.substringMatchingRule = substringMatchingRule;
+    }
+
+    /**
+     * Set the superiorType.
+     * 
+     * @param superiorType
+     *          The superiorType.
+     */
+    public void setSuperiorType(AttributeType superiorType) {
+      this.superiorType = superiorType;
+    }
+
+    /**
+     * Set the syntax.
+     * 
+     * @param syntax
+     *          The syntax.
+     */
+    public void setSyntax(AttributeSyntax syntax) {
+      this.syntax = syntax;
+    }
+
+    /**
+     * Add attribute type name(s).
+     * 
+     * @param names
+     *          The attribute type name(s) to add.
+     */
+    public void addTypeNames(String... names) {
+      if (names == null) {
+        throw new NullPointerException("Null names");
+      }
+
+      if (typeNames == null) {
+        typeNames = new LinkedList<String>();
+      }
+
+      typeNames.addAll(Arrays.asList(names));
+    }
+  }
+
+  /**
+   * Once-only initialization.
+   * 
+   * @throws Exception
+   *           If an unexpected error occurred.
+   */
+  @BeforeClass
+  public void setUp() throws Exception {
+    // This test suite depends on having the schema available, so
+    // we'll
+    // start the server.
+    TestCaseUtils.startServer();
+  }
+
+  /**
+   * Check that the simple constructor throws an NPE when mandatory
+   * parameters are not specified.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = NullPointerException.class)
+  public void testSimpleConstructorNPE() throws Exception {
+    new AttributeType(null, null, null, null, null, null, null,
+        false, false, false, false);
+  }
+
+  /**
+   * Check that the complex constructor throws an NPE when mandatory
+   * parameters are not specified.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(expectedExceptions = NullPointerException.class)
+  public void testComplexConstructorNPE() throws Exception {
+    new AttributeType(null, null, null, null, null, null, null, null,
+        null, null, null, false, false, false, false, null);
+  }
+
+  /**
+   * Check that the complex constructor does not throw an exception
+   * when all optional parameters are not specified.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testComplexConstructorDefault() throws Exception {
+    AttributeType type = new AttributeType(null, null, "1.2.3", null,
+        null, null, null, null, null, null, null, false, false,
+        false, false, null);
+
+    Assert.assertNull(type.getPrimaryName());
+  }
+
+  /**
+   * Check that the primary name is added to the set of names.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorPrimaryName() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertTrue(type.hasName("testtype"));
+    Assert.assertFalse(type.hasName("xxx"));
+  }
+
+  /**
+   * Check that the type names are accessible.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorTypeNames() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+
+    builder.addTypeNames("testNameAlias", "anotherNameAlias");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertTrue(type.hasName("testtype"));
+    Assert.assertTrue(type.hasName("testnamealias"));
+    Assert.assertTrue(type.hasName("anothernamealias"));
+  }
+
+  /**
+   * Check constructor sets the default usage correctly.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorDefaultUsage() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertEquals(type.getUsage(),
+        AttributeUsage.USER_APPLICATIONS);
+  }
+
+  /**
+   * Check constructor sets the default syntax correctly.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorDefaultSyntax() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertEquals(type.getSyntax(), DirectoryServer
+        .getDefaultAttributeSyntax());
+  }
+
+  /**
+   * Check constructor sets the syntax correctly.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorSyntax() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    builder.setSyntax(DirectoryServer.getDefaultIntegerSyntax());
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertEquals(type.getSyntax(), DirectoryServer
+        .getDefaultIntegerSyntax());
+  }
+
+  /**
+   * Check constructor inherits the syntax from the parent type when
+   * required.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dependsOnMethods = "testConstructorSyntax")
+  public void testConstructorInheritsSyntax() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "parentType", "1.2.3");
+    builder.setSyntax(DirectoryServer.getDefaultIntegerSyntax());
+    AttributeType parent = builder.getAttributeType();
+
+    builder.setPrimaryName("childType");
+    builder.setOid("4.5.6");
+    builder.setSuperiorType(parent);
+    AttributeType child = builder.getAttributeType();
+
+    Assert.assertEquals(parent.getSyntax(), child.getSyntax());
+  }
+
+  /**
+   * Check constructor sets the default matching rules correctly.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorDefaultMatchingRules() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    AttributeSyntax syntax = DirectoryServer
+        .getDefaultAttributeSyntax();
+    Assert.assertEquals(type.getApproximateMatchingRule(), syntax
+        .getApproximateMatchingRule());
+    Assert.assertEquals(type.getEqualityMatchingRule(), syntax
+        .getEqualityMatchingRule());
+    Assert.assertEquals(type.getOrderingMatchingRule(), syntax
+        .getOrderingMatchingRule());
+    Assert.assertEquals(type.getSubstringMatchingRule(), syntax
+        .getSubstringMatchingRule());
+  }
+
+  /**
+   * Check constructor sets the matching rules correctly.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testConstructorMatchingRules() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeSyntax syntax = DirectoryServer.getDefaultStringSyntax();
+    builder.setApproximateMatchingRule(syntax
+        .getApproximateMatchingRule());
+    builder.setEqualityMatchingRule(syntax.getEqualityMatchingRule());
+    builder.setOrderingMatchingRule(syntax.getOrderingMatchingRule());
+    builder.setSubstringMatchingRule(syntax
+        .getSubstringMatchingRule());
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertEquals(type.getApproximateMatchingRule(), syntax
+        .getApproximateMatchingRule());
+    Assert.assertEquals(type.getEqualityMatchingRule(), syntax
+        .getEqualityMatchingRule());
+    Assert.assertEquals(type.getOrderingMatchingRule(), syntax
+        .getOrderingMatchingRule());
+    Assert.assertEquals(type.getSubstringMatchingRule(), syntax
+        .getSubstringMatchingRule());
+  }
+
+  /**
+   * Check constructor inherits the matching rules from the parent
+   * type when required.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dependsOnMethods = "testConstructorMatchingRules")
+  public void testConstructorInheritsMatchingRules() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "parentType", "1.2.3");
+    AttributeSyntax syntax = DirectoryServer.getDefaultStringSyntax();
+    builder.setApproximateMatchingRule(syntax
+        .getApproximateMatchingRule());
+    builder.setEqualityMatchingRule(syntax.getEqualityMatchingRule());
+    builder.setOrderingMatchingRule(syntax.getOrderingMatchingRule());
+    builder.setSubstringMatchingRule(syntax
+        .getSubstringMatchingRule());
+
+    AttributeType parent = builder.getAttributeType();
+
+    builder.setPrimaryName("childType");
+    builder.setOid("4.5.6");
+    builder.setSuperiorType(parent);
+    AttributeType child = builder.getAttributeType();
+
+    Assert.assertEquals(parent.getApproximateMatchingRule(), child
+        .getApproximateMatchingRule());
+    Assert.assertEquals(parent.getEqualityMatchingRule(), child
+        .getEqualityMatchingRule());
+    Assert.assertEquals(parent.getOrderingMatchingRule(), child
+        .getOrderingMatchingRule());
+    Assert.assertEquals(parent.getSubstringMatchingRule(), child
+        .getSubstringMatchingRule());
+  }
+
+  /**
+   * Create test data for testing the
+   * {@link AttributeType#isObjectClassType()} method.
+   * 
+   * @return Returns the array of test data.
+   */
+  @DataProvider(name = "isObjectClassTypeTestData")
+  public Object[][] createIsObjectClassTypeTestData() {
+    return new Object[][] { { "testType", false },
+        { "objectclass", true }, { "objectClass", true },
+        { "OBJECTCLASS", true } };
+  }
+
+  /**
+   * Check that the objectClass attribute type is correctly
+   * identified.
+   * 
+   * @param name
+   *          The primary name.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "isObjectClassTypeTestData")
+  public void testIsObjectClassType(String name, boolean result)
+      throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(name,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertEquals(type.isObjectClassType(), result);
+  }
+
+  /**
+   * Create test data for testing the
+   * {@link AttributeType#equals(Object)} method.
+   * 
+   * @return Returns the array of test data.
+   */
+  @DataProvider(name = "equalsTestData")
+  public Object[][] createEqualsTestData() {
+    return new Object[][] {
+        { "testType", "1.2.3", "testType", "1.2.3", true },
+        { "testType", "1.2.3", "xxx", "1.2.3", true },
+        { "testType", "1.2.3", "testType", "1.2.4", false },
+        { "testType", "1.2.3", "xxx", "1.2.4", false } };
+  }
+
+  /**
+   * Check that the equals operator works as expected.
+   * 
+   * @param name1
+   *          The first primary name.
+   * @param oid1
+   *          The first oid.
+   * @param name2
+   *          The second primary name.
+   * @param oid2
+   *          The second oid.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "equalsTestData")
+  public void testEquals(String name1, String oid1, String name2,
+      String oid2, boolean result) throws Exception {
+    AttributeTypeBuilder builder1 = new AttributeTypeBuilder(name1,
+        oid1);
+    AttributeType type1 = builder1.getAttributeType();
+
+    AttributeTypeBuilder builder2 = new AttributeTypeBuilder(name2,
+        oid2);
+    AttributeType type2 = builder2.getAttributeType();
+
+    Assert.assertEquals(type1.equals(type2), result);
+    Assert.assertEquals(type2.equals(type1), result);
+  }
+
+  /**
+   * Check that the hasCode method operator works as expected.
+   * 
+   * @param name1
+   *          The first primary name.
+   * @param oid1
+   *          The first oid.
+   * @param name2
+   *          The second primary name.
+   * @param oid2
+   *          The second oid.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "equalsTestData")
+  public void testHashCode(String name1, String oid1, String name2,
+      String oid2, boolean result) throws Exception {
+    AttributeTypeBuilder builder1 = new AttributeTypeBuilder(name1,
+        oid1);
+    AttributeType type1 = builder1.getAttributeType();
+
+    AttributeTypeBuilder builder2 = new AttributeTypeBuilder(name2,
+        oid2);
+    AttributeType type2 = builder2.getAttributeType();
+
+    Assert.assertEquals(type1.hashCode() == type2.hashCode(), result);
+  }
+
+  /**
+   * Create test data for testing the
+   * {@link AttributeType#generateHashCode(AttributeValue)} method.
+   * 
+   * @return Returns the array of test data.
+   */
+  @DataProvider(name = "generateHashCodeTestData")
+  public Object[][] createGenerateHashCodeTestData() {
+    return new Object[][] { { "one", "one", true },
+        { "one", "ONE", true }, { "one", "  oNe  ", true },
+        { "one two", " one  two  ", true },
+        { "one two", "onetwo", false }, { "one", "two", false } };
+  }
+
+  /**
+   * Check that the
+   * {@link AttributeType#generateHashCode(AttributeValue)} method
+   * works as expected.
+   * 
+   * @param value1
+   *          The first test value.
+   * @param value2
+   *          The second test value.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "generateHashCodeTestData")
+  public void testGenerateHashCodeTestData(String value1,
+      String value2, boolean result) throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
+    AttributeType type = builder.getAttributeType();
+
+    AttributeValue av1 = new AttributeValue(type, value1);
+    AttributeValue av2 = new AttributeValue(type, value2);
+
+    int h1 = type.generateHashCode(av1);
+    int h2 = type.generateHashCode(av2);
+
+    Assert.assertEquals(h1 == h2, result);
+  }
+
+  /**
+   * Check that the {@link AttributeType#normalize(ByteString)} method
+   * works as expected.
+   * 
+   * @param value1
+   *          The first test value.
+   * @param value2
+   *          The second test value.
+   * @param result
+   *          The expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "generateHashCodeTestData")
+  public void testNormalize(String value1, String value2,
+      boolean result) throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
+    AttributeType type = builder.getAttributeType();
+
+    ByteString b1 = new ASN1OctetString(value1);
+    ByteString b2 = new ASN1OctetString(value2);
+
+    ByteString r1 = type.normalize(b1);
+    ByteString r2 = type.normalize(b2);
+
+    Assert.assertEquals(r1.equals(r2), result);
+  }
+
+  /**
+   * Check that the {@link AttributeType#getDescription()} method
+   * returns <code>null</code> when there is no description.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetDescriptionDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertNull(type.getDescription());
+  }
+
+  /**
+   * Check that the {@link AttributeType#getDescription()} method
+   * returns a description.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetDescription() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    builder.setDescription("hello");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getDescription(), "hello");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getExtraProperty(String)}
+   * method returns <code>null</code> when there is no property.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetExtraPropertyDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertNull(type.getExtraProperty("test"));
+  }
+
+  /**
+   * Check that the {@link AttributeType#getExtraProperty(String)}
+   * method returns values.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetExtraProperty() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    String[] expectedValues = new String[] { "one", "two" };
+    builder.addExtraProperty("test", expectedValues);
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertNotNull(type.getExtraProperty("test"));
+    int i = 0;
+    for (String value : type.getExtraProperty("test")) {
+      Assert.assertEquals(value, expectedValues[i]);
+      i++;
+    }
+  }
+
+  /**
+   * Check that the {@link AttributeType#getExtraPropertyNames()}
+   * method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetExtraPropertyNames() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertFalse(type.getExtraPropertyNames().iterator()
+        .hasNext());
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNameOrOID()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNameOrOIDReturnsOID() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getNameOrOID(), "1.2.3");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNameOrOID()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNameOrOIDReturnsPrimaryName() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getNameOrOID(), "testType");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNameOrOID()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNameOrOIDReturnsOtherName() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    builder.addTypeNames("anotherName");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getNameOrOID(), "anotherName");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNormalizedNames()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNormalizedNames() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    builder.addTypeNames("anotherName", "yetAnotherName");
+    AttributeType type = builder.getAttributeType();
+
+    boolean gotTestType = false;
+    boolean gotAnotherName = false;
+    boolean gotYetAnotherName = false;
+
+    for (String name : type.getNormalizedNames()) {
+      if (name.equals("testtype")) {
+        gotTestType = true;
+      } else if (name.equals("anothername")) {
+        gotAnotherName = true;
+      } else if (name.equals("yetanothername")) {
+        gotYetAnotherName = true;
+      } else {
+        Assert.fail("Got unexpected normalized name: " + name);
+      }
+    }
+
+    Assert.assertTrue(gotTestType && gotAnotherName
+        && gotYetAnotherName);
+  }
+
+  /**
+   * Check that the {@link AttributeType#getUserDefinedNames()}
+   * method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetUserDefinedNames() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    builder.addTypeNames("anotherName", "yetAnotherName");
+    AttributeType type = builder.getAttributeType();
+
+    boolean gotTestType = false;
+    boolean gotAnotherName = false;
+    boolean gotYetAnotherName = false;
+
+    for (String name : type.getUserDefinedNames()) {
+      if (name.equals("testType")) {
+        gotTestType = true;
+      } else if (name.equals("anotherName")) {
+        gotAnotherName = true;
+      } else if (name.equals("yetAnotherName")) {
+        gotYetAnotherName = true;
+      } else {
+        Assert.fail("Got unexpected user defined name: " + name);
+      }
+    }
+
+    Assert.assertTrue(gotTestType && gotAnotherName
+        && gotYetAnotherName);
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNormalizedPrimaryName()}
+   * method returns <code>null</code> when there is no primary name.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNormalizedPrimaryNameDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertNull(type.getNormalizedPrimaryName());
+  }
+
+  /**
+   * Check that the {@link AttributeType#getNormalizedPrimaryName()}
+   * method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetNormalizedPrimaryName() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getNormalizedPrimaryName(), "testtype");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getOID()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetOID() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getOID(), "1.2.3");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getPrimaryName()} method
+   * returns <code>null</code> when there is no primary name.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetPrimaryNameDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertNull(type.getPrimaryName());
+  }
+
+  /**
+   * Check that the {@link AttributeType#getPrimaryName()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetPrimaryName() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getPrimaryName(), "testType");
+  }
+
+  /**
+   * Check that the {@link AttributeType#getSchemaFile()} method
+   * returns <code>null</code> when there is no schema file.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetSchemaFileDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertNull(type.getSchemaFile());
+  }
+
+  /**
+   * Check that the {@link AttributeType#getSchemaFile()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testGetSchemaFile() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    builder.addExtraProperty(
+        ServerConstants.SCHEMA_PROPERTY_FILENAME, "/foo/bar");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.getSchemaFile(), "/foo/bar");
+  }
+
+  /**
+   * Check that the {@link AttributeType#hasNameOrOID(String)} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testHasNameOrOID() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertTrue(type.hasNameOrOID("testtype"));
+    Assert.assertTrue(type.hasNameOrOID("1.2.3"));
+    Assert.assertFalse(type.hasNameOrOID("x.y.z"));
+  }
+
+  /**
+   * Check that the {@link AttributeType#isCollective()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsCollective() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertFalse(type.isCollective());
+
+    builder = new AttributeTypeBuilder("testType", "1.2.3");
+    builder.setCollective(true);
+    type = builder.getAttributeType();
+
+    Assert.assertTrue(type.isCollective());
+  }
+
+  /**
+   * Check that the {@link AttributeType#isNoUserModification()}
+   * method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsNoUserModification() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertFalse(type.isNoUserModification());
+
+    builder = new AttributeTypeBuilder("testType", "1.2.3");
+    builder.setNoUserModification(true);
+    type = builder.getAttributeType();
+
+    Assert.assertTrue(type.isNoUserModification());
+  }
+
+  /**
+   * Check that the {@link AttributeType#isObsolete()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsObsolete() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertFalse(type.isObsolete());
+
+    builder = new AttributeTypeBuilder("testType", "1.2.3");
+    builder.setObsolete(true);
+    type = builder.getAttributeType();
+
+    Assert.assertTrue(type.isObsolete());
+  }
+
+  /**
+   * Check that the {@link AttributeType#isSingleValue()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testIsSingleValue() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    AttributeType type = builder.getAttributeType();
+
+    Assert.assertFalse(type.isSingleValue());
+
+    builder = new AttributeTypeBuilder("testType", "1.2.3");
+    builder.setSingleValue(true);
+    type = builder.getAttributeType();
+
+    Assert.assertTrue(type.isSingleValue());
+  }
+
+  /**
+   * Create test data for testing the
+   * {@link AttributeType#isOperational()} method.
+   * 
+   * @return Returns the array of test data.
+   */
+  @DataProvider(name = "isOperationalTestData")
+  public Object[][] createIsOperationalTestData() {
+    return new Object[][] { { null, false },
+        { AttributeUsage.USER_APPLICATIONS, false },
+        { AttributeUsage.DIRECTORY_OPERATION, true },
+        { AttributeUsage.DISTRIBUTED_OPERATION, true },
+        { AttributeUsage.DSA_OPERATION, true } };
+  }
+
+  /**
+   * Check that the {@link AttributeType#isOperational()} method.
+   * 
+   * @param usage
+   *          The attribute usage.
+   * @param result
+   *          Expected result.
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test(dataProvider = "isOperationalTestData")
+  public void testIsOperational(AttributeUsage usage, boolean result)
+      throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    builder.setAttributeUsage(usage);
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.isOperational(), result);
+  }
+
+  /**
+   * Check that the {@link AttributeType#toString()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testToStringDefault() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
+        "1.2.3");
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.toString(), "( 1.2.3 "
+        + "EQUALITY caseIgnoreMatch "
+        + "ORDERING caseIgnoreOrderingMatch "
+        + "SUBSTR caseIgnoreSubstringsMatch "
+        + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
+        + "USAGE userApplications )");
+  }
+
+  /**
+   * Check that the {@link AttributeType#toString()} method.
+   * 
+   * @throws Exception
+   *           If the test failed unexpectedly.
+   */
+  @Test
+  public void testToString() throws Exception {
+    AttributeTypeBuilder builder = new AttributeTypeBuilder(
+        "testType", "1.2.3");
+    builder.addTypeNames("anotherName");
+    builder.setAttributeUsage(AttributeUsage.DIRECTORY_OPERATION);
+    builder.setSingleValue(true);
+    builder.setSyntax(DirectoryServer.getDefaultBooleanSyntax());
+    builder.addExtraProperty(
+        ServerConstants.SCHEMA_PROPERTY_FILENAME, "/foo/bar");
+
+    AttributeType type = builder.getAttributeType();
+    Assert.assertEquals(type.toString(), "( 1.2.3 "
+        + "NAME ( 'anotherName' 'testType' ) "
+        + "EQUALITY booleanMatch "
+        + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " + "SINGLE-VALUE "
+        + "USAGE directoryOperation " + "X-SCHEMA-FILE '/foo/bar' )");
+  }
+}

--
Gitblit v1.10.0