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

neil_a_wilson
26.04.2007 5f215775a6fcba6deaf66b03a48dd03dda308280
Update the server schema processing so that interactions with entries (e.g.,
getting attributes, comparing filters, etc.) work properly with attribute
subtypes. Additional work is required in the JE backend to fully support this
capability, particularly in the area of index management for modify and modify
DN operations.

OpenDS Issue Number: 739
5 files modified
1424 ■■■■■ changed files
opends/src/server/org/opends/server/types/AttributeType.java 49 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Entry.java 529 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Schema.java 129 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/ServerConstants.java 3 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java 714 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/AttributeType.java
@@ -101,6 +101,13 @@
  // Indicates whether this attribute type is declared "single-value".
  private final boolean isSingleValue;
  // Indicates whether there is a possibility that this attribute type
  // may have one or more subtypes that list this type or one of its
  // subtypes as a superior.  Note that this variable is intentional
  // not declared "final", but if it ever gets set to "true", then it
  // should never be unset back to "false".
  private boolean mayHaveSubordinateTypes;
  // The equality matching rule for this attribute type.
  private final EqualityMatchingRule equalityMatchingRule;
@@ -286,6 +293,8 @@
    this.isNoUserModification = isNoUserModification;
    this.isSingleValue = isSingleValue;
    mayHaveSubordinateTypes = false;
    if (syntax == null)
    {
      if (superiorType != null)
@@ -407,6 +416,7 @@
         AttributeTypeSyntax.decodeAttributeType(value, schema,
                                              false);
    at.setSchemaFile(getSchemaFile());
    at.mayHaveSubordinateTypes = mayHaveSubordinateTypes;
    return at;
  }
