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

matthew_swift
29.43.2009 cd57b969289f568da79e41fffe451aa0ed837722
Fix issue 3446 and improve fix for issue 3726:

* introduce comprehensive unit test for checking
attribute filtering in search operations

* improvements to virtual attribute provider API

* improvements to virtual attribute processing
during Entry duplication

* fixes for bugs identified in new unit test.
19 files modified
1092 ■■■■ changed files
opends/src/server/org/opends/server/api/VirtualAttributeProvider.java 39 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SearchOperationBasis.java 201 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java 18 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java 20 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java 15 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java 14 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java 27 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java 15 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java 29 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java 32 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Entry.java 351 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/VirtualAttribute.java 16 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java 264 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java 7 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java 5 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java 18 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java 8 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java 7 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java 6 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/VirtualAttributeProvider.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.api;
import org.opends.messages.Message;
@@ -31,8 +31,8 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.opends.server.admin.std.server.VirtualAttributeCfg;
import org.opends.server.config.ConfigException;
@@ -147,19 +147,18 @@
  /**
   * Generates a set of values for the provided entry.
   * Generates an unmodifiable set of values for the provided entry.
   *
   * @param  entry  The entry for which the values are to be
   *                generated.
   * @param  rule   The virtual attribute rule which defines the
   *                constraints for the virtual attribute.
   *
   * @return  The set of values generated for the provided entry.  It
   *          may be empty, but it must not be {@code null}.
   * @param entry
   *          The entry for which the values are to be generated.
   * @param rule
   *          The virtual attribute rule which defines the constraints
   *          for the virtual attribute.
   * @return The unmodifiable set of values generated for the provided
   *         entry. It may be empty, but it must not be {@code null}.
   */
  public abstract LinkedHashSet<AttributeValue>
                       getValues(Entry entry,
                                 VirtualAttributeRule rule);
  public abstract Set<AttributeValue> getValues(
      Entry entry, VirtualAttributeRule rule);
@@ -221,15 +220,8 @@
  public boolean hasAllValues(Entry entry, VirtualAttributeRule rule,
                              Collection<AttributeValue> values)
  {
    for (AttributeValue value : values)
    {
      if (! getValues(entry, rule).contains(value))
      {
        return false;
      }
    }
    return true;
    Set<AttributeValue> virtualValues = getValues(entry, rule);
    return virtualValues.containsAll(values);
  }
