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

matthew_swift
02.39.2006 57d38c450aab6379ce7c08d58757cdddba7ef1ab
Add test suite for org.opends.server.types.ObjectClass and perform the following refactoring:

* make ObjectClass immutable
* pull out common schema definition elements into a separate common base class and refactor both ObjectClass and AttributeType to use it
* create test suite for common schema definition elements.
3 files added
8 files modified
5067 ■■■■■ changed files
opends/src/server/org/opends/server/core/DirectoryServer.java 64 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/Schema.java 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SchemaConfigManager.java 2 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java 3 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/ObjectClassSyntax.java 35 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/AttributeType.java 509 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/CommonSchemaElements.java 562 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/ObjectClass.java 1136 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java 724 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestCommonSchemaElements.java 789 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java 1237 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -2867,24 +2867,10 @@
         directoryServer.schema.getObjectClass(TOP_OBJECTCLASS_NAME);
    if (objectClass == null)
    {
      ConcurrentHashMap<String,String> names =
           new ConcurrentHashMap<String,String>(1);
      names.put(TOP_OBJECTCLASS_NAME, TOP_OBJECTCLASS_NAME);
      CopyOnWriteArraySet<AttributeType> requiredAttrs =
           new CopyOnWriteArraySet<AttributeType>();
      CopyOnWriteArraySet<AttributeType> optionalAttrs =
           new CopyOnWriteArraySet<AttributeType>();
      ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
           new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>(0);
      objectClass = new ObjectClass(TOP_OBJECTCLASS_NAME, names,
                                    TOP_OBJECTCLASS_OID,
                                    TOP_OBJECTCLASS_DESCRIPTION, null,
                                    requiredAttrs, optionalAttrs,
                                    ObjectClassType.ABSTRACT, false,
                                    extraProperties);
      objectClass = new ObjectClass(TOP_OBJECTCLASS_NAME, Collections
          .singleton(TOP_OBJECTCLASS_NAME), TOP_OBJECTCLASS_OID,
          TOP_OBJECTCLASS_DESCRIPTION, null, null, null,
          ObjectClassType.ABSTRACT, false, null);
    }
    return objectClass;
@@ -2893,13 +2879,15 @@
  /**
   * Causes the Directory Server to construct a new objectclass definition with
   * the provided name and with no required or allowed attributes.  This should
   * only be used if there is no objectclass for the specified name.  It will
   * not register the created objectclass with the Directory Server.
   * Causes the Directory Server to construct a new objectclass
   * definition with the provided name and with no required or allowed
   * attributes. This should only be used if there is no objectclass
   * for the specified name. It will not register the created
   * objectclass with the Directory Server.
   *
   * @param  name  The name to use for the objectclass, as provided by the user.
   *
   * @param name
   *          The name to use for the objectclass, as provided by the
   *          user.
   * @return  The constructed objectclass definition.
   */
  public static ObjectClass getDefaultObjectClass(String name)
@@ -2911,22 +2899,10 @@
    ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
    if (objectClass == null)
    {
      ConcurrentHashMap<String,String> names =
           new ConcurrentHashMap<String,String>(1);
      names.put(lowerName, name);
      CopyOnWriteArraySet<AttributeType> requiredAttrs =
           new CopyOnWriteArraySet<AttributeType>();
      CopyOnWriteArraySet<AttributeType> optionalAttrs =
           new CopyOnWriteArraySet<AttributeType>();
      ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
           new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>(0);
      objectClass = new ObjectClass(name, names, lowerName, null,
                                    getTopObjectClass(), requiredAttrs,
                                    optionalAttrs, ObjectClassType.ABSTRACT,
                                    false, extraProperties);
      objectClass = new ObjectClass(name,
          Collections.singleton(name), lowerName, null,
          getTopObjectClass(), null, null, ObjectClassType.ABSTRACT,
          false, null);
    }
    return objectClass;
@@ -2935,11 +2911,11 @@
  /**
   * Retrieves the set of attribute type definitions that have been defined in
   * the Directory Server.
   * Retrieves the set of attribute type definitions that have been
   * defined in the Directory Server.
   *
   * @return  The set of attribute type definitions that have been defined in
   *          the Directory Server.
   * @return The set of attribute type definitions that have been
   *         defined in the Directory Server.
   */
  public static ConcurrentHashMap<String,AttributeType> getAttributeTypes()
  {
opends/src/server/org/opends/server/core/Schema.java
@@ -448,7 +448,7 @@
                                       msgID);
        }
        for (String name : objectClass.getNames().keySet())
        for (String name : objectClass.getNormalizedNames())
        {
          if (objectClasses.containsKey(name))
          {
@@ -465,7 +465,7 @@
      objectClasses.put(toLowerCase(objectClass.getOID()), objectClass);
      for (String name : objectClass.getNames().keySet())
      for (String name : objectClass.getNormalizedNames())
      {
        objectClasses.put(name, objectClass);
      }
@@ -496,7 +496,7 @@
    {
      objectClasses.remove(toLowerCase(objectClass.getOID()), objectClass);
      for (String name : objectClass.getNames().keySet())
      for (String name : objectClass.getNormalizedNames())
      {
        objectClasses.remove(name, objectClass);
      }
opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -1005,8 +1005,6 @@
            try
            {
              oc = ocSyntax.decodeObjectClass(v.getValue(), schema);
              oc.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
              oc.setSchemaFile(schemaFile);
            }
            catch (DirectoryException de)
            {
opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
@@ -30,6 +30,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import org.opends.server.api.ApproximateMatchingRule;
@@ -491,7 +492,7 @@
    boolean isObsolete = false;
    boolean isSingleValue = false;
    HashMap<String,List<String>> extraProperties =
         new HashMap<String,List<String>>();
         new LinkedHashMap<String,List<String>>();
    while (true)
opends/src/server/org/opends/server/schema/ObjectClassSyntax.java
@@ -28,10 +28,12 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
@@ -478,18 +480,16 @@
    // 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> names =
         new ConcurrentHashMap<String,String>();
    List<String> names = new LinkedList<String>();
    String description = null;
    boolean isObsolete = false;
    ObjectClass superiorClass = DirectoryServer.getTopObjectClass();
    CopyOnWriteArraySet<AttributeType> requiredAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    CopyOnWriteArraySet<AttributeType> optionalAttributes =
         new CopyOnWriteArraySet<AttributeType>();
    ObjectClassType objectClassType = superiorClass.getObjectClassType();
    ConcurrentHashMap<String,CopyOnWriteArrayList<String>> extraProperties =
         new ConcurrentHashMap<String,CopyOnWriteArrayList<String>>();
    Set<AttributeType> requiredAttributes = new LinkedHashSet<AttributeType>();
    Set<AttributeType> optionalAttributes = new LinkedHashSet<AttributeType>();
    ObjectClassType objectClassType = superiorClass
        .getObjectClassType();
    Map<String, List<String>> extraProperties =
      new LinkedHashMap<String, List<String>>();
    while (true)
@@ -525,7 +525,7 @@
          pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer,
                                 (pos-1));
          primaryName = userBuffer.toString();
          names.put(lowerBuffer.toString(), primaryName);
          names.add(primaryName);
        }
        else if (c == '(')
        {
@@ -534,7 +534,7 @@
          pos = readQuotedString(valueStr, lowerStr, userBuffer, lowerBuffer,
                                 pos);
          primaryName = userBuffer.toString();
          names.put(lowerBuffer.toString(), primaryName);
          names.add(primaryName);
          while (true)
@@ -557,7 +557,7 @@
              pos = readQuotedString(valueStr, lowerStr, userBuffer,
                                     lowerBuffer, pos);
              names.put(lowerBuffer.toString(), userBuffer.toString());
              names.add(userBuffer.toString());
            }
          }
        }
@@ -792,8 +792,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 LinkedList<String>();
        pos = readExtraParameterValues(valueStr, valueList, pos);
        extraProperties.put(tokenName, valueList);
      }
