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

boli
31.19.2007 87ea6a1089819313e274c7954ec1cd5513503908
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/ApproximateIndexer.java
@@ -176,7 +176,37 @@
                          Set<ASN1OctetString> addKeys,
                          Set<ASN1OctetString> delKeys)
  {
    replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    HashSet<AttributeValue> newValues;
    HashSet<AttributeValue> oldValues;
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        HashSet<ASN1OctetString> newKeys =
            new HashSet<ASN1OctetString>();
        HashSet<ASN1OctetString> oldKeys =
            new HashSet<ASN1OctetString>();
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
  }
  /**
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -3789,15 +3789,27 @@
    {
      // Check whether any modifications apply to this indexed attribute.
      boolean attributeModified = false;
      AttributeType indexAttributeType = index.getAttributeType();
      Iterable<AttributeType> subTypes =
          DirectoryServer.getSchema().getSubTypes(indexAttributeType);
      for (Modification mod : mods)
      {
        Attribute modAttr = mod.getAttribute();
        AttributeType modAttrType = modAttr.getAttributeType();
        if (modAttrType.equals(index.getAttributeType()))
        if (modAttrType.equals(indexAttributeType))
        {
          attributeModified = true;
          break;
        }
        for(AttributeType subType : subTypes)
        {
          if(modAttrType.equals(subType))
          {
            attributeModified = true;
            break;
          }
        }
      }
      if (attributeModified)
      {
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/EqualityIndexer.java
@@ -45,7 +45,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.ArrayList;
/**
 * An implementation of an Indexer for attribute equality.
@@ -191,140 +190,44 @@
                          Set<ASN1OctetString> delKeys)
       throws DatabaseException
  {
    // Optimize for the case where there are no attribute options
    // involved and only simple addition and deletion of individual values.
    // An issue with attribute options is that the values can not be assumed
    // to be unique.
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    HashSet<AttributeValue> newValues;
    HashSet<AttributeValue> oldValues;
    List<Attribute> beforeList;
    List<Attribute> afterList;
    beforeList = oldEntry.getAttribute(attributeType);
    afterList = newEntry.getAttribute(attributeType);
    boolean hasOptions = false;
    if (beforeList != null)
    if(newAttributes == null)
    {
      for (Attribute a : beforeList)
      {
        if (a.hasOptions())
        {
          hasOptions = true;
          break;
        }
      }
    }
    if (afterList != null)
    {
      for (Attribute a : afterList)
      {
        if (a.hasOptions())
        {
          hasOptions = true;
          break;
        }
      }
    }
    boolean hasOnlySimpleMods = true;
    List<Modification> simpleMods = new ArrayList<Modification>();
    for (Modification mod : mods)
    {
      Attribute modAttr = mod.getAttribute();
      AttributeType modAttrType = modAttr.getAttributeType();
      if (modAttrType.equals(attributeType))
      {
        if (modAttr.hasOptions())
        {
          hasOptions = true;
        }
        switch (mod.getModificationType())
        {
          case ADD:
            simpleMods.add(mod);
            break;
          case DELETE:
            if (!modAttr.hasValue())
            {
              hasOnlySimpleMods = false;
            }
            else
            {
              simpleMods.add(mod);
            }
            break;
          default:
            hasOnlySimpleMods = false;
            break;
        }
      }
    }
    if (hasOnlySimpleMods && !hasOptions)
    {
      // This is the optimized case where there are no attribute options
      // involved and only simple addition and deletion of individual values.
      // It should be efficient for adding and/or deleting a few values of an
      // attribute with lots of values.
      for (Modification mod : simpleMods)
      {
        Set<AttributeValue> values = mod.getAttribute().getValues();
        Set<ASN1OctetString> keys =
             new HashSet<ASN1OctetString>(values.size());
        indexValues(values, keys);
        switch (mod.getModificationType())
        {
          case ADD:
            for (ASN1OctetString key : keys)
            {
              if (delKeys.contains(key))
              {
                delKeys.remove(key);
              }
              else
              {
                addKeys.add(key);
              }
            }
            break;
          case DELETE:
            for (ASN1OctetString key : keys)
            {
              if (addKeys.contains(key))
              {
                addKeys.remove(key);
              }
              else
              {
                delKeys.add(key);
              }
            }
            break;
        }
      }
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      // This is the non-optimized case that should be correct in all cases.
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        newValues = new HashSet<AttributeValue>();
        oldValues = new HashSet<AttributeValue>();
        for(Attribute a : newAttributes)
        {
          newValues.addAll(a.getValues());
        }
        for(Attribute a : oldAttributes)
        {
          oldValues.addAll(a.getValues());
        }
      Set<ASN1OctetString> oldSet = new HashSet<ASN1OctetString>();
      indexAttribute(beforeList, oldSet);
        HashSet<AttributeValue> valuesToAdd =
            new HashSet<AttributeValue>(newValues);
        HashSet<AttributeValue> valuesToDel =
            new HashSet<AttributeValue>(oldValues);
        valuesToAdd.removeAll(oldValues);
        valuesToDel.removeAll(newValues);
      Set<ASN1OctetString> newSet = new HashSet<ASN1OctetString>();
      indexAttribute(afterList, newSet);
      HashSet<ASN1OctetString> removeSet = new HashSet<ASN1OctetString>(oldSet);
      removeSet.removeAll(newSet);
      delKeys.addAll(removeSet);
      HashSet<ASN1OctetString> addSet = new HashSet<ASN1OctetString>(newSet);
      addSet.removeAll(oldSet);
      addKeys.addAll(addSet);
        indexValues(valuesToDel, delKeys);
        indexValues(valuesToAdd, addKeys);
      }
    }
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/OrderingIndexer.java
@@ -180,72 +180,43 @@
                          Set<ASN1OctetString> delKeys)
       throws DatabaseException
  {
    List<Attribute> beforeList;
    beforeList = oldEntry.getAttribute(attributeType);
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    HashSet<AttributeValue> newValues;
    HashSet<AttributeValue> oldValues;
    // Pick out the modifications that apply to this indexed attribute
    /**
     * FIXME unusual modifications can insert spurious index values
     * The following sequence of modifications will insert A into the
     * index, yet A is not a resulting value for the attribute.
     *
     * add: cn
     * cn: A
     * -
     * replace: cn
     * cn: B
     * -
     *
     */
    for (Modification mod : mods)
    if(newAttributes == null)
    {
      Attribute modAttr = mod.getAttribute();
      AttributeType modAttrType = modAttr.getAttributeType();
      if (modAttrType.equals(attributeType))
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        switch (mod.getModificationType())
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        newValues = new HashSet<AttributeValue>();
        oldValues = new HashSet<AttributeValue>();
        for(Attribute a : newAttributes)
        {
          case REPLACE:
          case INCREMENT:
            if (beforeList != null)
            {
              for (Attribute attr : beforeList)
              {
                if (attr.hasOptions(modAttr.getOptions()))
                {
                  indexValues(attr.getValues(), delKeys);
                }
              }
            }
            indexValues(modAttr.getValues(), addKeys);
            break;
          case ADD:
            indexValues(modAttr.getValues(), addKeys);
            break;
          case DELETE:
            if (!modAttr.hasValue())
            {
              if (beforeList != null)
              {
                for (Attribute attr : beforeList)
                {
                  if (attr.hasOptions(modAttr.getOptions()))
                  {
                    indexValues(attr.getValues(), delKeys);
                  }
                }
              }
            }
            else
            {
              indexValues(modAttr.getValues(), delKeys);
            }
            break;
          newValues.addAll(a.getValues());
        }
        for(Attribute a : oldAttributes)
        {
          oldValues.addAll(a.getValues());
        }
        HashSet<AttributeValue> valuesToAdd =
            new HashSet<AttributeValue>(newValues);
        HashSet<AttributeValue> valuesToDel =
            new HashSet<AttributeValue>(oldValues);
        valuesToAdd.removeAll(oldValues);
        valuesToDel.removeAll(newValues);
        indexValues(valuesToDel, delKeys);
        indexValues(valuesToAdd, addKeys);
      }
    }
  }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/PresenceIndexer.java