@@ -251,9 +243,10 @@
  public boolean hasAnyValue(Entry entry, VirtualAttributeRule rule,
                             Collection<AttributeValue> values)
  {
    Set<AttributeValue> virtualValues = getValues(entry, rule);
    for (AttributeValue value : values)
    {
      if (getValues(entry, rule).contains(value))
      if (virtualValues.contains(value))
      {
        return true;
      }
opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.core;
@@ -35,6 +35,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PluginResult;
@@ -714,10 +715,13 @@
    // Make a copy of the entry and pare it down to only include the set
    // of requested attributes.
    Entry entryToReturn;
    boolean omitReal = isVirtualAttributesOnly();
    boolean omitVirtual = isRealAttributesOnly();
    if ((getAttributes() == null) || getAttributes().isEmpty())
    {
      entryToReturn = entry.duplicateWithoutOperationalAttributes(typesOnly,
                                                                  true);
      entryToReturn =
          entry.duplicateWithoutOperationalAttributes(typesOnly,
              omitReal, omitVirtual);
    }
    else
    {
@@ -729,22 +733,26 @@
        {
          // This is a special placeholder indicating that all user attributes
          // should be returned.
          if (typesOnly)
          if (!omitReal)
          {
            // First, add the placeholder for the objectclass attribute.
            AttributeType ocType =
                 DirectoryServer.getObjectClassAttributeType();
            List<Attribute> ocList = new ArrayList<Attribute>(1);
            ocList.add(Attributes.empty(ocType));
            entryToReturn.putAttribute(ocType, ocList);
          }
          else
          {
            // First, add the objectclass attribute.
            Attribute ocAttr = entry.getObjectClassAttribute();
            if (ocAttr != null)
            if (typesOnly)
            {
              entryToReturn.replaceAttribute(ocAttr);
              // First, add the placeholder for the objectclass
              // attribute.
              AttributeType ocType =
                  DirectoryServer.getObjectClassAttributeType();
              List<Attribute> ocList = new ArrayList<Attribute>(1);
              ocList.add(Attributes.empty(ocType));
              entryToReturn.putAttribute(ocType, ocList);
            }
            else
            {
              // First, add the objectclass attribute.
              Attribute ocAttr = entry.getObjectClassAttribute();
              if (ocAttr != null)
              {
                entryToReturn.replaceAttribute(ocAttr);
              }
            }
          }
@@ -752,8 +760,12 @@
          for (AttributeType t : entry.getUserAttributes().keySet())
          {
            List<Attribute> attrList =
                 entry.duplicateUserAttribute(t, null, typesOnly);
            entryToReturn.putAttribute(t, attrList);
                duplicateUserAttribute(entry, t, null, typesOnly,
                    omitReal, omitVirtual);
            if (attrList != null)
            {
              entryToReturn.putAttribute(t, attrList);
            }
          }
          continue;
@@ -765,8 +777,12 @@
          for (AttributeType t : entry.getOperationalAttributes().keySet())
          {
            List<Attribute> attrList =
                 entry.duplicateOperationalAttribute(t, null, typesOnly);
            entryToReturn.putAttribute(t, attrList);
                duplicateOperationalAttribute(entry, t, null,
                    typesOnly, omitReal, omitVirtual);
            if (attrList != null)
            {
              entryToReturn.putAttribute(t, attrList);
            }
          }
          continue;
@@ -787,7 +803,6 @@
            semicolonPos = nextPos;
            nextPos = attrName.indexOf(';', semicolonPos+1);
          }
          options.add(attrName.substring(semicolonPos+1));
        }
        else
@@ -796,7 +811,6 @@
          options = null;
        }
        AttributeType attrType = DirectoryServer.getAttributeType(lowerName);
        if (attrType == null)
        {
@@ -806,11 +820,11 @@
            if (t.hasNameOrOID(lowerName))
            {
              List<Attribute> attrList =
                   entry.duplicateUserAttribute(t, options, typesOnly);
                  duplicateUserAttribute(entry, t, options, typesOnly,
                      omitReal, omitVirtual);
              if (attrList != null)
              {
                entryToReturn.putAttribute(t, attrList);
                added = true;
                break;
              }
@@ -827,11 +841,11 @@
            if (t.hasNameOrOID(lowerName))
            {
              List<Attribute> attrList =
                   entry.duplicateOperationalAttribute(t, options, typesOnly);
                  duplicateOperationalAttribute(entry, t, options,
                      typesOnly, omitReal, omitVirtual);
              if (attrList != null)
              {
                entryToReturn.putAttribute(t, attrList);
                break;
              }
            }
@@ -840,30 +854,34 @@
        else
        {
          if (attrType.isObjectClassType()) {
            if (typesOnly)
            if (!omitReal)
            {
              AttributeType ocType =
                   DirectoryServer.getObjectClassAttributeType();
              List<Attribute> ocList = new ArrayList<Attribute>(1);
              ocList.add(Attributes.empty(ocType));
              entryToReturn.putAttribute(ocType, ocList);
            }
            else
            {
              List<Attribute> attrList = new ArrayList<Attribute>(1);
              attrList.add(entry.getObjectClassAttribute());
              entryToReturn.putAttribute(attrType, attrList);
              if (typesOnly)
              {
                AttributeType ocType =
                    DirectoryServer.getObjectClassAttributeType();
                List<Attribute> ocList = new ArrayList<Attribute>(1);
                ocList.add(Attributes.empty(ocType));
                entryToReturn.putAttribute(ocType, ocList);
              }
              else
              {
                List<Attribute> attrList = new ArrayList<Attribute>(1);
                attrList.add(entry.getObjectClassAttribute());
                entryToReturn.putAttribute(attrType, attrList);
              }
            }
          }
          else
          {
            List<Attribute> attrList =
                 entry.duplicateOperationalAttribute(attrType, options,
                                                     typesOnly);
                duplicateOperationalAttribute(entry, attrType, options,
                    typesOnly, omitReal, omitVirtual);
            if (attrList == null)
            {
              attrList = entry.duplicateUserAttribute(attrType, options,
                                                      typesOnly);
              attrList =
                  duplicateUserAttribute(entry, attrType, options,
                      typesOnly, omitReal, omitVirtual);
            }
            if (attrList != null)
            {
@@ -874,15 +892,6 @@
      }
    }
    if (isRealAttributesOnly())
    {
      entryToReturn.stripVirtualAttributes();
    }
    else if (isVirtualAttributesOnly())
    {
      entryToReturn.stripRealAttributes();
    }
    // If there is a matched values control, then further pare down the entry
    // based on the filters that it contains.
    MatchedValuesControl matchedValuesControl = getMatchedValuesControl();
@@ -1466,6 +1475,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public final void run()
  {
    setResultCode(ResultCode.UNDEFINED);
@@ -1617,4 +1627,91 @@
    appendErrorMessage(message);
  }
  // Copies non-empty attributes.
  private List<Attribute> duplicateAttribute(
       List<Attribute> attrList,
       Set<String> options,
       boolean omitValues,
       boolean omitReal,
       boolean omitVirtual)
  {
    if (attrList == null)
    {
      return null;
    }
    ArrayList<Attribute> duplicateList =
         new ArrayList<Attribute>(attrList.size());
    for (Attribute a : attrList)
    {
      if (a.hasAllOptions(options))
      {
        if (omitReal && !a.isVirtual())
        {
          continue;
        }
        else if (omitVirtual && a.isVirtual())
        {
          continue;
        }
        else if (a.isEmpty())
        {
          continue;
        }
        else if (omitValues)
        {
          duplicateList.add(Attributes.empty(a));
        }
        else
        {
          duplicateList.add(a);
        }
      }
    }
    if (duplicateList.isEmpty())
    {
      return null;
    }
    else
    {
      return duplicateList;
    }
  }
  // Copy a user attribute - may return null if the attribute was
  // not found or if it was empty.
  private List<Attribute> duplicateUserAttribute(
       Entry entry,
       AttributeType attributeType,
       Set<String> options,
       boolean omitValues,
       boolean omitReal,
       boolean omitVirtual)
  {
    List<Attribute> currentList = entry.getUserAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues,
        omitReal, omitVirtual);
  }
  // Copy an operational attribute - may return null if the
  // attribute was not found or if it was empty.
  private List<Attribute> duplicateOperationalAttribute(
       Entry entry,
       AttributeType attributeType,
       Set<String> options,
       boolean omitValues,
       boolean omitReal,
       boolean omitVirtual)
  {
    List<Attribute> currentList =
         entry.getOperationalAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues,
        omitReal, omitVirtual);
  }
}
opends/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProvider.java
@@ -22,15 +22,17 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.opends.server.admin.std.server.EntryDNVirtualAttributeCfg;
import org.opends.server.api.VirtualAttributeProvider;
@@ -109,16 +111,14 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    String normDNString = entry.getDN().toNormalizedString();
    values.add(new AttributeValue(ByteStringFactory.create(normDNString),
                                  ByteStringFactory.create(normDNString)));
    return values;
    AttributeValue value = new AttributeValue(
                                  ByteStringFactory.create(normDNString),
                                  ByteStringFactory.create(normDNString));
    return Collections.singleton(value);
  }
