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

sin
15.38.2009 be7229164665d731e28aff50068366a1733b9f07
issue 3961:Implement operational attribute 'governingstructurerule
6 files added
5 files modified
2458 ■■■■■ changed files
opends/resource/config/config.ldif 20 ●●●●● patch | view | raw | blame | history
opends/resource/schema/00-core.ldif 6 ●●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif 10 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/GoverningStructureRuleVirtualAttributeConfiguration.xml 69 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/StructuralObjectClassVirtualAttributeConfiguration.xml 69 ●●●●● patch | view | raw | blame | history
opends/src/messages/messages/extension.properties 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProvider.java 298 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProvider.java 214 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java 2 ●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java 898 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java 870 ●●●●● patch | view | raw | blame | history
opends/resource/config/config.ldif
@@ -2394,6 +2394,26 @@
ds-cfg-attribute-type: subschemaSubentry
ds-cfg-conflict-behavior: virtual-overrides-real
dn: cn=structuralObjectClass,cn=Virtual Attributes,cn=config
objectClass: top
objectClass: ds-cfg-virtual-attribute
objectClass: ds-cfg-structural-object-class-virtual-attribute
cn: structuralObjectClass
ds-cfg-java-class: org.opends.server.extensions.StructuralObjectClassVirtualAttributeProvider
ds-cfg-enabled: true
ds-cfg-attribute-type: structuralObjectClass
ds-cfg-conflict-behavior: virtual-overrides-real
dn: cn=governingStructureRule,cn=Virtual Attributes,cn=config
objectClass: top
objectClass: ds-cfg-virtual-attribute
objectClass: ds-cfg-governing-structure-rule-virtual-attribute
cn: governingStructureRule
ds-cfg-java-class: org.opends.server.extensions.GoverningStructureRuleVirtualAttributeProvider
ds-cfg-enabled: true
ds-cfg-attribute-type: governingStructureRule
ds-cfg-conflict-behavior: virtual-overrides-real
dn: cn=Virtual Static member,cn=Virtual Attributes,cn=config
objectClass: top
objectClass: ds-cfg-virtual-attribute
opends/resource/schema/00-core.ldif
@@ -195,6 +195,12 @@
attributeTypes: ( 2.5.21.8 NAME 'matchingRuleUse' EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation
  X-ORIGIN 'RFC 4512' )
attributeTypes: ( 2.5.21.9 NAME 'structuralObjectClass' EQUALITY objectIdentifierMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 SINGLE-VALUE NO-USER-MODIFICATION
  USAGE directoryOperation X-ORIGIN 'RFC 4512' )
attributeTypes: ( 2.5.21.10 NAME 'governingStructureRule' EQUALITY integerMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE NO-USER-MODIFICATION
  USAGE directoryOperation X-ORIGIN 'RFC 4512' )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation X-ORIGIN 'RFC 4512' )
attributeTypes: ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer'
opends/resource/schema/02-config.ldif
@@ -4039,4 +4039,14 @@
  SUP ds-cfg-backend
  STRUCTURAL
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.201
  NAME 'ds-cfg-structural-object-class-virtual-attribute'
  SUP ds-cfg-virtual-attribute
  STRUCTURAL
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.202
  NAME 'ds-cfg-governing-structure-rule-virtual-attribute'
  SUP ds-cfg-virtual-attribute
  STRUCTURAL
  X-ORIGIN 'OpenDS Directory Server' )
opends/src/admin/defn/org/opends/server/admin/std/GoverningStructureRuleVirtualAttributeConfiguration.xml
New file
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ! CDDL HEADER START
  !
  ! The contents of this file are subject to the terms of the
  ! Common Development and Distribution License, Version 1.0 only
  ! (the "License").  You may not use this file except in compliance
  ! with the License.
  !
  ! You can obtain a copy of the license at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
  ! See the License for the specific language governing permissions
  ! and limitations under the License.
  !
  ! When distributing Covered Code, include this CDDL HEADER in each
  ! file and include the License file at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
  ! add the following below this CDDL HEADER, with the fields enclosed
  ! by brackets "[]" replaced with your own identifying information:
  !      Portions Copyright [yyyy] [name of copyright owner]
  !
  ! CDDL HEADER END
  !
  !
  !      Copyright 2009 Sun Microsystems, Inc.
  ! -->