@@ -171,6 +171,23 @@
                          Set<ASN1OctetString> delKeys)
       throws DatabaseException
  {
    replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    if(oldAttributes == null)
    {
      if(newAttributes != null)
      {
        addKeys.add(
              new ASN1OctetString(AttributeIndex.presenceKey.getData()));
      }
    }
    else
    {
      if(newAttributes == null)
      {
        delKeys.add(
              new ASN1OctetString(AttributeIndex.presenceKey.getData()));
      }
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/SubstringIndexer.java
@@ -34,7 +34,6 @@
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -179,7 +178,37 @@
                          Set<ASN1OctetString> addKeys,
                          Set<ASN1OctetString> delKeys)
  {
    replaceEntry(txn, oldEntry, newEntry, addKeys, delKeys);
    List<Attribute> newAttributes = newEntry.getAttribute(attributeType, true);
    List<Attribute> oldAttributes = oldEntry.getAttribute(attributeType, true);
    HashSet<AttributeValue> newValues;
    HashSet<AttributeValue> oldValues;
    if(newAttributes == null)
    {
      indexAttribute(oldAttributes, delKeys);
    }
    else
    {
      if(oldAttributes == null)
      {
        indexAttribute(newAttributes, addKeys);
      }
      else
      {
        HashSet<ASN1OctetString> newKeys =
            new HashSet<ASN1OctetString>();
        HashSet<ASN1OctetString> oldKeys =
            new HashSet<ASN1OctetString>();
        indexAttribute(newAttributes, newKeys);
        indexAttribute(oldAttributes, oldKeys);
        addKeys.addAll(newKeys);
        addKeys.removeAll(oldKeys);
        delKeys.addAll(oldKeys);
        delKeys.removeAll(newKeys);
      }
    }
  }
@@ -187,30 +216,42 @@
  /**
   * Generate the set of substring index keys for an attribute.
   * @param attrList The attribute for which substring keys are required.
   * @param addKeys The set into which the generated keys will be inserted.
   * @param keys The set into which the generated keys will be inserted.
   */
  private void indexAttribute(List<Attribute> attrList,
                              Set<ASN1OctetString> addKeys)
                              Set<ASN1OctetString> keys)
  {
    if (attrList == null) return;
    for (Attribute attr : attrList)
    {
      LinkedHashSet<AttributeValue> values = attr.getValues();
      for (AttributeValue value : values)
      {
        try
        {
          byte[] normalizedBytes = value.getNormalizedValue().value();
      indexValues(attr.getValues(), keys);
    }
  }
          substringKeys(normalizedBytes, addKeys);
        }
        catch (DirectoryException e)
  /**
   * Generate the set of index keys for a set of attribute values.
   * @param values The set of attribute values to be indexed.
   * @param keys The set into which the keys will be inserted.
   */
  private void indexValues(Set<AttributeValue> values,
                           Set<ASN1OctetString> keys)
  {
    if (values == null) return;
    for (AttributeValue value : values)
    {
      try
      {
        byte[] normalizedBytes = value.getNormalizedValue().value();
        substringKeys(normalizedBytes, keys);
      }
      catch (DirectoryException e)
      {
        if (debugEnabled())
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/VLVIndex.java
@@ -383,14 +383,25 @@
        SortKey[] sortKeys = sortOrder.getSortKeys();
        for(SortKey sortKey : sortKeys)
        {
          AttributeType attributeType = sortKey.getAttributeType();
          Iterable<AttributeType> subTypes =
              DirectoryServer.getSchema().getSubTypes(attributeType);
          for(Modification mod : mods)
          {
            if(mod.getAttribute().getAttributeType().
                equals(sortKey.getAttributeType()))
            AttributeType modAttrType = mod.getAttribute().getAttributeType();
            if(modAttrType.equals(attributeType))
            {
              sortAttributeModified = true;
              break;
            }
            for(AttributeType subType : subTypes)
            {
              if(modAttrType.equals(subType))
              {
                sortAttributeModified = true;
                break;
              }
            }
          }
          if(sortAttributeModified)
          {
opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
@@ -608,25 +608,47 @@
  }
  /**
   * Indicates whether this entry contains the specified attribute.
   * Any subordinate attribute of the specified attribute will also
   * be used in the determination.
   *
   * @param  attributeType  The attribute type for which to make the
   *                        determination.
   *
   * @param  attributeType       The attribute type for which to
   *                             make the determination.
   *
   * @return  <CODE>true</CODE> if this entry contains the specified
   *          attribute, or <CODE>false</CODE> if not.
   */
  public boolean hasAttribute(AttributeType attributeType)
  {
    return hasAttribute(attributeType, true);
  }
  /**
   * Indicates whether this entry contains the specified attribute.
   *
   * @param  attributeType       The attribute type for which to
   *                             make the determination.
   * @param  includeSubordinates Whether to include any subordinate
   *                             attributes of the attribute type
   *                             being retrieved.
   *
   * @return  <CODE>true</CODE> if this entry contains the specified
   *          attribute, or <CODE>false</CODE> if not.
   */
  public boolean hasAttribute(AttributeType attributeType,
                              boolean includeSubordinates)
  {
    if (userAttributes.containsKey(attributeType) ||
        operationalAttributes.containsKey(attributeType))
    {
      return true;
    }
    if (attributeType.mayHaveSubordinateTypes())
    if (includeSubordinates &&
        attributeType.mayHaveSubordinateTypes())
    {
      for (AttributeType at : schema.getSubTypes(attributeType))
      {
@@ -643,15 +665,16 @@
  }
  /**
   * Indicates whether this entry contains the specified attribute
   * with all of the options in the provided set.
   * with all of the options in the provided set. Any subordinate
   * attribute of the specified attribute will also be used in
   * the determination.
   *
   * @param  attributeType     The attribute type for which to make
   *                           the determination.
   * @param  attributeOptions  The set of options to use in the
   *                           determination.
   * @param  attributeType       The attribute type for which to
   *                             make the determination.
   * @param  attributeOptions    The set of options to use in the
   *                             determination.
   *
   * @return  <CODE>true</CODE> if this entry contains the specified
   *          attribute, or <CODE>false</CODE> if not.
@@ -659,8 +682,32 @@
  public boolean hasAttribute(AttributeType attributeType,
                              Set<String> attributeOptions)
  {
    return hasAttribute(attributeType, true, attributeOptions);
  }
  /**
   * Indicates whether this entry contains the specified attribute
   * with all of the options in the provided set.
   *
   * @param  attributeType       The attribute type for which to
   *                             make the determination.
   * @param  includeSubordinates Whether to include any subordinate
   *                             attributes of the attribute type
   *                             being retrieved.
   * @param  attributeOptions    The set of options to use in the
   *                             determination.
   *
   * @return  <CODE>true</CODE> if this entry contains the specified
   *          attribute, or <CODE>false</CODE> if not.
   */
  public boolean hasAttribute(AttributeType attributeType,
                              boolean includeSubordinates,
                              Set<String> attributeOptions)
  {
    List<Attribute> attributes;
    if (attributeType.mayHaveSubordinateTypes())
    if (includeSubordinates &&
        attributeType.mayHaveSubordinateTypes())
    {
      attributes = new LinkedList<Attribute>();
      List<Attribute> attrs = userAttributes.get(attributeType);
@@ -726,13 +773,12 @@
    return false;
  }
  /**
   * Retrieves the requested attribute element(s) for the specified
   * attribute type.  The list returned may include multiple elements
   * if the same attribute exists in the entry multiple times with
   * different sets of options.
   * different sets of options. It may also include any subordinate
   * attributes of the attribute being retrieved.
   *
   * @param  attributeType  The attribute type to retrieve.
   *
@@ -742,7 +788,30 @@
   */
  public List<Attribute> getAttribute(AttributeType attributeType)
  {
    if (attributeType.mayHaveSubordinateTypes())
    return getAttribute(attributeType, true);
  }
  /**
   * Retrieves the requested attribute element(s) for the specified
   * attribute type.  The list returned may include multiple elements
   * if the same attribute exists in the entry multiple times with
   * different sets of options.
   *
   * @param  attributeType       The attribute type to retrieve.
   * @param  includeSubordinates Whether to include any subordinate
   *                             attributes of the attribute type
   *                             being retrieved.
   *
   * @return  The requested attribute element(s) for the specified
   *          attribute type, or <CODE>null</CODE> if the specified
   *          attribute type is not present in this entry.
   */
  public List<Attribute> getAttribute(AttributeType attributeType,
                                      boolean includeSubordinates)
  {
    if (includeSubordinates &&
        attributeType.mayHaveSubordinateTypes())
    {
      List<Attribute> attributes = new LinkedList<Attribute>();
@@ -821,7 +890,9 @@
   * Retrieves the requested attribute element(s) for the attribute
   * with the specified name or OID.  The list returned may include
   * multiple elements if the same attribute exists in the entry
   * multiple times with different sets of options.
   * multiple times with different sets of options. It may also
   * include any subordinate attributes of the attribute being
   * retrieved.
   * <BR><BR>
   * Note that this method should only be used in cases in which the
   * Directory Server schema has no reference of an attribute type
@@ -842,7 +913,7 @@
    {
      if (attr.hasNameOrOID(lowerName))
      {
        return getAttribute(attr);
        return getAttribute(attr, true);
      }
    }
@@ -850,7 +921,7 @@
    {
      if (attr.hasNameOrOID(lowerName))
      {
        return getAttribute(attr);
        return getAttribute(attr, true);
      }
    }
@@ -865,17 +936,16 @@
    return null;
  }
  /**
   * Retrieves the requested attribute element(s) for the specified
   * attribute type.  The list returned may include multiple elements
   * if the same attribute exists in the entry multiple times with
   * different sets of options.
   * different sets of options. It may also include any subordinate
   * attributes of the attribute being retrieved.
   *
   * @param  attributeType  The attribute type to retrieve.
   * @param  options        The set of attribute options to include in
   *                        matching elements.
   * @param  attributeType       The attribute type to retrieve.
   * @param  options             The set of attribute options to
   *                             include in matching elements.
   *
   * @return  The requested attribute element(s) for the specified
   *          attribute type, or <CODE>null</CODE> if the specified
@@ -885,8 +955,34 @@
  public List<Attribute> getAttribute(AttributeType attributeType,
                                      Set<String> options)
  {
    return getAttribute(attributeType, true, options);
  }
  /**
   * Retrieves the requested attribute element(s) for the specified
   * attribute type.  The list returned may include multiple elements
   * if the same attribute exists in the entry multiple times with
   * different sets of options.
   *
   * @param  attributeType       The attribute type to retrieve.
   * @param  includeSubordinates Whether to include any subordinate
   *                             attributes of the attribute type
   *                             being retrieved.
   * @param  options             The set of attribute options to
   *                             include in matching elements.
   *
   * @return  The requested attribute element(s) for the specified
   *          attribute type, or <CODE>null</CODE> if the specified
   *          attribute type is not present in this entry with the
   *          provided set of options.
   */
  public List<Attribute> getAttribute(AttributeType attributeType,
                                      boolean includeSubordinates,
                                      Set<String> options)
  {
    List<Attribute> attributes = new LinkedList<Attribute>();
    if (attributeType.mayHaveSubordinateTypes())
    if (includeSubordinates &&
        attributeType.mayHaveSubordinateTypes())
    {
      List<Attribute> attrs = userAttributes.get(attributeType);
      if (attrs != null)
@@ -1053,7 +1149,7 @@
  public final <T> T getAttributeValue(AttributeType attributeType,
      AttributeValueDecoder<T> decoder) throws DirectoryException
  {
    List<Attribute> attributes = getAttribute(attributeType);
    List<Attribute> attributes = getAttribute(attributeType, true);
    AttributeValueIterable values =
         new AttributeValueIterable(attributes);
    Iterator<AttributeValue> iterator = values.iterator();
@@ -1100,7 +1196,7 @@
      Collection<T> collection)
      throws DirectoryException
  {
    List<Attribute> attributes = getAttribute(attributeType);
    List<Attribute> attributes = getAttribute(attributeType, true);
    AttributeValueIterable values =
         new AttributeValueIterable(attributes);
@@ -1664,7 +1760,7 @@
    attachment = null;
    List<Attribute> attrList =
         getAttribute(attribute.getAttributeType());
         getAttribute(attribute.getAttributeType(), false);
    if (attrList == null)
    {
      // There are no instances of the specified attribute in this
@@ -1721,10 +1817,11 @@
  /**
   * Removes all instances of the specified attribute type from this
   * entry.  If the provided attribute type is the objectclass type,
   * then all objectclass values will be removed (but must be replaced
   * for the entry to be valid).  If the specified attribute type is
   * not present in this entry, then this method will have no effect.
   * entry, including any instances with options.  If the provided
   * attribute type is the objectclass type, then all objectclass
   * values will be removed (but must be replaced for the entry to
   * be valid).  If the specified attribute type is not present in
   * this entry, then this method will have no effect.
   *
   * @param  attributeType  The attribute type for the attribute to
   *                        remove from this entry.
@@ -1753,12 +1850,10 @@
  /**
   * Removes the attribute with the provided type and set of options
   * from this entry.  If the provided set of options is
   * <CODE>null</CODE> or empty, then all occurrences of the specified
   * attribute will be removed.  Otherwise, only the instance with the
   * exact set of options provided will be removed.  This has no
   * effect if the specified attribute is not present in this entry
   * with the given set of options.
   * from this entry.  Only the instance with the exact set of
   * options provided will be removed.  This has no effect if the
   * specified attribute is not present in this entry with the given
   * set of options.
   *
   * @param  attributeType  The attribute type for the attribute to
   *                        remove from this entry.
@@ -1774,44 +1869,37 @@
  {
    attachment = null;
    if ((options == null) || options.isEmpty())
    List<Attribute> attrList = userAttributes.get(attributeType);
    if (attrList == null)
    {
      return removeAttribute(attributeType);
    }
    else
    {
      List<Attribute> attrList = userAttributes.get(attributeType);
      attrList = operationalAttributes.get(attributeType);
      if (attrList == null)
      {
        attrList = operationalAttributes.get(attributeType);
        if (attrList == null)
        {
          return false;
        }
        return false;
      }
      boolean removed = false;
      Iterator<Attribute> iterator = attrList.iterator();
      while (iterator.hasNext())
      {
        Attribute a = iterator.next();
        if (a.optionsEqual(options))
        {
          iterator.remove();
          removed = true;
          break;
        }
      }
      if (attrList.isEmpty())
      {
        userAttributes.remove(attributeType);
        operationalAttributes.remove(attributeType);
      }
      return removed;
    }
    boolean removed = false;
    Iterator<Attribute> iterator = attrList.iterator();
    while (iterator.hasNext())
    {
      Attribute a = iterator.next();
      if (a.optionsEqual(options))
      {
        iterator.remove();
        removed = true;
        break;
      }
    }
    if (attrList.isEmpty())
    {
      userAttributes.remove(attributeType);
      operationalAttributes.remove(attributeType);
    }
    return removed;
  }
@@ -1906,7 +1994,7 @@
      }
      List<Attribute> attrList =
           getAttribute(attribute.getAttributeType());
           getAttribute(attribute.getAttributeType(), false);
      if (attrList == null)
      {
        return false;
@@ -1944,11 +2032,11 @@
      LinkedHashSet<AttributeValue> valueSet = attribute.getValues();
      if ((valueSet == null) || valueSet.isEmpty())
      {
        return removeAttribute(attribute.getAttributeType());
        return removeAttribute(attribute.getAttributeType(), null);
      }
      List<Attribute> attrList =
           getAttribute(attribute.getAttributeType());
           getAttribute(attribute.getAttributeType(), false);
      if (attrList == null)
      {
        return false;
@@ -1971,7 +2059,8 @@
          if (existingValueSet.isEmpty())
          {
            return removeAttribute(attribute.getAttributeType());
            return removeAttribute(attribute.getAttributeType(),
                null);
          }
          return true;
@@ -2050,7 +2139,7 @@
  public boolean hasValue(AttributeType attributeType,
                          Set<String> options, AttributeValue value)
  {
    List<Attribute> attrList = getAttribute(attributeType);
    List<Attribute> attrList = getAttribute(attributeType, true);
    if ((attrList == null) || attrList.isEmpty())
    {
      return false;
@@ -2196,7 +2285,7 @@
        break;
      case INCREMENT:
        List<Attribute> attrList = getAttribute(t);
        List<Attribute> attrList = getAttribute(t, false);
        if ((attrList == null) || attrList.isEmpty())
        {
          Message message =
opendj-sdk/opends/tests/unit-tests-testng/resource/config-changes.ldif
@@ -1246,6 +1246,18 @@
objectClass: ds-cfg-branch
cn: Index
dn: ds-cfg-attribute=name,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config
changetype: add
objectClass: top
objectClass: ds-cfg-local-db-index
ds-cfg-attribute: name
ds-cfg-index-type: presence
ds-cfg-index-type: equality
ds-cfg-index-type: substring
ds-cfg-index-type: ordering
ds-cfg-index-type: approximate
ds-cfg-index-entry-limit: 4000
dn: ds-cfg-attribute=cn,cn=Index,ds-cfg-backend-id=indexRoot,cn=Backends,cn=config
changetype: add
objectClass: top
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -129,6 +129,9 @@
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "givenName: Aaren",
        "givenName;lang-fr: test2",
        "givenName;lang-cn: test2",
        "givenName;lang-es: test3",
        "sn: Atp",
        "cn: Aaren Atp",
        "initials: APA",
@@ -1019,7 +1022,8 @@
    Entry newEntry;
    EntryID entryID;
    AttributeType attribute;
    AttributeIndex index;
    AttributeIndex titleIndex;
    AttributeIndex nameIndex;
    HashSet<ASN1OctetString> addKeys;
    DatabaseEntry key;
    PresenceIndexer presenceIndexer;
@@ -1036,12 +1040,46 @@
      ArrayList<Modification> modifications = new ArrayList<Modification>();
      modifications.add(new Modification(ModificationType.ADD, new
          Attribute("title", "debugger")));
      attribute = DirectoryServer.getAttributeType("title");
      LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(attribute, "debugger2"));
      LinkedHashSet<String> options = new LinkedHashSet<String>(1);
      options.add("lang-en");
      Attribute attr = new Attribute(attribute, "title", options, values);
      modifications.add(new Modification(ModificationType.ADD, attr));
      modifications.add(new Modification(ModificationType.DELETE, new
          Attribute("cn", "Aaren Atp")));
      modifications.add(new Modification(ModificationType.ADD, new
          Attribute("cn", "Aaren Rigor")));
      modifications.add(new Modification(ModificationType.ADD, new
          Attribute("cn", "Aarenister Rigor")));
      attribute = DirectoryServer.getAttributeType("givenname");
      values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(attribute, "test"));
      options = new LinkedHashSet<String>(1);
      options.add("lang-de");
      attr = new Attribute(attribute, "givenName", options, values);
      modifications.add(new Modification(ModificationType.ADD, attr));
      attribute = DirectoryServer.getAttributeType("givenname");
      values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(attribute, "test2"));
      options = new LinkedHashSet<String>(1);
      options.add("lang-cn");
      attr = new Attribute(attribute, "givenName", options, values);
      modifications.add(new Modification(ModificationType.DELETE, attr));
      attribute = DirectoryServer.getAttributeType("givenname");
      values = new LinkedHashSet<AttributeValue>();
      values.add(new AttributeValue(attribute, "newtest3"));
      options = new LinkedHashSet<String>(1);
      options.add("lang-es");
      attr = new Attribute(attribute, "givenName", options, values);
      modifications.add(new Modification(ModificationType.REPLACE, attr));
      modifications.add(new Modification(ModificationType.REPLACE, new
          Attribute("employeenumber", "222")));
@@ -1053,19 +1091,31 @@
      assertNotNull(entryID);
      attribute = newEntry.getAttribute("title").get(0).getAttributeType();
      index = ec.getAttributeIndex(attribute);
      attribute = DirectoryServer.getAttributeType("title");
      titleIndex = ec.getAttributeIndex(attribute);
      attribute = DirectoryServer.getAttributeType("name");
      nameIndex = ec.getAttributeIndex(attribute);
      //This current entry in the DB shouldn't be in the presence index.
      //This current entry in the DB shouldn't be in the presence titleIndex.
      addKeys = new HashSet<ASN1OctetString>();
      addKeys.add(new ASN1OctetString(AttributeIndex.presenceKey.getData()));
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(index.presenceIndex.containsID(null, key, entryID),
      assertEquals(titleIndex.presenceIndex.containsID(null, key, entryID),
          ConditionResult.FALSE);
      //This current entry should be in the presence nameIndex.
      addKeys = new HashSet<ASN1OctetString>();
      addKeys.add(new ASN1OctetString(AttributeIndex.presenceKey.getData()));
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(nameIndex.presenceIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      ArrayList<Control> noControls = new ArrayList<Control>(0);
      InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
@@ -1098,55 +1148,123 @@
              entry.getAttribute("cn").get(0).getAttributeType(),
              "Aaren Atp")));
      options = new LinkedHashSet<String>();
      options.add("lang-de");
      assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
          new AttributeValue(
              entry.getAttribute("givenname", options).get(0).getAttributeType(),
              "test")));
      options = new LinkedHashSet<String>();
      options.add("lang-cn");
      assertNull
          (entry.getAttribute("givenname", options));
      options = new LinkedHashSet<String>();
      options.add("lang-es");
      assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
          new AttributeValue(
              entry.getAttribute("givenname", options).get(0).getAttributeType(),
              "newtest3")));
      options = new LinkedHashSet<String>();
      options.add("lang-fr");
      assertTrue(entry.getAttribute("givenname", options).get(0).getValues().contains(
          new AttributeValue(
              entry.getAttribute("givenname", options).get(0).getAttributeType(),
              "test2")));
      assertTrue(entry.getAttribute("employeenumber").contains(new
          Attribute("employeenumber", "222")));
      assertFalse(entry.getAttribute("employeenumber").contains(new
          Attribute("employeenumber", "1")));
      addKeys = new HashSet<ASN1OctetString>();
      presenceIndexer = new PresenceIndexer(index.getAttributeType());
      presenceIndexer = new PresenceIndexer(titleIndex.getAttributeType());
      presenceIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(index.presenceIndex.containsID(null, key, entryID),
        assertEquals(titleIndex.presenceIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      orderingIndexer = new OrderingIndexer(index.getAttributeType());
      presenceIndexer = new PresenceIndexer(nameIndex.getAttributeType());
      presenceIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
        assertEquals(nameIndex.presenceIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      orderingIndexer = new OrderingIndexer(titleIndex.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(index.orderingIndex.containsID(null, key, entryID),
        assertEquals(titleIndex.orderingIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      equalityIndexer = new EqualityIndexer(index.getAttributeType());
      orderingIndexer = new OrderingIndexer(nameIndex.getAttributeType());
      orderingIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
        assertEquals(nameIndex.orderingIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      equalityIndexer = new EqualityIndexer(titleIndex.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(index.equalityIndex.containsID(null, key, entryID),
        assertEquals(titleIndex.equalityIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      substringIndexer = new SubstringIndexer(index.getAttributeType(),
                   index.getConfiguration().getSubstringLength());
      equalityIndexer = new EqualityIndexer(nameIndex.getAttributeType());
      equalityIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
        assertEquals(nameIndex.equalityIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      substringIndexer = new SubstringIndexer(titleIndex.getAttributeType(),
                   titleIndex.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
      }
      assertEquals(index.substringIndex.containsID(null, key, entryID),
        assertEquals(titleIndex.substringIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
      addKeys = new HashSet<ASN1OctetString>();
      substringIndexer = new SubstringIndexer(nameIndex.getAttributeType(),
                   nameIndex.getConfiguration().getSubstringLength());
      substringIndexer.indexEntry(null, entry, addKeys);
      key = new DatabaseEntry();
      for (ASN1OctetString keyBytes : addKeys) {
        key.setData(keyBytes.value());
        assertEquals(nameIndex.substringIndex.containsID(null, key, entryID),
          ConditionResult.TRUE);
      }
    }
    finally
    {
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/EntrySchemaCheckingTestCase.java
@@ -1430,5 +1430,35 @@
    invalidReason = new MessageBuilder();
    failOnlyForStrictEvaluation(e);
  }
  /**
   * Tests schema checking for an entry that includes an attribute not
   * defined in any objectClasses but the subtypes of the attribute are.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testInvalidSuperiorAttribute()
         throws Exception
  {
    // The LDIF reader won't let us do this directly, so we have to hack around
    // it.
    Entry e = TestCaseUtils.makeEntry(
         "dn: uid=test.user,o=test",
         "objectClass: top",
         "objectClass: person",
         "objectClass: organizationalPerson",
         "objectClass: inetOrgPerson",
         "objectClass: account",
         "uid: test.user",
         "givenName: Test",
         "sn: User",
         "cn: Test User");
    e.addAttribute(new Attribute("name", "foo"),
                   new LinkedList<AttributeValue>());
    assertFalse(e.conformsToSchema(null, false, true, true, new MessageBuilder()));
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -343,6 +343,7 @@
    assertTrue(e.hasAttribute(ocType));
    assertTrue(e.hasAttribute(cnType));
    assertTrue(e.hasAttribute(nameType));
    assertFalse(e.hasAttribute(nameType, false));
    assertFalse(e.hasAttribute(uidType));
    assertTrue(e.hasAttribute(mnType));
@@ -350,6 +351,7 @@
    assertTrue(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(nameType, false, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertTrue(e.hasAttribute(mnType, options));
@@ -357,6 +359,7 @@
    assertTrue(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(nameType, false, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertTrue(e.hasAttribute(mnType, options));
@@ -364,6 +367,7 @@
    assertFalse(e.hasAttribute(ocType, options));
    assertTrue(e.hasAttribute(cnType, options));
    assertTrue(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(nameType, false, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
@@ -371,6 +375,7 @@
    assertFalse(e.hasAttribute(ocType, options));
    assertFalse(e.hasAttribute(cnType, options));
    assertFalse(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(nameType, false, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
@@ -379,6 +384,7 @@
    assertFalse(e.hasAttribute(ocType, options));
    assertFalse(e.hasAttribute(cnType, options));
    assertFalse(e.hasAttribute(nameType, options));
    assertFalse(e.hasAttribute(nameType, false, options));
    assertFalse(e.hasAttribute(uidType, options));
    assertFalse(e.hasAttribute(mnType, options));
  }
@@ -526,6 +532,9 @@
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(nameType, false);
    assertNull(attrs);
    attrs = e.getAttribute(uidType);
    assertNull(attrs);
@@ -563,6 +572,9 @@
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(nameType, false, options);
    assertNull(attrs);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
@@ -600,6 +612,9 @@
    assertNotNull(attrs);
    assertEquals(attrs.size(), 6);
    attrs = e.getAttribute(nameType, false, options);
    assertNull(attrs);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);
@@ -636,6 +651,9 @@
    assertNotNull(attrs);
    assertEquals(attrs.size(), 3);
    attrs = e.getAttribute(nameType, false, options);
    assertNull(attrs);
    attrs = e.getAttribute(uidType, options);
    assertNull(attrs);