opends/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProvider.java
@@ -22,14 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.opends.messages.Message;
@@ -50,7 +51,6 @@
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -112,18 +112,16 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    String normDNString = entry.getDN().toNormalizedString();
    String uuidString =
         UUID.nameUUIDFromBytes(getBytes(normDNString)).toString();
    values.add(new AttributeValue(ByteStringFactory.create(uuidString),
                                  ByteStringFactory.create(uuidString)));
    return values;
    AttributeValue value = new AttributeValue(
        ByteStringFactory.create(uuidString),
        ByteStringFactory.create(uuidString));
    return Collections.singleton(value);
  }
opends/src/server/org/opends/server/extensions/HasSubordinatesVirtualAttributeProvider.java
@@ -22,14 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.HasSubordinatesVirtualAttributeCfg;
@@ -109,11 +110,9 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    Backend backend = DirectoryServer.getBackend(entry.getDN());
    try
@@ -124,7 +123,7 @@
        AttributeValue value =
            new AttributeValue(ByteStringFactory.create(ret.toString()),
                               ByteStringFactory.create(ret.toString()));
        values.add(value);
        return Collections.singleton(value);
      }
    }
    catch(DirectoryException de)
@@ -135,7 +134,7 @@
      }
    }
    return values;
    return Collections.emptySet();
  }
opends/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProvider.java
@@ -22,15 +22,17 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.opends.server.admin.std.server.IsMemberOfVirtualAttributeCfg;
import org.opends.server.api.Group;
@@ -112,11 +114,11 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    // FIXME -- This probably isn't the most efficient implementation.
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
    HashSet<AttributeValue> values = new HashSet<AttributeValue>();
    for (Group g : DirectoryServer.getGroupManager().getGroupInstances())
    {
      try
@@ -136,7 +138,7 @@
      }
    }
    return values;
    return Collections.unmodifiableSet(values);
  }
opends/src/server/org/opends/server/extensions/MemberVirtualAttributeProvider.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.Message;
@@ -30,8 +30,10 @@
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.MemberVirtualAttributeCfg;
@@ -40,7 +42,6 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.SearchOperation;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConditionResult;
@@ -56,7 +57,6 @@
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.server.util.ServerConstants.*;
@@ -74,10 +74,6 @@
   */
  private static final DebugTracer TRACER = getTracer();
  // The attribute type used to indicate which target group should be used to
  // obtain the member list.
  private AttributeType targetGroupType;
  // The current configuration for this member virtual attribute.
  private MemberVirtualAttributeCfg currentConfig;
@@ -106,9 +102,6 @@
  {
    configuration.addMemberChangeListener(this);
    currentConfig = configuration;
    targetGroupType =
         DirectoryServer.getAttributeType(ATTR_TARGET_GROUP_DN, true);
  }
@@ -128,21 +121,21 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    if (! currentConfig.isAllowRetrievingMembership())
    {
      return new LinkedHashSet<AttributeValue>(0);
      return Collections.emptySet();
    }
    Group g = DirectoryServer.getGroupManager().getGroupInstance(entry.getDN());
    if (g == null)
    {
      return new LinkedHashSet<AttributeValue>(0);
      return Collections.emptySet();
    }
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
    HashSet<AttributeValue> values = new HashSet<AttributeValue>();
    try
    {
      MemberList memberList = g.getMembers();
@@ -174,7 +167,7 @@
      }
    }
    return values;
    return Collections.unmodifiableSet(values);
  }
opends/src/server/org/opends/server/extensions/NumSubordinatesVirtualAttributeProvider.java
@@ -22,14 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.NumSubordinatesVirtualAttributeCfg;
@@ -110,11 +111,9 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    Backend backend = DirectoryServer.getBackend(entry.getDN());
    try
@@ -125,7 +124,7 @@
        AttributeValue value =
            new AttributeValue(ByteStringFactory.create(String.valueOf(count)),
                               ByteStringFactory.create(String.valueOf(count)));
        values.add(value);
        return Collections.singleton(value);
      }
    }
    catch(DirectoryException de)
@@ -136,7 +135,7 @@
      }
    }
    return values;
    return Collections.emptySet();
  }
opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java
@@ -22,14 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.SubschemaSubentryVirtualAttributeCfg;
@@ -37,7 +38,6 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.SearchOperation;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConditionResult;
@@ -46,9 +46,7 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.VirtualAttributeRule;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.util.ServerConstants.*;
@@ -60,13 +58,6 @@
       extends VirtualAttributeProvider<SubschemaSubentryVirtualAttributeCfg>
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * Creates a new instance of this subschemaSubentry virtual attribute
   * provider.
   */
@@ -108,15 +99,13 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    values.add(new AttributeValue(rule.getAttributeType(),
                                  DirectoryServer.getSchemaDN().toString()));
    return values;
    AttributeValue value =
        new AttributeValue(rule.getAttributeType(),
                           DirectoryServer.getSchemaDN().toString());
    return Collections.singleton(value);
  }
opends/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProvider.java
@@ -22,14 +22,15 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import org.opends.messages.Message;
import java.util.LinkedHashSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -124,20 +125,27 @@
   * {@inheritDoc}
   */
  @Override()
  public LinkedHashSet<AttributeValue> getValues(Entry entry,
                                                 VirtualAttributeRule rule)
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    AttributeType attributeType = rule.getAttributeType();
    Set<String> userDefinedValues = currentConfig.getValue();
    LinkedHashSet<AttributeValue> values =
         new LinkedHashSet<AttributeValue>(userDefinedValues.size());
    for (String valueString : userDefinedValues)
    {
      values.add(new AttributeValue(attributeType, valueString));
    switch (userDefinedValues.size()) {
    case 0:
      return Collections.emptySet();
    case 1:
      String valueString = userDefinedValues.iterator().next();
      AttributeValue value = new AttributeValue(attributeType, valueString);
      return Collections.singleton(value);
    default:
      HashSet<AttributeValue> values =
          new HashSet<AttributeValue>(userDefinedValues.size());
      for (String valueString2 : userDefinedValues)
      {
        values.add(new AttributeValue(attributeType, valueString2));
      }
      return Collections.unmodifiableSet(values);
    }
    return values;
  }
opends/src/server/org/opends/server/types/Entry.java
@@ -96,10 +96,6 @@
   */
  private static final DebugTracer TRACER = getTracer();
  // Indicates whether virtual attribute processing has been performed
  // for this entry.
  private boolean virtualAttributeProcessingPerformed;
  // The set of operational attributes for this entry.
  private Map<AttributeType,List<Attribute>> operationalAttributes;
@@ -120,7 +116,7 @@
  private transient Object attachment;
  // The schema used to govern this entry.
  private Schema schema;
  private final Schema schema;