@@ -1228,7 +1227,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",
opends/src/server/org/opends/server/types/AttributeType.java
@@ -29,9 +29,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.opends.server.api.ApproximateMatchingRule;
@@ -46,7 +43,6 @@
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -55,8 +51,17 @@
 * with an attribute type, which contains information about the format
 * of an attribute and the syntax and matching rules that should be
 * used when interacting with it.
 * <p>
 * Any methods which accesses the set of names associated with this
 * attribute type, will retrieve the primary name as the first name,
 * regardless of whether or not it was contained in the original set
 * of <code>names</code> passed to the constructor.
 * <p>
 * Where ordered sets of names, or extra properties are provided, the
 * ordering will be preserved when the associated fields are accessed
 * via their getters or via the {@link #toString()} methods.
 */
public final class AttributeType
public final class AttributeType extends CommonSchemaElements
{
  /**
   * The fully-qualified name of this class for debugging purposes.
@@ -89,38 +94,15 @@
  // Indicates whether this attribute type is the objectclass type.
  private final boolean isObjectClassType;
  // Indicates whether this attribute type is declared "obsolete".
  private final boolean isObsolete;
  // Indicates whether this attribute type is declared "single-value".
  private final boolean isSingleValue;
  // The set of additional name-value pairs associated with this
  // attribute type definition.
  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 final Map<String,String> typeNames;
  // The equality matching rule for this attribute type.
  private final EqualityMatchingRule equalityMatchingRule;
  // The ordering matching rule for this attribute type.
  private final OrderingMatchingRule orderingMatchingRule;
  // The description for this attribute type.
  private final String description;
  // The OID that may be used to reference this attribute type.
  private final String oid;
  // The primary name to use for this attribute type.
  private final String primaryName;
  // The lower case name for this attribute type.
  private final String lowerName;
  // The substring matching rule for this attribute type.
  private final SubstringMatchingRule substringMatchingRule;
@@ -128,6 +110,11 @@
  /**
   * Creates a new attribute type with the provided information.
   * <p>
   * If no <code>primaryName</code> is specified, but a set of
   * <code>names</code> is specified, then the first name retrieved
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param primaryName
   *          The primary name for this attribute type, or
@@ -184,6 +171,11 @@
  /**
   * Creates a new attribute type with the provided information.
   * <p>
   * If no <code>primaryName</code> is specified, but a set of
   * <code>names</code> is specified, then the first name retrieved
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param primaryName
   *          The primary name for this attribute type, or
@@ -234,6 +226,8 @@
   * @param extraProperties
   *          A set of extra properties for this attribute type, or
   *          <code>null</code> if there are no extra properties.
   * @throws NullPointerException
   *           If the provided OID was <code>null</code>.
   */
  public AttributeType(String primaryName,
                       Collection<String> typeNames,
@@ -250,7 +244,11 @@
                       boolean isNoUserModification,
                       boolean isObsolete, boolean isSingleValue,
                       Map<String,List<String>> extraProperties)
                       throws NullPointerException
  {
    super(primaryName, typeNames, oid, description, isObsolete,
        extraProperties);
    assert debugConstructor(CLASS_NAME,String.valueOf(primaryName),
                              String.valueOf(typeNames),
                              String.valueOf(oid),
@@ -268,43 +266,11 @@
                              String.valueOf(isSingleValue),
                              String.valueOf(extraProperties));
    // Make sure mandatory parameters are specified.
    if (oid == null)
    {
      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.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)
    {
      if (superiorType != null)
@@ -380,208 +346,8 @@
    }
    else
    {
      isObjectClassType =
        this.typeNames.containsKey(OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
      isObjectClassType = hasName(OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
    }
    if (extraProperties != null)
    {
      this.extraProperties =
        new HashMap<String, List<String>>(extraProperties);
    }
    else
    {
      this.extraProperties = Collections.emptyMap();
    }
  }
  /**
   * Retrieves 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()
  {
    assert debugEnter(CLASS_NAME, "getPrimaryName");
    return primaryName;
  }
  /**
   * Retrieve the normalized primary 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 getNormalizedPrimaryName()
  {
    assert debugEnter(CLASS_NAME, "getNormalizedPrimaryName");
    return lowerName;
  }
  /**
   * 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.
   *
   * @return Returns an iterable over the set of normalized names that
   *         may be used to reference this attribute type.
   */
  public Iterable<String> getNormalizedNames()
  {
    assert debugEnter(CLASS_NAME, "getNormalizedNames");
    return typeNames.keySet();
  }
  /**
   * Retrieves an iterable over the set of user-defined 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 Iterable<String> getUserDefinedNames()
  {
    assert debugEnter(CLASS_NAME, "getUserDefinedNames");
    return typeNames.values();
  }
  /**
   * Indicates whether this attribute type has the specified name.
   *
   * @param  lowerName  The lowercase name for which to make the
   *                    determination.
   *
   * @return  <CODE>true</CODE> if the specified name is assigned to
   *          this attribute type, or <CODE>false</CODE> if not.
   */
  public boolean hasName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "hasName",
                      String.valueOf(lowerName));
    return typeNames.containsKey(lowerName);
  }
  /**
   * Retrieves the OID for this attribute type.
   *
   * @return  The OID for this attribute type.
   */
  public String getOID()
  {
    assert debugEnter(CLASS_NAME, "getOID");
    return 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.
   *
   * @return  The name or OID for this attribute type.
   */
  public String getNameOrOID()
  {
    assert debugEnter(CLASS_NAME, "getNameOrOID");
    if (primaryName != null)
    {
      return primaryName;
    }
    if (typeNames.isEmpty())
    {
      return oid;
    }
    else
    {
      return typeNames.values().iterator().next();
    }
  }
  /**
   * Indicates whether this attribute type has the specified name or
   * OID.
   *
   * @param  lowerValue  The lowercase value for which to make the
   *                     determination.
   *
   * @return  <CODE>true</CODE> if the provided value matches the OID
   *          or one of the names assigned to this attribute type, or
   *          <CODE>false</CODE> if not.
   */
  public boolean hasNameOrOID(String lowerValue)
  {
    assert debugEnter(CLASS_NAME, "hasNameOrOID",
                      String.valueOf(lowerValue));
    if (typeNames.containsKey(lowerValue))
    {
      return true;
    }
    return oid.equals(lowerValue);
  }
  /**
   * Retrieves the path to the schema file that contains the
   * definition for this attribute type.
   *
   * @return  The path to the schema file that contains the definition
   *          for this attribute type, or <CODE>null</CODE> if it is
   *          not known or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    List<String> values =
      extraProperties.get(SCHEMA_PROPERTY_FILENAME);
    if (values != null && !values.isEmpty()) {
      return values.get(0);
    }
    return null;
  }
  /**
   * Retrieves 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()
  {
    assert debugEnter(CLASS_NAME, "getDescription");
    return description;
  }
@@ -759,21 +525,6 @@
  /**
   * Indicates whether this attribute type is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this attribute type is declared
   *          "obsolete", or <CODE>false</CODE> if not.
   */
  public boolean isObsolete()
  {
    assert debugEnter(CLASS_NAME, "isObsolete");
    return isObsolete;
  }
  /**
   * Indicates whether this attribute type is declared "single-value".
   *
   * @return  <CODE>true</CODE> if this attribute type is declared
@@ -789,43 +540,6 @@
  /**
   * Retrieves an iterable over the names of "extra" properties
   * associated with this attribute type.
   *
   * @return Returns an iterable over the names of "extra" properties
   *         associated with this attribute type.
   */
  public Iterable<String> getExtraPropertyNames()
  {
    assert debugEnter(CLASS_NAME, "getExtraPropertyNames");
    return extraProperties.keySet();
  }
  /**
   * Retrieves an iterable over the value(s) of the specified "extra"
   * property for this attribute type.
   *
   * @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 Iterable<String> getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
    return extraProperties.get(propertyName);
  }
  /**
   * Indicates whether this attribute type represents the
   * "objectclass" attribute.  The determination will be made based on
   * the name and/or OID.
@@ -875,57 +589,6 @@
  /**
   * Indicates whether the provided object is equal to this attribute
   * type.  The object will be considered equal if it is an attribute
   * type with the same OID as the current type.
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this attribute type, or <CODE>false</CODE> if not.
   */
  public boolean equals(Object o)
  {
    assert debugEnter(CLASS_NAME, "equals");
    if (this == o)
    {
      return true;
    }
    if ((o == null) || (! (o instanceof AttributeType)))
    {
      return false;
    }
    return oid.equals(((AttributeType) o).oid);
  }
  /**
   * Retrieves the hash code for this attribute type.  It will be
   * based on the sum of the bytes of the OID.
   *
   * @return  The hash code for this attribute type.
   */
  public int hashCode()
  {
    assert debugEnter(CLASS_NAME, "hashCode");
    int oidLength = oid.length();
    int hashCode  = 0;
    for (int i=0; i < oidLength; i++)
    {
      hashCode += oid.charAt(i);
    }
    return hashCode;
  }
  /**
   * Generates a hash code for the specified attribute value.  If an
   * equality matching rule is defined for this type, then it will be
   * used to generate the hash code.  If the value does not have an
@@ -982,81 +645,12 @@
  /**
   * Retrieves the string representation of this attribute type in the
   * form specified in RFC 2252.
   *
   * @return  The string representation of this attribute type in the
   *          form specified in RFC 2252.
   * {@inheritDoc}
   */
  public String toString()
  protected void toStringContent(StringBuilder buffer)
  {
    assert debugEnter(CLASS_NAME, "toString");
    StringBuilder buffer = new StringBuilder();
    toString(buffer, true);
    return buffer.toString();
  }
  /**
   * Appends a string representation of this attribute type in the
   * form specified in RFC 2252 to the provided buffer.
   *
   * @param  buffer              The buffer to which the information
   *                             should be appended.
   * @param  includeFileElement  Indicates whether to include an
   *                             "extra" property that specifies the
   *                             path to the schema file from which
   *                             this attribute type was loaded.
   */
  public void toString(StringBuilder buffer,
                       boolean includeFileElement)
  {
    assert debugEnter(CLASS_NAME, "toString",
                      "java.lang.StringBuilder",
                      String.valueOf(includeFileElement));
    buffer.append("( ");
    buffer.append(oid);
    if (! typeNames.isEmpty())
    {
      Iterator<String> iterator = typeNames.values().iterator();
      String firstName = iterator.next();
      if (iterator.hasNext())
      {
        buffer.append(" NAME ( '");
        buffer.append(firstName);
        while (iterator.hasNext())
        {
          buffer.append("' '");
          buffer.append(iterator.next());
        }
        buffer.append("' )");
      }
      else
      {
        buffer.append(" NAME '");
        buffer.append(firstName);
        buffer.append("'");
      }
    }
    if ((description != null) && (description.length() > 0))
    {
      buffer.append(" DESC '");
      buffer.append(description);
      buffer.append("'");
    }
    if (isObsolete)
    {
      buffer.append(" OBSOLETE");
    }
    assert debugEnter(CLASS_NAME, "toStringContent",
                      "java.lang.StringBuilder");
    if (superiorType != null)
    {
@@ -1114,47 +708,6 @@
      buffer.append(" USAGE ");
      buffer.append(attributeUsage.toString());
    }
    if (! extraProperties.isEmpty())
    {
      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);
        if (valueList.size() == 1)
        {
          buffer.append(" '");
          buffer.append(valueList.get(0));
          buffer.append("'");
        }
        else
        {
          buffer.append(" ( ");
          for (String value : valueList)
          {
            buffer.append("'");
            buffer.append(value);
            buffer.append("' ");
          }
          buffer.append(")");
        }
      }
    }
    buffer.append(" )");
  }
}
opends/src/server/org/opends/server/types/CommonSchemaElements.java
New file
@@ -0,0 +1,562 @@
/*
 * 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 static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.toLowerCase;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
 * An abstract base class for LDAP schema definitions which contain an
 * OID, optional names, description, an obsolete flag, and an optional
 * set of extra properties.
 * <p>
 * This class defines common properties and behaviour of the various
 * types of schema definitions (e.g. object class definitions, and
 * attribute type definitions).
 * <p>
 * Any methods which accesses the set of names associated with this
 * definition, will retrieve the primary name as the first name,
 * regardless of whether or not it was contained in the original set
 * of <code>names</code> passed to the constructor.
 * <p>
 * Where ordered sets of names, or extra properties are provided, the
 * ordering will be preserved when the associated fields are accessed
 * via their getters or via the {@link #toString()} methods.
 */