@@ -429,6 +439,45 @@
  /**
   * Indicates whether there is a possibility that this attribute type
   * may have one or more subordinate attribute types defined in the
   * server schema.  This is only intended for use by the
   * {@code org.opends.server.types.Entry} class for the purpose of
   * determining whether to check for subtypes when retrieving
   * attributes.  Note that it is possible for this method to report
   * false positives (if an attribute type that previously had one or
   * more subordinate types no longer has any), but not false
   * negatives.
   *
   * @return  {@code true} if the {@code hasSubordinateTypes} flag has
   *          been set for this attribute type at any time since
   *          startup, or {@code false} if not.
   */
  boolean mayHaveSubordinateTypes()
  {
    assert debugEnter(CLASS_NAME, "mayHaveSubordinateTypes");
    return mayHaveSubordinateTypes;
  }
  /**
   * Sets a flag indicating that this attribute type may have one or
   * more subordinate attribute types defined in the server schema.
   * This is only intended for use by the
   * {@code org.opends.server.types.Schema} class.
   */
  void setMayHaveSubordinateTypes()
  {
    assert debugEnter(CLASS_NAME, "setMayHaveSubordinateTypes");
    mayHaveSubordinateTypes = true;
  }
  /**
   * Retrieves the syntax for this attribute type.
   *
   * @return  The syntax for this attribute type.
opends/src/server/org/opends/server/types/Entry.java
@@ -107,6 +107,9 @@
  // with some other object.
  private transient Object attachment;
  // The schema used to govern this entry.
  private Schema schema;
  /**
@@ -139,6 +142,7 @@
    attachment = null;
    schema     = DirectoryServer.getSchema();
    if (dn == null)
@@ -635,6 +639,18 @@
      return true;
    }
    if (attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        if (userAttributes.containsKey(at) ||
            operationalAttributes.containsKey(at))
        {
          return true;
        }
      }
    }
    return (attributeType.isObjectClassType() &&
            (! objectClasses.isEmpty()));
  }
@@ -660,21 +676,55 @@
                      String.valueOf(attributeType),
                      String.valueOf(attributeOptions));
    List<Attribute> attributes = userAttributes.get(attributeType);
    if (attributes == null)
    List<Attribute> attributes;
    if (attributeType.mayHaveSubordinateTypes())
    {
      attributes = operationalAttributes.get(attributeType);
      attributes = new LinkedList<Attribute>();
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      attrs = operationalAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
    }
    else
    {
      attributes = userAttributes.get(attributeType);
      if (attributes == null)
      {
        if (attributeType.isObjectClassType() &&
            (! objectClasses.isEmpty()))
        attributes = operationalAttributes.get(attributeType);
        if (attributes == null)
        {
          return ((attributeOptions == null) ||
                  attributeOptions.isEmpty());
        }
        else
        {
          return false;
          if (attributeType.isObjectClassType() &&
              (! objectClasses.isEmpty()))
          {
            return ((attributeOptions == null) ||
                    attributeOptions.isEmpty());
          }
          else
          {
            return false;
          }
        }
      }
    }
@@ -684,7 +734,7 @@
    // attribute.
    for (Attribute a : attributes)
    {
      if (a.hasValue())
      if (a.hasValue() && a.hasOptions(attributeOptions))
      {
        return true;
      }
@@ -712,25 +762,41 @@
    assert debugEnter(CLASS_NAME, "getAttribute",
                      String.valueOf(attributeType));
    List<Attribute> attributes = userAttributes.get(attributeType);
    if (attributes == null)
    if (attributeType.mayHaveSubordinateTypes())
    {
      attributes = operationalAttributes.get(attributeType);
      if (attributes == null)
      List<Attribute> attributes = new LinkedList<Attribute>();
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs != null)
      {
        if (attributeType.isObjectClassType() &&
            (! objectClasses.isEmpty()))
        attributes.addAll(attrs);
      }
      attrs = operationalAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          attributes = new ArrayList<Attribute>(1);
          attributes.add(getObjectClassAttribute());
          return attributes;
          attributes.addAll(attrs);
        }
        else
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          return null;
          attributes.addAll(attrs);
        }
      }
      if (attributes.isEmpty())
      {
        return null;
      }
      else
      {
        return attributes;
@@ -738,7 +804,34 @@
    }
    else
    {
      return attributes;
      List<Attribute> attributes = userAttributes.get(attributeType);
      if (attributes == null)
      {
        attributes = operationalAttributes.get(attributeType);
        if (attributes == null)
        {
          if (attributeType.isObjectClassType() &&
              (! objectClasses.isEmpty()))
          {
            attributes = new ArrayList<Attribute>(1);
            attributes.add(getObjectClassAttribute());
            return attributes;
          }
          else
          {
            return null;
          }
        }
        else
        {
          return attributes;
        }
      }
      else
      {
        return attributes;
      }
    }
  }
@@ -772,7 +865,7 @@
    {
      if (attr.hasNameOrOID(lowerName))
      {
        return userAttributes.get(attr);
        return getAttribute(attr);
      }
    }
@@ -780,10 +873,18 @@
    {
      if (attr.hasNameOrOID(lowerName))
      {
        return operationalAttributes.get(attr);
        return getAttribute(attr);
      }
    }
    if (lowerName.equals(OBJECTCLASS_ATTRIBUTE_TYPE_NAME) &&
        (! objectClasses.isEmpty()))
    {
      LinkedList<Attribute> attrList = new LinkedList<Attribute>();
      attrList.add(getObjectClassAttribute());
      return attrList;
    }
    return null;
  }
@@ -811,44 +912,85 @@
                      String.valueOf(attributeType),
                       String.valueOf(options));
    List<Attribute> attributes = userAttributes.get(attributeType);
    if (attributes == null)
    List<Attribute> attributes = new LinkedList<Attribute>();
    if (attributeType.mayHaveSubordinateTypes())
    {
      attributes = operationalAttributes.get(attributeType);
      if (attributes == null)
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs != null)
      {
        if (attributeType.isObjectClassType() &&
            (! objectClasses.isEmpty()) &&
            ((options == null) || (options.isEmpty())))
        attributes.addAll(attrs);
      }
      attrs = operationalAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          attributes = new ArrayList<Attribute>(1);
          attributes.add(getObjectClassAttribute());
          return attributes;
          attributes.addAll(attrs);
        }
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
    }
    else
    {
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs == null)
      {
        attrs = operationalAttributes.get(attributeType);
        if (attrs == null)
        {
          if (attributeType.isObjectClassType() &&
              (! objectClasses.isEmpty()) &&
              ((options == null) || options.isEmpty()))
          {
            attributes.add(getObjectClassAttribute());
            return attributes;
          }
          else
          {
            return null;
          }
        }
        else
        {
          return null;
          attributes.addAll(attrs);
        }
      }
    }
    ArrayList<Attribute> returnAttrs =
         new ArrayList<Attribute>(attributes.size());
    for (Attribute a : attributes)
    {
      if (a.hasOptions(options))
      else
      {
        returnAttrs.add(a);
        attributes.addAll(attrs);
      }
    }
    if (returnAttrs.isEmpty())
    Iterator<Attribute> iterator = attributes.iterator();
    while (iterator.hasNext())
    {
      Attribute a = iterator.next();
      if (! a.hasOptions(options))
      {
        iterator.remove();
      }
    }
    if (attributes.isEmpty())
    {
      return null;
    }
    else
    {
      return returnAttrs;
      return attributes;
    }
  }
@@ -883,52 +1025,32 @@
                      String.valueOf(lowerName),
                      String.valueOf(options));
    List<Attribute> attrList = null;
    for (AttributeType attr : userAttributes.keySet())
    {
      if (attr.hasNameOrOID(lowerName))
      {
        attrList = userAttributes.get(attr);
        break;
        return getAttribute(attr, options);
      }
    }
    if (attrList == null)
    for (AttributeType attr : operationalAttributes.keySet())
    {
      for (AttributeType attr : operationalAttributes.keySet())
      if (attr.hasNameOrOID(lowerName))
      {
        if (attr.hasNameOrOID(lowerName))
        {
          attrList = operationalAttributes.get(attr);
          break;
        }
      }
      if (attrList == null)
      {
        return null;
        return getAttribute(attr, options);
      }
    }
    ArrayList<Attribute> returnAttrs =
         new ArrayList<Attribute>(attrList.size());
    for (Attribute a : attrList)
    if (lowerName.equals(OBJECTCLASS_ATTRIBUTE_TYPE_NAME) &&
        ((options == null) || options.isEmpty()))
    {
      if (a.hasOptions(options))
      {
        returnAttrs.add(a);
      }
    }
    if (returnAttrs.isEmpty())
    {
      return null;
      LinkedList<Attribute> attributes = new LinkedList<Attribute>();
      attributes.add(getObjectClassAttribute());
      return attributes;
    }
    else
    {
      return returnAttrs;
      return null;
    }
  }
@@ -1043,7 +1165,23 @@
    assert debugEnter(CLASS_NAME, "hasUserAttribute",
                      String.valueOf(attributeType));
    return userAttributes.containsKey(attributeType);
    if (userAttributes.containsKey(attributeType))
    {
      return true;
    }
    if (attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        if (userAttributes.containsKey(at))
        {
          return true;
        }
      }
    }
    return false;
  }
@@ -1065,7 +1203,38 @@
    assert debugEnter(CLASS_NAME, "getUserAttribute",
                      String.valueOf(attributeType));
    return userAttributes.get(attributeType);
    if (attributeType.mayHaveSubordinateTypes())
    {
      LinkedList<Attribute> attributes = new LinkedList<Attribute>();
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
      if (attributes.isEmpty())
      {
        return null;
      }
      else
      {
        return attributes;
      }
    }
    else
    {
      return userAttributes.get(attributeType);
    }
  }
@@ -1091,29 +1260,42 @@
                      String.valueOf(attributeType),
                      String.valueOf(options));
    List<Attribute> attributes = userAttributes.get(attributeType);
    if (attributes == null)
    LinkedList<Attribute> attributes = new LinkedList<Attribute>();
    List<Attribute> attrs = userAttributes.get(attributeType);
    if (attrs != null)
    {
      return null;
      attributes.addAll(attrs);
    }
    ArrayList<Attribute> returnAttrs =
         new ArrayList<Attribute>(attributes.size());
    for (Attribute a : attributes)
    if (attributeType.mayHaveSubordinateTypes())
    {
      if (a.hasOptions(options))
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        returnAttrs.add(a);
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
    }
    if (returnAttrs.isEmpty())
    Iterator<Attribute> iterator = attributes.iterator();
    while (iterator.hasNext())
    {
      Attribute a = iterator.next();
      if (! a.hasOptions(options))
      {
        iterator.remove();
      }
    }
    if (attributes.isEmpty())
    {
      return null;
    }
    else
    {
      return returnAttrs;
      return attributes;
    }
  }
@@ -1135,20 +1317,40 @@
    assert debugEnter(CLASS_NAME, "duplicateUserAttribute",
                      String.valueOf(attributeType));
    List<Attribute> currentList = userAttributes.get(attributeType);
    if (currentList == null)
    LinkedList<Attribute> attributes = new LinkedList<Attribute>();
    List<Attribute> attrs = userAttributes.get(attributeType);
    if (attrs != null)
    {
      for (Attribute a : attrs)
      {
        attributes.add(a.duplicate());
      }
    }
    if (attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = userAttributes.get(at);
        if (attrs != null)
        {
          for (Attribute a : attrs)
          {
            attributes.add(a.duplicate());
          }
        }
      }
    }
    if (attributes.isEmpty())
    {
      return null;
    }
    ArrayList<Attribute> duplicateList =
         new ArrayList<Attribute>(currentList.size());
    for (Attribute a : currentList)
    else
    {
      duplicateList.add(a.duplicate());
      return attributes;
    }
    return duplicateList;
  }
@@ -1230,7 +1432,7 @@
                      String.valueOf(options),
                      String.valueOf(omitValues));
    List<Attribute> currentList = userAttributes.get(attributeType);
    List<Attribute> currentList = getUserAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues);
  }
@@ -1264,7 +1466,7 @@
                      String.valueOf(omitValues));
    List<Attribute> currentList =
         operationalAttributes.get(attributeType);
         getOperationalAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues);
  }
@@ -1284,7 +1486,23 @@
    assert debugEnter(CLASS_NAME, "hasOperationalAttribute",
                      String.valueOf(attributeType));
    return operationalAttributes.containsKey(attributeType);
    if (operationalAttributes.containsKey(attributeType))
    {
      return true;
    }
    if (attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        if (operationalAttributes.containsKey(at))
        {
          return true;
        }
      }
    }
    return false;
  }
@@ -1307,7 +1525,39 @@
    assert debugEnter(CLASS_NAME, "getOperationalAttribute",
                      String.valueOf(attributeType));
    return operationalAttributes.get(attributeType);
    if (attributeType.mayHaveSubordinateTypes())
    {
      LinkedList<Attribute> attributes = new LinkedList<Attribute>();
      List<Attribute> attrs =
           operationalAttributes.get(attributeType);
      if (attrs != null)
      {
        attributes.addAll(attrs);
      }
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
      if (attributes.isEmpty())
      {
        return null;
      }
      else
      {
        return attributes;
      }
    }
    else
    {
      return operationalAttributes.get(attributeType);
    }
  }
@@ -1334,30 +1584,42 @@
                      String.valueOf(attributeType),
                      String.valueOf(options));
    List<Attribute> attributes =
         operationalAttributes.get(attributeType);
    if (attributes == null)
    LinkedList<Attribute> attributes = new LinkedList<Attribute>();
    List<Attribute> attrs = operationalAttributes.get(attributeType);
    if (attrs != null)
    {
      return null;
      attributes.addAll(attrs);
    }
    ArrayList<Attribute> returnAttrs =
         new ArrayList<Attribute>(attributes.size());
    for (Attribute a : attributes)
    if (attributeType.mayHaveSubordinateTypes())
    {
      if (a.hasOptions(options))
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        returnAttrs.add(a);
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          attributes.addAll(attrs);
        }
      }
    }
    if (returnAttrs.isEmpty())
    Iterator<Attribute> iterator = attributes.iterator();
    while (iterator.hasNext())
    {
      Attribute a = iterator.next();
      if (! a.hasOptions(options))
      {
        iterator.remove();
      }
    }
    if (attributes.isEmpty())
    {
      return null;
    }
    else
    {
      return returnAttrs;
      return attributes;
    }
  }
@@ -1380,21 +1642,40 @@
    assert debugEnter(CLASS_NAME, "duplicateOperationalAttribute",
                      String.valueOf(attributeType));
    List<Attribute> currentList =
         operationalAttributes.get(attributeType);
    if (currentList == null)
    LinkedList<Attribute> attributes = new LinkedList<Attribute>();
    List<Attribute> attrs = operationalAttributes.get(attributeType);
    if (attrs != null)
    {
      for (Attribute a : attrs)
      {
        attributes.add(a.duplicate());
      }
    }
    if (attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
        attrs = operationalAttributes.get(at);
        if (attrs != null)
        {
          for (Attribute a : attrs)
          {
            attributes.add(a.duplicate());
          }
        }
      }
    }
    if (attributes.isEmpty())
    {
      return null;
    }
    ArrayList<Attribute> duplicateList =
         new ArrayList<Attribute>(currentList.size());
    for (Attribute a : currentList)
    else
    {
      duplicateList.add(a.duplicate());
      return attributes;
    }
    return duplicateList;
  }
opends/src/server/org/opends/server/types/Schema.java
@@ -28,7 +28,10 @@
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.opends.server.api.ApproximateMatchingRule;
@@ -72,6 +75,11 @@
  // The set of subordinate attribute types registered within the
  // server schema.
  private ConcurrentHashMap<AttributeType,List<AttributeType>>
               subordinateTypes;
  // The set of attribute type definitions for this schema, mapped
  // between the lowercase names and OID for the definition and the
  // attribute type itself.
@@ -212,6 +220,8 @@
         new ConcurrentHashMap<NameForm,DITStructureRule>();
    nameFormsByOC = new ConcurrentHashMap<ObjectClass,NameForm>();
    nameFormsByName = new ConcurrentHashMap<String,NameForm>();
    subordinateTypes =
         new ConcurrentHashMap<AttributeType,List<AttributeType>>();
    syntaxSet           = new LinkedHashSet<AttributeValue>();
@@ -371,6 +381,12 @@
        attributeTypes.put(name, attributeType);
      }
      AttributeType superiorType = attributeType.getSuperiorType();
      if (superiorType != null)
      {
        registerSubordinateType(attributeType, superiorType);
      }
      // We'll use an attribute value including the normalized value
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
@@ -408,6 +424,12 @@
        attributeTypes.remove(name, attributeType);
      }
      AttributeType superiorType = attributeType.getSuperiorType();
      if (superiorType != null)
      {
        deregisterSubordinateType(attributeType, superiorType);
      }
      // We'll use an attribute value including the normalized value
      // rather than the attribute type because otherwise it would use
      // a very expensive matching rule (OID first component match)
@@ -424,6 +446,112 @@
  /**
   * Registers the provided attribute type as a subtype of the given
   * superior attribute type, recursively following any additional
   * elements in the superior chain.
   *
   * @param  attributeType  The attribute type to be registered as a
   *                        subtype for the given superior type.
   * @param  superiorType   The superior type for which to register
   *                        the given attribute type as a subtype.
   */
  private final void registerSubordinateType(
                          AttributeType attributeType,
                          AttributeType superiorType)
  {
    assert debugEnter(CLASS_NAME, "registerSubordinateType",
                      String.valueOf(attributeType),
                      String.valueOf(superiorType));
    List<AttributeType> subTypes = subordinateTypes.get(superiorType);
    if (subTypes == null)
    {
      superiorType.setMayHaveSubordinateTypes();
      subTypes = new LinkedList<AttributeType>();
      subTypes.add(attributeType);
      subordinateTypes.put(superiorType, subTypes);
    }
    else if (! subTypes.contains(attributeType))
    {
      superiorType.setMayHaveSubordinateTypes();
      subTypes.add(attributeType);
      AttributeType higherSuperior = superiorType.getSuperiorType();
      if (higherSuperior != null)
      {
        registerSubordinateType(attributeType, higherSuperior);
      }
    }
  }
  /**
   * Deregisters the provided attribute type as a subtype of the given
   * superior attribute type, recursively following any additional
   * elements in the superior chain.
   *
   * @param  attributeType  The attribute type to be deregistered as a
   *                        subtype for the given superior type.
   * @param  superiorType   The superior type for which to deregister
   *                        the given attribute type as a subtype.
   */
  private final void deregisterSubordinateType(
                          AttributeType attributeType,
                          AttributeType superiorType)
  {
    assert debugEnter(CLASS_NAME, "deregisterSubordinateType",
                      String.valueOf(attributeType),
                      String.valueOf(superiorType));
    List<AttributeType> subTypes = subordinateTypes.get(superiorType);
    if (subTypes != null)
    {
      if (subTypes.remove(attributeType))
      {
        AttributeType higherSuperior = superiorType.getSuperiorType();
        if (higherSuperior != null)
        {
          deregisterSubordinateType(attributeType, higherSuperior);
        }
      }
    }
  }
  /**
   * Retrieves the set of subtypes registered for the given attribute
   * type.
   *
   * @param  attributeType  The attribute type for which to retrieve
   *                        the set of registered subtypes.
   *
   * @return  The set of subtypes registered for the given attribute
   *          type, or an empty set if there are no subtypes
   *          registered for the attribute type.
   */
  public final Iterable<AttributeType>
                    getSubTypes(AttributeType attributeType)
  {
    assert debugEnter(CLASS_NAME, "getSubordinateTypes",
                      String.valueOf(attributeType));
    List<AttributeType> subTypes =
         subordinateTypes.get(attributeType);
    if (subTypes == null)
    {
      return Collections.<AttributeType>emptyList();
    }
    else
    {
      return subTypes;
    }
  }
  /**
   * Retrieves the objectclass definitions for this schema, as a
   * mapping between the lowercase names and OIDs for the objectclass
   * and the objectclass itself.  Each objectclass may be associated
@@ -2876,6 +3004,7 @@
    Schema dupSchema = new Schema();
    dupSchema.attributeTypes.putAll(attributeTypes);
    dupSchema.subordinateTypes.putAll(subordinateTypes);
    dupSchema.objectClasses.putAll(objectClasses);
    dupSchema.syntaxes.putAll(syntaxes);
    dupSchema.matchingRules.putAll(matchingRules);
opends/src/server/org/opends/server/util/ServerConstants.java
@@ -1469,7 +1469,8 @@
  /**
   * The name of the attribute type that represents the "objectclass" attribute.
   * The name of the attribute type that represents the "objectclass" attribute,
   * formatted in all lowercase characters.
   */
  public static final String OBJECTCLASS_ATTRIBUTE_TYPE_NAME = "objectclass";
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -26,12 +26,13 @@
 */
