From 9b9e1da7fc84d1f2c93e5bb6093bd5073557f804 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 25 Feb 2011 15:23:20 +0000
Subject: [PATCH] Fix issue OPENDJ-75: Combine RFC 3672 and relative subtree specification syntax  https://bugster.forgerock.org/jira/browse/OPENDJ-75

---
 opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java                      |   61 -
 /dev/null                                                                                                  |  180 ----
 opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java                                         |   30 
 opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecification.java                             | 1836 +++++++++++++++++++++++++++++++++++++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java                |   15 
 opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecificationSet.java                          |    6 
 opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java                                   |   15 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.java |  198 +++-
 opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java                                 |   25 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java   |    9 
 10 files changed, 1,998 insertions(+), 377 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java
deleted file mode 100644
index ffebe35..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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.
- */
-package org.opends.server.api;
-
-
-
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-
-
-
-/**
- * Generic subtree specification interface.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
-public abstract class SubtreeSpecification
-{
-  /**
-   * Create a new subtree specification.
-   */
-  protected SubtreeSpecification()
-  {
-    // No implementation required.
-  }
-
-
-
-  /**
-   * Get the absolute base DN of the subtree specification.
-   *
-   * @return Returns the absolute base DN of the subtree
-   *         specification.
-   */
-  public abstract DN getBaseDN();
-
-
-
-  /**
-   * 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 abstract boolean isWithinScope(Entry entry);
-
-
-
-  /**
-   * 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 abstract boolean isDNWithinScope(DN dn);
-
-
-
-  /**
-   * 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 abstract boolean equals(Object obj);
-
-
-
-  /**
-   * Retrieves the hash code for this subtree specification object.
-   *
-   * @return  The hash code for this subtree specification object.
-   */
-  @Override
-  public abstract int hashCode();
-
-
-
-  /**
-   * Append the string representation of the subtree specification to
-   * the provided string builder.
-   *
-   * @param  builder  The string builder.
-   * @return  The string builder.
-   */
-  public abstract StringBuilder toString(StringBuilder builder);
-
-
-
-  /**
-   * Retrieves a string representation of this subtree specification
-   * object.
-   *
-   * @return  A string representation of this subtree specification
-   *          object.
-   */
-  @Override
-  public final String toString()
-  {
-    StringBuilder builder = new StringBuilder();
-    return toString(builder).toString();
-  }
-}
-
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/RFC3672SubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/RFC3672SubtreeSpecification.java
deleted file mode 100644
index 2d2adf8..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/core/RFC3672SubtreeSpecification.java
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * 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-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.core;
-import org.opends.messages.Message;
-
-import static org.opends.messages.SchemaMessages.*;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.InputMismatchException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.ResultCode;
-import org.opends.server.util.StaticUtils;
-
-/**
- * An RFC 3672 subtree specification.
- * <p>
- * Refer to RFC 3672 for a detailed definition of the subtree
- * specification string representation.
- */
-public final class RFC3672SubtreeSpecification extends
-    SimpleSubtreeSpecification {
-
-  // The root DN.
-  private DN rootDN;
-
-  // The optional relative base DN.
-  private DN relativeBaseDN;
-
-  // The optional specification filter refinements.
-  private Refinement refinements;
-
-  /**
-   * Abstract interface for RFC3672 specification filter refinements.
-   */
-  public static abstract class Refinement {
-    /**
-     * Create a new RFC3672 specification filter refinement.
-     */
-    protected Refinement() {
-      // No implementation required.
-    }
-
-    /**
-     * 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() {
-      StringBuilder builder = new StringBuilder();
-
-      return toString(builder).toString();
-    }
-
-    /**
-     * Append the string representation of the refinement to the
-     * provided string builder.
-     *
-     * @param builder
-     *          The string builder.
-     * @return The string builder.
-     */
-    public abstract StringBuilder toString(StringBuilder builder);
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public abstract boolean equals(Object obj);
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public abstract int hashCode();
-  }
-
-  /**
-   * 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 String objectClass;
-
-    // The item's normalized object class.
-    private String normalizedObjectClass;
-
-    /**
-     * Create a new item refinement.
-     *
-     * @param objectClass
-     *          The item's object class.
-     */
-    public ItemRefinement(String objectClass) {
-
-      this.objectClass = objectClass;
-      this.normalizedObjectClass = StaticUtils.toLowerCase(objectClass
-          .trim());
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean matches(Entry entry) {
-      ObjectClass oc = DirectoryServer
-          .getObjectClass(normalizedObjectClass);
-
-      if (oc == null) {
-        return false;
-      } else {
-        return entry.hasObjectClass(oc);
-      }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public StringBuilder toString(StringBuilder builder) {
-      builder.append("item:");
-      builder.append(objectClass);
-      return builder;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object obj) {
-
-      if (this == obj) {
-        return true;
-      }
-
-      if (obj instanceof ItemRefinement) {
-        ItemRefinement other = (ItemRefinement) obj;
-
-        return normalizedObjectClass.equals(other.normalizedObjectClass);
-      }
-
-      return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-
-      return normalizedObjectClass.hashCode();
-    }
-  }
-
-  /**
-   * 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 Refinement refinement;
-
-    /**
-     * Create a new NOT refinement.
-     *
-     * @param refinement
-     *          The refinement which must be <code>false</code>.
-     */
-    public NotRefinement(Refinement refinement) {
-
-      this.refinement = refinement;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean matches(Entry entry) {
-      return !refinement.matches(entry);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public StringBuilder toString(StringBuilder builder) {
-      builder.append("not:");
-      return refinement.toString(builder);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object obj) {
-
-      if (this == obj) {
-        return true;
-      }
-
-      if (obj instanceof NotRefinement) {
-        NotRefinement other = (NotRefinement) obj;
-
-        return refinement.equals(other.refinement);
-      }
-
-      return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-
-      return refinement.hashCode();
-    }
-  }
-
-  /**
-   * 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 Collection<Refinement> refinementSet;
-
-    /**
-     * Create a new AND refinement.
-     *
-     * @param refinementSet
-     *          The set of refinements which must all be
-     *          <code>true</code>.
-     */
-    public AndRefinement(Collection<Refinement> refinementSet) {
-
-      this.refinementSet = refinementSet;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean matches(Entry entry) {
-      for (Refinement refinement : refinementSet) {
-        if (refinement.matches(entry) == false) {
-          return false;
-        }
-      }
-
-      // All sub-refinements matched.
-      return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public StringBuilder toString(StringBuilder builder) {
-      switch (refinementSet.size()) {
-      case 0:
-        // Do nothing.
-        break;
-      case 1:
-        refinementSet.iterator().next().toString(builder);
-        break;
-      default:
-        builder.append("and:{");
-        Iterator<Refinement> iterator = refinementSet.iterator();
-        iterator.next().toString(builder);
-        while (iterator.hasNext()) {
-          builder.append(", ");
-          iterator.next().toString(builder);
-        }
-        builder.append("}");
-        break;
-      }
-
-      return builder;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object obj) {
-
-      if (this == obj) {
-        return true;
-      }
-
-      if (obj instanceof AndRefinement) {
-        AndRefinement other = (AndRefinement) obj;
-
-        return refinementSet.equals(other.refinementSet);
-      }
-
-      return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-
-      return refinementSet.hashCode();
-    }
-  }
-
-  /**
-   * 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 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(Collection<Refinement> refinementSet) {
-
-      this.refinementSet = refinementSet;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean matches(Entry entry) {
-      for (Refinement refinement : refinementSet) {
-        if (refinement.matches(entry) == true) {
-          return true;
-        }
-      }
-
-      // No sub-refinements matched.
-      return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public StringBuilder toString(StringBuilder builder) {
-      switch (refinementSet.size()) {
-      case 0:
-        // Do nothing.
-        break;
-      case 1:
-        refinementSet.iterator().next().toString(builder);
-        break;
-      default:
-        builder.append("or:{");
-        Iterator<Refinement> iterator = refinementSet.iterator();
-        iterator.next().toString(builder);
-        while (iterator.hasNext()) {
-          builder.append(", ");
-          iterator.next().toString(builder);
-        }
-        builder.append("}");
-        break;
-      }
-
-      return builder;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object obj) {
-
-      if (this == obj) {
-        return true;
-      }
-
-      if (obj instanceof AndRefinement) {
-        AndRefinement other = (AndRefinement) obj;
-
-        return refinementSet.equals(other.refinementSet);
-      }
-
-      return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-
-      return refinementSet.hashCode();
-    }
-  }
-
-  /**
-   * 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 RFC3672SubtreeSpecification valueOf(DN rootDN, String s)
-      throws DirectoryException {
-
-    // Default values.
-    DN relativeBaseDN = null;
-
-    int minimum = -1;
-    int maximum = -1;
-
-    HashSet<DN> chopBefore = new HashSet<DN>();
-    HashSet<DN> chopAfter = new HashSet<DN>();
-
-    Refinement refinement = null;
-
-    // Value must have an opening left brace.
-    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;
-        }
-
-        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();
-          }
-
-          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 (InputMismatchException e) {
-      isValid = false;
-    } catch (NoSuchElementException e) {
-      isValid = false;
-    }
-
-    if (isValid) {
-      return new RFC3672SubtreeSpecification(rootDN, relativeBaseDN,
-          minimum, maximum, chopBefore, chopAfter, refinement);
-    } else {
-      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(Parser parser)
-      throws InputMismatchException, NoSuchElementException {
-    // Get the type of refinement.
-    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")) {
-      Refinement refinement = parseRefinement(parser);
-      return new NotRefinement(refinement);
-    } else if (type.equals("and")) {
-      ArrayList<Refinement> refinements = parseRefinementSet(parser);
-      return new AndRefinement(refinements);
-    } else if (type.equals("or")) {
-      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(Parser parser)
-      throws InputMismatchException, NoSuchElementException {
-    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.
-      Refinement refinement = parseRefinement(parser);
-      refinements.add(refinement);
-    }
-
-    return 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 RFC3672SubtreeSpecification(DN rootDN, DN relativeBaseDN,
-      int minimumDepth, int maximumDepth, Iterable<DN> chopBefore,
-      Iterable<DN> chopAfter, Refinement refinements) {
-    super(relativeBaseDN == null ? rootDN : rootDN.concat(relativeBaseDN),
-        minimumDepth, maximumDepth, chopBefore, chopAfter);
-
-
-    this.rootDN = rootDN;
-    this.relativeBaseDN = relativeBaseDN;
-    this.refinements = refinements;
-  }
-
-  /**
-   * Get the root DN.
-   *
-   * @return Returns the root DN.
-   */
-  public DN getRootDN() {
-    return rootDN;
-  }
-
-  /**
-   * 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 specification filter refinements.
-   *
-   * @return Returns the specification filter refinements, or
-   *         <code>null</code> if none were specified.
-   */
-  public Refinement getRefinements() {
-    return refinements;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isWithinScope(Entry entry) {
-
-    if (isDNWithinScope(entry.getDN())) {
-      if (refinements != null) {
-        return refinements.matches(entry);
-      } else {
-        return true;
-      }
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public StringBuilder toString(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.
-    Iterable<DN> chopBefore = getChopBefore();
-    Iterable<DN> chopAfter = getChopAfter();
-
-    if ((chopBefore != null && chopBefore.iterator().hasNext())
-        || (chopAfter != null && chopAfter.iterator().hasNext())) {
-
-      if (!isFirstElement) {
-        builder.append(",");
-      } else {
-        isFirstElement = false;
-      }
-      builder.append(" specificExclusions { ");
-
-      boolean isFirst = true;
-
-      if (chopBefore != null) {
-        for (DN dn : chopBefore) {
-          if (!isFirst) {
-            builder.append(", chopBefore:");
-          } else {
-            builder.append("chopBefore:");
-            isFirst = false;
-          }
-          StaticUtils.toRFC3641StringValue(builder, dn.toString());
-        }
-      }
-
-      if (chopAfter != null) {
-        for (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;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean equals(Object obj) {
-
-    if (this == obj) {
-      return true;
-    }
-
-    if (obj instanceof RFC3672SubtreeSpecification) {
-      RFC3672SubtreeSpecification other = (RFC3672SubtreeSpecification) 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;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public int hashCode() {
-
-    int hash = commonComponentsHashCode();
-
-    hash = hash * 31 + getBaseDN().hashCode();
-
-    if (refinements != null) {
-      hash = hash * 31 + refinements.hashCode();
-    }
-
-    return hash;
-  }
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
deleted file mode 100644
index 125c65e..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * 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.
- */
-package org.opends.server.core;
-import org.opends.messages.Message;
-
-import static org.opends.messages.SchemaMessages.*;
-
-import java.util.HashSet;
-import java.util.InputMismatchException;
-import java.util.NoSuchElementException;
-
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.util.StaticUtils;
-
-/**
- * A relative subtree specification.
- * <p>
- * Relative subtree specifications are very similar toRFC 3672 subtree
- * specifications with the only difference being that the specification
- * filter is not a set of refinements, but an LDAP search filter.
- * <p>
- * The string representation of a relative subtree specification is
- * defined by the following grammar:
- *
- * <pre>
- *  SubtreeSpecification  = &quot;{&quot;
- *                              [     sp ss-relative-base ]
- *                              [ sep sp ss-specificExclusions ]
- *                              [ sep sp ss-minimum ]
- *                              [ sep sp ss-maximum ]
- *                              [ sep sp ss-specificationFilter ]
- *                       sp &quot;}&quot;
- *
- *  ss-relative-base      = &quot;relativeBase&amp;quot msp DistinguishedName
- *
- *  ss-specificExclusions = &quot;specificExclusions&amp;quot
- *                                             msp SpecificExclusions
- *
- *  ss-minimum            = &quot;minimum&amp;quot msp BaseDistance
- *
- *  ss-maximum            = &quot;maximum&amp;quot msp BaseDistance
- *
- *  ss-specificationFilter = &quot;specificationFilter&amp;quot msp Filter
- *
- *  SpecificExclusions    = &quot;{&quot;
- *                              [ sp SpecificExclusion
- *                                  ( &quot;,&quot; sp SpecificExclusion ) ]
- *                       sp &quot;}&quot;
- *
- *  SpecificExclusion     = chopBefore / chopAfter
- *
- *  chopBefore            = &quot;chopBefore&amp;quot &quot;:&quot; LocalName
- *
- *  chopAfter             = &quot;chopAfter&amp;quot &quot;:&quot; LocalName
- *
- *  Filter                = dquote *SafeUTF8Character dquote
- * </pre>
- */
-public final class RelativeSubtreeSpecification extends
-    SimpleSubtreeSpecification {
-
-  // The root DN.
-  private DN rootDN;
-
-  // The optional relative base DN.
-  private DN relativeBaseDN;
-
-  // The optional search filter.
-  private SearchFilter filter;
-
-  /**
-   * Parses the string argument as a relative subtree specification.
-   *
-   * @param rootDN
-   *          The DN of the subtree specification's base entry.
-   * @param s
-   *          The string to be parsed.
-   * @return The relative subtree specification represented by the
-   *         string argument.
-   * @throws DirectoryException
-   *           If the string does not contain a parsable relative
-   *           subtree specification.
-   */
-  public static RelativeSubtreeSpecification valueOf(DN rootDN, String s)
-      throws DirectoryException {
-
-    // Default values.
-    DN relativeBaseDN = null;
-
-    int minimum = -1;
-    int maximum = -1;
-
-    HashSet<DN> chopBefore = new HashSet<DN>();
-    HashSet<DN> chopAfter = new HashSet<DN>();
-
-    SearchFilter filter = null;
-
-    // Value must have an opening left brace.
-    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;
-        }
-
-        String key = parser.nextKey();
-        if (key.equals("relativebase")) {
-          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 (filter != null) {
-            // Filter specified more than once.
-            throw new InputMismatchException();
-          }
-          filter = SearchFilter.createFilterFromString(parser
-              .nextStringValue());
-        } 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 (InputMismatchException e) {
-      isValid = false;
-    } catch (NoSuchElementException e) {
-      isValid = false;
-    }
-
-    if (isValid) {
-      return new RelativeSubtreeSpecification(rootDN, relativeBaseDN,
-          minimum, maximum, chopBefore, chopAfter, filter);
-    } else {
-      Message message =
-          ERR_ATTR_SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_INVALID.get(s);
-      throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
-          message);
-    }
-  }
-
-  /**
-   * Create a new relative 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 base
-   *          DN), or <code>null</code> if there are none.
-   * @param chopAfter
-   *          The set of chop after local names (relative to the base
-   *          DN), or <code>null</code> if there are none.
-   * @param filter
-   *          The optional search filter (<code>null</code> if there
-   *          is no filter).
-   */
-  public RelativeSubtreeSpecification(DN rootDN, DN relativeBaseDN,
-      int minimumDepth, int maximumDepth, Iterable<DN> chopBefore,
-      Iterable<DN> chopAfter, SearchFilter filter) {
-    super(relativeBaseDN == null ? rootDN : rootDN.concat(relativeBaseDN),
-        minimumDepth, maximumDepth, chopBefore, chopAfter);
-
-
-    this.rootDN = rootDN;
-    this.relativeBaseDN = relativeBaseDN;
-    this.filter = filter;
-  }
-
-  /**
-   * Get the root DN.
-   *
-   * @return Returns the root DN.
-   */
-  public DN getRootDN() {
-    return rootDN;
-  }
-
-  /**
-   * 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 specification filter.
-   *
-   * @return Returns the search filter, or <code>null</code> if there
-   *         is no filter.
-   */
-  public SearchFilter getFilter() {
-    return filter;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean isWithinScope(Entry entry) {
-
-    if (isDNWithinScope(entry.getDN())) {
-      if (filter != null) {
-        try {
-          return filter.matchesEntry(entry);
-        } catch (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;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public StringBuilder toString(StringBuilder builder) {
-
-    boolean isFirstElement = true;
-
-    // Output the optional base DN.
-    builder.append("{");
-    if (relativeBaseDN != null && !relativeBaseDN.isNullDN()) {
-      builder.append(" relativeBase ");
-      StaticUtils.toRFC3641StringValue(builder, relativeBaseDN.toString());
-      isFirstElement = false;
-    }
-
-    // Output the optional specific exclusions.
-    Iterable<DN> chopBefore = getChopBefore();
-    Iterable<DN> chopAfter = getChopAfter();
-
-    if ((chopBefore != null && chopBefore.iterator().hasNext())
-        || (chopAfter != null && chopAfter.iterator().hasNext())) {
-
-      if (!isFirstElement) {
-        builder.append(",");
-      } else {
-        isFirstElement = false;
-      }
-      builder.append(" specificExclusions { ");
-
-      boolean isFirst = true;
-
-      if (chopBefore != null) {
-        for (DN dn : chopBefore) {
-          if (!isFirst) {
-            builder.append(", chopBefore:");
-          } else {
-            builder.append("chopBefore:");
-            isFirst = false;
-          }
-          StaticUtils.toRFC3641StringValue(builder, dn.toString());
-        }
-      }
-
-      if (chopAfter != null) {
-        for (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 filter.
-    if (filter != null) {
-      if (!isFirstElement) {
-        builder.append(",");
-      } else {
-        isFirstElement = false;
-      }
-      builder.append(" specificationFilter ");
-      StaticUtils.toRFC3641StringValue(builder, filter.toString());
-    }
-
-    builder.append(" }");
-
-    return builder;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean equals(Object obj) {
-
-    if (this == obj) {
-      return true;
-    }
-
-    if (obj instanceof RelativeSubtreeSpecification) {
-      RelativeSubtreeSpecification other = (RelativeSubtreeSpecification) obj;
-
-      if (!commonComponentsEquals(other)) {
-        return false;
-      }
-
-      if (!getBaseDN().equals(other.getBaseDN())) {
-        return false;
-      }
-
-      if (filter != null) {
-        return filter.equals(other.filter);
-      } else {
-        return filter == other.filter;
-      }
-    }
-
-    return false;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public int hashCode() {
-
-    int hash = commonComponentsHashCode();
-
-    hash = hash * 31 + getBaseDN().hashCode();
-
-    if (filter != null) {
-      hash = hash * 31 + filter.hashCode();
-    }
-
-    return hash;
-  }
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
deleted file mode 100644
index d303493..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * 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.
- */
-package org.opends.server.core;
-
-import java.util.InputMismatchException;
-import java.util.NoSuchElementException;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.regex.Pattern;
-
-import org.opends.server.api.SubtreeSpecification;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.util.StaticUtils;
-
-/**
- * A simple subtree specification implementation that has a subtree
- * base, optional minimum and maximum depths, and a set of chop
- * specifications.
- */
-public abstract class SimpleSubtreeSpecification extends
-    SubtreeSpecification {
-
-
-  // The absolute base of the subtree.
-  private DN baseDN;
-
-  // Optional minimum depth (<=0 means unlimited).
-  private int minimumDepth;
-
-  // Optional maximum depth (<0 means unlimited).
-  private int maximumDepth;
-
-  // Optional set of chop before absolute DNs (mapping to their
-  // local-names).
-  private TreeMap<DN, DN> chopBefore;
-
-  // Optional set of chop after absolute DNs (mapping to their
-  // local-names).
-  private TreeMap<DN, DN> chopAfter;
-
-  /**
-   * 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 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(String value) {
-      this.scanner = new Scanner(value);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * 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);
-    }
-
-    /**
-     * Determine if there are remaining tokens.
-     *
-     * @return <code>true</code> if and only if there are remaining
-     *         tokens.
-     */
-    public boolean hasNext() {
-      return scanner.hasNext();
-    }
-
-    /**
-     * 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 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 {
-      String s = nextValue(INT, INT_TOKEN);
-      return Integer.parseInt(s);
-    }
-
-    /**
-     * 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
-     * escaped 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 {
-      String s = nextValue(STRING_VALUE, STRING_VALUE_TOKEN);
-      return s.substring(1, s.length() - 1).replace("\"\"", "\"");
-    }
-
-    /**
-     * 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(Set<DN> chopBefore, 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>.
-        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();
-        }
-      }
-    }
-
-    /**
-     * 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(Pattern head, Pattern content)
-        throws InputMismatchException, NoSuchElementException {
-      if (!scanner.hasNext()) {
-        throw new java.util.NoSuchElementException();
-      }
-
-      if (!scanner.hasNext(head)) {
-        throw new java.util.InputMismatchException();
-      }
-
-      String s = scanner.findInLine(content);
-      if (s == null) {
-        throw new java.util.InputMismatchException();
-      }
-
-      return s;
-    }
-  }
-
-  /**
-   * Create a new simple subtree specification.
-   *
-   * @param baseDN
-   *          The absolute base DN of the subtree.
-   * @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 base
-   *          DN), or <code>null</code> if there are none.
-   * @param chopAfter
-   *          The set of chop after local names (relative to the base
-   *          DN), or <code>null</code> if there are none.
-   */
-  protected SimpleSubtreeSpecification(DN baseDN, int minimumDepth,
-      int maximumDepth, Iterable<DN> chopBefore, Iterable<DN> chopAfter) {
-
-    this.baseDN = baseDN;
-    this.minimumDepth = minimumDepth;
-    this.maximumDepth = maximumDepth;
-
-    if (chopBefore != null && chopBefore.iterator().hasNext()) {
-      // Calculate the absolute DNs.
-      this.chopBefore = new TreeMap<DN, DN>();
-
-      for (DN localName : chopBefore) {
-        this.chopBefore.put(baseDN.concat(localName), localName);
-      }
-    } else {
-      // No chop before specifications.
-      this.chopBefore = null;
-    }
-
-    if (chopAfter != null && chopAfter.iterator().hasNext()) {
-      // Calculate the absolute DNs.
-      this.chopAfter = new TreeMap<DN, DN>();
-
-      for (DN localName : chopAfter) {
-        this.chopAfter.put(baseDN.concat(localName), localName);
-      }
-    } else {
-      // No chop after specifications.
-      this.chopAfter = null;
-    }
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public final boolean isDNWithinScope(DN dn) {
-
-    if (!dn.isDescendantOf(baseDN)) {
-      return false;
-    }
-
-    // Check minimum and maximum depths.
-    int baseRDNCount = baseDN.getNumComponents();
-
-    if (minimumDepth > 0) {
-      int entryRDNCount = dn.getNumComponents();
-
-      if (entryRDNCount - baseRDNCount < minimumDepth) {
-        return false;
-      }
-    }
-
-    if (maximumDepth >= 0) {
-      int entryRDNCount = dn.getNumComponents();
-
-      if (entryRDNCount - baseRDNCount > maximumDepth) {
-        return false;
-      }
-    }
-
-    // Check exclusions.
-    if (chopBefore != null) {
-      for (DN chopBeforeDN : chopBefore.keySet()) {
-        if (dn.isDescendantOf(chopBeforeDN)) {
-          return false;
-        }
-      }
-    }
-
-    if (chopAfter != null) {
-      for (DN chopAfterDN : chopAfter.keySet()) {
-        if (!dn.equals(chopAfterDN) && dn.isDescendantOf(chopAfterDN)) {
-          return false;
-        }
-      }
-    }
-
-    // Everything seemed to match.
-    return true;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public final DN getBaseDN() {
-    return baseDN;
-  }
-
-  /**
-   * Determine if the common components of this subtree specification
-   * are equal to the common components of another subtre specification.
-   *
-   * @param other
-   *          The other subtree specification.
-   * @return Returns <code>true</code> if they are equal.
-   */
-  protected final boolean commonComponentsEquals(
-      SimpleSubtreeSpecification other) {
-
-    if (this == other) {
-      return true;
-    }
-
-    if (minimumDepth != other.minimumDepth) {
-      return false;
-    }
-
-    if (maximumDepth != other.maximumDepth) {
-      return false;
-    }
-
-    if (chopBefore != null && other.chopBefore != null) {
-      if (!chopBefore.values().equals(other.chopBefore.values())) {
-        return false;
-      }
-    } else if (chopBefore != other.chopBefore) {
-      return false;
-    }
-
-    if (chopAfter != null && other.chopAfter != null) {
-      if (!chopAfter.values().equals(other.chopAfter.values())) {
-        return false;
-      }
-    } else if (chopAfter != other.chopAfter) {
-      return false;
-    }
-
-    return true;
-  }
-
-  /**
-   * Get a hash code of the subtree specification's common components.
-   *
-   * @return The computed hash code.
-   */
-  protected final int commonComponentsHashCode() {
-
-    int hash = minimumDepth * 31 + maximumDepth;
-
-    if (chopBefore != null) {
-      hash = hash * 31 + chopBefore.values().hashCode();
-    }
-
-    if (chopAfter != null) {
-      hash = hash * 31 + chopAfter.values().hashCode();
-    }
-
-    return hash;
-  }
-
-  /**
-   * Get the set of chop after relative DNs.
-   *
-   * @return Returns the set of chop after relative DNs, or
-   *         <code>null</code> if there are not any.
-   */
-  public final Iterable<DN> getChopAfter() {
-
-    if (chopAfter != null) {
-      return chopAfter.values();
-    } else {
-      return null;
-    }
-  }
-
-  /**
-   * Get the set of chop before relative DNs.
-   *
-   * @return Returns the set of chop before relative DNs, or
-   *         <code>null</code> if there are not any.
-   */
-  public final Iterable<DN> getChopBefore() {
-
-    if (chopBefore != null) {
-      return chopBefore.values();
-    } else {
-      return null;
-    }
-  }
-
-  /**
-   * Get the maximum depth of the subtree specification.
-   *
-   * @return Returns the maximum depth (<0 indicates unlimited depth).
-   */
-  public final int getMaximumDepth() {
-    return maximumDepth;
-  }
-
-  /**
-   * Get the minimum depth of the subtree specification.
-   *
-   * @return Returns the minimum depth (<=0 indicates unlimited depth).
-   */
-  public final int getMinimumDepth() {
-    return minimumDepth;
-  }
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java
index b94f46a..df7d46c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java
+++ b/opendj-sdk/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;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java b/opendj-sdk/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
deleted file mode 100644
index 3328aad..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/RFC3672SubtreeSpecificationSyntax.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.schema;
-
-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.*;
-import org.opends.messages.MessageBuilder;
-import static org.opends.server.schema.SchemaConstants.*;
-
-import org.opends.server.admin.std.server.AttributeSyntaxCfg;
-import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.api.AttributeSyntax;
-import org.opends.server.api.AttributeValueDecoder;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.config.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.RFC3672SubtreeSpecification;
-import org.opends.server.types.*;
-
-
-/**
- * This class defines the subtree specification attribute syntax, which
- * is used to specify the scope of sub-entries (RFC 3672). Equality will
- * be allowed eventually, although it's not implemented yet.
- */
-public final class RFC3672SubtreeSpecificationSyntax
-       extends AttributeSyntax<AttributeSyntaxCfg>
-{
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  // The default equality matching rule for this syntax.
-  private EqualityMatchingRule defaultEqualityMatchingRule;
-
-  // The default ordering matching rule for this syntax.
-  private OrderingMatchingRule defaultOrderingMatchingRule;
-
-  // The default substring matching rule for this syntax.
-  private SubstringMatchingRule defaultSubstringMatchingRule;
-
-  /**
-   * Create a new attribute value decoder with the specified root DN.
-   *
-   * @param rootDN
-   *          The root DN for all decoded subtree specifications.
-   * @return The attribute value decoder.
-   */
-  public static AttributeValueDecoder<RFC3672SubtreeSpecification>
-      createAttributeValueDecoder(DN rootDN) {
-    return new Decoder(rootDN);
-  }
-
-  /**
-   * Internal class implementing an attribute value decoder.
-   */
-  private static class Decoder implements
-      AttributeValueDecoder<RFC3672SubtreeSpecification> {
-
-    // The root DN for all decoded relative subtree specifications.
-    private DN rootDN;
-
-    /**
-     * Create a new decoder with the specified root DN.
-     *
-     * @param rootDN
-     *          The root DN for all decoded relative subtree
-     *          specifications.
-     */
-    public Decoder(DN rootDN) {
-      this.rootDN = rootDN;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public RFC3672SubtreeSpecification decode(AttributeValue value)
-        throws DirectoryException {
-      return RFC3672SubtreeSpecification.valueOf(rootDN, value
-          .getValue().toString());
-    }
-  }
-
-  /**
-   * Creates a new instance of this syntax. Note that the only thing
-   * that should be done here is to invoke the default constructor for
-   * the superclass. All initialization should be performed in the
-   * <CODE>initializeSyntax</CODE> method.
-   */
-  public RFC3672SubtreeSpecificationSyntax() {
-    // No implementation required.
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public void initializeSyntax(AttributeSyntaxCfg configuration)
-      throws ConfigException {
-
-    defaultEqualityMatchingRule = DirectoryServer
-        .getEqualityMatchingRule(EMR_OCTET_STRING_OID);
-    if (defaultEqualityMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
-          EMR_OCTET_STRING_OID, SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME));
-    }
-
-    defaultOrderingMatchingRule = DirectoryServer
-        .getOrderingMatchingRule(OMR_OCTET_STRING_OID);
-    if (defaultOrderingMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
-          OMR_OCTET_STRING_OID, SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME));
-    }
-
-    defaultSubstringMatchingRule = DirectoryServer
-        .getSubstringMatchingRule(SMR_OCTET_STRING_OID);
-    if (defaultSubstringMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
-          SMR_OCTET_STRING_OID, SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME));
-    }
-  }
-
-  /**
-   * Retrieves the common name for this attribute syntax.
-   *
-   * @return The common name for this attribute syntax.
-   */
-  public String getSyntaxName() {
-
-    return SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME;
-  }
-
-  /**
-   * Retrieves the OID for this attribute syntax.
-   *
-   * @return The OID for this attribute syntax.
-   */
-  public String getOID() {
-
-    return SYNTAX_RFC3672_SUBTREE_SPECIFICATION_OID;
-  }
-
-  /**
-   * Retrieves a description for this attribute syntax.
-   *
-   * @return A description for this attribute syntax.
-   */
-  public String getDescription() {
-
-    return SYNTAX_RFC3672_SUBTREE_SPECIFICATION_DESCRIPTION;
-  }
-
-  /**
-   * Retrieves the default equality matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default equality matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         equality matches will not be allowed for this type by
-   *         default.
-   */
-  public EqualityMatchingRule getEqualityMatchingRule() {
-
-    return defaultEqualityMatchingRule;
-  }
-
-  /**
-   * Retrieves the default ordering matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default ordering matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         ordering matches will not be allowed for this type by
-   *         default.
-   */
-  public OrderingMatchingRule getOrderingMatchingRule() {
-
-    return defaultOrderingMatchingRule;
-  }
-
-  /**
-   * Retrieves the default substring matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default substring matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         substring matches will not be allowed for this type by
-   *         default.
-   */
-  public SubstringMatchingRule getSubstringMatchingRule() {
-
-    return defaultSubstringMatchingRule;
-  }
-
-  /**
-   * Retrieves the default approximate matching rule that will be used
-   * for attributes with this syntax.
-   *
-   * @return The default approximate matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         approximate matches will not be allowed for this type by
-   *         default.
-   */
-  public ApproximateMatchingRule getApproximateMatchingRule() {
-
-    // There is no approximate matching rule by default.
-    return null;
-  }
-
-  /**
-   * Indicates whether the provided value is acceptable for use in an
-   * attribute with this syntax. If it is not, then the reason may be
-   * appended to the provided buffer.
-   *
-   * @param value
-   *          The value for which to make the determination.
-   * @param invalidReason
-   *          The buffer to which the invalid reason should be appended.
-   * @return <CODE>true</CODE> if the provided value is acceptable for
-   *         use with this syntax, or <CODE>false</CODE> if not.
-   */
-  public boolean valueIsAcceptable(ByteSequence value,
-                                   MessageBuilder invalidReason) {
-
-    // Use the subtree specification code to make this determination.
-    try {
-      RFC3672SubtreeSpecification.valueOf(DN.nullDN(), value.toString());
-
-      return true;
-    } catch (DirectoryException e) {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      invalidReason.append(e.getMessageObject());
-      return false;
-    }
-  }
-
-
-
- /**
-   * {@inheritDoc}
-   */
-  public boolean isBinary()
-  {
-    return false;
-  }
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java b/opendj-sdk/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
deleted file mode 100644
index 2442d14..0000000
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/RelativeSubtreeSpecificationSyntax.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * 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-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.schema;
-
-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.*;
-import org.opends.messages.MessageBuilder;
-import static org.opends.server.schema.SchemaConstants.*;
-
-import org.opends.server.admin.std.server.AttributeSyntaxCfg;
-import org.opends.server.api.ApproximateMatchingRule;
-import org.opends.server.api.AttributeSyntax;
-import org.opends.server.api.AttributeValueDecoder;
-import org.opends.server.api.EqualityMatchingRule;
-import org.opends.server.api.OrderingMatchingRule;
-import org.opends.server.api.SubstringMatchingRule;
-import org.opends.server.config.ConfigException;
-import org.opends.server.core.DirectoryServer;
-import org.opends.server.core.RelativeSubtreeSpecification;
-import org.opends.server.types.*;
-
-
-/**
- * This class defines the relative subtree specification attribute
- * syntax, which is used to specify the scope of access controls and
- * their parameters.
- */
-public final class RelativeSubtreeSpecificationSyntax
-       extends AttributeSyntax<AttributeSyntaxCfg>
-{
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  // The default equality matching rule for this syntax.
-  private EqualityMatchingRule defaultEqualityMatchingRule;
-
-  // The default ordering matching rule for this syntax.
-  private OrderingMatchingRule defaultOrderingMatchingRule;
-
-  // The default substring matching rule for this syntax.
-  private SubstringMatchingRule defaultSubstringMatchingRule;
-
-
-
-  /**
-   * Create a new attribute value decoder with the specified root DN.
-   *
-   * @param rootDN
-   *          The root DN for all decoded relative subtree
-   *          specifications.
-   * @return The attribute value decoder.
-   */
-  public static AttributeValueDecoder<RelativeSubtreeSpecification>
-      createAttributeValueDecoder(DN rootDN) {
-    return new Decoder(rootDN);
-  }
-
-  /**
-   * Internal class implementing an attribute value decoder.
-   */
-  private static class Decoder implements
-      AttributeValueDecoder<RelativeSubtreeSpecification> {
-
-    // The root DN for all decoded relative subtree specifications.
-    private DN rootDN;
-
-    /**
-     * Create a new decoder with the specified root DN.
-     *
-     * @param rootDN
-     *          The root DN for all decoded relative subtree
-     *          specifications.
-     */
-    public Decoder(DN rootDN) {
-      this.rootDN = rootDN;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public RelativeSubtreeSpecification decode(AttributeValue value)
-        throws DirectoryException {
-      return RelativeSubtreeSpecification.valueOf(rootDN, value
-          .getValue().toString());
-    }
-  }
-
-  /**
-   * Creates a new instance of this syntax. Note that the only thing
-   * that should be done here is to invoke the default constructor for
-   * the superclass. All initialization should be performed in the
-   * <CODE>initializeSyntax</CODE> method.
-   */
-  public RelativeSubtreeSpecificationSyntax() {
-    // No implementation required.
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public void initializeSyntax(AttributeSyntaxCfg configuration)
-         throws ConfigException {
-
-    defaultEqualityMatchingRule = DirectoryServer
-        .getEqualityMatchingRule(EMR_OCTET_STRING_OID);
-    if (defaultEqualityMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
-          EMR_OCTET_STRING_OID, SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME));
-    }
-
-    defaultOrderingMatchingRule = DirectoryServer
-        .getOrderingMatchingRule(OMR_OCTET_STRING_OID);
-    if (defaultOrderingMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
-          OMR_OCTET_STRING_OID, SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME));
-    }
-
-    defaultSubstringMatchingRule = DirectoryServer
-        .getSubstringMatchingRule(SMR_OCTET_STRING_OID);
-    if (defaultSubstringMatchingRule == null) {
-      logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
-          SMR_OCTET_STRING_OID, SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME));
-    }
-  }
-
-  /**
-   * Retrieves the common name for this attribute syntax.
-   *
-   * @return The common name for this attribute syntax.
-   */
-  public String getSyntaxName() {
-
-    return SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME;
-  }
-
-  /**
-   * Retrieves the OID for this attribute syntax.
-   *
-   * @return The OID for this attribute syntax.
-   */
-  public String getOID() {
-
-    return SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_OID;
-  }
-
-  /**
-   * Retrieves a description for this attribute syntax.
-   *
-   * @return A description for this attribute syntax.
-   */
-  public String getDescription() {
-
-    return SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_DESCRIPTION;
-  }
-
-  /**
-   * Retrieves the default equality matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default equality matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         equality matches will not be allowed for this type by
-   *         default.
-   */
-  public EqualityMatchingRule getEqualityMatchingRule() {
-
-    return defaultEqualityMatchingRule;
-  }
-
-  /**
-   * Retrieves the default ordering matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default ordering matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         ordering matches will not be allowed for this type by
-   *         default.
-   */
-  public OrderingMatchingRule getOrderingMatchingRule() {
-
-    return defaultOrderingMatchingRule;
-  }
-
-  /**
-   * Retrieves the default substring matching rule that will be used for
-   * attributes with this syntax.
-   *
-   * @return The default substring matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         substring matches will not be allowed for this type by
-   *         default.
-   */
-  public SubstringMatchingRule getSubstringMatchingRule() {
-
-    return defaultSubstringMatchingRule;
-  }
-
-  /**
-   * Retrieves the default approximate matching rule that will be used
-   * for attributes with this syntax.
-   *
-   * @return The default approximate matching rule that will be used for
-   *         attributes with this syntax, or <CODE>null</CODE> if
-   *         approximate matches will not be allowed for this type by
-   *         default.
-   */
-  public ApproximateMatchingRule getApproximateMatchingRule() {
-
-    // There is no approximate matching rule by default.
-    return null;
-  }
-
-  /**
-   * Indicates whether the provided value is acceptable for use in an
-   * attribute with this syntax. If it is not, then the reason may be
-   * appended to the provided buffer.
-   *
-   * @param value
-   *          The value for which to make the determination.
-   * @param invalidReason
-   *          The buffer to which the invalid reason should be appended.
-   * @return <CODE>true</CODE> if the provided value is acceptable for
-   *         use with this syntax, or <CODE>false</CODE> if not.
-   */
-  public boolean valueIsAcceptable(ByteSequence value,
-                                   MessageBuilder invalidReason) {
-
-    // Use the subtree specification code to make this determination.
-    try {
-      RelativeSubtreeSpecification.valueOf(DN.nullDN(), value.toString());
-
-      return true;
-    } catch (DirectoryException e) {
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      invalidReason.append(e.getMessageObject());
-      return false;
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean isBinary()
-  {
-    return false;
-  }
-}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java b/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java
index ad1987f..1ee117c 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java
+++ b/opendj-sdk/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 =
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java b/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
index b747ba6..17f5893 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
+++ b/opendj-sdk/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;
   }
 
  /**
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java b/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java
index e916f12..86944a3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java
+++ b/opendj-sdk/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);
     }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecification.java
new file mode 100644
index 0000000..103a880
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecification.java
@@ -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;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecificationSet.java b/opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecificationSet.java
similarity index 96%
rename from opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecificationSet.java
rename to opendj-sdk/opends/src/server/org/opends/server/types/SubtreeSpecificationSet.java
index 5f3dab9..bcc982a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecificationSet.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/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
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
index 70ee499..8f8fb61 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
+++ b/opendj-sdk/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);
       }
     }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRelativeSubtreeSpecification.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRelativeSubtreeSpecification.java
deleted file mode 100644
index 34d726a..0000000
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRelativeSubtreeSpecification.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.core;
-
-import static org.testng.AssertJUnit.assertEquals;
-
-import org.opends.server.api.SubtreeSpecification;
-import org.opends.server.types.DN;
-import org.testng.annotations.Test;
-
-/**
- * This class defines a set of tests for the
- * {@link org.opends.server.core.RelativeSubtreeSpecification} class.
- * <p>
- * This test suite is shorter than the RFC 3672 test suite because it
- * focuses on testing only the pieces of functionality that are specific
- * to the syntax.
- */
-public final class TestRelativeSubtreeSpecification extends
-    SubtreeSpecificationTestCase {
-
-  // Cached root DN.
-  private DN rootDN = DN.nullDN();
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#valueOf(DN, String)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testValueOf1() throws Exception {
-
-    String input = "{}";
-    String output = "{ }";
-
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        input);
-    assertEquals(output, ss.toString());
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#valueOf(DN, String)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testValueOf2() throws Exception {
-
-    String input = "  {    }    ";
-    String output = "{ }";
-
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        input);
-    assertEquals(output, ss.toString());
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#valueOf(DN, String)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testValueOf3() throws Exception {
-
-    String input = "{ relativeBase \"dc=sun, dc=com\" }";
-    String output = "{ relativeBase \"dc=sun,dc=com\" }";
-
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        input);
-    assertEquals(output, ss.toString());
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#valueOf(DN, String)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testValueOf4() throws Exception {
-
-    String input = "{relativeBase \"dc=sun, dc=com\"}";
-    String output = "{ relativeBase \"dc=sun,dc=com\" }";
-
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        input);
-    assertEquals(output, ss.toString());
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#valueOf(DN, String)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testValueOf5() throws Exception {
-
-    String input = "{ relativeBase \"dc=sun, dc=com\", "
-        + "specificationFilter \"(objectClass=*)\" }";
-    String output = "{ relativeBase \"dc=sun,dc=com\", "
-        + "specificationFilter \"(objectClass=*)\" }";
-
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        input);
-    assertEquals(output, ss.toString());
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#isWithinScope(Entry)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testMatches1() throws Exception {
-    DN dn = DN.decode("dc=abc, dc=sun, dc=com");
-
-    String value = "{ relativeBase \"dc=sun, dc=com\", "
-        + "specificationFilter \"(objectClass=person)\" }";
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        value);
-
-    assertEquals(true, ss
-        .isWithinScope(createEntry(dn, getObjectClasses())));
-  }
-
-  /**
-   * Tests the {@link RelativeSubtreeSpecification#isWithinScope(Entry)}
-   * method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testMatches2() throws Exception {
-    DN dn = DN.decode("dc=abc, dc=sun, dc=com");
-
-    String value = "{ relativeBase \"dc=sun, dc=com\", "
-        + "specificationFilter \"(objectClass=organization)\" }";
-    SubtreeSpecification ss = RelativeSubtreeSpecification.valueOf(rootDN,
-        value);
-
-    assertEquals(false, ss
-        .isWithinScope(createEntry(dn, getObjectClasses())));
-  }
-}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
index a02d6a0..303b64a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
+++ b/opendj-sdk/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);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRFC3672SubtreeSpecification.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.java
similarity index 69%
rename from opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRFC3672SubtreeSpecification.java
rename to opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.java
index 686ead3..a2ed15d 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestRFC3672SubtreeSpecification.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/TestSubtreeSpecification.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())));
+  }
 }

--
Gitblit v1.10.0