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

Matthew Swift
25.23.2011 0f682577196526a40a6653bdd6ef8f44b5167dca
Fix issue OPENDJ-75: Combine RFC 3672 and relative subtree specification syntax 
https://bugster.forgerock.org/jira/browse/OPENDJ-75

Merge RelativeSubtreeSpecification and RFC3672SubtreeSpecification into a single implementation and pull up into SubtreeSpecification.
7 files deleted
1 files added
2 files renamed
6 files modified
4973 ■■■■■ changed files
opends/src/server/org/opends/server/api/SubtreeSpecification.java 142 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/RFC3672SubtreeSpecification.java 873 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java 449 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java 571 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SubentryManager.java 15 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java 280 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java 283 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/SchemaConstants.java 25 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java 61 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/SubEntry.java 30 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/SubtreeSpecification.java 1836 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/SubtreeSpecificationSet.java 6 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java 9 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRelativeSubtreeSpecification.java 180 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java 15 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.java 198 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/SubtreeSpecification.java
File was deleted
opends/src/server/org/opends/server/core/RFC3672SubtreeSpecification.java
File was deleted
opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
File was deleted
opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
File was deleted
opends/src/server/org/opends/server/core/SubentryManager.java
@@ -23,13 +23,13 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.core;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.SubtreeSpecification;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -47,18 +47,7 @@
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.types.Control;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SubEntry;
import org.opends.server.types.*;
import org.opends.server.types.operation.PostOperationAddOperation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
File was deleted
opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
File was deleted
opends/src/server/org/opends/server/schema/SchemaConstants.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.schema;
@@ -1668,30 +1669,6 @@
  /**
   * The OID for the RFC3672 subtree specification attribute syntax.
   */
  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_OID =
    SYNTAX_SUBTREE_SPECIFICATION_OID;
  /**
   * The description for the RFC3672 subtree specification attribute syntax.
   */
  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_DESCRIPTION =
    "RFC3672 Subtree Specification";
  /**
   * The name for the RFC3672 subtree specification attribute syntax.
   */
  public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME =
    SYNTAX_SUBTREE_SPECIFICATION_NAME;
  /**
   * The OID for the relative subtree specification attribute syntax.
   */
  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_OID =
opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
@@ -23,11 +23,12 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.schema;
import org.opends.messages.Message;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.messages.SchemaMessages.*;
@@ -41,11 +42,8 @@
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.opends.server.api.SubtreeSpecification;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.RFC3672SubtreeSpecification;
import org.opends.server.core.RelativeSubtreeSpecification;
import org.opends.server.types.*;
@@ -107,30 +105,8 @@
     */
    public SubtreeSpecification decode(AttributeValue value)
        throws DirectoryException {
      // Try parsing the value with every subtree spec known.
      SubtreeSpecification subTreeSpec = null;
      String specString = value.toString();
      try {
        subTreeSpec = RFC3672SubtreeSpecification.valueOf(
                rootDN, specString);
        return subTreeSpec;
      } catch (DirectoryException de) {}
      try {
        subTreeSpec = RelativeSubtreeSpecification.valueOf(
                rootDN, specString);
        return subTreeSpec;
      } catch (DirectoryException de) {}
      if (subTreeSpec == null) {
        Message message =
          ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
            specString);
        throw new DirectoryException(
                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
      }
      return subTreeSpec;
      return SubtreeSpecification.valueOf(rootDN, value
          .getValue().toString());
    }
  }
@@ -275,28 +251,19 @@
                                   MessageBuilder invalidReason) {
    // Use the subtree specification code to make this determination.
    // Try parsing the value with every subtree spec known.
    SubtreeSpecification subTreeSpec = null;
    String specString = value.toString();
    try {
      subTreeSpec = RFC3672SubtreeSpecification.valueOf(
              DN.nullDN(), specString);
      return true;
    } catch (DirectoryException de) {}
    try {
      subTreeSpec = RelativeSubtreeSpecification.valueOf(
              DN.nullDN(), specString);
      return true;
    } catch (DirectoryException de) {}
      SubtreeSpecification.valueOf(DN.nullDN(), value.toString());
    if (subTreeSpec == null) {
      Message message =
        ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
          specString);
      invalidReason.append(message);
      return true;
    } catch (DirectoryException e) {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      invalidReason.append(e.getMessageObject());
      return false;
    }
    return false;
  }
 /**
opends/src/server/org/opends/server/types/SubEntry.java
@@ -23,23 +23,19 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.types;
import org.opends.messages.Message;
import org.opends.server.core.RelativeSubtreeSpecification;
import org.opends.server.api.SubtreeSpecification;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.LinkedHashSet;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.RFC3672SubtreeSpecification;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.SchemaMessages.*;
/**
@@ -48,11 +44,6 @@
 */