<adm:managed-object name="governing-structure-rule-virtual-attribute"
  plural-name="governing-structure-rule-virtual-attributes"
  package="org.opends.server.admin.std" extends="virtual-attribute"
  xmlns:adm="http://www.opends.org/admin"
  xmlns:ldap="http://www.opends.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
      generates a virtual attribute that specifies the DIT structure rule
      with the schema definitions in effect for the
      entry. This attribute is defined in RFC 4512.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-governing-structure-rule-virtual-attribute</ldap:name>
      <ldap:superior>ds-cfg-virtual-attribute</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.GoverningSturctureRuleVirtualAttributeProvider
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-override name="conflict-behavior" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>virtual-overrides-real</adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-override name="attribute-type">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>governingStructureRule</adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
</adm:managed-object>
opends/src/admin/defn/org/opends/server/admin/std/StructuralObjectClassVirtualAttributeConfiguration.xml
New file
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
  ! CDDL HEADER START
  !
  ! The contents of this file are subject to the terms of the
  ! Common Development and Distribution License, Version 1.0 only
  ! (the "License").  You may not use this file except in compliance
  ! with the License.
  !
  ! You can obtain a copy of the license at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
  ! See the License for the specific language governing permissions
  ! and limitations under the License.
  !
  ! When distributing Covered Code, include this CDDL HEADER in each
  ! file and include the License file at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
  ! add the following below this CDDL HEADER, with the fields enclosed
  ! by brackets "[]" replaced with your own identifying information:
  !      Portions Copyright [yyyy] [name of copyright owner]
  !
  ! CDDL HEADER END
  !
  !
  !      Copyright 2009 Sun Microsystems, Inc.
  ! -->
<adm:managed-object name="structural-object-class-virtual-attribute"
  plural-name="structural-object-class-virtual-attributes"
  package="org.opends.server.admin.std" extends="virtual-attribute"
  xmlns:adm="http://www.opends.org/admin"
  xmlns:ldap="http://www.opends.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
      generates a virtual attribute that specifies the structural object class
      with the schema definitions in effect for the
      entry. This attribute is defined in RFC 4512.
  </adm:synopsis>
  <adm:profile name="ldap">
    <ldap:object-class>
      <ldap:name>ds-cfg-structural-object-class-virtual-attribute</ldap:name>
      <ldap:superior>ds-cfg-virtual-attribute</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-class" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.extensions.StructuralObjectClassVirtualAttributeProvider
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-override name="conflict-behavior" advanced="true">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>virtual-overrides-real</adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-override name="attribute-type">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>structuralObjectClass</adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
</adm:managed-object>
opends/src/messages/messages/extension.properties
@@ -1134,7 +1134,7 @@
MILD_ERR_UNIQUECHARS_VALIDATOR_NOT_ENOUGH_UNIQUE_CHARS_458=The provided \
 password does not contain enough unique characters.  The minimum number of \
 unique characters that may appear in a user password is %d
MILD_ERR_SUBSCHEMASUBENTRY_VATTR_NOT_SEARCHABLE_459=The %s attribute is not \
MILD_ERR_VATTR_NOT_SEARCHABLE_459=The %s attribute is not \
 searchable and should not be included in otherwise unindexed search filters
MILD_ERR_DICTIONARY_VALIDATOR_PASSWORD_IN_DICTIONARY_460=The provided \
 password was found in the server's dictionary
opends/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProvider.java
New file
@@ -0,0 +1,298 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.
        GoverningStructureRuleVirtualAttributeCfg;
import org.opends.server.api.VirtualAttributeProvider;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.SearchOperation;
import org.opends.server.types.*;
import static org.opends.messages.ExtensionMessages.*;
/**
 * This class implements a virtual attribute provider that is meant to serve
 * the governingStructuralRule operational attribute as described in RFC 4512.
 */