public abstract class CommonSchemaElements {
  /**
   * The fully-qualified name of this class for debugging purposes.
   */
  private static final String CLASS_NAME =
    "org.opends.server.types.CommonSchemaElements";
  // Indicates whether this definition is declared "obsolete".
  private final boolean isObsolete;
  // The set of additional name-value pairs associated with this
  // definition.
  private final Map<String, List<String>> extraProperties;
  // The set of names for this definition, in a mapping between
  // the all-lowercase form and the user-defined form.
  private final Map<String, String> names;
  // The description for this definition.
  private final String description;
  // The OID that may be used to reference this definition.
  private final String oid;
  // The primary name to use for this definition.
  private final String primaryName;
  // The lower case name for this definition.
  private final String lowerName;
  /**
   * Creates a new definition with the provided information.
   * <p>
   * If no <code>primaryName</code> is specified, but a set of
   * <code>names</code> is specified, then the first name retrieved
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param primaryName
   *          The primary name for this definition, or
   *          <code>null</code> if there is no primary name.
   * @param names
   *          The full set of names for this definition, or
   *          <code>null</code> if there are no names.
   * @param oid
   *          The OID for this definition (must not be
   *          <code>null</code>).
   * @param description
   *          The description for the definition, or <code>null</code>
   *          if there is no description.
   * @param isObsolete
   *          Indicates whether this definition is declared
   *          "obsolete".
   * @param extraProperties
   *          A set of extra properties for this definition, or
   *          <code>null</code> if there are no extra properties.
   * @throws NullPointerException
   *           If the provided OID was <code>null</code>.
   */
  protected CommonSchemaElements(String primaryName,
      Collection<String> names, String oid, String description,
      boolean isObsolete, Map<String, List<String>> extraProperties)
      throws NullPointerException {
    assert debugConstructor(CLASS_NAME, String.valueOf(primaryName),
        String.valueOf(names), String.valueOf(oid), String
            .valueOf(description), String.valueOf(isObsolete), String
            .valueOf(extraProperties));
    // Make sure mandatory parameters are specified.
    if (oid == null) {
      throw new NullPointerException(
          "No oid specified in constructor");
    }
    this.oid = oid;
    this.description = description;
    this.isObsolete = isObsolete;
    // Make sure we have a primary name if possible.
    if (primaryName == null) {
      if (names != null && !names.isEmpty()) {
        this.primaryName = names.iterator().next();
      } else {
        this.primaryName = null;
      }
    } else {
      this.primaryName = primaryName;
    }
    this.lowerName = toLowerCase(primaryName);
    // Construct the normalized attribute name mapping.
    if (names != null) {
      this.names = new LinkedHashMap<String, String>(names.size());
      // Make sure the primary name is first (never null).
      this.names.put(lowerName, this.primaryName);
      // Add the remaining names in the order specified.
      for (String name : names) {
        this.names.put(toLowerCase(name), name);
      }
    } else if (this.primaryName != null) {
      this.names = Collections.singletonMap(lowerName,
          this.primaryName);
    } else {
      this.names = Collections.emptyMap();
    }
    // FIXME: should really be a deep-copy.
    if (extraProperties != null) {
      this.extraProperties = new LinkedHashMap<String, List<String>>(
          extraProperties);
    } else {
      this.extraProperties = Collections.emptyMap();
    }
  }
  /**
   * Retrieves the primary name for this schema definition.
   *
   * @return The primary name for this schema definition, or
   *         <code>null</code> if there is no primary name.
   */
  public final String getPrimaryName() {
    assert debugEnter(CLASS_NAME, "getPrimaryName");
    return primaryName;
  }
  /**
   * Retrieve the normalized primary name for this schema definition.
   *
   * @return Returns the normalized primary name for this attribute
   *         type, or <code>null</code> if there is no primary name.
   */
  public final String getNormalizedPrimaryName() {
    assert debugEnter(CLASS_NAME, "getNormalizedPrimaryName");
    return lowerName;
  }
  /**
   * Retrieves an iterable over the set of normalized names that may
   * be used to reference this schema definition. The normalized form
   * of an attribute name is defined as the user-defined name
   * converted to lower-case.
   *
   * @return Returns an iterable over the set of normalized names that
   *         may be used to reference this schema definition.
   */
  public final Iterable<String> getNormalizedNames() {
    assert debugEnter(CLASS_NAME, "getNormalizedNames");
    return names.keySet();
  }
  /**
   * Retrieves an iterable over the set of user-defined names that may
   * be used to reference this schema definition.
   *
   * @return Returns an iterable over the set of user-defined names
   *         that may be used to reference this schema definition.
   */
  public final Iterable<String> getUserDefinedNames() {
    assert debugEnter(CLASS_NAME, "getUserDefinedNames");
    return names.values();
  }
  /**
   * Indicates whether this schema definition has the specified name.
   *
   * @param lowerName
   *          The lowercase name for which to make the determination.
   * @return <code>true</code> if the specified name is assigned to
   *         this schema definition, or <code>false</code> if not.
   */
  public final boolean hasName(String lowerName) {
    assert debugEnter(CLASS_NAME, "hasName", String
        .valueOf(lowerName));
    return names.containsKey(lowerName);
  }
  /**
   * Retrieves the OID for this schema definition.
   *
   * @return The OID for this schema definition.
   */
  public final String getOID() {
    assert debugEnter(CLASS_NAME, "getOID");
    return oid;
  }
  /**
   * Retrieves the name or OID for this schema definition. 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.
   *
   * @return The name or OID for this schema definition.
   */
  public final String getNameOrOID() {
    assert debugEnter(CLASS_NAME, "getNameOrOID");
    if (primaryName != null) {
      return primaryName;
    } else {
      // Guaranteed not to be null.
      return oid;
    }
  }
  /**
   * Indicates whether this schema definition has the specified name
   * or OID.
   *
   * @param lowerValue
   *          The lowercase value for which to make the determination.
   * @return <code>true</code> if the provided value matches the OID
   *         or one of the names assigned to this schema definition,
   *         or <code>false</code> if not.
   */
  public final boolean hasNameOrOID(String lowerValue) {
    assert debugEnter(CLASS_NAME, "hasNameOrOID", String
        .valueOf(lowerValue));
    if (names.containsKey(lowerValue)) {
      return true;
    }
    return oid.equals(lowerValue);
  }
  /**
   * Retrieves the path to the schema file that contains the
   * definition for this schema definition.
   *
   * @return The path to the schema file that contains the definition
   *         for this schema definition, or <code>null</code> if it
   *         is not known or if it is not stored in any schema file.
   */
  public final String getSchemaFile() {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    List<String> values = extraProperties
        .get(SCHEMA_PROPERTY_FILENAME);
    if (values != null && !values.isEmpty()) {
      return values.get(0);
    }
    return null;
  }
  /**
   * Retrieves the description for this schema definition.
   *
   * @return The description for this schema definition, or
   *         <code>null</code> if there is no description.
   */
  public final String getDescription() {
    assert debugEnter(CLASS_NAME, "getDescription");
    return description;
  }
  /**
   * Indicates whether this schema definition is declared "obsolete".
   *
   * @return <code>true</code> if this schema definition is declared
   *         "obsolete", or <code>false</code> if not.
   */
  public final boolean isObsolete() {
    assert debugEnter(CLASS_NAME, "isObsolete");
    return isObsolete;
  }
  /**
   * Retrieves an iterable over the names of "extra" properties
   * associated with this schema definition.
   *
   * @return Returns an iterable over the names of "extra" properties
   *         associated with this schema definition.
   */
  public final Iterable<String> getExtraPropertyNames() {
    assert debugEnter(CLASS_NAME, "getExtraPropertyNames");
    return extraProperties.keySet();
  }
  /**
   * Retrieves an iterable over the value(s) of the specified "extra"
   * property for this schema definition.
   *
   * @param name
   *          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 schema definition, or
   *         <code>null</code> if no such property is defined.
   */
  public final Iterable<String> getExtraProperty(String name) {
    assert debugEnter(CLASS_NAME, "getExtraProperty", String
        .valueOf(name));
    return extraProperties.get(name);
  }
  /**
   * Indicates whether the provided object is equal to this attribute
   * type. The object will be considered equal if it is an attribute
   * type with the same OID as the current type.
   *
   * @param o
   *          The object for which to make the determination.
   * @return <code>true</code> if the provided object is equal to
   *         this schema definition, or <code>false</code> if not.
   */
  public final boolean equals(Object o) {
    assert debugEnter(CLASS_NAME, "equals");
    if (this == o) {
      return true;
    }
    if (o instanceof CommonSchemaElements) {
      CommonSchemaElements other = (CommonSchemaElements) o;
      return oid.equals(other.oid);
    }
    return false;
  }
  /**
   * Retrieves the hash code for this schema definition. It will be
   * based on the sum of the bytes of the OID.
   *
   * @return The hash code for this schema definition.
   */
  public final int hashCode() {
    assert debugEnter(CLASS_NAME, "hashCode");
    return oid.hashCode();
  }
  /**
   * Retrieves the string representation of this schema definition in
   * the form specified in RFC 2252.
   *
   * @return The string representation of this schema definition in
   *         the form specified in RFC 2252.
   */
  public final String toString() {
    assert debugEnter(CLASS_NAME, "toString");
    StringBuilder buffer = new StringBuilder();
    toString(buffer, true);
    return buffer.toString();
  }
  /**
   * Appends a string representation of this schema definition in the
   * form specified in RFC 2252 to the provided buffer.
   *
   * @param buffer
   *          The buffer to which the information should be appended.
   * @param includeFileElement
   *          Indicates whether to include an "extra" property that
   *          specifies the path to the schema file from which this
   *          schema definition was loaded.
   */
  public final void toString(StringBuilder buffer,
      boolean includeFileElement) {
    assert debugEnter(CLASS_NAME, "toString",
        "java.lang.StringBuilder",
        String.valueOf(includeFileElement));
    buffer.append("( ");
    buffer.append(oid);
    if (!names.isEmpty()) {
      Iterator<String> iterator = names.values().iterator();
      String firstName = iterator.next();
      if (iterator.hasNext()) {
        buffer.append(" NAME ( '");
        buffer.append(firstName);
        while (iterator.hasNext()) {
          buffer.append("' '");
          buffer.append(iterator.next());
        }
        buffer.append("' )");
      } else {
        buffer.append(" NAME '");
        buffer.append(firstName);
        buffer.append("'");
      }
    }
    if ((description != null) && (description.length() > 0)) {
      buffer.append(" DESC '");
      buffer.append(description);
      buffer.append("'");
    }
    if (isObsolete) {
      buffer.append(" OBSOLETE");
    }
    // Delegate remaining string output to sub-class.
    toStringContent(buffer);
    if (!extraProperties.isEmpty()) {
      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);
        if (valueList.size() == 1) {
          buffer.append(" '");
          buffer.append(valueList.get(0));
          buffer.append("'");
        } else {
          buffer.append(" ( ");
          for (String value : valueList) {
            buffer.append("'");
            buffer.append(value);
            buffer.append("' ");
          }
          buffer.append(")");
        }
      }
    }
    buffer.append(" )");
  }
  /**
   * Appends a string representation of this schema definition's
   * non-generic properties to the provided buffer.
   *
   * @param buffer
   *          The buffer to which the information should be appended.
   */
  protected abstract void toStringContent(StringBuilder buffer);
}
opends/src/server/org/opends/server/types/ObjectClass.java
@@ -28,16 +28,18 @@
import static org.opends.server.loggers.Debug.debugConstructor;
import static org.opends.server.loggers.Debug.debugEnter;
import static org.opends.server.util.ServerConstants.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import static org.opends.server.loggers.Debug.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -45,393 +47,168 @@
 * This class defines a data structure for storing and interacting
 * with an objectclass, which contains a collection of attributes that
 * must and/or may be present in an entry with that objectclass.
 * <p>
 * Any methods which accesses the set of names associated with this
 * object class, will retrieve the primary name as the first name,
 * regardless of whether or not it was contained in the original set
 * of <code>names</code> passed to the constructor.
 * <p>
 * Where ordered sets of names, attribute types, or extra properties
 * are provided, the ordering will be preserved when the associated
 * fields are accessed via their getters or via the
 * {@link #toString()} methods.
 */
public class ObjectClass
{
public final class ObjectClass extends CommonSchemaElements {
  /**
   * The fully-qualified name of this class for debugging purposes.
   */
  private static final String CLASS_NAME =
       "org.opends.server.types.ObjectClass";
  // Indicates whether this objectclass is declared "obsolete".
  private boolean isObsolete;
  // The set of additional name-value pairs associated with this
  // objectclass definition.
  private ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
               extraProperties;
  // The mapping between the lowercase names and the user-provided
  // names for this objectclass.
  private ConcurrentHashMap<String,String> names;
  // The set of optional attribute types for this objectclass.
  private CopyOnWriteArraySet<AttributeType> optionalAttributes;
  private final Set<AttributeType> optionalAttributes;
  // The set of optional attribute types for this objectclass and its
  // superclasses.
  private final Set<AttributeType> optionalAttributesChain;
  // The set of required attribute types for this objectclass.
  private CopyOnWriteArraySet<AttributeType> requiredAttributes;
  private final Set<AttributeType> requiredAttributes;
  // The set of required attribute types for this objectclass and its
  // superclasses.
  private final Set<AttributeType> requiredAttributesChain;
  // The reference to the superior objectclass.
  private ObjectClass superiorClass;
  private final ObjectClass superiorClass;
  // The objectclass type for this objectclass.
  private ObjectClassType objectClassType;
  private final ObjectClassType objectClassType;
  // The description for this objectclass.
  private String description;
  // The OID for this objectclass.
  private String oid;
  // The primary name for this objectclass.
  private String primaryName;
  // The path to the schema file that contains this objectclass
  // definition.
  private String schemaFile;
  // Indicates whether or not this object class is allowed to
  // contain any attribute.
  private final boolean isExtensibleObject;
  /**
   * Creates a new objectclass definition with the provided
   * information.
   * <p>
   * If no <code>primaryName</code> is specified, but a set of
   * <code>names</code> is specified, then the first name retrieved
   * from the set of <code>names</code> will be used as the primary
   * name.
   *
   * @param  primaryName         The primary name for this
   *                             objectclass.
   * @param  names               The set of names that may be used to
   *                             reference this objectclass.
   * @param  oid                 The OID for this objectclass.
   * @param  description         The description for this objectclass.
   * @param  superiorClass       The superior class for this
   *                             objectclass.
   * @param  requiredAttributes  The set of required attribute types
   *                             for this objectclass.
   * @param  optionalAttributes  The set of optional attribute types
   *                             for this objectclass.
   * @param  objectClassType     The objectclass type for this
   *                             objectclass.
   * @param  isObsolete          Indicates whether this objectclass is
   *                             declared "obsolete".
   * @param  extraProperties     A set of extra properties for this
   *                             objectclass.
   * @param primaryName
   *          The primary name for this objectclass, or
   *          <code>null</code> if there is no primary name.
   * @param names
   *          The set of names that may be used to reference this
   *          objectclass, or <code>null</code> if there are no
   *          name.
   * @param oid
   *          The OID for this objectclass (must not be
   *          <code>null</code>).
   * @param description
   *          The description for this objectclass, or
   *          <code>null</code> if there is no description.
   * @param superiorClass
   *          The superior class for this objectclass, or
   *          <code>null</code> if there is no superior object
   *          classes.
   * @param requiredAttributes
   *          The set of required attribute types for this
   *          objectclass, or <code>null</code> if there are no
   *          required attribute types.
   * @param optionalAttributes
   *          The set of optional attribute types for this
   *          objectclass, or <code>null</code> if there are no
   *          optional attribute types.
   * @param objectClassType
   *          The objectclass type for this objectclass, or
   *          <code>null</code> to default to structural.
   * @param isObsolete
   *          Indicates whether this objectclass is declared
   *          "obsolete".
   * @param extraProperties
   *          A set of extra properties for this objectclass, or
   *          <code>null</code> if there are no extra properties.
   * @throws NullPointerException
   *           If the <code>oid</code> is <code>null</code>.
   */
  public ObjectClass(String primaryName,
             ConcurrentHashMap<String,String> names, String oid,
             String description, ObjectClass superiorClass,
             CopyOnWriteArraySet<AttributeType> requiredAttributes,
             CopyOnWriteArraySet<AttributeType> optionalAttributes,
  public ObjectClass(String primaryName, Collection<String> names,
      String oid, String description, ObjectClass superiorClass,
      Set<AttributeType> requiredAttributes,
      Set<AttributeType> optionalAttributes,
             ObjectClassType objectClassType, boolean isObsolete,
             ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
                  extraProperties)
  {
    assert debugConstructor(CLASS_NAME,
                            new String[]
                            {
                              String.valueOf(primaryName),
                              String.valueOf(names),
                              String.valueOf(oid),
                              String.valueOf(description),
                              String.valueOf(superiorClass),
                              String.valueOf(requiredAttributes),
                              String.valueOf(optionalAttributes),
                              String.valueOf(objectClassType),
                              String.valueOf(isObsolete),
                              String.valueOf(extraProperties)
                            });
      Map<String, List<String>> extraProperties)
      throws NullPointerException {
    this.primaryName        = primaryName;
    this.names              = names;
    this.oid                = oid;
    this.description        = description;
    super(primaryName, names, oid, description, isObsolete,
        extraProperties);
    assert debugConstructor(CLASS_NAME, String.valueOf(primaryName),
        String.valueOf(names), String.valueOf(oid), String
            .valueOf(description), String.valueOf(superiorClass),
        String.valueOf(requiredAttributes), String
            .valueOf(optionalAttributes), String
            .valueOf(objectClassType), String.valueOf(isObsolete),
        String.valueOf(extraProperties));
    this.superiorClass      = superiorClass;
    this.requiredAttributes = requiredAttributes;
    this.optionalAttributes = optionalAttributes;
    // Set flag indicating whether or not this object class allows any
    // attributes.
    if (hasName(OC_EXTENSIBLE_OBJECT_LC)
        || oid.equals(OID_EXTENSIBLE_OBJECT)) {
      this.isExtensibleObject = true;
    } else {
      this.isExtensibleObject = false;
    }
    // Construct unmodifiable views of the required attributes.
    if (requiredAttributes != null) {
      this.requiredAttributes = Collections
          .unmodifiableSet(new LinkedHashSet<AttributeType>(
              requiredAttributes));
    } else {
      this.requiredAttributes = Collections.emptySet();
    }
    if (this.superiorClass == null) {
      this.requiredAttributesChain = this.requiredAttributes;
    } else {
      Set<AttributeType> tmp = new HashSet<AttributeType>(
          this.requiredAttributes);
      tmp.addAll(this.superiorClass.getRequiredAttributeChain());
      this.requiredAttributesChain = Collections.unmodifiableSet(tmp);
    }
    // Construct unmodifiable views of the optional attributes.
    if (optionalAttributes != null) {
      this.optionalAttributes = Collections
          .unmodifiableSet(new LinkedHashSet<AttributeType>(
              optionalAttributes));
    } else {
      this.optionalAttributes = Collections.emptySet();
    }
    if (this.superiorClass == null) {
      this.optionalAttributesChain = this.optionalAttributes;
    } else {
      Set<AttributeType> tmp = new HashSet<AttributeType>(
          this.optionalAttributes);
      tmp.addAll(this.superiorClass.getOptionalAttributeChain());
      this.optionalAttributesChain = Collections.unmodifiableSet(tmp);
    }
    // Object class type defaults to structural.
    if (objectClassType != null) {
    this.objectClassType    = objectClassType;
    this.isObsolete         = isObsolete;
    this.schemaFile         = null;
    this.extraProperties    = extraProperties;
    } else {
      this.objectClassType = ObjectClassType.STRUCTURAL;
  }
  /**
   * Retrieves the primary name for this objectclass.
   *
   * @return  The primary name for this objectClass, or
   *          <CODE>null</CODE> if there is none.
   */
  public String getPrimaryName()
  {
    assert debugEnter(CLASS_NAME, "getPrimaryName");
    return primaryName;
  }
  /**
   * Specifies the primary name for this objectclass.
   *
   * @param  primaryName  The primary name for this objectclass.
   */
  public void setPrimaryName(String primaryName)
  {
    assert debugEnter(CLASS_NAME, "setPrimaryName",
                      String.valueOf(primaryName));
    this.primaryName = primaryName;
    String lowerName = toLowerCase(primaryName);
    names.put(lowerName, primaryName);
  }
  /**
   * Retrieves the set of names that may be used to reference this
   * objectclass.   The returned object will be a mapping between each
   * name in all lowercase characters and that name in a user-defined
   * form (which may include mixed capitalization).
   *
   * @return  The set of names that may be used to reference this
   *          objectclass.
   */
  public ConcurrentHashMap<String,String> getNames()
  {
    assert debugEnter(CLASS_NAME, "getNames");
    return names;
  }
  /**
   * Specifies the set of names that may be used to reference this
   * objectclass.  The provided set must provide a mapping between
   * each name in all lowercase characters and that name in a
   * user-defined form (which may include mixed capitalization).
   *
   * @param  names  The set of names that may be used to reference
   *                this objectclass.
   */
  public void setNames(ConcurrentHashMap<String,String> names)
  {
    assert debugEnter(CLASS_NAME, "setNames", String.valueOf(names));
    this.names = names;
  }
  /**
   * Indicates whether the provided lowercase name may be used to
   * reference this objectclass.
   *
   * @param  lowerName  The name for which to make the determination,
   *                    in all lowercase characters.
   *
   * @return  <CODE>true</CODE> if the provided lowercase name may be
   *          used to reference this objectclass, or
   *          <CODE>false</CODE> if not.
   */
  public boolean hasName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "hasName",
                      String.valueOf(lowerName));
    return names.containsKey(lowerName);
  }
  /**
   * Adds the provided name to the set of names that may be used to
   * reference this objectclass.
   *
   * @param  name  The name to add to the set of names that may be
   *               used to reference this objectclass.
   */
  public void addName(String name)
  {
    assert debugEnter(CLASS_NAME, "addName", String.valueOf(name));
    String lowerName = toLowerCase(name);
    names.put(lowerName, name);
  }
  /**
   * Removes the provided lowercase name from the set of names that
   * may be used to reference this objectclass.
   *
   * @param  lowerName  The name to remove from the set of names that
   *                    may be used to reference this objectclass, in
   *                    all lowercase characters.
   */
  public void removeName(String lowerName)
  {
    assert debugEnter(CLASS_NAME, "removeName",
                      String.valueOf(lowerName));
    names.remove(lowerName);
    if (lowerName.equalsIgnoreCase(primaryName))
    {
      if (names.isEmpty())
      {
        primaryName = null;
      }
      else
      {
        primaryName = names.values().iterator().next();
      }
    }
  }
  /**
   * Retrieves the OID for this objectclass.
   *
   * @return  The OID for this objectclass.
   */
  public String getOID()
  {
    assert debugEnter(CLASS_NAME, "getOID");
    return oid;
  }
  /**
   * Specifies the OID for this objectclass.
   *
   * @param  oid  The OID for this objectclass.
   */
  public void setOID(String oid)
  {
    assert debugEnter(CLASS_NAME, "setOID", String.valueOf(oid));
    this.oid = oid;
  }
  /**
   * Retrieves the name or OID that should be used to reference this
   * objectclass.  If a primary name is defined, then that will be
   * returned.  Otherwise, the OID will be returned.
   *
   * @return  The primary name if one is defined for this objectclass,
   *          or the OID if there is no primary name.
   */
  public String getNameOrOID()
  {
    assert debugEnter(CLASS_NAME, "getNameOrOID");
    if (primaryName == null)
    {
      return oid;
    }
    else
    {
      return primaryName;
    }
  }
  /**
   * Indicates whether the provided lowercase value is equal to the
   * OID or any of the names that may be used to reference this
   * objectclass.
   *
   * @param  lowerValue  The value, in all lowercase characters, that
   *                     may be used to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided lowercase value is one
   *          of the names or the OID of this objectclass, or
   *          <CODE>false</CODE> if it is not.
   */
  public boolean hasNameOrOID(String lowerValue)
  {
    assert debugEnter(CLASS_NAME, "hasNameOrOID",
                      String.valueOf(lowerValue));
    if (names.containsKey(lowerValue))
    {
      return true;
    }
    return lowerValue.equals(oid);
  }
  /**
   * Retrieves the path to the schema file that contains the
   * definition for this objectclass.
   *
   * @return  The path to the schema file that contains the definition
   *          for this objectclass, or <CODE>null</CODE> if it is not
   *          known or if it is not stored in any schema file.
   */
  public String getSchemaFile()
  {
    assert debugEnter(CLASS_NAME, "getSchemaFile");
    return schemaFile;
  }
  /**
   * Specifies the path to the schema file that contains the
   * definition for this objectclass.
   *
   * @param  schemaFile  The path to the schema file that contains the
   *                     definition for this objectclass.
   */
  public void setSchemaFile(String schemaFile)
  {
    assert debugEnter(CLASS_NAME, "setSchemaFile",
                      String.valueOf(schemaFile));
    this.schemaFile = schemaFile;
  }
  /**
   * Retrieves the description for this objectclass.
   *
   * @return  The description for this objectclass, or
   *          <CODE>null</CODE> if there is none.
   */
  public String getDescription()
  {
    assert debugEnter(CLASS_NAME, "getDescription");
    return description;
  }
  /**
   * Specifies the description for this objectclass.
   *
   * @param  description  The description for this objectclass.
   */
  public void setDescription(String description)
  {
    assert debugEnter(CLASS_NAME, "setDescription",
                      String.valueOf(description));
    this.description = description;
  }
@@ -440,11 +217,10 @@
   * Retrieves the reference to the superior class for this
   * objectclass.
   *
   * @return  The reference to the superior class for this
   *          objectlass, or <CODE>null</CODE> if there is none.
   * @return The reference to the superior class for this objectlass,
   *         or <code>null</code> if there is none.
   */
  public ObjectClass getSuperiorClass()
  {
  public ObjectClass getSuperiorClass() {
    assert debugEnter(CLASS_NAME, "getSuperiorClass");
    return superiorClass;
@@ -453,55 +229,37 @@
  /**
   * Specifies the superior class for this objectclass.
   *
   * @param  superiorClass  The superior class for this objectclass.
   */
  public void setSuperiorClass(ObjectClass superiorClass)
  {
    assert debugEnter(CLASS_NAME, "setSuperiorClass",
                      String.valueOf(superiorClass));
    this.superiorClass = superiorClass;
  }
  /**
   * Indicates whether this objectclass is a descendant of the
   * provided class.
   *
   * @param  objectClass  The objectClass for which to make the
   *                      determination.
   *
   * @return  <CODE>true</CODE> if this objectclass is a descendant of
   *          the provided class, or <CODE>false</CODE> if not.
   * @param objectClass
   *          The objectClass for which to make the determination.
   * @return <code>true</code> if this objectclass is a descendant
   *         of the provided class, or <code>false</code> if not.
   */
  public boolean isDescendantOf(ObjectClass objectClass)
  {
    assert debugEnter(CLASS_NAME, "isDescendantOf",
                      String.valueOf(objectClass));
  public boolean isDescendantOf(ObjectClass objectClass) {
    assert debugEnter(CLASS_NAME, "isDescendantOf", String
        .valueOf(objectClass));
    if (superiorClass == null)
    {
    if (superiorClass == null) {
      return false;
    }
    return (superiorClass.equals(objectClass) ||
            superiorClass.isDescendantOf(objectClass));
    return (superiorClass.equals(objectClass) || superiorClass
        .isDescendantOf(objectClass));
  }
  /**
   * Retrieves the set of required attributes for this objectclass.
   * Note that this list will not automatically include any required
   * attributes for superior objectclasses.
   * Retrieves an unmodifiable view of the set of required attributes
   * for this objectclass. Note that this set will not automatically
   * include any required attributes for superior objectclasses.
   *
   * @return  The set of required attributes for this objectclass.
   * @return Returns an unmodifiable view of the set of required
   *         attributes for this objectclass.
   */
  public CopyOnWriteArraySet<AttributeType> getRequiredAttributes()
  {
  public Set<AttributeType> getRequiredAttributes() {
    assert debugEnter(CLASS_NAME, "getRequiredAttributes");
    return requiredAttributes;
@@ -510,27 +268,18 @@
  /**
   * Retrieves the set of all required attributes for this objectclass
   * and any superior objectclasses that it might have.
   * Retrieves an unmodifiable view of the set of all required
   * attributes for this objectclass and any superior objectclasses
   * that it might have.
   *
   * @return  The set of all required attributes for this objectclass
   *          and any superior objectclasses that it might have.
   * @return Returns an unmodifiable view of the set of all required
   *         attributes for this objectclass and any superior
   *         objectclasses that it might have.
   */
  public Set<AttributeType> getRequiredAttributeChain()
  {
  public Set<AttributeType> getRequiredAttributeChain() {
    assert debugEnter(CLASS_NAME, "getRequiredAttributeChain");
    if (superiorClass == null)
    {
      return requiredAttributes;
    }
    else
    {
      HashSet<AttributeType> attrs = new HashSet<AttributeType>();
      attrs.addAll(requiredAttributes);
      attrs.addAll(superiorClass.getRequiredAttributeChain());
      return attrs;
    }
    return requiredAttributesChain;
  }
@@ -540,94 +289,30 @@
   * required attribute list for this or any of its superior
   * objectclasses.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   * @param attributeType
   *          The attribute type for which to make the determination.
   * @return <code>true</code> if the provided attribute type is
   *          required by this objectclass or any of its superior
   *          classes, or <CODE>false</CODE> if not.
   *         classes, or <code>false</code> if not.
   */
  public boolean isRequired(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "isRequired",
                      String.valueOf(attributeType));
  public boolean isRequired(AttributeType attributeType) {
    assert debugEnter(CLASS_NAME, "isRequired", String
        .valueOf(attributeType));
    if (requiredAttributes.contains(attributeType))
    {
      return true;
    }
    if (superiorClass != null)
    {
      return superiorClass.isRequired(attributeType);
    }
    return false;
    return requiredAttributesChain.contains(attributeType);
  }
  /**
   * Specifies the set of required attributes for this objectclass.
   * Retrieves an unmodifiable view of the set of optional attributes
   * for this objectclass. Note that this list will not automatically
   * include any optional attributes for superior objectclasses.
   *
   * @param  requiredAttributes  The set of required attributes for
   *                             this objectclass.
   */
  public void setRequiredAttributes(CopyOnWriteArraySet<AttributeType>
                                         requiredAttributes)
  {
    assert debugEnter(CLASS_NAME, "setRequiredAttributes",
                      String.valueOf(requiredAttributes));
    this.requiredAttributes = requiredAttributes;
  }
  /**
   * Adds the provided attribute to the set of required attributes for
   * this objectclass.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        required attributes for this objectclass.
   */
  public void addRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of required
   * @return Returns an unmodifiable view of the set of optional
   * attributes for this objectclass.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of required attributes for this
   *                        objectclass.
   */
  public void removeRequiredAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeRequiredAttribute",
                      String.valueOf(attributeType));
    requiredAttributes.remove(attributeType);
  }
  /**
   * Retrieves the set of optional attributes for this objectclass.
   * Note that this list will not automatically include any optional
   * attributes for superior objectclasses.
   *
   * @return  The set of optional attributes for this objectclass.
   */
  public CopyOnWriteArraySet<AttributeType> getOptionalAttributes()
  {
  public Set<AttributeType> getOptionalAttributes() {
    assert debugEnter(CLASS_NAME, "getOptionalAttributes");
    return optionalAttributes;
@@ -636,27 +321,18 @@
  /**
   * Retrieves the set of all optional attributes for this objectclass
   * and any superior objectclasses that it might have.
   * Retrieves an unmodifiable view of the set of optional attributes
   * for this objectclass and any superior objectclasses that it might
   * have.
   *
   * @return  The set of all optional attributes for this objectclass
   *          and any superior objectclasses that it might have.
   * @return Returns an unmodifiable view of the set of optional
   *         attributes for this objectclass and any superior
   *         objectclasses that it might have.
   */
  public Set<AttributeType> getOptionalAttributeChain()
  {
  public Set<AttributeType> getOptionalAttributeChain() {
    assert debugEnter(CLASS_NAME, "getOptionalAttributeChain");
    if (superiorClass == null)
    {
      return optionalAttributes;
    }
    else
    {
      HashSet<AttributeType> attrs = new HashSet<AttributeType>();
      attrs.addAll(optionalAttributes);
      attrs.addAll(superiorClass.getOptionalAttributeChain());
      return attrs;
    }
    return optionalAttributesChain;
  }
@@ -666,131 +342,49 @@
   * optional attribute list for this or any of its superior
   * objectclasses.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   * @param attributeType
   *          The attribute type for which to make the determination.
   * @return <code>true</code> if the provided attribute type is
   *          optional for this objectclass or any of its superior
   *          classes, or <CODE>false</CODE> if not.
   *         classes, or <code>false</code> if not.
   */
  public boolean isOptional(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "isOptional",
                      String.valueOf(attributeType));
  public boolean isOptional(AttributeType attributeType) {
    assert debugEnter(CLASS_NAME, "isOptional", String
        .valueOf(attributeType));
    if (optionalAttributes.contains(attributeType))
    {
    if (optionalAttributesChain.contains(attributeType)) {
      return true;
    }
    if (isExtensibleObject() &&
        (! requiredAttributes.contains(attributeType)))
    {
    if (isExtensibleObject
        && !requiredAttributesChain.contains(attributeType)) {
      // FIXME -- Do we need to do other checks here, like whether the
      //          attribute type is actually defined in the schema?
      //          What about DIT content rules?
      return true;
    }
    if (superiorClass != null)
    {
      return superiorClass.isOptional(attributeType);
    }
    return false;
  }
  /**
   * Specifies the set of optional attributes for this objectclass.
   *
   * @param  optionalAttributes  The set of optional attributes for
   *                             this objectclass.
   */
  public void setOptionalAttributes(CopyOnWriteArraySet<AttributeType>
                                         optionalAttributes)
  {
    assert debugEnter(CLASS_NAME, "setOptionalAttributes",
                      String.valueOf(optionalAttributes));
    this.optionalAttributes = optionalAttributes;
  }
  /**
   * Adds the provided attribute to the set of optional attributes for
   * this objectclass.
   *
   * @param  attributeType  The attribute type to add to the set of
   *                        optional attributes for this objectclass.
   */
  public void addOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "addOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.add(attributeType);
  }
  /**
   * Removes the provided attribute from the set of optional
   * attributes for this objectclass.
   *
   * @param  attributeType  The attribute type to remove from the set
   *                        of optional attributes for this
   *                        objectclass.
   */
  public void removeOptionalAttribute(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "removeOptionalAttribute",
                      String.valueOf(attributeType));
    optionalAttributes.remove(attributeType);
  }
  /**
   * Indicates whether the provided attribute type is in the list of
   * required or optional attributes for this objectclass or any of
   * its superior classes.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @return  <CODE>true</CODE> if the provided attribute type is
   * @param attributeType
   *          The attribute type for which to make the determination.
   * @return <code>true</code> if the provided attribute type is
   *          required or allowed for this objectclass or any of its
   *          superior classes, or <CODE>false</CODE> if it is not.
   *         superior classes, or <code>false</code> if it is not.
   */
  public boolean isRequiredOrOptional(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "isRequiredOrOptional",
                      String.valueOf(attributeType));
  public boolean isRequiredOrOptional(AttributeType attributeType) {
    assert debugEnter(CLASS_NAME, "isRequiredOrOptional", String
        .valueOf(attributeType));
    if (requiredAttributes.contains(attributeType) ||
        optionalAttributes.contains(attributeType))
    {
      return true;
    }
    if (isExtensibleObject())
    {
      // FIXME -- Do we need to do other checks here, like whether the
      //          attribute type is actually defined in the schema?
      //          What about DIT content rules?
      return true;
    }
    if (superiorClass != null)
    {
      return superiorClass.isRequiredOrOptional(attributeType);
    }
    return false;
    return (isRequired(attributeType) || isOptional(attributeType));
  }
@@ -800,8 +394,7 @@
   *
   * @return  The objectclass type for this objectclass.
   */
  public ObjectClassType getObjectClassType()
  {
  public ObjectClassType getObjectClassType() {
    assert debugEnter(CLASS_NAME, "getObjectClassType");
    return objectClassType;
@@ -810,345 +403,78 @@
  /**
   * Specifies the objectclass type for this objectclass.
   *
   * @param  objectClassType  The objectclass type for this
   *                          objectclass.
   */
  public void setObjectClassType(ObjectClassType objectClassType)
  {
    assert debugEnter(CLASS_NAME, "setObjectClassType",
                      String.valueOf(objectClassType));
  }
  /**
   * Indicates whether this objectclass is declared "obsolete".
   *
   * @return  <CODE>true</CODE> if this objectclass is declared
   *          "obsolete", or <CODE>false</CODE> if it is not.
   */
  public boolean isObsolete()
  {
    assert debugEnter(CLASS_NAME, "isObsolete");
    return isObsolete;
  }
  /**
   * Specifies whether this objectclass is declared "obsolete".
   *
   * @param  isObsolete  Specifies whether this objectclass is
   *                     declared "obsolete".
   */
  public void setObsolete(boolean isObsolete)
  {
    assert debugEnter(CLASS_NAME, "setObsolete",
                      String.valueOf(isObsolete));
    this.isObsolete = isObsolete;
  }
  /**
   * Indicates whether this objectclass is the extensibleObject
   * objectclass.
   *
   * @return  <CODE>true</CODE> if this objectclass is the
   *          extensibleObject objectclass, or <CODE>false</CODE> if
   * @return <code>true</code> if this objectclass is the
   *         extensibleObject objectclass, or <code>false</code> if
   *          it is not.
   */
  public boolean isExtensibleObject()
  {
  public boolean isExtensibleObject() {
    assert debugEnter(CLASS_NAME, "isExtensibleObject");
    return (names.containsKey(OC_EXTENSIBLE_OBJECT_LC) ||
            oid.equals(OID_EXTENSIBLE_OBJECT));
    return isExtensibleObject;
  }
  /**
   * Retrieves a mapping between the names of any extra non-standard
   * properties that may be associated with this objectclass and the
   * value for that property.  The caller may alter the contents of
   * this mapping.
   *
   * @return  A mapping between the names of any extra non-standard
   *          properties that may be associated with this objectclass
   *          and the value for that property.
   * {@inheritDoc}
   */
  public ConcurrentHashMap<String,CopyOnWriteArrayList<String>>
              getExtraProperties()
  {
    assert debugEnter(CLASS_NAME, "getExtraProperties");
    return extraProperties;
  }
  /**
   * Retrieves the value of the specified "extra" property for this
   * objectclass.
   *
   * @param  propertyName  The name of the "extra" property for which
   *                       to retrieve the value.
   *
   * @return  The value of the specified "extra" property for this
   *          objectclass, or <CODE>null</CODE> if no such property is
   *          defined.
   */
  public CopyOnWriteArrayList<String>
              getExtraProperty(String propertyName)
  {
    assert debugEnter(CLASS_NAME, "getExtraProperty",
                      String.valueOf(propertyName));
    return extraProperties.get(propertyName);
  }
  /**
   * Indicates whether the provided object is equal to this
   * objectclass.  The object will be considered equal if it is an
   * attribute type with the same OID as the current type.
   *
   * @param  o  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal to
   *          this objectclass, or <CODE>false</CODE> if not.
   */
  public boolean equals(Object o)
  {
    assert debugEnter(CLASS_NAME, "equals");
    if (this == o)
    {
      return true;
    }
    if ((o == null) || (! (o instanceof ObjectClass)))
    {
      return false;
    }
    return oid.equals(((ObjectClass) o).oid);
  }
  /**
   * Retrieves the hash code for this objectclass.  It will be based
   * on the sum of the bytes of the OID.
   *
   * @return  The hash code for this objectclass.
   */
  public int hashCode()
  {
    assert debugEnter(CLASS_NAME, "hashCode");
    int oidLength = oid.length();
    int hashCode  = 0;
    for (int i=0; i < oidLength; i++)
    {
      hashCode += oid.charAt(i);
    }
    return hashCode;
  }
  /**
   * Retrieves the string representation of this objectclass in the
   * form specified in RFC 2252.
   *
   * @return  The string representation of this objectclass in the
   *          form specified in RFC 2252.
   */
  public String toString()
  {
    assert debugEnter(CLASS_NAME, "toString");
    StringBuilder buffer = new StringBuilder();
    toString(buffer, true);
    return buffer.toString();
  }
  /**
   * Appends a string representation of this objectclass in the form
   * specified in RFC 2252 to the provided buffer.
   *
   * @param  buffer              The buffer to which the information
   *                             should be appended.
   * @param  includeFileElement  Indicates whether to include an
   *                             "extra" property that specifies the
   *                             path to the schema file from which
   *                             this objectclass was loaded.
   */
  public void toString(StringBuilder buffer,
                       boolean includeFileElement)
  {
  protected void toStringContent(StringBuilder buffer) {
    assert debugEnter(CLASS_NAME, "toString",
                      "java.lang.StringBuilder",
                      String.valueOf(includeFileElement));
        "java.lang.StringBuilder");
    buffer.append("( ");
    buffer.append(oid);
    if (! names.isEmpty())
    {
      Iterator<String> iterator = names.values().iterator();
      String firstName = iterator.next();
      if (iterator.hasNext())
      {
        buffer.append(" NAME ( '");
        buffer.append(firstName);
        while (iterator.hasNext())
        {
          buffer.append("' '");
          buffer.append(iterator.next());
        }
        buffer.append("' )");
      }
      else
      {
        buffer.append(" NAME '");
        buffer.append(firstName);
        buffer.append("'");
      }
    }
    if ((description != null) && (description.length() > 0))
    {
      buffer.append(" DESC '");
      buffer.append(description);
      buffer.append("'");
    }
    if (isObsolete)
    {
      buffer.append(" OBSOLETE");
    }
    if (superiorClass != null)
    {
    if (superiorClass != null) {
      buffer.append(" SUP ");
      buffer.append(superiorClass.getNameOrOID());
    }
    if (objectClassType != null)
    {
    if (objectClassType != null) {
      buffer.append(" ");
      buffer.append(objectClassType.toString());
    }
    if (! requiredAttributes.isEmpty())
    {
      Iterator<AttributeType> iterator =
           requiredAttributes.iterator();
    if (!requiredAttributes.isEmpty()) {
      Iterator<AttributeType> iterator = requiredAttributes
          .iterator();
      String firstName = iterator.next().getNameOrOID();
      if (iterator.hasNext())
      {
      if (iterator.hasNext()) {
        buffer.append(" MUST ( ");
        buffer.append(firstName);
        while (iterator.hasNext())
        {
        while (iterator.hasNext()) {
          buffer.append(" $ ");
          buffer.append(iterator.next().getNameOrOID());
        }
        buffer.append(" )");
      }
      else
      {
      } else {
        buffer.append(" MUST ");
        buffer.append(firstName);
      }
    }
    if (! optionalAttributes.isEmpty())
    {
      Iterator<AttributeType> iterator =
           optionalAttributes.iterator();
    if (!optionalAttributes.isEmpty()) {
      Iterator<AttributeType> iterator = optionalAttributes
          .iterator();
      String firstName = iterator.next().getNameOrOID();
      if (iterator.hasNext())
      {
      if (iterator.hasNext()) {
        buffer.append(" MAY ( ");
        buffer.append(firstName);
        while (iterator.hasNext())
        {
        while (iterator.hasNext()) {
          buffer.append(" $ ");
          buffer.append(iterator.next().getNameOrOID());
        }
        buffer.append(" )");
      }
      else
      {
      } else {
        buffer.append(" MAY ");
        buffer.append(firstName);
      }
    }
    if (! extraProperties.isEmpty())
    {
      for (String property : extraProperties.keySet())
      {
        CopyOnWriteArrayList<String> valueList =
             extraProperties.get(property);
        buffer.append(" ");
        buffer.append(property);
        if (valueList.size() == 1)
        {
          buffer.append(" '");
          buffer.append(valueList.get(0));
          buffer.append("'");
        }
        else
        {
          buffer.append(" ( ");
          for (String value : valueList)
          {
            buffer.append("'");
            buffer.append(value);
            buffer.append("' ");
          }
          buffer.append(")");
        }
      }
    }
    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(" )");
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeType.java
@@ -26,14 +26,12 @@
 */
package org.opends.server.types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Collection;
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;
@@ -43,31 +41,21 @@
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 {
public final class TestAttributeType extends TestCommonSchemaElements {
  /**
   * 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;
  private static final class AttributeTypeBuilder extends
      SchemaDefinitionBuilder<AttributeType> {
    // The superior attribute type from which this attribute type
    // inherits.
    private AttributeType superiorType;
@@ -97,23 +85,16 @@
    // "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;
    /**
     * {@inheritDoc}
     */
    protected void resetBuilder() {
      this.superiorType = null;
      this.syntax = null;
      this.approximateMatchingRule = null;
@@ -123,18 +104,20 @@
      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();
      super();
    }
    /**
     * Create a new attribute type builder.
     * 
@@ -144,35 +127,27 @@
     *          The attribute type OID.
     */
    public AttributeTypeBuilder(String primaryName, String oid) {
      reset();
      this.primaryName = primaryName;
      this.oid = oid;
      super(primaryName, oid);
    }
    /**
     * Construct an attribute type based on the properties of the
     * builder.
     *
     * @return The new attribute type.
     * {@inheritDoc}
     */
    public AttributeType getAttributeType() {
      if (oid == null) {
        throw new IllegalStateException("Null OID.");
    @Override
    protected AttributeType buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties) {
      return new AttributeType(primaryName, names, oid, description,
          superiorType, syntax, approximateMatchingRule,
          equalityMatchingRule, orderingMatchingRule,
          substringMatchingRule, attributeUsage, isCollective,
          isNoUserModification, isObsolete, isSingleValue,
          extraProperties);
      }
      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.
@@ -185,6 +160,8 @@
      this.approximateMatchingRule = approximateMatchingRule;
    }
    /**
     * Set the attributeUsage.
     * 
@@ -195,15 +172,7 @@
      this.attributeUsage = attributeUsage;
    }
    /**
     * Set the description.
     *
     * @param description
     *          The description.
     */
    public void setDescription(String description) {
      this.description = description;
    }
    /**
     * Set the equalityMatchingRule.
@@ -216,34 +185,7 @@
      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.
@@ -255,6 +197,8 @@
      this.isCollective = isCollective;
    }
    /**
     * Set the isNoUserModification.
     * 
@@ -265,15 +209,7 @@
      this.isNoUserModification = isNoUserModification;
    }
    /**
     * Set the isObsolete.
     *
     * @param isObsolete
     *          The isObsolete.
     */
    public void setObsolete(boolean isObsolete) {
      this.isObsolete = isObsolete;
    }
    /**
     * Set the isSingleValue.
@@ -285,19 +221,7 @@
      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.
@@ -310,15 +234,7 @@
      this.orderingMatchingRule = orderingMatchingRule;
    }
    /**
     * Set the primaryName.
     *
     * @param primaryName
     *          The primaryName.
     */
    public void setPrimaryName(String primaryName) {
      this.primaryName = primaryName;
    }
    /**
     * Set the substringMatchingRule.
@@ -331,6 +247,8 @@
      this.substringMatchingRule = substringMatchingRule;
    }
    /**
     * Set the superiorType.
     * 
@@ -341,6 +259,8 @@
      this.superiorType = superiorType;
    }
    /**
     * Set the syntax.
     * 
@@ -350,39 +270,9 @@
    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
@@ -397,6 +287,8 @@
        false, false, false, false);
  }
  /**
   * Check that the complex constructor throws an NPE when mandatory
   * parameters are not specified.
@@ -410,6 +302,8 @@
        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.
@@ -426,40 +320,7 @@
    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.
@@ -471,12 +332,14 @@
  public void testConstructorDefaultUsage() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.getUsage(),
        AttributeUsage.USER_APPLICATIONS);
  }
  /**
   * Check constructor sets the default syntax correctly.
   * 
@@ -487,12 +350,14 @@
  public void testConstructorDefaultSyntax() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.getSyntax(), DirectoryServer
        .getDefaultAttributeSyntax());
  }
  /**
   * Check constructor sets the syntax correctly.
   * 
@@ -504,12 +369,14 @@
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    builder.setSyntax(DirectoryServer.getDefaultIntegerSyntax());
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.getSyntax(), DirectoryServer
        .getDefaultIntegerSyntax());
  }
  /**
   * Check constructor inherits the syntax from the parent type when
   * required.
@@ -522,16 +389,18 @@
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "parentType", "1.2.3");
    builder.setSyntax(DirectoryServer.getDefaultIntegerSyntax());
    AttributeType parent = builder.getAttributeType();
    AttributeType parent = builder.getInstance();
    builder.setPrimaryName("childType");
    builder.setOid("4.5.6");
    builder.setSuperiorType(parent);
    AttributeType child = builder.getAttributeType();
    AttributeType child = builder.getInstance();
    Assert.assertEquals(parent.getSyntax(), child.getSyntax());
  }
  /**
   * Check constructor sets the default matching rules correctly.
   * 
@@ -542,7 +411,7 @@
  public void testConstructorDefaultMatchingRules() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    AttributeSyntax syntax = DirectoryServer
        .getDefaultAttributeSyntax();
@@ -556,6 +425,8 @@
        .getSubstringMatchingRule());
  }
  /**
   * Check constructor sets the matching rules correctly.
   * 
@@ -573,7 +444,7 @@
    builder.setOrderingMatchingRule(syntax.getOrderingMatchingRule());
    builder.setSubstringMatchingRule(syntax
        .getSubstringMatchingRule());
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.getApproximateMatchingRule(), syntax
        .getApproximateMatchingRule());
@@ -585,6 +456,8 @@
        .getSubstringMatchingRule());
  }
  /**
   * Check constructor inherits the matching rules from the parent
   * type when required.
@@ -604,12 +477,12 @@
    builder.setSubstringMatchingRule(syntax
        .getSubstringMatchingRule());
    AttributeType parent = builder.getAttributeType();
    AttributeType parent = builder.getInstance();
    builder.setPrimaryName("childType");
    builder.setOid("4.5.6");
    builder.setSuperiorType(parent);
    AttributeType child = builder.getAttributeType();
    AttributeType child = builder.getInstance();
    Assert.assertEquals(parent.getApproximateMatchingRule(), child
        .getApproximateMatchingRule());
@@ -621,6 +494,8 @@
        .getSubstringMatchingRule());
  }
  /**
   * Create test data for testing the
   * {@link AttributeType#isObjectClassType()} method.
@@ -634,6 +509,8 @@
        { "OBJECTCLASS", true } };
  }
  /**
   * Check that the objectClass attribute type is correctly
   * identified.
@@ -650,86 +527,12 @@
      throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(name,
        "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    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
@@ -745,6 +548,8 @@
        { "one two", "onetwo", false }, { "one", "two", false } };
  }
  /**
   * Check that the
   * {@link AttributeType#generateHashCode(AttributeValue)} method
@@ -765,7 +570,7 @@
    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
        "1.2.3");
    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    AttributeValue av1 = new AttributeValue(type, value1);
    AttributeValue av2 = new AttributeValue(type, value2);
@@ -776,6 +581,8 @@
    Assert.assertEquals(h1 == h2, result);
  }
  /**
   * Check that the {@link AttributeType#normalize(ByteString)} method
   * works as expected.
@@ -795,7 +602,7 @@
    AttributeTypeBuilder builder = new AttributeTypeBuilder("test",
        "1.2.3");
    builder.setSyntax(DirectoryServer.getDefaultStringSyntax());
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    ByteString b1 = new ASN1OctetString(value1);
    ByteString b2 = new ASN1OctetString(value2);
@@ -806,321 +613,7 @@
    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.
@@ -1132,17 +625,19 @@
  public void testIsCollective() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertFalse(type.isCollective());
    builder = new AttributeTypeBuilder("testType", "1.2.3");
    builder.setCollective(true);
    type = builder.getAttributeType();
    type = builder.getInstance();
    Assert.assertTrue(type.isCollective());
  }
  /**
   * Check that the {@link AttributeType#isNoUserModification()}
   * method.
@@ -1154,37 +649,18 @@
  public void testIsNoUserModification() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertFalse(type.isNoUserModification());
    builder = new AttributeTypeBuilder("testType", "1.2.3");
    builder.setNoUserModification(true);
    type = builder.getAttributeType();
    type = builder.getInstance();
    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.
@@ -1196,17 +672,19 @@
  public void testIsSingleValue() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertFalse(type.isSingleValue());
    builder = new AttributeTypeBuilder("testType", "1.2.3");
    builder.setSingleValue(true);
    type = builder.getAttributeType();
    type = builder.getInstance();
    Assert.assertTrue(type.isSingleValue());
  }
  /**
   * Create test data for testing the
   * {@link AttributeType#isOperational()} method.
@@ -1222,6 +700,8 @@
        { AttributeUsage.DSA_OPERATION, true } };
  }
  /**
   * Check that the {@link AttributeType#isOperational()} method.
   * 
@@ -1238,10 +718,12 @@
    AttributeTypeBuilder builder = new AttributeTypeBuilder(
        "testType", "1.2.3");
    builder.setAttributeUsage(usage);
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.isOperational(), result);
  }
  /**
   * Check that the {@link AttributeType#toString()} method.
   * 
@@ -1252,7 +734,7 @@
  public void testToStringDefault() throws Exception {
    AttributeTypeBuilder builder = new AttributeTypeBuilder(null,
        "1.2.3");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.toString(), "( 1.2.3 "
        + "EQUALITY caseIgnoreMatch "
        + "ORDERING caseIgnoreOrderingMatch "
@@ -1261,6 +743,8 @@
        + "USAGE userApplications )");
  }
  /**
   * Check that the {@link AttributeType#toString()} method.
   * 
@@ -1278,11 +762,21 @@
    builder.addExtraProperty(
        ServerConstants.SCHEMA_PROPERTY_FILENAME, "/foo/bar");
    AttributeType type = builder.getAttributeType();
    AttributeType type = builder.getInstance();
    Assert.assertEquals(type.toString(), "( 1.2.3 "
        + "NAME ( 'anotherName' 'testType' ) "
        + "NAME ( 'testType' 'anotherName' ) "
        + "EQUALITY booleanMatch "
        + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " + "SINGLE-VALUE "
        + "USAGE directoryOperation " + "X-SCHEMA-FILE '/foo/bar' )");
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected SchemaDefinitionBuilder getBuilder(String name, String oid) {
    return new AttributeTypeBuilder(name, oid);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestCommonSchemaElements.java
New file
@@ -0,0 +1,789 @@
/*
 * 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.Collection;
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.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.CommonSchemaElements} class and
 * derived classes.
 */
public abstract class TestCommonSchemaElements extends TypesTestCase {
  /**
   * Internal class to simplify construction of attribute types.
   *
   * @param <T>
   *          The type of definition that this builder constructs.
   */
  protected static abstract class SchemaDefinitionBuilder<T extends CommonSchemaElements> {
    // The primary name to use for this attribute type.
    private String primaryName;
    // The set of names for this attribute type.
    private List<String> names;
    // The OID that may be used to reference this attribute type.
    private String oid;
    // The description for this attribute type.
    private String description;
    // Indicates whether this attribute type is declared "obsolete".
    private boolean isObsolete;
    // 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.names = null;
      this.oid = null;
      this.description = null;
      this.isObsolete = false;
      this.extraProperties = null;
      resetBuilder();
    }
    /**
     * Create a new attribute type builder.
     */
    protected SchemaDefinitionBuilder() {
      reset();
    }
    /**
     * Create a new attribute type builder.
     *
     * @param primaryName
     *          The attribute type primary name.
     * @param oid
     *          The attribute type OID.
     */
    protected SchemaDefinitionBuilder(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 final T getInstance() {
      if (oid == null) {
        throw new IllegalStateException("Null OID.");
      }
      T instance = buildInstance(primaryName, names, oid,
          description, isObsolete, extraProperties);
      // Reset the internal state.
      reset();
      return instance;
    }
    /**
     * Build a new instance using this builder.
     *
     * @param primaryName
     *          The primary name.
     * @param names
     *          The optional names.
     * @param oid
     *          The OID.
     * @param description
     *          The optional description.
     * @param isObsolete
     *          Whether or not the definition is obsolete.
     * @param extraProperties
     *          The extra properties.
     * @return Returns the newly constructed definition.
     */
    protected abstract T buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties);
    /**
     * Reset the internal state of the builder.
     */
    protected abstract void resetBuilder();
    /**
     * Set the description.
     *
     * @param description
     *          The description.
     */
    public final void setDescription(String description) {
      this.description = description;
    }
    /**
     * Add extra property value(s).
     *
     * @param name
     *          The name of the extra property.
     * @param values
     *          The value(s) of the extra property.
     */
    public final 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 isObsolete.
     *
     * @param isObsolete
     *          The isObsolete.
     */
    public final void setObsolete(boolean isObsolete) {
      this.isObsolete = isObsolete;
    }
    /**
     * Set the oid.
     *
     * @param oid
     *          The oid.
     */
    public final void setOid(String oid) {
      if (oid == null) {
        throw new NullPointerException("Null OID");
      }
      this.oid = oid;
    }
    /**
     * Set the primaryName.
     *
     * @param primaryName
     *          The primaryName.
     */
    public final void setPrimaryName(String primaryName) {
      this.primaryName = primaryName;
    }
    /**
     * Add attribute type name(s).
     *
     * @param names
     *          The attribute type name(s) to add.
     */
    public final void addTypeNames(String... names) {
      if (names == null) {
        throw new NullPointerException("Null names");
      }
      if (this.names == null) {
        this.names = new LinkedList<String>();
      }
      this.names.addAll(Arrays.asList(names));
    }
  }
  /**
   * Create a new schema definition builder.
   *
   * @param name
   *          The schema definition's primary name.
   * @param oid
   *          The OID of the schema definition.
   * @return The new builder.
   */
  protected abstract SchemaDefinitionBuilder getBuilder(String name,
      String oid);
  /**
   * Once-only initialization.
   *
   * @throws Exception
   *           If an unexpected error occurred.
   */
  @BeforeClass
  public final void setUp() throws Exception {
    // This test suite depends on having the schema available, so
    // we'll
    // start the server.
    TestCaseUtils.startServer();
  }
  /**
   * Check that the primary name is added to the set of names.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testConstructorPrimaryName() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertTrue(d.hasName("testtype"));
    Assert.assertFalse(d.hasName("xxx"));
  }
  /**
   * Check that the type names are accessible.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testConstructorTypeNames() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    builder.addTypeNames("testNameAlias", "anotherNameAlias");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertTrue(d.hasName("testtype"));
    Assert.assertTrue(d.hasName("testnamealias"));
    Assert.assertTrue(d.hasName("anothernamealias"));
  }
  /**
   * Create test data for testing the
   * {@link CommonSchemaElements#equals(Object)} method.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "equalsTestData")
  public final 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 final void testEquals(String name1, String oid1,
      String name2, String oid2, boolean result) throws Exception {
    SchemaDefinitionBuilder builder1 = getBuilder(name1, oid1);
    CommonSchemaElements d1 = builder1.getInstance();
    SchemaDefinitionBuilder builder2 = getBuilder(name2, oid2);
    CommonSchemaElements d2 = builder2.getInstance();
    Assert.assertEquals(d1.equals(d2), result);
    Assert.assertEquals(d2.equals(d1), 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 final void testHashCode(String name1, String oid1,
      String name2, String oid2, boolean result) throws Exception {
    SchemaDefinitionBuilder builder1 = getBuilder(name1, oid1);
    CommonSchemaElements d1 = builder1.getInstance();
    SchemaDefinitionBuilder builder2 = getBuilder(name2, oid2);
    CommonSchemaElements d2 = builder2.getInstance();
    Assert.assertEquals(d1.hashCode() == d2.hashCode(), result);
  }
  /**
   * Check that the {@link CommonSchemaElements#getDescription()}
   * method returns <code>null</code> when there is no description.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetDescriptionDefault() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("test", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNull(d.getDescription());
  }
  /**
   * Check that the {@link CommonSchemaElements#getDescription()}
   * method returns a description.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetDescription() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("test", "1.2.3");
    builder.setDescription("hello");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getDescription(), "hello");
  }
  /**
   * Check that the
   * {@link CommonSchemaElements#getExtraProperty(String)} method
   * returns <code>null</code> when there is no property.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetExtraPropertyDefault() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("test", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNull(d.getExtraProperty("test"));
  }
  /**
   * Check that the
   * {@link CommonSchemaElements#getExtraProperty(String)} method
   * returns values.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetExtraProperty() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("test", "1.2.3");
    String[] expectedValues = new String[] { "one", "two" };
    builder.addExtraProperty("test", expectedValues);
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNotNull(d.getExtraProperty("test"));
    int i = 0;
    for (String value : d.getExtraProperty("test")) {
      Assert.assertEquals(value, expectedValues[i]);
      i++;
    }
  }
  /**
   * Check that the
   * {@link CommonSchemaElements#getExtraPropertyNames()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetExtraPropertyNames() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("test", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert
        .assertFalse(d.getExtraPropertyNames().iterator().hasNext());
  }
  /**
   * Check that the {@link CommonSchemaElements#getNameOrOID()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNameOrOIDReturnsOID() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getNameOrOID(), "1.2.3");
  }
  /**
   * Check that the {@link CommonSchemaElements#getNameOrOID()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNameOrOIDReturnsPrimaryName()
      throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getNameOrOID(), "testType");
  }
  /**
   * Check that the {@link CommonSchemaElements#getNameOrOID()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNameOrOIDReturnsOtherName()
      throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    builder.addTypeNames("anotherName");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getNameOrOID(), "anotherName");
  }
  /**
   * Check that the {@link CommonSchemaElements#getNormalizedNames()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNormalizedNames() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    builder.addTypeNames("anotherName", "yetAnotherName");
    CommonSchemaElements d = builder.getInstance();
    boolean gotTestType = false;
    boolean gotAnotherName = false;
    boolean gotYetAnotherName = false;
    for (String name : d.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 CommonSchemaElements#getUserDefinedNames()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetUserDefinedNames() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    builder.addTypeNames("anotherName", "yetAnotherName");
    CommonSchemaElements d = builder.getInstance();
    boolean gotTestType = false;
    boolean gotAnotherName = false;
    boolean gotYetAnotherName = false;
    for (String name : d.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 CommonSchemaElements#getNormalizedPrimaryName()} method
   * returns <code>null</code> when there is no primary name.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNormalizedPrimaryNameDefault()
      throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNull(d.getNormalizedPrimaryName());
  }
  /**
   * Check that the
   * {@link CommonSchemaElements#getNormalizedPrimaryName()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetNormalizedPrimaryName() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getNormalizedPrimaryName(), "testtype");
  }
  /**
   * Check that the {@link CommonSchemaElements#getOID()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetOID() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getOID(), "1.2.3");
  }
  /**
   * Check that the {@link CommonSchemaElements#getPrimaryName()}
   * method returns <code>null</code> when there is no primary name.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetPrimaryNameDefault() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNull(d.getPrimaryName());
  }
  /**
   * Check that the {@link CommonSchemaElements#getPrimaryName()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetPrimaryName() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getPrimaryName(), "testType");
  }
  /**
   * Check that the {@link CommonSchemaElements#getSchemaFile()}
   * method returns <code>null</code> when there is no schema file.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetSchemaFileDefault() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertNull(d.getSchemaFile());
  }
  /**
   * Check that the {@link CommonSchemaElements#getSchemaFile()}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testGetSchemaFile() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder(null, "1.2.3");
    builder.addExtraProperty(
        ServerConstants.SCHEMA_PROPERTY_FILENAME, "/foo/bar");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertEquals(d.getSchemaFile(), "/foo/bar");
  }
  /**
   * Check that the {@link CommonSchemaElements#hasNameOrOID(String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testHasNameOrOID() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertTrue(d.hasNameOrOID("testtype"));
    Assert.assertTrue(d.hasNameOrOID("1.2.3"));
    Assert.assertFalse(d.hasNameOrOID("x.y.z"));
  }
  /**
   * Check that the {@link CommonSchemaElements#isObsolete()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public final void testIsObsolete() throws Exception {
    SchemaDefinitionBuilder builder = getBuilder("testType", "1.2.3");
    CommonSchemaElements d = builder.getInstance();
    Assert.assertFalse(d.isObsolete());
    builder = getBuilder("testType", "1.2.3");
    builder.setObsolete(true);
    d = builder.getInstance();
    Assert.assertTrue(d.isObsolete());
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestObjectClass.java
New file
@@ -0,0 +1,1237 @@
/*
 * 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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.opends.server.core.DirectoryServer;
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.ObjectClass} class.
 */
public final class TestObjectClass extends TestCommonSchemaElements {
  /**
   * Internal class to simplify construction of object classes.
   */
  private static final class ObjectClassBuilder extends
      SchemaDefinitionBuilder<ObjectClass> {
    // The superior object class from which this object class
    // inherits.
    private ObjectClass superior;
    // The type of object class.
    private ObjectClassType objectClassType;
    // The set of required attribute types.
    private Set<AttributeType> requiredAttributeTypes;
    // The set of optional attribute types.
    private Set<AttributeType> optionalAttributeTypes;
    /**
     * {@inheritDoc}
     */
    protected void resetBuilder() {
      this.superior = null;
      this.objectClassType = ObjectClassType.STRUCTURAL;
      this.requiredAttributeTypes = null;
      this.optionalAttributeTypes = null;
    }
    /**
     * Create a new object class builder.
     */
    public ObjectClassBuilder() {
      super();
    }
    /**
     * Create a new object class builder.
     *
     * @param primaryName
     *          The object class primary name.
     * @param oid
     *          The object class OID.
     */
    public ObjectClassBuilder(String primaryName, String oid) {
      super(primaryName, oid);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected ObjectClass buildInstance(String primaryName,
        Collection<String> names, String oid, String description,
        boolean isObsolete, Map<String, List<String>> extraProperties) {
      return new ObjectClass(primaryName, names, oid, description,
          superior, requiredAttributeTypes, optionalAttributeTypes,
          objectClassType, isObsolete, extraProperties);
    }
    /**
     * Set the objectClassType.
     *
     * @param objectClassType
     *          The objectClassType.
     */
    public void setObjectClassType(ObjectClassType objectClassType) {
      this.objectClassType = objectClassType;
    }
    /**
     * Set the superior.
     *
     * @param superior
     *          The superior.
     */
    public void setSuperior(ObjectClass superior) {
      this.superior = superior;
    }
    /**
     * Add required attribute types.
     *
     * @param types
     *          The required attribute type(s) to add.
     */
    public void addRequiredAttributeTypes(AttributeType... types) {
      if (types == null) {
        throw new NullPointerException("Null types");
      }
      if (this.requiredAttributeTypes == null) {
        this.requiredAttributeTypes = new LinkedHashSet<AttributeType>();
      }
      this.requiredAttributeTypes.addAll(Arrays.asList(types));
    }
    /**
     * Add optional attribute types.
     *
     * @param types
     *          The optional attribute type(s) to add.
     */
    public void addOptionalAttributeTypes(AttributeType... types) {
      if (types == null) {
        throw new NullPointerException("Null types");
      }
      if (this.optionalAttributeTypes == null) {
        this.optionalAttributeTypes = new LinkedHashSet<AttributeType>();
      }
      this.optionalAttributeTypes.addAll(Arrays.asList(types));
    }
  }
  // Array of attribute types to use in tests.
  private AttributeType[] types;
  /**
   * Once-only initialization.
   *
   * @throws Exception
   *           If an unexpected error occurred.
   */
  @BeforeClass(dependsOnMethods = "setUp")
  public final void setUpTypes() throws Exception {
    types = new AttributeType[10];
    for (int i = 0; i < types.length; i++) {
      String name = "testType" + i;
      types[i] = DirectoryServer.getDefaultAttributeType(name);
    }
  }
  /**
   * Check that the constructor throws an NPE when mandatory
   * parameters are not specified.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(expectedExceptions = NullPointerException.class)
  public void testConstructorNPE() throws Exception {
    Set<AttributeType> emptySet = Collections.emptySet();
    Map<String, List<String>> emptyMap = Collections.emptyMap();
    new ObjectClass("test", Collections.singleton("test"), null,
        "description", DirectoryServer.getTopObjectClass(), emptySet,
        emptySet, ObjectClassType.STRUCTURAL, false, emptyMap);
  }
  /**
   * Check that the constructor does not throw an exception when all
   * optional parameters are not specified.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testConstructorDefault() throws Exception {
    ObjectClass type = new ObjectClass(null, null, "1.2.3", null,
        null, null, null, null, false, null);
    Assert.assertNull(type.getPrimaryName());
  }
  /**
   * Create test data for testing the
   * {@link AttributeType#isOperational()} method.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "getObjectClassTypeTestData")
  public Object[][] createGetObjectClassTypeTestData() {
    return new Object[][] { { null, ObjectClassType.STRUCTURAL },
        { ObjectClassType.STRUCTURAL, ObjectClassType.STRUCTURAL },
        { ObjectClassType.ABSTRACT, ObjectClassType.ABSTRACT },
        { ObjectClassType.AUXILIARY, ObjectClassType.AUXILIARY } };
  }
  /**
   * Check that the {@link ObjectClass#getObjectClassType()} method.
   *
   * @param type
   *          The object class type.
   * @param result
   *          Expected result.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "getObjectClassTypeTestData")
  public void testGetObjectClassType(ObjectClassType type,
      ObjectClassType result) throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.setObjectClassType(type);
    ObjectClass c = builder.getInstance();
    Assert.assertEquals(c.getObjectClassType(), result);
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getOptionalAttributeChain().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainNoSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();
    Set<AttributeType> chain = c.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChainEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributeChain()} method
   * with a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributeChain() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getOptionalAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getOptionalAttributes().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();
    Set<AttributeType> chain = c.getOptionalAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributesEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.getOptionalAttributes().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getOptionalAttributes()} method with
   * a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetOptionalAttributes() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getOptionalAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getRequiredAttributeChain().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainNoSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();
    Set<AttributeType> chain = c.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChainEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributeChain()} method
   * with a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributeChain() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getRequiredAttributeChain();
    Assert.assertEquals(chain.size(), 6);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * no superior and no optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesNoSuperiorEmpty()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.getRequiredAttributes().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * no superior and some optional attributes.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass c = builder.getInstance();
    Set<AttributeType> chain = c.getRequiredAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[0]));
    Assert.assertTrue(chain.contains(types[1]));
    Assert.assertTrue(chain.contains(types[2]));
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * a superior but no optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributesEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.getRequiredAttributes().isEmpty());
  }
  /**
   * Check the {@link ObjectClass#getRequiredAttributes()} method with
   * a superior and some optional attributes of its own.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetRequiredAttributes() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[3], types[4], types[5]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Set<AttributeType> chain = child.getRequiredAttributes();
    Assert.assertEquals(chain.size(), 3);
    Assert.assertTrue(chain.contains(types[3]));
    Assert.assertTrue(chain.contains(types[4]));
    Assert.assertTrue(chain.contains(types[5]));
  }
  /**
   * Check the {@link ObjectClass#getSuperiorClass()} method with no
   * superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetSuperiorClassNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertNull(c.getSuperiorClass());
  }
  /**
   * Check the {@link ObjectClass#getSuperiorClass()} method with a
   * superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetSuperiorClassWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertEquals(child.getSuperiorClass(), parent);
  }
  /**
   * Check the {@link ObjectClass#isDescendantOf(ObjectClass)} method
   * with no superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsDescendantOfNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("testType1",
        "1.2.1");
    ObjectClass c1 = builder.getInstance();
    builder = new ObjectClassBuilder("testType2", "1.2.2");
    ObjectClass c2 = builder.getInstance();
    Assert.assertFalse(c1.isDescendantOf(c2));
  }
  /**
   * Check the {@link ObjectClass#isDescendantOf(ObjectClass)} method
   * with a superior.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsDescendantOfWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "grandParent", "1.2.1");
    ObjectClass grandParent = builder.getInstance();
    builder = new ObjectClassBuilder("parent", "1.2.2");
    builder.setSuperior(grandParent);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(parent.isDescendantOf(grandParent));
    Assert.assertTrue(child.isDescendantOf(parent));
    Assert.assertTrue(child.isDescendantOf(grandParent));
    Assert.assertFalse(child.isDescendantOf(child));
    Assert.assertFalse(parent.isDescendantOf(child));
    Assert.assertFalse(grandParent.isDescendantOf(child));
  }
  /**
   * Create test data for testing the
   * {@link ObjectClass#isExtensibleObject()} method.
   *
   * @return Returns the array of test data.
   */
  @DataProvider(name = "isExtensibleObjectTestData")
  public Object[][] createIsExtensibleObjectTestData() {
    return new Object[][] { { "test", "1.2.3", false },
        { "extensibleObject", "1.2.3", true },
        { "test", "1.3.6.1.4.1.1466.101.120.111", true },
        { "extensibleObject", "1.3.6.1.4.1.1466.101.120.111", true } };
  }
  /**
   * Check that the {@link ObjectClass#getObjectClassType()} method.
   *
   * @param name
   *          The object class name.
   * @param oid
   *          The object class oid.
   * @param result
   *          Expected result.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "isExtensibleObjectTestData")
  public void testIsExtensibleObject(String name, String oid,
      boolean result) throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(name, oid);
    ObjectClass c = builder.getInstance();
    Assert.assertEquals(c.isExtensibleObject(), result);
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isOptional(types[0]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isOptional(types[0]));
    Assert.assertFalse(c.isOptional(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalEmptyWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isOptional(types[0]));
    Assert.assertFalse(child.isOptional(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsOptionalWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[1]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isOptional(types[0]));
    Assert.assertTrue(child.isOptional(types[1]));
    Assert.assertFalse(child.isOptional(types[2]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensible() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isOptional(types[0]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensibleRequired() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isOptional(types[0]));
    Assert.assertTrue(c.isOptional(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isOptional(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsOptionalExtensibleRequiredSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("extensibleObject", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isOptional(types[0]));
    Assert.assertTrue(c.isOptional(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isRequired(types[0]));
  }
  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequired(types[0]));
    Assert.assertFalse(c.isRequired(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredEmptyWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isRequired(types[0]));
    Assert.assertFalse(child.isRequired(types[1]));
  }
  /**
   * Check that the {@link ObjectClass#isRequired(AttributeType)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addRequiredAttributeTypes(types[1]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isRequired(types[0]));
    Assert.assertTrue(child.isRequired(types[1]));
    Assert.assertFalse(child.isRequired(types[2]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalEmpty() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertFalse(c.isRequiredOrOptional(types[0]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalNoSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("test",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
    Assert.assertFalse(c.isRequiredOrOptional(types[2]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalEmptyWithSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isRequiredOrOptional(types[0]));
    Assert.assertTrue(child.isRequiredOrOptional(types[1]));
    Assert.assertFalse(child.isRequiredOrOptional(types[2]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testIsRequiredOrOptionalWithSuperior() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addOptionalAttributeTypes(types[0]);
    builder.addRequiredAttributeTypes(types[1]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("child", "1.2.3");
    builder.addOptionalAttributeTypes(types[2]);
    builder.addRequiredAttributeTypes(types[3]);
    builder.setSuperior(parent);
    ObjectClass child = builder.getInstance();
    Assert.assertTrue(child.isRequiredOrOptional(types[0]));
    Assert.assertTrue(child.isRequiredOrOptional(types[1]));
    Assert.assertTrue(child.isRequiredOrOptional(types[2]));
    Assert.assertTrue(child.isRequiredOrOptional(types[3]));
    Assert.assertFalse(child.isRequiredOrOptional(types[4]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensible() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensibleRequired()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "extensibleObject", "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
  }
  /**
   * Check that the
   * {@link ObjectClass#isRequiredOrOptional(AttributeType)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dependsOnMethods = "testIsExtensibleObject")
  public void testIsRequiredOrOptionalExtensibleRequiredSuperior()
      throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder("parent",
        "1.2.3");
    builder.addRequiredAttributeTypes(types[0]);
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("extensibleObject", "1.2.3");
    builder.setSuperior(parent);
    ObjectClass c = builder.getInstance();
    Assert.assertTrue(c.isRequiredOrOptional(types[0]));
    Assert.assertTrue(c.isRequiredOrOptional(types[1]));
  }
  /**
   * Check the {@link ObjectClass#toString()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testToStringDefault() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(null, "1.2.3");
    ObjectClass type = builder.getInstance();
    Assert.assertEquals(type.toString(), "( 1.2.3 STRUCTURAL )");
  }
  /**
   * Check the {@link ObjectClass#toString()} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testToString() throws Exception {
    ObjectClassBuilder builder = new ObjectClassBuilder(
        "parentClass", "1.2.1");
    ObjectClass parent = builder.getInstance();
    builder = new ObjectClassBuilder("childClass", "1.2.2");
    builder.addTypeNames("anotherName");
    builder.setDescription("A description");
    builder.setObjectClassType(ObjectClassType.ABSTRACT);
    builder.setObsolete(true);
    builder.setSuperior(parent);
    builder.addRequiredAttributeTypes(types[0], types[1], types[2]);
    builder.addOptionalAttributeTypes(types[3]);
    builder.addExtraProperty(
        ServerConstants.SCHEMA_PROPERTY_FILENAME, "/foo/bar");
    ObjectClass type = builder.getInstance();
    Assert.assertEquals(type.toString(), "( 1.2.2 "
        + "NAME ( 'childClass' 'anotherName' ) "
        + "DESC 'A description' " + "OBSOLETE " + "SUP parentClass "
        + "ABSTRACT " + "MUST ( testType0 $ testType1 $ testType2 ) "
        + "MAY testType3 " + "X-SCHEMA-FILE '/foo/bar' )");
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected SchemaDefinitionBuilder getBuilder(String name, String oid) {
    return new ObjectClassBuilder(name, oid);
  }
}