@@ -149,13 +145,9 @@
  {
    attachment                          = null;
    schema                              = DirectoryServer.getSchema();
    virtualAttributeProcessingPerformed = false;
    suppressedAttributes =
         new LinkedHashMap<AttributeType,List<Attribute>>();
    if (dn == null)
    {
      this.dn = DN.nullDN();
@@ -1214,114 +1206,6 @@
  /**
   * Makes a copy of attributes matching the specified options.
   *
   * @param  attrList       The attributes to be copied.
   * @param  options        The set of attribute options to include in
   *                        matching elements.
   * @param  omitValues     <CODE>true</CODE> if the values are to be
   *                        omitted.
   *
   * @return  A copy of the attributes matching the specified options,
   *          or <CODE>null</CODE> if there is no such attribute with
   *          the specified set of options.
   */
  private static List<Attribute> duplicateAttribute(
       List<Attribute> attrList,
       Set<String> options,
       boolean omitValues)
  {
    if (attrList == null)
    {
      return null;
    }
    ArrayList<Attribute> duplicateList =
         new ArrayList<Attribute>(attrList.size());
    for (Attribute a : attrList)
    {
      if (a.hasAllOptions(options))
      {
        if (omitValues && !a.isVirtual())
        {
          duplicateList.add(Attributes.empty(a));
        }
        else
        {
          duplicateList.add(a);
        }
      }
    }
    if (duplicateList.isEmpty())
    {
      return null;
    }
    else
    {
      return duplicateList;
    }
  }
  /**
   * Retrieves a copy of the requested user 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  options        The set of attribute options to include in
   *                        matching elements.
   * @param  omitValues     <CODE>true</CODE> if the values are to be
   *                        omitted.
   *
   * @return  A copy of the requested attribute element(s) for the
   *          specified attribute type, or <CODE>null</CODE> if there
   *          is no such user attribute with the specified set of
   *          options.
   */
  public List<Attribute> duplicateUserAttribute(
       AttributeType attributeType,
       Set<String> options,
       boolean omitValues)
  {
    List<Attribute> currentList = getUserAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues);
  }
  /**
   * Retrieves a copy of the requested operational 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  options        The set of attribute options to include in
   *                        matching elements.
   * @param  omitValues     <CODE>true</CODE> if the values are to be
   *                        omitted.
   *
   * @return  A copy of the requested attribute element(s) for the
   *          specified attribute type, or <CODE>null</CODE> if there
   *          is no such user attribute with the specified set of
   *          options.
   */
  public List<Attribute> duplicateOperationalAttribute(
       AttributeType attributeType,
       Set<String> options,
       boolean omitValues)
  {
    List<Attribute> currentList =
         getOperationalAttribute(attributeType);
    return duplicateAttribute(currentList, options, omitValues);
  }
  /**
   * Indicates whether this entry contains the specified operational
   * attribute.
   *
@@ -2966,12 +2850,14 @@
    HashMap<AttributeType,List<Attribute>> userAttrsCopy =
         new HashMap<AttributeType,List<Attribute>>(
              userAttributes.size());
    deepCopy(userAttributes, userAttrsCopy, false);
    deepCopy(userAttributes, userAttrsCopy, false, false, false,
        true);
    HashMap<AttributeType,List<Attribute>> operationalAttrsCopy =
         new HashMap<AttributeType,List<Attribute>>(
                  operationalAttributes.size());
    deepCopy(operationalAttributes, operationalAttrsCopy, false);
    deepCopy(operationalAttributes, operationalAttrsCopy, false,
        false, false, true);
    for (AttributeType t : suppressedAttributes.keySet())
    {
@@ -2999,24 +2885,29 @@
  /**
   * Creates a duplicate of this entry without any operational
   * attributes that may be altered without impacting the information
   * in this entry.
   * attributes that may be altered without impacting the
   * information in this entry.
   * <p>
   * TODO: this method is very specific to search result
   * processing but we are forced to have it here due to tight
   * coupling and performance reasons.
   *
   * @param  typesOnly       Indicates whether to include attribute
   *                         types only without values.
   * @param  processVirtual  Indicates whether virtual attribute
   *                         processing should be performed for the
   *                         entry.
   *
   * @return  A duplicate of this entry that may be altered without
   *          impacting the information in this entry and that does
   *          not contain any operational attributes.
   * @param typesOnly
   *          Indicates whether to include attribute types only
   *          without values.
   * @param omitReal
   *          Indicates whether to exclude real attributes.
   * @param omitVirtual
   *          Indicates whether to exclude virtual attributes.
   * @return A duplicate of this entry that may be altered without
   *         impacting the information in this entry and that does not
   *         contain any operational attributes.
   */
  public Entry duplicateWithoutOperationalAttributes(
                    boolean typesOnly, boolean processVirtual)
      boolean typesOnly, boolean omitReal, boolean omitVirtual)
  {
    HashMap<ObjectClass,String> objectClassesCopy;
    if (typesOnly)
    if (typesOnly || omitReal)
    {
      objectClassesCopy = new HashMap<ObjectClass,String>(0);
    }
@@ -3029,7 +2920,8 @@
    HashMap<AttributeType,List<Attribute>> userAttrsCopy =
         new HashMap<AttributeType,List<Attribute>>(
              userAttributes.size());
    if (typesOnly)
    if (typesOnly && !omitReal)
    {
      // Make sure to include the objectClass attribute here because
      // it won't make it in otherwise.
@@ -3040,49 +2932,47 @@
      userAttrsCopy.put(ocType, ocList);
    }
    deepCopy(userAttributes, userAttrsCopy, typesOnly);
    deepCopy(userAttributes, userAttrsCopy, typesOnly, true,
        omitReal, omitVirtual);
    HashMap<AttributeType,List<Attribute>> operationalAttrsCopy =
         new HashMap<AttributeType,List<Attribute>>(0);
    for (AttributeType t : suppressedAttributes.keySet())
    {
      List<Attribute> attrList = suppressedAttributes.get(t);
      if (! t.isOperational())
      {
        userAttributes.put(t, attrList);
      }
    }
    Entry e = new Entry(dn, objectClassesCopy, userAttrsCopy,
                        operationalAttrsCopy);
    if (processVirtual)
    {
      e.processVirtualAttributes(false);
    }
    return e;
  }
  /**
   * Performs a deep copy from the source map to the target map.  In
   * this case, the attributes in the list will be duplicates rather
   * than re-using the same reference.  Virtual attributes will not be
   * included when making the copy.
   * Performs a deep copy from the source map to the target map.
   * In this case, the attributes in the list will be duplicates
   * rather than re-using the same reference.
   *
   * @param  source      The source map from which to obtain the
   *                     information.
   * @param  target      The target map into which to place the
   *                     copied information.
   * @param  omitValues  Indicates whether to omit attribute values
   *                     when processing.
   * @param source
   *          The source map from which to obtain the information.
   * @param target
   *          The target map into which to place the copied
   *          information.
   * @param omitValues
   *          Indicates whether to omit attribute values when
   *          processing.
   * @param omitEmpty
   *          Indicates whether to omit empty attributes when
   *          processing.
   * @param omitReal
   *          Indicates whether to exclude real attributes.
   * @param omitVirtual
   *          Indicates whether to exclude virtual attributes.
   */
  private void deepCopy(Map<AttributeType,List<Attribute>> source,
                        Map<AttributeType,List<Attribute>> target,
                        boolean omitValues)
                        boolean omitValues,
                        boolean omitEmpty,
                        boolean omitReal,
                        boolean omitVirtual)
  {
    for (AttributeType t : source.keySet())
    {
@@ -3092,12 +2982,19 @@
      for (Attribute a : sourceList)
      {
        if (a.isVirtual())
        if (omitReal && !a.isVirtual())
        {
          continue;
        }
        if (omitValues)
        else if (omitVirtual && a.isVirtual())
        {
          continue;
        }
        else if (omitEmpty && a.isEmpty())
        {
          continue;
        }
        else if (omitValues)
        {
          targetList.add(Attributes.empty(a));
        }
@@ -3107,7 +3004,7 @@
        }
      }
      if (! targetList.isEmpty())
      if (!targetList.isEmpty())
      {
        target.put(t, targetList);
      }
@@ -3569,133 +3466,6 @@
        }
      }
    }
    virtualAttributeProcessingPerformed = true;
  }
  /**
   * Indicates whether virtual attribute processing has been performed
   * for this entry.
   *
   * @return  {@code true} if virtual attribute processing has been
   *          performed for this entry, or {@code false} if not.
   */
  public boolean virtualAttributeProcessingPerformed()
  {
    return virtualAttributeProcessingPerformed;
  }
  /**
   * Strips out all real attributes from this entry so that it only
   * contains virtual attributes.
   */
  public void stripRealAttributes()
  {
    // The objectClass attribute will always be a real attribute.
    objectClasses.clear();
    Iterator<Map.Entry<AttributeType,List<Attribute>>>
         attrListIterator = userAttributes.entrySet().iterator();
    while (attrListIterator.hasNext())
    {
      Map.Entry<AttributeType,List<Attribute>> mapEntry =
           attrListIterator.next();
      Iterator<Attribute> attrIterator =
           mapEntry.getValue().iterator();
      while (attrIterator.hasNext())
      {
        Attribute a = attrIterator.next();
        if (! a.isVirtual())
        {
          attrIterator.remove();
        }
      }
      if (mapEntry.getValue().isEmpty())
      {
        attrListIterator.remove();
      }
    }
    attrListIterator = operationalAttributes.entrySet().iterator();
    while (attrListIterator.hasNext())
    {
      Map.Entry<AttributeType,List<Attribute>> mapEntry =
           attrListIterator.next();
      Iterator<Attribute> attrIterator =
           mapEntry.getValue().iterator();
      while (attrIterator.hasNext())
      {
        Attribute a = attrIterator.next();
        if (! a.isVirtual())
        {
          attrIterator.remove();
        }
      }
      if (mapEntry.getValue().isEmpty())
      {
        attrListIterator.remove();
      }
    }
  }
  /**
   * Strips out all virtual attributes from this entry so that it only
   * contains real attributes.
   */
  public void stripVirtualAttributes()
  {
    Iterator<Map.Entry<AttributeType,List<Attribute>>>
         attrListIterator = userAttributes.entrySet().iterator();
    while (attrListIterator.hasNext())
    {
      Map.Entry<AttributeType,List<Attribute>> mapEntry =
           attrListIterator.next();
      Iterator<Attribute> attrIterator =
           mapEntry.getValue().iterator();
      while (attrIterator.hasNext())
      {
        Attribute a = attrIterator.next();
        if (a.isVirtual())
        {
          attrIterator.remove();
        }
      }
      if (mapEntry.getValue().isEmpty())
      {
        attrListIterator.remove();
      }
    }
    attrListIterator = operationalAttributes.entrySet().iterator();
    while (attrListIterator.hasNext())
    {
      Map.Entry<AttributeType,List<Attribute>> mapEntry =
           attrListIterator.next();
      Iterator<Attribute> attrIterator =
           mapEntry.getValue().iterator();
      while (attrIterator.hasNext())
      {
        Attribute a = attrIterator.next();
        if (a.isVirtual())
        {
          attrIterator.remove();
        }
      }
      if (mapEntry.getValue().isEmpty())
      {
        attrListIterator.remove();
      }
    }
  }