package org.opends.server.types;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.SubtreeSpecificationSet;
@@ -298,4 +299,715 @@
    assertEquals(expected, result);
  }
  /**
   * Tests the {@code hasAttribute} method variants to ensure that they work
   * properly for both attributes included directly, as well as attributes
   * included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    assertTrue(e.hasAttribute(ocType));
    assertTrue(e.hasAttribute(cnType));
    assertTrue(e.hasAttribute(nameType));
    assertFalse(e.hasAttribute(uidType));
    assertTrue(e.hasAttribute(mnType));
    LinkedHashSet<String> options = null;
    assertTrue(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertTrue(e.hasAttribute(mnType, options));
    options = new LinkedHashSet<String>();
    assertTrue(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertTrue(e.hasAttribute(mnType, options));
    options.add("lang-en-US");
    assertFalse(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
    options.add("lang-en-GB");
    assertFalse(e.hasAttribute(ocType, options));
    assertFalse(e.hasAttribute(cnType, options));
    assertFalse(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
    options.clear();
    options.add("lang-en-GB");
    assertFalse(e.hasAttribute(ocType, options));
    assertFalse(e.hasAttribute(cnType, options));
    assertFalse(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
  }
  /**
   * Tests the {@code hasUserAttribute} method variants to ensure that they work
   * properly for both attributes included directly, as well as attributes
   * included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasUserAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    assertFalse(e.hasUserAttribute(ocType));
    assertTrue(e.hasUserAttribute(cnType));
    assertTrue(e.hasUserAttribute(nameType));
    assertFalse(e.hasUserAttribute(uidType));
    assertFalse(e.hasUserAttribute(mnType));
  }
  /**
   * Tests the {@code hasOperationalAttribute} method variants to ensure that
   * they work properly for both attributes included directly, as well as
   * attributes included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasOperationalAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    assertFalse(e.hasOperationalAttribute(ocType));
    assertFalse(e.hasOperationalAttribute(cnType));
    assertFalse(e.hasOperationalAttribute(nameType));
    assertFalse(e.hasOperationalAttribute(uidType));
    assertTrue(e.hasOperationalAttribute(mnType));
  }
  /**
   * Tests the {@code getAttribute} method variants to ensure that they work
   * properly for both attributes included directly, as well as attributes
   * included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    List<Attribute> attrs = e.getAttribute(ocType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute(cnType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute(nameType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(uidType);
    assertNull(attrs);
    attrs = e.getAttribute(mnType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("objectclass");
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("cn");
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute("uid");
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname");
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    LinkedHashSet<String> options = null;
    attrs = e.getAttribute(ocType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getAttribute(mnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("objectclass", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("cn", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute("uid", options);
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    options = new LinkedHashSet<String>();
    attrs = e.getAttribute(ocType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getAttribute(mnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("objectclass", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("cn", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getAttribute("uid", options);
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    options.add("lang-en-US");
    attrs = e.getAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 3);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getAttribute(mnType, options);
    assertNull(attrs);
    attrs = e.getAttribute("objectclass", options);
    assertNull(attrs);
    attrs = e.getAttribute("cn", options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getAttribute("uid", options);
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname", options);
    assertNull(attrs);
    options.add("lang-en-GB");
    attrs = e.getAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getAttribute(mnType, options);
    assertNull(attrs);
    attrs = e.getAttribute("objectclass", options);
    assertNull(attrs);
    attrs = e.getAttribute("cn", options);
    assertNull(attrs);
    attrs = e.getAttribute("uid", options);
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname", options);
    assertNull(attrs);
    options.clear();
    options.add("lang-en-GB");
    attrs = e.getAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getAttribute(mnType, options);
    assertNull(attrs);
    attrs = e.getAttribute("objectclass", options);
    assertNull(attrs);
    attrs = e.getAttribute("cn", options);
    assertNull(attrs);
    attrs = e.getAttribute("uid", options);
    assertNull(attrs);
    attrs = e.getAttribute("modifiersname", options);
    assertNull(attrs);
  }
  /**
   * Tests the {@code getUserAttribute} method variants to ensure that they work
   * properly for both attributes included directly, as well as attributes
   * included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetUserAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    List<Attribute> attrs = e.getUserAttribute(ocType);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getUserAttribute(nameType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getUserAttribute(uidType);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType);
    assertNull(attrs);
    LinkedHashSet<String> options = null;
    attrs = e.getUserAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getUserAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getUserAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType, options);
    assertNull(attrs);
    options = new LinkedHashSet<String>();
    attrs = e.getUserAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 2);
    attrs = e.getUserAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getUserAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType, options);
    assertNull(attrs);
    options.add("lang-en-US");
    attrs = e.getUserAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    attrs = e.getUserAttribute(nameType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 3);
    attrs = e.getUserAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType, options);
    assertNull(attrs);
    options.add("lang-en-GB");
    attrs = e.getUserAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType, options);
    assertNull(attrs);
    options.clear();
    options.add("lang-en-GB");
    attrs = e.getUserAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getUserAttribute(mnType, options);
    assertNull(attrs);
  }
  /**
   * Tests the {@code getOperationalAttribute} method variants to ensure that
   * they work properly for both attributes included directly, as well as
   * attributes included as subtypes.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetOperationalAttribute()
         throws Exception
  {
    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,ou=People,dc=example,dc=com",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "cn: Test User",
         "cn;lang-en-US: Test User",
         "givenName: Test",
         "givenName;lang-en-US: Test",
         "sn: User",
         "sn;lang-en-US: User",
         "creatorsName: cn=Directory Manager",
         "createTimestamp: 20070101000000Z",
         "modifiersName: cn=Directory Manager",
         "modifyTimestamp: 20070101000001Z");
    assertTrue(e.conformsToSchema(null, false, false, false,
                                  new StringBuilder()));
    AttributeType ocType   = DirectoryServer.getAttributeType("objectclass");
    AttributeType cnType   = DirectoryServer.getAttributeType("cn");
    AttributeType nameType = DirectoryServer.getAttributeType("name");
    AttributeType uidType  = DirectoryServer.getAttributeType("uid");
    AttributeType mnType   = DirectoryServer.getAttributeType("modifiersname");
    List<Attribute> attrs = e.getOperationalAttribute(ocType);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    LinkedHashSet<String> options = null;
    attrs = e.getOperationalAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    options = new LinkedHashSet<String>();
    attrs = e.getOperationalAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType, options);
    assertNotNull(attrs);
    assertEquals(attrs.size(), 1);
    options.add("lang-en-US");
    attrs = e.getOperationalAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType, options);
    assertNull(attrs);
    options.add("lang-en-GB");
    attrs = e.getOperationalAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType, options);
    assertNull(attrs);
    options.clear();
    options.add("lang-en-GB");
    attrs = e.getOperationalAttribute(ocType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(cnType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(nameType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(uidType, options);
    assertNull(attrs);
    attrs = e.getOperationalAttribute(mnType, options);
    assertNull(attrs);
  }
}