public class GoverningStructureRuleVirtualAttributeProvider  extends
         VirtualAttributeProvider<GoverningStructureRuleVirtualAttributeCfg>
{
  /**
   * Creates a new instance of this governingStructureRule virtual attribute
   * provider.
   */
  public GoverningStructureRuleVirtualAttributeProvider()
  {
    super();
    // All initialization should be performed in the
    // initializeVirtualAttributeProvider method.
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public void initializeVirtualAttributeProvider(
                      GoverningStructureRuleVirtualAttributeCfg configuration)
         throws ConfigException, InitializationException
  {
    // No initialization is required.
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isMultiValued()
  {
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    DITStructureRule ditRule = getDITStructureRule(entry);
    if(ditRule !=null)
    {
      return Collections.singleton(AttributeValues.create(
                  rule.getAttributeType(),
                  String.valueOf(ditRule.getRuleID())));
    }
    return Collections.<AttributeValue>emptySet();
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean hasValue(Entry entry, VirtualAttributeRule rule)
  {
    return getDITStructureRule(entry)!=null;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult matchesSubstring(Entry entry,
                                          VirtualAttributeRule rule,
                                          ByteString subInitial,
                                          List<ByteString> subAny,
                                          ByteString subFinal)
  {
    // DITStructureRule cannot be used in substring matching.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult greaterThanOrEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // DITStructureRule cannot be used in ordering matching.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult lessThanOrEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // DITStructureRule cannot be used in ordering matching.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult approximatelyEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // DITStructureRule cannot be used in approximate matching.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}.  This virtual attribute will support search operations only
   * if one of the following is true about the search filter:
   * <UL>
   *   <LI>It is an equality filter targeting the associated attribute
   *       type.</LI>
   *   <LI>It is an AND filter in which at least one of the components is an
   *       equality filter targeting the associated attribute type.</LI>
   *   <LI>It is an OR filter in which all of the components are equality
   *       filters targeting the associated attribute type.</LI>
   * </UL>
   */
  @Override()
  public boolean isSearchable(VirtualAttributeRule rule,
                              SearchOperation searchOperation)
  {
    //Non-searchable for unindexed searches.
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public void processSearch(VirtualAttributeRule rule,
                            SearchOperation searchOperation)
  {
    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
    Message message = ERR_VATTR_NOT_SEARCHABLE.get(
            rule.getAttributeType().getNameOrOID());
    searchOperation.appendErrorMessage(message);
  }
  //Checks if the entry matches the nameform.
  private boolean matchesNameForm(NameForm nameForm,
                       AcceptRejectWarn structuralPolicy,
                       Entry entry)
  {
    RDN rdn = entry.getDN().getRDN();
    if (rdn != null)
    {
      // Make sure that all the required attributes are present.
      for (AttributeType t : nameForm.getRequiredAttributes())
      {
        if (! rdn.hasAttributeType(t))
        {
          if (structuralPolicy == AcceptRejectWarn.REJECT)
          {
            return false;
          }
        }
      }
      // Make sure that all attributes in the RDN are allowed.
      int numAVAs = rdn.getNumValues();
      for (int i = 0; i < numAVAs; i++)
      {
        AttributeType t = rdn.getAttributeType(i);
        if (! nameForm.isRequiredOrOptional(t))
        {
          if (structuralPolicy == AcceptRejectWarn.REJECT)
          {
            return false;
          }
        }
       }
     }
    return true;
  }
  //Finds the appropriate DIT structure rule for an entry.
  private DITStructureRule getDITStructureRule(Entry entry)
  {
    ObjectClass oc = entry.getStructuralObjectClass();
    List<NameForm> listForms = DirectoryServer.getNameForm(oc);
    NameForm nameForm = null;
    DITStructureRule ditRule = null;
    //We iterate over all the nameforms while creating the entry and
    //select the first one that matches. Since the entry exists, the same
    //algorithm should work fine to retrieve the nameform which was
    //applied while creating the entry.
    if(listForms != null)
    {
      boolean obsolete = true;
      AcceptRejectWarn structuralPolicy =
         DirectoryServer.getSingleStructuralObjectClassPolicy();
      for(NameForm nf : listForms)
      {
        if(!nf.isObsolete())
        {
          obsolete = false;
          if(matchesNameForm(nf,
                  structuralPolicy, entry))
          {
           nameForm = nf;
           break;
          }
        }
      }
      if( nameForm != null && !obsolete)
      {
        ditRule =
                DirectoryServer.getDITStructureRule(nameForm);
      }
    }
    return ditRule;
  }
}
opends/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProvider.java
New file
@@ -0,0 +1,214 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.
        StructuralObjectClassVirtualAttributeCfg;
import org.opends.server.api.VirtualAttributeProvider;
import org.opends.server.config.ConfigException;
import org.opends.server.core.SearchOperation;
import org.opends.server.types.*;
import static org.opends.messages.ExtensionMessages.*;
/**
 * This class implements a virtual attribute provider that is meant to serve
 * the structuralObjectClass operational attribute as described in RFC 4512.
 */
public class StructuralObjectClassVirtualAttributeProvider
     extends VirtualAttributeProvider<StructuralObjectClassVirtualAttributeCfg>
{
  /**
   * Creates a new instance of this structuralObjectClass virtual attribute
   * provider.
   */
  public StructuralObjectClassVirtualAttributeProvider()
  {
    super();
    // All initialization should be performed in the
    // initializeVirtualAttributeProvider method.
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public void initializeVirtualAttributeProvider(
                    StructuralObjectClassVirtualAttributeCfg configuration)
         throws ConfigException, InitializationException
  {
    // No initialization is required.
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean isMultiValued()
  {
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public Set<AttributeValue> getValues(Entry entry,
                                       VirtualAttributeRule rule)
  {
    AttributeValue value =
        AttributeValues.create(rule.getAttributeType(),
        entry.getStructuralObjectClass().getNameOrOID());
    return Collections.singleton(value);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean hasValue(Entry entry, VirtualAttributeRule rule)
  {
    //A structural object class is always present in an entry.
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult matchesSubstring(Entry entry,
                                          VirtualAttributeRule rule,
                                          ByteString subInitial,
                                          List<ByteString> subAny,
                                          ByteString subFinal)
  {
    //Substring matching is not supported.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult greaterThanOrEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // An object class can not be used for ordering.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult lessThanOrEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // An object class can not be used for ordering.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public ConditionResult approximatelyEqualTo(Entry entry,
                              VirtualAttributeRule rule,
                              AttributeValue value)
  {
    // An object class can not be used in approximate matching.
    return ConditionResult.UNDEFINED;
  }
  /**
   * {@inheritDoc}.  This virtual attribute will support search operations only
   * if one of the following is true about the search filter:
   * <UL>
   *   <LI>It is an equality filter targeting the associated attribute
   *       type.</LI>
   *   <LI>It is an AND filter in which at least one of the components is an
   *       equality filter targeting the associated attribute type.</LI>
   *   <LI>It is an OR filter in which all of the components are equality
   *       filters targeting the associated attribute type.</LI>
   * </UL>
   */
  @Override()
  public boolean isSearchable(VirtualAttributeRule rule,
                              SearchOperation searchOperation)
  {
    // This attribute is not searchable, since it will have the same value in
    // tons of entries.
    return false;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public void processSearch(VirtualAttributeRule rule,
                            SearchOperation searchOperation)
  {
    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
    Message message = ERR_VATTR_NOT_SEARCHABLE.get(
            rule.getAttributeType().getNameOrOID());
    searchOperation.appendErrorMessage(message);
  }
}
opends/src/server/org/opends/server/extensions/SubschemaSubentryVirtualAttributeProvider.java
@@ -194,7 +194,7 @@
  {
    searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
    Message message = ERR_SUBSCHEMASUBENTRY_VATTR_NOT_SEARCHABLE.get(
    Message message = ERR_VATTR_NOT_SEARCHABLE.get(
            rule.getAttributeType().getNameOrOID());
    searchOperation.appendErrorMessage(message);
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/GoverningStructureRuleVirtualAttributeProviderTestCase.java
New file
@@ -0,0 +1,898 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import static org.opends.server.util.ServerConstants.*;
import static org.testng.Assert.*;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchScope;
import org.opends.server.types.VirtualAttributeRule;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * A set of test cases for the governing structure rule virtual attribute
 * provider.
 */
public class GoverningStructureRuleVirtualAttributeProviderTestCase
       extends ExtensionsTestCase
{
  // The attribute type for the governingStructureRule attribute.
  private AttributeType governingStructureRuleType;
  /**
   * Ensures that the Directory Server is running.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
    governingStructureRuleType =
         DirectoryServer.getAttributeType("governingstructurerule", false);
    assertNotNull(governingStructureRuleType);
    int resultCode = TestCaseUtils.applyModifications(true,
    "dn: cn=schema",
    "changetype: modify",
    "add: nameForms",
    "nameForms: ( domainNameForm-oid NAME 'domainNameForm' OC domain MUST ( dc ) )",
    "nameForms: ( organizationalNameForm-oid NAME 'organizationalNameForm' OC organization MUST ( o ) )",
    "-",
    "add: ditStructureRules",
    "dITStructureRules: ( 21 NAME 'domainStructureRule' FORM domainNameForm )",
    "dITStructureRules: ( 22 NAME 'organizationalStructureRule' FORM organizationalNameForm SUP 21 )"
    );
    assertTrue(resultCode == 0);
  }
  /**
   * Ensures that the schema is cleaned up.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
 @AfterClass()
 public void cleanup() throws Exception
 {
    int resultCode = TestCaseUtils.applyModifications(true,
    "dn: cn=schema",
    "changetype: modify",
    "delete: ditStructureRules",
    "dITStructureRules: ( 22 NAME 'organizationalStructureRule' FORM organizationalNameForm SUP 21 )",
    "dITStructureRules: ( 21 NAME 'domainStructureRule' FORM domainNameForm )",
    "-",
    "delete: nameForms",
    "nameForms: ( domainNameForm-oid NAME 'domainNameForm' OC domain MUST ( dc ) )",
    "nameForms: ( organizationalNameForm-oid NAME 'organizationalNameForm' OC organization MUST ( o ) )"
     );
    assertTrue(resultCode == 0);
 }
  /**
   * Retrieves a set of entry DNs for use in testing the
   * governingStructureRule virtual attribute.
   *
   * @return  A set of entry DNs for use in testing the governingStructureRule
   *          virtual attribute.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @DataProvider(name = "testEntryDNs")
  public Object[][] getTestEntryDNs()
         throws Exception
  {
    return new Object[][]
    {
      new Object[] { DN.decode("o=test") },
      new Object[] { DN.decode("dc=example,dc=com") }
    };
  }
  /**
   * Retrieves a set of entry DNs and corresponding governing structure rule
   * ids for use in testing the governingStructureRule virtual attribute.
   *
   * @return  A set of entry DNs and id for use in testing the
   *           governingStructureRule virtual attribute.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @DataProvider(name = "testDNRuleID")
  public Object[][] getTestEntryDNRuleID()
         throws Exception
  {
    return new Object[][] {
        {DN.decode("o=test"), "22"},
        {DN.decode("dc=example,dc=com"), "21"},
    };
  }
  /**
   * Tests the {@code getEntry} method for the specified entry to ensure that
   * the entry returned includes the governingStructureRule operational
   * attribute with the correct value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   * @param ruleId The rule id of the DITStructureRule.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testDNRuleID")
  public void testGetEntry(DN entryDN,String ruleId)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    Entry e = DirectoryServer.getEntry(entryDN);
    assertNotNull(e);
    assertTrue(e.hasAttribute(governingStructureRuleType));
    List<Attribute> attrList = e.getAttribute(governingStructureRuleType);
    assertNotNull(attrList);
    assertFalse(attrList.isEmpty());
    for (Attribute a : attrList)
    {
      assertTrue(!a.isEmpty());
      assertEquals(a.size(), 1);
      assertTrue(a.contains(AttributeValues.create(governingStructureRuleType,
                              ruleId)));
    }
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is not included when the list of attributes
   * requested is empty (defaulting to all user attributes).
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchEmptyAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT, filter);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is not included when the list of requested
   * attributes is "1.1", meaning no attributes.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchNoAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("1.1");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is not included when all user attributes
   * are requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchAllUserAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("*");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRuleType attribute is included when all operational attributes
   * are requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchAllOperationalAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("+");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is included when that attribute is
   * specifically requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchGoverningStructureRulesAttr(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("governingStructureRule");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is not included when it is not in the list
   * of attributes that is explicitly requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchExcludeGovStructRuleAttr(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("objectClass");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is included when that attribute is
   * specifically requested and the governingStructureRule attribute is used in the
   * search filter with a matching value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testDNRuleID")
  public void testSearchGovStructRuleInMatchingFilter(DN entryDN,String oc)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("governingstructurerule="+oc);
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("governingStructureRule");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * no entries are returned when the governingStructureRule attribute is used in the
   * search filter with a non-matching value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchGovStructRuleAttrInNonMatchingFilter(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(governingStructureRule=1)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("governingStructureRuleType");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 0);
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is not included when that attribute is
   * specifically requested and the real attributes only control is included in
   * the request.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchGovStructRuleAttrRealAttrsOnly(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("governingStructureRuleType");
    LinkedList<Control> requestControls = new LinkedList<Control>();
    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
        new InternalSearchOperation(conn, InternalClientConnection
            .nextOperationID(), InternalClientConnection
            .nextMessageID(), requestControls, entryDN,
            SearchScope.BASE_OBJECT,
            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
            attrList, null);
    searchOperation.run();
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the governingStructureRule attribute is included when that attribute is
   * specifically requested and the virtual attributes only control is included
   * in the request.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchGovStructRuleAttrVirtualAttrsOnly(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("governingStructureRule");
    LinkedList<Control> requestControls = new LinkedList<Control>();
    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
    InternalClientConnection conn =
        InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
        new InternalSearchOperation(conn, InternalClientConnection
            .nextOperationID(), InternalClientConnection
            .nextMessageID(), requestControls, entryDN,
            SearchScope.BASE_OBJECT,
            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
            attrList, null);
    searchOperation.run();
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(governingStructureRuleType));
  }
  /**
   * Tests the {@code isMultiValued} method.
   */
  @Test()
  public void testIsMultiValued()
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    assertFalse(provider.isMultiValued());
  }
  /**
   * Tests the {@code getValues} method for an entry.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetValues()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectclass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertEquals(values.size(), 1);
    assertTrue(values.contains(AttributeValues.create(governingStructureRuleType,
                                  "22")));
  }
  /**
   * Tests the {@code hasValue} method variant that doesn't take a specific
   * value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValue()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertTrue(provider.hasValue(entry, rule));
  }
  /**
   * Tests the {@code hasValue} method variant that takes a specific value when
   * the provided value is a match.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasMatchingValue()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectclass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertTrue(provider.hasValue(entry, rule,
        AttributeValues.create(governingStructureRuleType,"22")));
  }
  /**
   * Tests the {@code hasValue} method variant that takes a specific value when
   * the provided value is not a match.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasNonMatchingValue()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertFalse(provider.hasValue(entry, rule,
        AttributeValues.create(governingStructureRuleType,
                                        "1")));
  }
  /**
   * Tests the {@code hasAnyValue} method with an empty set of values.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueEmptySet()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectclass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertFalse(provider.hasAnyValue(entry, rule,
                                     Collections.<AttributeValue>emptySet()));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing only
   * the correct value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueOnlyCorrect()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    values.add(AttributeValues.create(governingStructureRuleType, "22"));
    assertTrue(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing only
   * an incorrect value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueOnlyIncorrect()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectclass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    values.add(AttributeValues.create(governingStructureRuleType, "1"));
    assertFalse(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing the
   * correct value as well as multiple incorrect values.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueIncludesCorrect()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
    values.add(AttributeValues.create(governingStructureRuleType, "22"));
    values.add(AttributeValues.create(governingStructureRuleType, "1"));
    values.add(AttributeValues.create(governingStructureRuleType,"2"));
    assertTrue(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of multiple values, none of
   * which are correct.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueMissingCorrect()
         throws Exception
  {
    GoverningStructureRuleVirtualAttributeProvider provider =
         new GoverningStructureRuleVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectclass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(governingStructureRuleType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
    values.add(AttributeValues.create(governingStructureRuleType, "1"));
    values.add(AttributeValues.create(governingStructureRuleType, "2"));
    values.add(AttributeValues.create(governingStructureRuleType,"3"));
    assertFalse(provider.hasAnyValue(entry, rule, values));
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/StructuralObjectClassVirtualAttributeProviderTestCase.java
New file
@@ -0,0 +1,870 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
import static org.opends.server.util.ServerConstants.*;
import static org.testng.Assert.*;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.VirtualAttributeCfgDefn;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchScope;
import org.opends.server.types.VirtualAttributeRule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * A set of test cases for the structural object class virtual attribute
 * provider.
 */
public class StructuralObjectClassVirtualAttributeProviderTestCase
       extends ExtensionsTestCase
{
  // The attribute type for the structuralobjectclass attribute.
  private AttributeType structuralObjectClassType;
  /**
   * Ensures that the Directory Server is running.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
    structuralObjectClassType =
         DirectoryServer.getAttributeType("structuralobjectclass", false);
    assertNotNull(structuralObjectClassType);
  }
  /**
   * Retrieves a set of entry DNs for use in testing the
   * structuralObjectClassType virtual attribute.
   *
   * @return  A set of entry DNs for use in testing the structuralobjectclass
   *          virtual attribute.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @DataProvider(name = "testEntryDNs")
  public Object[][] getTestEntryDNs()
         throws Exception
  {
    return new Object[][]
    {
      new Object[] { DN.decode("") },
      new Object[] { DN.decode("o=test") },
      new Object[] { DN.decode("dc=example,dc=com") },
      new Object[] { DN.decode("cn=config") },
      new Object[] { DN.decode("cn=schema") },
      new Object[] { DN.decode("cn=tasks") },
      new Object[] { DN.decode("cn=monitor") },
      new Object[] { DN.decode("cn=backups") }
    };
  }
  /**
   * Retrieves a set of entry DNs and corresponding structural object classes
   * for use in testing the structuralObjectClassType virtual attribute.
   *
   * @return  A set of entry DNs and oc for use in testing the
   *           structuralobjectclass virtual attribute.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @DataProvider(name = "testDNOC")
  public Object[][] getTestEntryDNOC()
         throws Exception
  {
    return new Object[][] {
        {DN.decode("o=test"), "structuralObjectClass=organization"},
        {DN.decode("dc=example,dc=com"), "structuralObjectClass=domain"},
    };
  }
  /**
   * Tests the {@code getEntry} method for the specified entry to ensure that
   * the entry returned includes the structuralObjectClass operational
   * attribute with the correct value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testGetEntry(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    Entry e = DirectoryServer.getEntry(entryDN);
    assertNotNull(e);
    assertTrue(e.hasAttribute(structuralObjectClassType));
    List<Attribute> attrList = e.getAttribute(structuralObjectClassType);
    assertNotNull(attrList);
    assertFalse(attrList.isEmpty());
    for (Attribute a : attrList)
    {
      assertTrue(!a.isEmpty());
      assertEquals(a.size(), 1);
      assertTrue(a.contains(AttributeValues.create(structuralObjectClassType,
                              e.getStructuralObjectClass().getNameOrOID())));
    }
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is not included when the list of attributes
   * requested is empty (defaulting to all user attributes).
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchEmptyAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT, filter);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is not included when the list of requested
   * attributes is "1.1", meaning no attributes.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchNoAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("1.1");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is not included when all user attributes
   * are requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchAllUserAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("*");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is included when all operational attributes
   * are requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchAllOperationalAttrs(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("+");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is included when that attribute is
   * specifically requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchStructuralOCAttr(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("structuralobjectclass");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is not included when it is not in the list
   * of attributes that is explicitly requested.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchExcludeStructuralOCAttr(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("objectClass");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is included when that attribute is
   * specifically requested and the structuralObjectClass attribute is used in the
   * search filter with a matching value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testDNOC")
  public void testSearchStructuralOCAttrInMatchingFilter(DN entryDN,String oc)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString(oc);
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("structuralObjectClass");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * no entries are returned when the structuralObjectClass attribute is used in the
   * search filter with a non-matching value.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchStructuralOCAttrInNonMatchingFilter(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(structuralObjectClass=abc)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("structuralObjectClass");
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
         conn.processSearch(entryDN, SearchScope.BASE_OBJECT,
                            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                            filter, attrList);
    assertEquals(searchOperation.getSearchEntries().size(), 0);
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is not included when that attribute is
   * specifically requested and the real attributes only control is included in
   * the request.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchStructuralOCAttrRealAttrsOnly(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("structuralObjectClass");
    LinkedList<Control> requestControls = new LinkedList<Control>();
    requestControls.add(new LDAPControl(OID_REAL_ATTRS_ONLY, true));
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
        new InternalSearchOperation(conn, InternalClientConnection
            .nextOperationID(), InternalClientConnection
            .nextMessageID(), requestControls, entryDN,
            SearchScope.BASE_OBJECT,
            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
            attrList, null);
    searchOperation.run();
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertFalse(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Performs an internal search to retrieve the specified entry, ensuring that
   * the structuralObjectClass attribute is included when that attribute is
   * specifically requested and the virtual attributes only control is included
   * in the request.
   *
   * @param  entryDN  The DN of the entry to retrieve and verify.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(dataProvider = "testEntryDNs")
  public void testSearchStructuralOCAttrVirtualAttrsOnly(DN entryDN)
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com");
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectClass=*)");
    LinkedHashSet<String> attrList = new LinkedHashSet<String>(1);
    attrList.add("structuralObjectClass");
    LinkedList<Control> requestControls = new LinkedList<Control>();
    requestControls.add(new LDAPControl(OID_VIRTUAL_ATTRS_ONLY, true));
    InternalClientConnection conn =
        InternalClientConnection.getRootConnection();
    InternalSearchOperation searchOperation =
        new InternalSearchOperation(conn, InternalClientConnection
            .nextOperationID(), InternalClientConnection
            .nextMessageID(), requestControls, entryDN,
            SearchScope.BASE_OBJECT,
            DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter,
            attrList, null);
    searchOperation.run();
    assertEquals(searchOperation.getSearchEntries().size(), 1);
    Entry e = searchOperation.getSearchEntries().get(0);
    assertNotNull(e);
    assertTrue(e.hasAttribute(structuralObjectClassType));
  }
  /**
   * Tests the {@code isMultiValued} method.
   */
  @Test()
  public void testIsMultiValued()
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    assertFalse(provider.isMultiValued());
  }
  /**
   * Tests the {@code getValues} method for an entry.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetValues()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    Set<AttributeValue> values = provider.getValues(entry, rule);
    assertNotNull(values);
    assertEquals(values.size(), 1);
    assertTrue(values.contains(AttributeValues.create(structuralObjectClassType,
                                  entry.getStructuralObjectClass().getNameOrOID())));
  }
  /**
   * Tests the {@code hasValue} method variant that doesn't take a specific
   * value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValue()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertTrue(provider.hasValue(entry, rule));
  }
  /**
   * Tests the {@code hasValue} method variant that takes a specific value when
   * the provided value is a match.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasMatchingValue()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertTrue(provider.hasValue(entry, rule,
        AttributeValues.create(structuralObjectClassType,
                          entry.getStructuralObjectClass().getNameOrOID())));
  }
  /**
   * Tests the {@code hasValue} method variant that takes a specific value when
   * the provided value is not a match.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasNonMatchingValue()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertFalse(provider.hasValue(entry, rule,
        AttributeValues.create(structuralObjectClassType,
                                        "inetorgperson")));
  }
  /**
   * Tests the {@code hasAnyValue} method with an empty set of values.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueEmptySet()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    assertFalse(provider.hasAnyValue(entry, rule,
                                     Collections.<AttributeValue>emptySet()));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing only
   * the correct value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueOnlyCorrect()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    values.add(AttributeValues.create(structuralObjectClassType, "organization"));
    assertTrue(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing only
   * an incorrect value.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueOnlyIncorrect()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(1);
    values.add(AttributeValues.create(structuralObjectClassType, "inetorgperson"));
    assertFalse(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of values containing the
   * correct value as well as multiple incorrect values.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueIncludesCorrect()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
    values.add(AttributeValues.create(structuralObjectClassType, "organization"));
    values.add(AttributeValues.create(structuralObjectClassType, "inetorgperson"));
    values.add(AttributeValues.create(structuralObjectClassType,
                                  "top"));
    assertTrue(provider.hasAnyValue(entry, rule, values));
  }
  /**
   * Tests the {@code hasAnyValue} method with a set of multiple values, none of
   * which are correct.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testHasAnyValueMissingCorrect()
         throws Exception
  {
    StructuralObjectClassVirtualAttributeProvider provider =
         new StructuralObjectClassVirtualAttributeProvider();
    Entry entry = TestCaseUtils.makeEntry(
      "dn: o=test",
      "objectClass: top",
      "objectClass: organization",
      "o: test");
    entry.processVirtualAttributes();
    VirtualAttributeRule rule =
         new VirtualAttributeRule(structuralObjectClassType, provider,
                  Collections.<DN>emptySet(), Collections.<DN>emptySet(),
                  Collections.<SearchFilter>emptySet(),
                  VirtualAttributeCfgDefn.ConflictBehavior.
                       VIRTUAL_OVERRIDES_REAL);
    LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>(3);
    values.add(AttributeValues.create(structuralObjectClassType, "inetorgperson"));
    values.add(AttributeValues.create(structuralObjectClassType,
                                  "top"));
    values.add(AttributeValues.create(structuralObjectClassType,
                                  "domain"));
    assertFalse(provider.hasAnyValue(entry, rule, values));
  }
}