@@ -5652,6 +5422,7 @@
   *
   * @return  A string representation of this protocol element.
   */
  @Override
  public String toString()
  {
    StringBuilder buffer = new StringBuilder();
opends/src/server/org/opends/server/types/VirtualAttribute.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -131,18 +131,6 @@
  /**
   * Retrieves the entry in which this virtual attribute exists.
   *
   * @return The entry in which this virtual attribute exists.
   */
  public Entry getEntry()
  {
    return entry;
  }
  /**
   * {@inheritDoc}
   */
  @Override
@@ -247,7 +235,7 @@
  public Iterator<AttributeValue> iterator()
  {
    Set<AttributeValue> values = provider.getValues(entry, rule);
    return Collections.unmodifiableSet(values).iterator();
    return values.iterator();
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 */
package org.opends.server.core;
@@ -37,18 +37,20 @@
import org.opends.server.protocols.ldap.*;
import org.opends.server.types.*;
import org.opends.server.TestCaseUtils;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
import org.opends.server.controls.MatchedValuesFilter;
import org.opends.server.controls.MatchedValuesControl;
import org.opends.server.plugins.InvocationCounterPlugin;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.net.Socket;
import java.io.IOException;
@@ -418,6 +420,7 @@
    Entry resultEntry = searchInternalForSingleEntry(searchOperation);
    assertEquals(resultEntry.getObjectClasses().size(), 0);
    assertEquals(resultEntry.getUserAttributes().size(),
                 testEntry.getUserAttributes().size() + 1);
    assertEquals(resultEntry.getOperationalAttributes().size(), 0);
@@ -887,4 +890,257 @@
    assertEquals(searchOperation.getResultCode(), ResultCode.NO_SUCH_OBJECT);
    assertNotNull(searchOperation.getMatchedDN());
  }
  /**
   * Determines how attributes should be filtered in search operations.
   */
  private enum AttributeFilterType {
    DEFAULT, WILDCARDS, ENUMERATED;
  }
  /**
   * Returns test data for testSearchInternalAttributeFilters.
   *
   * @return The test data.
   */
  @DataProvider(name = "testSearchInternalAttributeFilters")
  public Object[][] createTestSearchInternalAttributeFiltersData()
  {
    // It was quicker to cut n paste...
    return new Object[][] {
        {AttributeFilterType.DEFAULT,     false, false, false},
        {AttributeFilterType.DEFAULT,     false, false, true},
        {AttributeFilterType.DEFAULT,     false, true,  false},
        {AttributeFilterType.DEFAULT,     false, true,  true},
        {AttributeFilterType.DEFAULT,     true,  false, false},
        {AttributeFilterType.DEFAULT,     true,  false, true},
        {AttributeFilterType.DEFAULT,     true,  true,  false},
        {AttributeFilterType.DEFAULT,     true,  true,  true},
        {AttributeFilterType.WILDCARDS,   false, false, false},
        {AttributeFilterType.WILDCARDS,   false, false, true},
        {AttributeFilterType.WILDCARDS,   false, true,  false},
        {AttributeFilterType.WILDCARDS,   false, true,  true},
        {AttributeFilterType.WILDCARDS,   true,  false, false},
        {AttributeFilterType.WILDCARDS,   true,  false, true},
        {AttributeFilterType.WILDCARDS,   true,  true,  false},
        {AttributeFilterType.WILDCARDS,   true,  true,  true},
        {AttributeFilterType.ENUMERATED,  false, false, false},
        {AttributeFilterType.ENUMERATED,  false, false, true},
        {AttributeFilterType.ENUMERATED,  false, true,  false},
        {AttributeFilterType.ENUMERATED,  false, true,  true},
        {AttributeFilterType.ENUMERATED,  true,  false, false},
        {AttributeFilterType.ENUMERATED,  true,  false, true},
        {AttributeFilterType.ENUMERATED,  true,  true,  false},
        {AttributeFilterType.ENUMERATED,  true,  true,  true},
    };
  }
  /**
   * Tests that attribute filtering is performed correctly for real and
   * virtual attributes when various combinations of typesOnly, and the
   * real-attributes-only and virtual-attributes-only controls are used
   * (issues 3446 and 3726).
   *
   * @param filterType
   *          Specifies how attributes should be filtered.
   * @param typesOnly
   *          Strip attribute values.
   * @param stripVirtualAttributes
   *          Strip virtual attributes.
   * @param stripRealAttributes
   *          Strip real attributes.
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test(dataProvider = "testSearchInternalAttributeFilters")
  public void testSearchInternalAttributeFilters(
      AttributeFilterType filterType, boolean typesOnly,
      boolean stripVirtualAttributes, boolean stripRealAttributes)
      throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    // Real attributes (these are all user attributes).
    List<String> realAttrTypes =
        Arrays.asList("objectclass", "uid", "cn", "sn", "givenname",
            "userpassword");
    // Virtual attributes (these are all operational attributes).
    List<String> virtualAttrTypes =
        Arrays.asList("numsubordinates", "hassubordinates",
            "subschemasubentry", "entrydn", "ismemberof");
    String userDNString = "uid=test.user,o=test";
    DN userDN = DN.decode(userDNString);
    TestCaseUtils.addEntry("dn: " + userDNString,
        "objectClass: top",
        "objectClass: person",
        "objectClass: organizationalPerson",
        "objectClass: inetOrgPerson",
        "uid: test.user",
        "givenName: Test",
        "sn: User",
        "cn: Test User",
        "userPassword: password");
    Entry userEntry = DirectoryServer.getEntry(userDN);
    assertNotNull(userEntry);
    LinkedHashSet<String> attributes = new LinkedHashSet<String>();
    switch (filterType)
    {
    case DEFAULT:
      // Only user attributes.
      attributes = null;
      break;
    case WILDCARDS:
      attributes.add("*");
      attributes.add("+");
      break;
    case ENUMERATED:
      attributes.addAll(realAttrTypes);
      attributes.addAll(virtualAttrTypes);
      break;
    }
    List<Control> controls = new LinkedList<Control>();
    if (stripRealAttributes)
    {
      controls.add(new Control(ServerConstants.OID_VIRTUAL_ATTRS_ONLY,
          false));
    }
    if (stripVirtualAttributes)
    {
      controls.add(new Control(ServerConstants.OID_REAL_ATTRS_ONLY,
          false));
    }
    InternalClientConnection conn =
        InternalClientConnection.getRootConnection();
    InternalSearchOperation search =
        conn.processSearch(userDNString, SearchScope.BASE_OBJECT,
            DereferencePolicy.NEVER_DEREF_ALIASES, 0, // Size limit
            0, // Time limit
            typesOnly, // Types only
            "(objectClass=*)", attributes, controls, null);
    assertEquals(search.getResultCode(), ResultCode.SUCCESS);
    LinkedList<SearchResultEntry> entries = search.getSearchEntries();
    assertEquals(entries.size(), 1);
    Entry entry = entries.getFirst();
    assertEquals(entry.getDN(), userDN);
    // Check real attributes.
    List<String> messages = new LinkedList<String>();
    for (String attrType : realAttrTypes)
    {
      List<Attribute> attrList = entry.getAttribute(attrType);
      if (stripRealAttributes)
      {
        if (attrList != null)
        {
          messages.add("Unexpected real attribute: " + attrType);
        }
      }
      else
      {
        if (attrList == null)
        {
          messages.add("Missing real attribute: " + attrType);
        }
        else
        {
          Attribute attr = attrList.get(0);
          if (typesOnly)
          {
            if (!attr.isEmpty())
            {
              messages.add("Unexpected non-empty real attribute: "
                  + attrType);
            }
          }
          else
          {
            if (attr.isEmpty())
            {
              messages.add("Unexpected empty real attribute: "
                  + attrType);
            }
          }
        }
      }
    }
    // Check virtual (operational) attributes.
    for (String attrType : virtualAttrTypes)
    {
      List<Attribute> attrList = entry.getAttribute(attrType);
      if (stripVirtualAttributes)
      {
        if (attrList != null)
        {
          messages.add("Unexpected virtual attribute: " + attrType);
        }
      }
      else if (filterType == AttributeFilterType.DEFAULT)
      {
        if (attrList != null)
        {
          messages.add("Unexpected operational attribute: " + attrType);
        }
      }
      else if (attrType.equals("ismemberof"))
      {
        // isMemberOf should never be returned as user is not in any
        // groups.
        if (attrList != null)
        {
          messages.add("Unexpected isMemberOf attribute");
        }
      }
      else
      {
        if (attrList == null)
        {
          messages.add("Missing virtual attribute: " + attrType);
        }
        else
        {
          Attribute attr = attrList.get(0);
          if (typesOnly)
          {
            if (!attr.isEmpty())
            {
              messages.add("Unexpected non-empty virtual attribute: "
                  + attrType);
            }
          }
          else
          {
            if (attr.isEmpty())
            {
              messages.add("Unexpected empty virtual attribute: "
                  + attrType);
            }
          }
        }
      }
    }
    assertTrue(messages.isEmpty(), "Entry invalid: " + messages);
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryDNVirtualAttributeProviderTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -32,6 +32,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -560,7 +561,7 @@
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertEquals(values.size(), 1);
    assertTrue(values.contains(new AttributeValue(entryDNType, "o=test")));
@@ -1104,7 +1105,7 @@
                                     0, false, filter, null, null);
    LocalBackendSearchOperation localSearch =
      new LocalBackendSearchOperation(searchOperation);
    provider.processSearch(rule, localSearch);
    if (shouldMatch)
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntryUUIDVirtualAttributeProviderTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -32,6 +32,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.testng.annotations.BeforeClass;
@@ -574,7 +575,7 @@
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertEquals(values.size(), 1);
    assertTrue(values.contains(new AttributeValue(entryUUIDType, uuidString)));
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/IsMemberOfVirtualAttributeProviderTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -31,7 +31,6 @@
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -49,7 +48,6 @@
import org.opends.server.types.ByteString;
import org.opends.server.types.ByteStringFactory;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.Control;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
@@ -61,8 +59,6 @@
import static org.testng.Assert.*;
import static org.opends.server.util.ServerConstants.*;
/**
@@ -1107,8 +1103,10 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                                     conn.nextMessageID(), null,
         new InternalSearchOperation(conn,
                                     InternalClientConnection.nextOperationID(),
                                     InternalClientConnection.nextMessageID(),
                                     null,
                                     DN.decode("o=test"),
                                     SearchScope.WHOLE_SUBTREE,
                                     DereferencePolicy.NEVER_DEREF_ALIASES, 0,
@@ -1232,8 +1230,10 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                                     conn.nextMessageID(), null,
         new InternalSearchOperation(conn,
                                     InternalClientConnection.nextOperationID(),
                                     InternalClientConnection.nextMessageID(),
                                     null,
                                     DN.decode("o=test"),
                                     SearchScope.WHOLE_SUBTREE,
                                     DereferencePolicy.NEVER_DEREF_ALIASES, 0,
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProviderTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -32,6 +32,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -45,9 +46,6 @@
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.ByteStringFactory;
import org.opends.server.types.ConditionResult;
import org.opends.server.types.Control;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DN;
@@ -559,7 +557,7 @@
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertEquals(values.size(), 1);
    assertTrue(values.contains(new AttributeValue(subschemaSubentryType,
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/VirtualStaticGroupTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -32,6 +32,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -658,7 +659,7 @@
    assertTrue(provider.isMultiValued());
    LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertFalse(values.isEmpty());
    assertTrue(provider.hasValue(entry, rule));
@@ -737,7 +738,7 @@
    assertTrue(provider.isMultiValued());
    LinkedHashSet<AttributeValue> values = provider.getValues(entry, rule);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertTrue(values.isEmpty());
    assertFalse(provider.hasValue(entry, rule));
opends/tests/unit-tests-testng/src/server/org/opends/server/types/VirtualAttributeTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.types;
@@ -102,10 +102,6 @@
  public void testGetters()
         throws Exception
  {
    assertNotNull(virtualAttribute.getEntry());
    assertEquals(virtualAttribute.getEntry().getDN(),
                 DN.decode("o=test"));
    assertEquals(virtualAttribute.getVirtualAttributeRule(),
                 virtualAttributeRule);