public class SubEntry {
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * Defines the set of permissable values for the conflict behavior.
   * Specifies the behavior that the server is to exhibit for entries
   * that already contain one or more real values for the associated
@@ -216,25 +207,10 @@
      {
        for (AttributeValue value : attr)
        {
          // Try parsing the value with every subtree spec known.
          specString = value.toString();
          try
          {
            this.subTreeSpec = RFC3672SubtreeSpecification.valueOf(
                    entry.getDN().getParent(), specString);
            isValidSpec = true;
          }
          catch (DirectoryException de)
          {
            isValidSpec = false;
          }
          if (this.subTreeSpec != null)
          {
            break;
          }
          try
          {
            this.subTreeSpec = RelativeSubtreeSpecification.valueOf(
            this.subTreeSpec = SubtreeSpecification.valueOf(
                    entry.getDN().getParent(), specString);
            isValidSpec = true;
          }
@@ -270,7 +246,7 @@
    {
      // There is none for some reason eg this could be
      // old Draft based ldapSubEntry so create a dummy.
      this.subTreeSpec = new RFC3672SubtreeSpecification(
      this.subTreeSpec = new SubtreeSpecification(
                DN.NULL_DN, null, -1, -1,
                null, null, null);
    }
opends/src/server/org/opends/server/types/SubtreeSpecification.java
New file
@@ -0,0 +1,1836 @@
/*
 * 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 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.types;
import static org.opends.messages.SchemaMessages.*;
import java.util.*;
import java.util.regex.Pattern;
import org.opends.messages.Message;
import org.opends.server.core.DirectoryServer;
import org.opends.server.util.StaticUtils;
/**
 * An RFC 3672 subtree specification.
 * <p>
 * This implementation extends RFC 3672 by supporting search filters
 * for specification filters. More specifically, the
 * {@code Refinement} product has been extended as follows:
 *
 * <pre>
 *  Refinement = item / and / or / not / Filter
 *
 *  Filter     = dquote *SafeUTF8Character dquote
 * </pre>
 *
 * @see <a href="http://tools.ietf.org/html/rfc3672">RFC 3672 -
 *      Subentries inthe Lightweight Directory Access Protocol (LDAP)
 *      </a>
 */
@org.opends.server.types.PublicAPI(
    stability = org.opends.server.types.StabilityLevel.VOLATILE,
    mayInstantiate = false,
    mayExtend = true,
    mayInvoke = false)
public final class SubtreeSpecification
{
  /**
   * RFC 3672 subtree specification AND refinement. This type of
   * refinement filters entries based on all of the underlying
   * refinements being <code>true</code>.
   */
  public static final class AndRefinement extends Refinement
  {
    // The set of refinements which must all be true.
    private final Collection<Refinement> refinementSet;
    /**
     * Create a new AND refinement.
     *
     * @param refinementSet
     *          The set of refinements which must all be
     *          <code>true</code>.
     */
    public AndRefinement(final Collection<Refinement> refinementSet)
    {
      this.refinementSet = refinementSet;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      if (obj instanceof AndRefinement)
      {
        final AndRefinement other = (AndRefinement) obj;
        return refinementSet.equals(other.refinementSet);
      }
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
      return refinementSet.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(final Entry entry)
    {
      for (final Refinement refinement : refinementSet)
      {
        if (refinement.matches(entry) == false)
        {
          return false;
        }
      }
      // All sub-refinements matched.
      return true;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
      switch (refinementSet.size())
      {
      case 0:
        // Do nothing.
        break;
      case 1:
        refinementSet.iterator().next().toString(builder);
        break;
      default:
        builder.append("and:{");
        final Iterator<Refinement> iterator = refinementSet
            .iterator();
        iterator.next().toString(builder);
        while (iterator.hasNext())
        {
          builder.append(", ");
          iterator.next().toString(builder);
        }
        builder.append("}");
        break;
      }
      return builder;
    }
  }
  /**
   * A refinement which uses a search filter.
   */
  public static final class FilterRefinement extends Refinement
  {
    // The search filter.
    private final SearchFilter filter;
    /**
     * Create a new filter refinement.
     *
     * @param filter
     *          The search filter.
     */
    public FilterRefinement(final SearchFilter filter)
    {
      this.filter = filter;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      if (obj instanceof FilterRefinement)
      {
        final FilterRefinement other = (FilterRefinement) obj;
        return filter.equals(other.filter);
      }
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
      return filter.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(final Entry entry)
    {
      try
      {
        return filter.matchesEntry(entry);
      }
      catch (final DirectoryException e)
      {
        // TODO: need to decide what to do with the exception here.
        // It's probably safe to ignore, but we could log it perhaps.
        return false;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
      StaticUtils.toRFC3641StringValue(builder, filter.toString());
      return builder;
    }
  }
  /**
   * RFC 3672 subtree specification Item refinement. This type of
   * refinement filters entries based on the presence of a specified
   * object class.
   */
  public static final class ItemRefinement extends Refinement
  {
    // The item's object class.
    private final String objectClass;
    // The item's normalized object class.
    private final String normalizedObjectClass;
    /**
     * Create a new item refinement.
     *
     * @param objectClass
     *          The item's object class.
     */
    public ItemRefinement(final String objectClass)
    {
      this.objectClass = objectClass;
      this.normalizedObjectClass = StaticUtils
          .toLowerCase(objectClass.trim());
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      if (obj instanceof ItemRefinement)
      {
        final ItemRefinement other = (ItemRefinement) obj;
        return normalizedObjectClass
            .equals(other.normalizedObjectClass);
      }
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
      return normalizedObjectClass.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(final Entry entry)
    {
      final ObjectClass oc = DirectoryServer
          .getObjectClass(normalizedObjectClass);
      if (oc == null)
      {
        return false;
      }
      else
      {
        return entry.hasObjectClass(oc);
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
      builder.append("item:");
      builder.append(objectClass);
      return builder;
    }
  }
  /**
   * RFC 3672 subtree specification NOT refinement. This type of
   * refinement filters entries based on the underlying refinement
   * being <code>false</code>
   * .
   */
  public static final class NotRefinement extends Refinement
  {
    // The inverted refinement.
    private final Refinement refinement;
    /**
     * Create a new NOT refinement.
     *
     * @param refinement
     *          The refinement which must be <code>false</code>.
     */
    public NotRefinement(final Refinement refinement)
    {
      this.refinement = refinement;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      if (obj instanceof NotRefinement)
      {
        final NotRefinement other = (NotRefinement) obj;
        return refinement.equals(other.refinement);
      }
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
      return refinement.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(final Entry entry)
    {
      return !refinement.matches(entry);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
      builder.append("not:");
      return refinement.toString(builder);
    }
  }
  /**
   * RFC 3672 subtree specification OR refinement. This type of
   * refinement filters entries based on at least one of the
   * underlying refinements being <code>true</code>.
   */
  public static final class OrRefinement extends Refinement
  {
    // The set of refinements of which at least one must be true.
    private final Collection<Refinement> refinementSet;
    /**
     * Create a new OR refinement.
     *
     * @param refinementSet
     *          The set of refinements of which at least one must be
     *          <code>true</code>.
     */
    public OrRefinement(final Collection<Refinement> refinementSet)
    {
      this.refinementSet = refinementSet;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(final Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      if (obj instanceof AndRefinement)
      {
        final AndRefinement other = (AndRefinement) obj;
        return refinementSet.equals(other.refinementSet);
      }
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode()
    {
      return refinementSet.hashCode();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(final Entry entry)
    {
      for (final Refinement refinement : refinementSet)
      {
        if (refinement.matches(entry) == true)
        {
          return true;
        }
      }
      // No sub-refinements matched.
      return false;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
      switch (refinementSet.size())
      {
      case 0:
        // Do nothing.
        break;
      case 1:
        refinementSet.iterator().next().toString(builder);
        break;
      default:
        builder.append("or:{");
        final Iterator<Refinement> iterator = refinementSet
            .iterator();
        iterator.next().toString(builder);
        while (iterator.hasNext())
        {
          builder.append(", ");
          iterator.next().toString(builder);
        }
        builder.append("}");
        break;
      }
      return builder;
    }
  }
  /**
   * Abstract interface for RFC3672 specification filter refinements.
   */
  public static abstract class Refinement
  {
    /**
     * Create a new RFC3672 specification filter refinement.
     */
    protected Refinement()
    {
      // No implementation required.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public abstract boolean equals(Object obj);
    /**
     * {@inheritDoc}
     */
    @Override
    public abstract int hashCode();
    /**
     * Check if the refinement matches the given entry.
     *
     * @param entry
     *          The filterable entry.
     * @return Returns <code>true</code> if the entry matches the
     *         refinement, or <code>false</code> otherwise.
     */
    public abstract boolean matches(Entry entry);
    /**
     * {@inheritDoc}
     */
    @Override
    public final String toString()
    {
      final StringBuilder builder = new StringBuilder();
      return toString(builder).toString();
    }
    /**
     * Append the string representation of the refinement to the
     * provided strin builder.
     *
     * @param builder
     *          The string builder.
     * @return The string builder.
     */
    public abstract StringBuilder toString(StringBuilder builder);
  }
  /**
   * Internal utility class which can be used by sub-classes to help
   * parse string representations.
   */
  protected static final class Parser
  {
    // Text scanner used to parse the string value.
    private final Scanner scanner;
    // Pattern used to detect left braces.
    private static Pattern LBRACE = Pattern.compile("\\{.*");
    // Pattern used to parse left braces.
    private static Pattern LBRACE_TOKEN = Pattern.compile("\\{");
    // Pattern used to detect right braces.
    private static Pattern RBRACE = Pattern.compile("\\}.*");
    // Pattern used to parse right braces.
    private static Pattern RBRACE_TOKEN = Pattern.compile("\\}");
    // Pattern used to detect comma separators.
    private static Pattern SEP = Pattern.compile(",.*");
    // Pattern used to parse comma separators.
    private static Pattern SEP_TOKEN = Pattern.compile(",");
    // Pattern used to detect colon separators.
    private static Pattern COLON = Pattern.compile(":.*");
    // Pattern used to parse colon separators.
    private static Pattern COLON_TOKEN = Pattern.compile(":");
    // Pattern used to detect integer values.
    private static Pattern INT = Pattern.compile("\\d.*");
    // Pattern used to parse integer values.
    private static Pattern INT_TOKEN = Pattern.compile("\\d+");
    // Pattern used to detect name values.
    private static Pattern NAME = Pattern.compile("[\\w_;-].*");
    // Pattern used to parse name values.
    private static Pattern NAME_TOKEN = Pattern.compile("[\\w_;-]+");
    // Pattern used to detect RFC3641 string values.
    private static Pattern STRING_VALUE = Pattern.compile("\".*");
    // Pattern used to parse RFC3641 string values.
    private static Pattern STRING_VALUE_TOKEN = Pattern
        .compile("\"([^\"]|(\"\"))*\"");
    /**
     * Create a new parser for a subtree specification string value.
     *
     * @param value
     *          The subtree specification string value.
     */
    public Parser(final String value)
    {
      this.scanner = new Scanner(value);
    }
    /**
     * Determine if there are remaining tokens.
     *
     * @return <code>true</code> if and only if there are remaining
     *         tokens.
     */
    public boolean hasNext()
    {
      return scanner.hasNext();
    }
    /**
     * Determine if the next token is a right-brace character.
     *
     * @return <code>true</code> if and only if the next token is a
     *         valid right brace character.
     */
    public boolean hasNextRightBrace()
    {
      return scanner.hasNext(RBRACE);
    }
    /**
     * Scans the next token of the input as a non-negative
     * <code>int</code> value.
     *
     * @return The name value scanned from the input.
     * @throws InputMismatchException
     *           If the next token is not a valid non-negative integer
     *           string.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public int nextInt() throws InputMismatchException,
        NoSuchElementException
    {
      final String s = nextValue(INT, INT_TOKEN);
      return Integer.parseInt(s);
    }
    /**
     * Scans the next token of the input as a key value.
     *
     * @return The lower-case key value scanned from the input.
     * @throws InputMismatchException
     *           If the next token is not a valid key string.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public String nextKey() throws InputMismatchException,
        NoSuchElementException
    {
      return StaticUtils.toLowerCase(scanner.next());
    }
    /**
     * Scans the next token of the input as a name value.
     * <p>
     * A name is any string containing only alpha-numeric characters
     * or hyphens, semi-colons, or underscores.
     *
     * @return The name value scanned from the input.
     * @throws InputMismatchException
     *           If the next token is not a valid name string.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public String nextName() throws InputMismatchException,
        NoSuchElementException
    {
      return nextValue(NAME, NAME_TOKEN);
    }
    /**
     * Scans the next tokens of the input as a set of specific
     * exclusions encoded according to the SpecificExclusion
     * production in RFC 3672.
     *
     * @param chopBefore
     *          The set of chop before local names.
     * @param chopAfter
     *          The set of chop after local names.
     * @throws InputMismatchException
     *           If the common component did not have a valid syntax.
     * @throws NoSuchElementException
     *           If input is exhausted.
     * @throws DirectoryException
     *           If an error occurred when attempting to parse a
     *           DN value.
     */
    public void nextSpecificExclusions(final Set<DN> chopBefore,
        final Set<DN> chopAfter) throws InputMismatchException,
        NoSuchElementException, DirectoryException
    {
      // Skip leading open-brace.
      skipLeftBrace();
      // Parse each chop DN in the sequence.
      boolean isFirstValue = true;
      while (true)
      {
        // Make sure that there is a closing brace.
        if (hasNextRightBrace())
        {
          skipRightBrace();
          break;
        }
        // Make sure that there is a comma separator if this is not
        // the first element.
        if (!isFirstValue)
        {
          skipSeparator();
        }
        else
        {
          isFirstValue = false;
        }
        // Parse each chop specification which is of the form
        // <type>:<value>.
        final String type = StaticUtils.toLowerCase(nextName());
        skipColon();
        if (type.equals("chopbefore"))
        {
          chopBefore.add(DN.decode(nextStringValue()));
        }
        else if (type.equals("chopafter"))
        {
          chopAfter.add(DN.decode(nextStringValue()));
        }
        else
        {
          throw new java.util.InputMismatchException();
        }
      }
    }
    /**
     * Scans the next token of the input as a string quoted according
     * to the StringValue production in RFC 3641.
     * <p>
     * The return string has its outer double quotes removed and any
     * escape inner double quotes unescaped.
     *
     * @return The string value scanned from the input.
     * @throws InputMismatchException
     *           If the next token is not a valid string.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public String nextStringValue() throws InputMismatchException,
        NoSuchElementException
    {
      final String s = nextValue(STRING_VALUE, STRING_VALUE_TOKEN);
      return s.substring(1, s.length() - 1).replace("\"\"", "\"");
    }
    /**
     * Skip a colon separator.
     *
     * @throws InputMismatchException
     *           If the next token is not a colon separator character.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public void skipColon() throws InputMismatchException,
        NoSuchElementException
    {
      nextValue(COLON, COLON_TOKEN);
    }
    /**
     * Skip a left-brace character.
     *
     * @throws InputMismatchException
     *           If the next token is not a left-brace character.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public void skipLeftBrace() throws InputMismatchException,
        NoSuchElementException
    {
      nextValue(LBRACE, LBRACE_TOKEN);
    }
    /**
     * Skip a right-brace character.
     *
     * @throws InputMismatchException
     *           If the next token is not a right-brace character.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public void skipRightBrace() throws InputMismatchException,
        NoSuchElementException
    {
      nextValue(RBRACE, RBRACE_TOKEN);
    }
    /**
     * Skip a comma separator.
     *
     * @throws InputMismatchException
     *           If the next token is not a comma separator character.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    public void skipSeparator() throws InputMismatchException,
        NoSuchElementException
    {
      nextValue(SEP, SEP_TOKEN);
    }
    /**
     * Parse the next token from the string using the specified
     * patterns.
     *
     * @param head
     *          The pattern used to determine if the next token is a
     *          possible match.
     * @param content
     *          The pattern used to parse the token content.
     * @return The next token matching the <code>content</code>
     *         pattern.
     * @throws InputMismatchException
     *           If the next token does not match the
     *           <code>content</code> pattern.
     * @throws NoSuchElementException
     *           If input is exhausted.
     */
    private String nextValue(final Pattern head,
        final Pattern content)
        throws InputMismatchException, NoSuchElementException
    {
      if (!scanner.hasNext())
      {
        throw new java.util.NoSuchElementException();
      }
      if (!scanner.hasNext(head))
      {
        throw new java.util.InputMismatchException();
      }
      final String s = scanner.findInLine(content);
      if (s == null)
      {
        throw new java.util.InputMismatchException();
      }
      return s;
    }
  }
  /**
   * Parses the string argument as an RFC3672 subtree specification.
   *
   * @param rootDN
   *          The DN of the subtree specification's base entry.
   * @param s
   *          The string to be parsed.
   * @return The RFC3672 subtree specification represented by the
   *         string argument.
   * @throws DirectoryException
   *           If the string does not contain a parsable relative
   *           subtree specification.
   */
  public static SubtreeSpecification valueOf(final DN rootDN,
      final String s) throws DirectoryException
  {
    // Default values.
    DN relativeBaseDN = null;
    int minimum = -1;
    int maximum = -1;
    final HashSet<DN> chopBefore = new HashSet<DN>();
    final HashSet<DN> chopAfter = new HashSet<DN>();
    Refinement refinement = null;
    // Value must have an opening left brace.
    final Parser parser = new Parser(s);
    boolean isValid = true;
    try
    {
      parser.skipLeftBrace();
      // Parse each element of the value sequence.
      boolean isFirst = true;
      while (true)
      {
        if (parser.hasNextRightBrace())
        {
          // Make sure that there is a closing brace and no trailing
          // text.
          parser.skipRightBrace();
          if (parser.hasNext())
          {
            throw new java.util.InputMismatchException();
          }
          break;
        }
        // Make sure that there is a comma separator if this is not
        // the first element.
        if (!isFirst)
        {
          parser.skipSeparator();
        }
        else
        {
          isFirst = false;
        }
        final String key = parser.nextKey();
        if (key.equals("base"))
        {
          if (relativeBaseDN != null)
          {
            // Relative base DN specified more than once.
            throw new InputMismatchException();
          }
          relativeBaseDN = DN.decode(parser.nextStringValue());
        }
        else if (key.equals("minimum"))
        {
          if (minimum != -1)
          {
            // Minimum specified more than once.
            throw new InputMismatchException();
          }
          minimum = parser.nextInt();
        }
        else if (key.equals("maximum"))
        {
          if (maximum != -1)
          {
            // Maximum specified more than once.
            throw new InputMismatchException();
          }
          maximum = parser.nextInt();
        }
        else if (key.equals("specificationfilter"))
        {
          if (refinement != null)
          {
            // Refinements specified more than once.
            throw new InputMismatchException();
          }
          // First try normal search filter before RFC3672
          // refinements.
          try
          {
            final SearchFilter filter = SearchFilter
                .createFilterFromString(parser.nextStringValue());
            refinement = new FilterRefinement(filter);
          }
          catch (final InputMismatchException e)
          {
            refinement = parseRefinement(parser);
          }
        }
        else if (key.equals("specificexclusions"))
        {
          if (!chopBefore.isEmpty() || !chopAfter.isEmpty())
          {
            // Specific exclusions specified more than once.
            throw new InputMismatchException();
          }
          parser.nextSpecificExclusions(chopBefore, chopAfter);
        }
        else
        {
          throw new InputMismatchException();
        }
      }
      // Make default minimum value is 0.
      if (minimum < 0)
      {
        minimum = 0;
      }
      // Check that the maximum, if specified, is gte the minimum.
      if (maximum >= 0 && maximum < minimum)
      {
        isValid = false;
      }
    }
    catch (final InputMismatchException e)
    {
      isValid = false;
    }
    catch (final NoSuchElementException e)
    {
      isValid = false;
    }
    if (isValid)
    {
      return new SubtreeSpecification(rootDN, relativeBaseDN,
          minimum, maximum, chopBefore, chopAfter, refinement);
    }
    else
    {
      final Message message =
        ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID.get(s);
      throw new DirectoryException(
          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
    }
  }
  /**
   * Parse a single refinement.
   *
   * @param parser
   *          The active subtree specification parser.
   * @return The parsed refinement.
   * @throws InputMismatchException
   *           If the common component did not have a valid syntax.
   * @throws NoSuchElementException
   *           If input is exhausted.
   */
  private static Refinement parseRefinement(final Parser parser)
      throws InputMismatchException, NoSuchElementException
  {
    // Get the type of refinement.
    final String type = StaticUtils.toLowerCase(parser.nextName());
    // Skip the colon separator.
    parser.skipColon();
    if (type.equals("item"))
    {
      return new ItemRefinement(parser.nextName());
    }
    else if (type.equals("not"))
    {
      final Refinement refinement = parseRefinement(parser);
      return new NotRefinement(refinement);
    }
    else if (type.equals("and"))
    {
      final ArrayList<Refinement> refinements =
        parseRefinementSet(parser);
      return new AndRefinement(refinements);
    }
    else if (type.equals("or"))
    {
      final ArrayList<Refinement> refinements =
        parseRefinementSet(parser);
      return new OrRefinement(refinements);
    }
    else
    {
      // Unknown refinement type.
      throw new InputMismatchException();
    }
  }
  /**
   * Parse a list of refinements.
   *
   * @param parser
   *          The active subtree specification parser.
   * @return The parsed refinement list.
   * @throws InputMismatchException
   *           If the common component did not have a valid syntax.
   * @throws NoSuchElementException
   *           If input is exhausted.
   */
  private static ArrayList<Refinement> parseRefinementSet(
      final Parser parser) throws InputMismatchException,
      NoSuchElementException
  {
    final ArrayList<Refinement> refinements =
      new ArrayList<Refinement>();
    // Skip leading open-brace.
    parser.skipLeftBrace();
    // Parse each chop DN in the sequence.
    boolean isFirstValue = true;
    while (true)
    {
      // Make sure that there is a closing brace.
      if (parser.hasNextRightBrace())
      {
        parser.skipRightBrace();
        break;
      }
      // Make sure that there is a comma separator if this is not
      // the first element.
      if (!isFirstValue)
      {
        parser.skipSeparator();
      }
      else
      {
        isFirstValue = false;
      }
      // Parse each sub-refinement.
      final Refinement refinement = parseRefinement(parser);
      refinements.add(refinement);
    }
    return refinements;
  }
  // The absolute base of the subtree.
  private final DN baseDN;
  // Optional minimum depth (<=0 means unlimited).
  private final int minimumDepth;
  // Optional maximum depth (<0 means unlimited).
  private final int maximumDepth;
  // Optional set of chop before absolute DNs (mapping to their
  // local-names).
  private final Map<DN, DN> chopBefore;
  // Optional set of chop after absolute DNs (mapping to their
  // local-names).
  private final Map<DN, DN> chopAfter;
  // The root DN.
  private final DN rootDN;
  // The optional relative base DN.
  private final DN relativeBaseDN;
  // The optional specification filter refinements.
  private final Refinement refinements;
  /**
   * Create a new RFC3672 subtree specification.
   *
   * @param rootDN
   *          The root DN of the subtree.
   * @param relativeBaseDN
   *          The relative base DN (or <code>null</code> if not
   *          specified).
   * @param minimumDepth
   *          The minimum depth (<=0 means unlimited).
   * @param maximumDepth
   *          The maximum depth (<0 means unlimited).
   * @param chopBefore
   *          The set of chop before local names (relative to the
   *          relative base DN), or <code>null</code> if there are
   *          none.
   * @param chopAfter
   *          The set of chop after local names (relative to the
   *          relative base DN), or <code>null</code> if there are
   *          none.
   * @param refinements
   *          The optional specification filter refinements, or
   *          <code>null</code> if there are none.
   */
  public SubtreeSpecification(final DN rootDN,
      final DN relativeBaseDN, final int minimumDepth,
      final int maximumDepth, final Iterable<DN> chopBefore,
      final Iterable<DN> chopAfter, final Refinement refinements)
  {
    this.baseDN = relativeBaseDN == null ? rootDN : rootDN
        .concat(relativeBaseDN);
    this.minimumDepth = minimumDepth;
    this.maximumDepth = maximumDepth;
    if (chopBefore != null && chopBefore.iterator().hasNext())
    {
      // Calculate the absolute DNs.
      final TreeMap<DN, DN> map = new TreeMap<DN, DN>();
      for (final DN localName : chopBefore)
      {
        map.put(baseDN.concat(localName), localName);
      }
      this.chopBefore = Collections.unmodifiableMap(map);
    }
    else
    {
      // No chop before specifications.
      this.chopBefore = Collections.emptyMap();
    }
    if (chopAfter != null && chopAfter.iterator().hasNext())
    {
      // Calculate the absolute DNs.
      final TreeMap<DN, DN> map = new TreeMap<DN, DN>();
      for (final DN localName : chopAfter)
      {
        map.put(baseDN.concat(localName), localName);
      }
      this.chopAfter = Collections.unmodifiableMap(map);
    }
    else
    {
      // No chop after specifications.
      this.chopAfter = Collections.emptyMap();
    }
    this.rootDN = rootDN;
    this.relativeBaseDN = relativeBaseDN;
    this.refinements = refinements;
  }
  /**
   * Indicates whether the provided object is logically equal to this
   * subtree specification object.
   *
   * @param obj
   *          The object for which to make the determination.
   * @return {@code true} if the provided object is logically equal
   *         to this subtree specification object, or {@code false}
   *         if not.
   */
  @Override
  public boolean equals(final Object obj)
  {
    if (this == obj)
    {
      return true;
    }
    if (obj instanceof SubtreeSpecification)
    {
      final SubtreeSpecification other = (SubtreeSpecification) obj;
      if (!commonComponentsEquals(other))
      {
        return false;
      }
      if (!getBaseDN().equals(other.getBaseDN()))
      {
        return false;
      }
      if (refinements != null)
      {
        return refinements.equals(other.refinements);
      }
      else
      {
        return refinements == other.refinements;
      }
    }
    return false;
  }
  /**
   * Get the absolute base DN of the subtree specification.
   *
   * @return Returns the absolute base DN of the subtree
   *         specification.
   */
  public DN getBaseDN()
  {
    return baseDN;
  }
  /**
   * Get the set of chop after relative DNs.
   *
   * @return Returns the set of chop after relative DNs.
   */
  public Iterable<DN> getChopAfter()
  {
    return chopAfter.values();
  }
  /**
   * Get the set of chop before relative DNs.
   *
   * @return Returns the set of chop before relative DNs.
   */
  public Iterable<DN> getChopBefore()
  {
    return chopBefore.values();
  }
  /**
   * Get the maximum depth of the subtree specification.
   *
   * @return Returns the maximum depth (<0 indicates unlimited depth).
   */
  public int getMaximumDepth()
  {
    return maximumDepth;
  }
  /**
   * Get the minimum depth of the subtree specification.
   *
   * @return Returns the minimum depth (<=0 indicates unlimited
   *         depth).
   */
  public int getMinimumDepth()
  {
    return minimumDepth;
  }
  /**
   * Get the specification filter refinements.
   *
   * @return Returns the specification filter refinements, or
   *         <code>null</code> if none were specified.
   */
  public Refinement getRefinements()
  {
    return refinements;
  }
  /**
   * Get the relative base DN.
   *
   * @return Returns the relative base DN or <code>null</code> if
   *         none was specified.
   */
  public DN getRelativeBaseDN()
  {
    return relativeBaseDN;
  }
  /**
   * Get the root DN.
   *
   * @return Returns the root DN.
   */
  public DN getRootDN()
  {
    return rootDN;
  }
  /**
   * Retrieves the hash code for this subtree specification object.
   *
   * @return The hash code for this subtree specification object.
   */
  @Override
  public int hashCode()
  {
    int hash = commonComponentsHashCode();
    hash = hash * 31 + getBaseDN().hashCode();
    if (refinements != null)
    {
      hash = hash * 31 + refinements.hashCode();
    }
    return hash;
  }
  /**
   * Determine if the specified DN is within the scope of the subtree
   * specification.
   *
   * @param dn
   *          The distinguished name.
   * @return Returns <code>true</code> if the DN is within the scope
   *         of the subtree specification, or <code>false</code>
   *         otherwise.
   */
  public boolean isDNWithinScope(final DN dn)
  {
    if (!dn.isDescendantOf(baseDN))
    {
      return false;
    }
    // Check minimum and maximum depths.
    final int baseRDNCount = baseDN.getNumComponents();
    if (minimumDepth > 0)
    {
      final int entryRDNCount = dn.getNumComponents();
      if (entryRDNCount - baseRDNCount < minimumDepth)
      {
        return false;
      }
    }
    if (maximumDepth >= 0)
    {
      final int entryRDNCount = dn.getNumComponents();
      if (entryRDNCount - baseRDNCount > maximumDepth)
      {
        return false;
      }
    }
    // Check exclusions.
    for (final DN chopBeforeDN : chopBefore.keySet())
    {
      if (dn.isDescendantOf(chopBeforeDN))
      {
        return false;
      }
    }
    for (final DN chopAfterDN : chopAfter.keySet())
    {
      if (!dn.equals(chopAfterDN) && dn.isDescendantOf(chopAfterDN))
      {
        return false;
      }
    }
    // Everything seemed to match.
    return true;
  }
  /**
   * Determine if an entry is within the scope of the subtree
   * specification.
   *
   * @param entry
   *          The entry.
   * @return {@code true} if the entry is within the scope of the
   *         subtree specification, or {@code false} if not.
   */
  public boolean isWithinScope(final Entry entry)
  {
    if (isDNWithinScope(entry.getDN()))
    {
      if (refinements != null)
      {
        return refinements.matches(entry);
      }
      else
      {
        return true;
      }
    }
    else
    {
      return false;
    }
  }
  /**
   * Retrieves a string representation of this subtree specification
   * object.
   *
   * @return A string representation of this subtree specification
   *         object.
   */
  @Override
  public String toString()
  {
    final StringBuilder builder = new StringBuilder();
    return toString(builder).toString();
  }
  /**
   * Append the string representation of the subtree specification to
   * the provided string builder.
   *
   * @param builder
   *          The string builder.
   * @return The string builder.
   */
  public StringBuilder toString(final StringBuilder builder)
  {
    boolean isFirstElement = true;
    // Output the optional base DN.
    builder.append("{");
    if (relativeBaseDN != null && !relativeBaseDN.isNullDN())
    {
      builder.append(" base ");
      StaticUtils.toRFC3641StringValue(builder,
          relativeBaseDN.toString());
      isFirstElement = false;
    }
    // Output the optional specific exclusions.
    final Iterable<DN> chopBefore = getChopBefore();
    final Iterable<DN> chopAfter = getChopAfter();
    if ((chopBefore.iterator().hasNext())
        || (chopAfter.iterator().hasNext()))
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" specificExclusions { ");
      boolean isFirst = true;
      for (final DN dn : chopBefore)
      {
        if (!isFirst)
        {
          builder.append(", chopBefore:");
        }
        else
        {
          builder.append("chopBefore:");
          isFirst = false;
        }
        StaticUtils.toRFC3641StringValue(builder, dn.toString());
      }
      for (final DN dn : chopAfter)
      {
        if (!isFirst)
        {
          builder.append(", chopAfter:");
        }
        else
        {
          builder.append("chopAfter:");
          isFirst = false;
        }
        StaticUtils.toRFC3641StringValue(builder, dn.toString());
      }
      builder.append(" }");
    }
    // Output the optional minimum depth.
    if (getMinimumDepth() > 0)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" minimum ");
      builder.append(getMinimumDepth());
    }
    // Output the optional maximum depth.
    if (getMaximumDepth() >= 0)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" maximum ");
      builder.append(getMaximumDepth());
    }
    // Output the optional refinements.
    if (refinements != null)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" specificationFilter ");
      refinements.toString(builder);
    }
    builder.append(" }");
    return builder;
  }
  /**
   * Determine if the common components of this subtree specification
   * are equal to the common components of another subtree
   * specification.
   *
   * @param other
   *          The other subtree specification.
   * @return Returns <code>true</code> if they are equal.
   */
  private boolean commonComponentsEquals(
      final SubtreeSpecification other)
  {
    if (this == other)
    {
      return true;
    }
    if (minimumDepth != other.minimumDepth)
    {
      return false;
    }
    if (maximumDepth != other.maximumDepth)
    {
      return false;
    }
    if (!chopBefore.values().equals(other.chopBefore.values()))
    {
      return false;
    }
    if (!chopAfter.values().equals(other.chopAfter.values()))
    {
      return false;
    }
    return true;
  }
  /**
   * Get a hash code of the subtree specification's common components.
   *
   * @return The computed hash code.
   */
  private int commonComponentsHashCode()
  {
    int hash = minimumDepth * 31 + maximumDepth;
    hash = hash * 31 + chopBefore.values().hashCode();
    hash = hash * 31 + chopAfter.values().hashCode();
    return hash;
  }
}
opends/src/server/org/opends/server/types/SubtreeSpecificationSet.java
File was renamed from opends/src/server/org/opends/server/api/SubtreeSpecificationSet.java
@@ -23,8 +23,9 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.api;
package org.opends.server.types;
@@ -33,13 +34,12 @@
import java.util.HashSet;
import java.util.Iterator;
import org.opends.server.types.Entry;
/**
 * This class implements the {@code Set} interface for
 * {@link org.opends.server.api.SubtreeSpecification}s.
 * {@link org.opends.server.types.SubtreeSpecification}s.
 * <p>
 * It is backed by a {@code HashSet} but provides additional
 * functionality, {@link #isWithinScope(Entry)}, for determining
opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
@@ -28,7 +28,6 @@
package org.opends.server.core;
import org.opends.server.api.SubtreeSpecification;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -175,7 +174,7 @@
        "objectClass: subentry",
        "objectClass: collectiveAttributeSubentry",
        "objectClass: extensibleObject",
        "subtreeSpecification: {relativebase \"\", specificationFilter \"(isMemberOf=cn=collective users,ou=people,o=test)\"}",
        "subtreeSpecification: {base \"\", specificationFilter \"(isMemberOf=cn=collective users,ou=people,o=test)\"}",
        "cn: description collective attribute",
        "description;collective: inherited description",
        "",
@@ -615,7 +614,7 @@
      if (subentry.getDN().equals(ldapSubentry.getDN()))
      {
        SubtreeSpecification spec = subentry.getSubTreeSpecification();
        assertTrue(spec instanceof RFC3672SubtreeSpecification);
        assertNull(spec.getRefinements());
      }
    }
@@ -627,7 +626,7 @@
         "dn: cn=Relative Subentry," + SUFFIX,
         "objectClass: top",
         "objectclass: subentry",
         "subtreeSpecification: {relativeBase \"ou=Test SubEntry Manager\"}",
         "subtreeSpecification: {base \"ou=Test SubEntry Manager\", specificationFilter \"(objectClass=*)\"}",
         "cn: Subentry");
    AddOperation addOperation =
         connection.processAdd(relativeSubentry.getDN(),
@@ -644,7 +643,7 @@
      if (subentry.getDN().equals(relativeSubentry.getDN()))
      {
        SubtreeSpecification spec = subentry.getSubTreeSpecification();
        assertTrue(spec instanceof RelativeSubtreeSpecification);
        assertTrue(spec.getRefinements() instanceof SubtreeSpecification.FilterRefinement);
      }
    }
opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRelativeSubtreeSpecification.java
File was deleted
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.types;
@@ -35,15 +36,9 @@
import java.util.List;
import org.opends.server.TestCaseUtils;
import org.opends.server.util.StaticUtils;
import org.opends.messages.MessageBuilder;
import org.opends.server.api.SubtreeSpecificationSet;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.RFC3672SubtreeSpecification;
import org.opends.server.schema.AttributeTypeSyntax;
import org.opends.server.schema.BooleanSyntax;
import org.opends.server.schema.IntegerSyntax;
import org.opends.server.schema.RFC3672SubtreeSpecificationSyntax;
import org.opends.server.schema.*;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeClass;
@@ -264,7 +259,7 @@
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetAttributeValuesRFC3672SubtreeSpecification()
  public void testGetAttributeValuesSubtreeSpecification()
      throws Exception {
    // Define a dummy attribute type, in case there is not one already
    // in the core schema.
@@ -286,12 +281,12 @@
    SubtreeSpecificationSet expected = new SubtreeSpecificationSet();
    for (String value : values) {
      expected.add(RFC3672SubtreeSpecification.valueOf(rootDN, value));
      expected.add(SubtreeSpecification.valueOf(rootDN, value));
    }
    Entry entry = createTestEntry(type, values);
    SubtreeSpecificationSet result = new SubtreeSpecificationSet();
    entry.getAttributeValues(type, RFC3672SubtreeSpecificationSyntax
    entry.getAttributeValues(type, SubtreeSpecificationSyntax
        .createAttributeValueDecoder(rootDN), result);
    assertEquals(expected, result);
opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.java
File was renamed from opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRFC3672SubtreeSpecification.java
@@ -23,27 +23,29 @@
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.core;
package org.opends.server.types;
import static org.testng.AssertJUnit.assertEquals;
import org.opends.server.api.SubtreeSpecification;
import org.opends.server.core.SubtreeSpecificationTestCase;
import org.opends.server.types.DN;
import org.opends.server.types.SubtreeSpecification;
import org.testng.annotations.Test;
/**
 * This class defines a set of tests for the
 * {@link org.opends.server.core.RFC3672SubtreeSpecification} class.
 * {@link org.opends.server.types.SubtreeSpecification} class.
 */
public final class TestRFC3672SubtreeSpecification extends
public final class TestSubtreeSpecification extends
    SubtreeSpecificationTestCase {
  // Cached root DN.
  private DN rootDN = DN.nullDN();
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -55,13 +57,13 @@
    String input = "{}";
    String output = "{ }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -73,13 +75,13 @@
    String input = "  {    }    ";
    String output = "{ }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -91,13 +93,13 @@
    String input = "{ base \"dc=sun, dc=com\" }";
    String output = "{ base \"dc=sun,dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -109,13 +111,13 @@
    String input = "{base \"dc=sun, dc=com\"}";
    String output = "{ base \"dc=sun,dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -129,13 +131,13 @@
    String output = "{ base \"dc=sun,dc=com\", "
        + "specificationFilter item:ds-config-rootDN }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -152,13 +154,13 @@
        + "chopAfter:\"o=xyz\" }, maximum 10, specificationFilter "
        + "not:not:item:foo }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -174,13 +176,13 @@
        + "chopAfter:\"o=xyz\" }, "
        + "maximum 10, specificationFilter not:not:item:foo }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -192,13 +194,13 @@
    String input = "{ specificationFilter and:{item:top, item:person} }";
    String output = "{ specificationFilter and:{item:top, item:person} }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -210,13 +212,13 @@
    String input = "{ specificationFilter or:{item:top, item:person} }";
    String output = "{ specificationFilter or:{item:top, item:person} }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#valueOf(DN, String)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
@@ -230,13 +232,33 @@
    String output = "{ specificationFilter "
        + "or:{item:top, item:foo, and:{item:one, item:two}} }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf11() throws Exception {
    String input = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter \"(objectClass=*)\" }";
    String output = "{ base \"dc=sun,dc=com\", "
        + "specificationFilter \"(objectClass=*)\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -247,7 +269,7 @@
    DN dn = DN.decode("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -255,7 +277,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -266,7 +288,7 @@
    DN dn = DN.decode("dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -274,7 +296,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -285,7 +307,7 @@
    DN dn = DN.decode("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -293,7 +315,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -304,7 +326,7 @@
    DN dn = DN.decode("dc=foo, dc=bar, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -312,7 +334,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -323,7 +345,7 @@
    DN dn = DN.decode("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -331,7 +353,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -342,7 +364,7 @@
    DN dn = DN.decode("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -350,7 +372,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -361,7 +383,7 @@
    DN dn = DN.decode("dc=xyz, dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -369,7 +391,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -380,7 +402,7 @@
    DN dn = DN.decode("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 0 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -388,7 +410,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -399,7 +421,7 @@
    DN dn = DN.decode("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 0 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -407,7 +429,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -418,7 +440,7 @@
    DN dn = DN.decode("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 1 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -426,7 +448,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -437,7 +459,7 @@
    DN dn = DN.decode("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 2 }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -445,7 +467,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -457,7 +479,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -465,7 +487,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -477,7 +499,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -485,7 +507,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -497,7 +519,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"dc=foo\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -505,7 +527,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -517,7 +539,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"dc=foo\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -525,7 +547,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -537,7 +559,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -545,7 +567,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -557,7 +579,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -565,7 +587,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -577,7 +599,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -585,7 +607,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -597,7 +619,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter item:person }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
@@ -605,7 +627,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -617,7 +639,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter item:organization }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -625,7 +647,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -637,7 +659,7 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter not:item:person }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
@@ -645,7 +667,7 @@
  }
  /**
   * Tests the {@link RFC3672SubtreeSpecification#isWithinScope(Entry)}
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
@@ -657,10 +679,50 @@
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter not:item:organization }";
    SubtreeSpecification ss = RFC3672SubtreeSpecification.valueOf(rootDN,
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@code SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches23() throws Exception {
    DN dn = DN.decode("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter \"(objectClass=person)\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@code SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches24() throws Exception {
    DN dn = DN.decode("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter \"(objectClass=organization)\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
}