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

Jean-Noël Rouvignac
24.25.2016 464832bbd5ec8f33c27aff4bbb58317415e35609
*.java: code cleanup

Removed code duplication
4 files modified
1835 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/core/SubentryManager.java 406 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/SubEntry.java 276 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/SubtreeSpecification.java 382 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/types/TestSubtreeSpecification.java 771 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/SubentryManager.java
@@ -12,11 +12,19 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2009-2010 Sun Microsystems, Inc.
 * Portions Copyright 2011-2015 ForgeRock AS.
 * Portions Copyright 2011-2016 ForgeRock AS.
 */
package org.opends.server.core;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -38,7 +46,14 @@
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
import org.opends.server.types.*;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.Privilege;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SubEntry;
import org.opends.server.types.SubtreeSpecification;
import org.opends.server.types.operation.PostOperationAddOperation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
@@ -75,27 +90,22 @@
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** A mapping between the DNs and applicable subentries. */
  private Map<DN,List<SubEntry>> dn2SubEntry;
  /** A mapping between the DNs and applicable collective subentries. */
  private Map<DN,List<SubEntry>> dn2CollectiveSubEntry;
  /** A mapping between subentry DNs and subentry objects. */
  private DITCacheMap<SubEntry> dit2SubEntry;
  /** Internal search all operational attributes. */
  private Set<String> requestAttrs;
  /** Lock to protect internal data structures. */
  private final ReadWriteLock lock;
  /** The set of change notification listeners. */
  private List<SubentryChangeListener> changeListeners;
  /** Dummy configuration DN for Subentry Manager. */
  private static final String CONFIG_DN = "cn=Subentry Manager,cn=config";
  /** A mapping between the DNs and applicable subentries. */
  private final Map<DN, List<SubEntry>> dn2SubEntry = new HashMap<>();
  /** A mapping between the DNs and applicable collective subentries. */
  private final Map<DN, List<SubEntry>> dn2CollectiveSubEntry = new HashMap<>();
  /** A mapping between subentry DNs and subentry objects. */
  private final DITCacheMap<SubEntry> dit2SubEntry = new DITCacheMap<>();
  /** Internal search all operational attributes. */
  private final Set<String> requestAttrs = newLinkedHashSet("*", "+");
  /** Lock to protect internal data structures. */
  private final ReadWriteLock lock = new ReentrantReadWriteLock();
  /** The set of change notification listeners. */
  private final List<SubentryChangeListener> changeListeners = new CopyOnWriteArrayList<>();
  /**
   * Creates a new instance of this subentry manager.
   *
@@ -120,14 +130,6 @@
          PluginType.POST_SYNCHRONIZATION_MODIFY_DN),
          true);
    lock = new ReentrantReadWriteLock();
    dn2SubEntry = new HashMap<>();
    dn2CollectiveSubEntry = new HashMap<>();
    dit2SubEntry = new DITCacheMap<>();
    changeListeners = new CopyOnWriteArrayList<>();
    requestAttrs = newLinkedHashSet("*", "+");
    DirectoryServer.registerInternalPlugin(this);
    DirectoryServer.registerBackendInitializationListener(this);
  }
@@ -179,32 +181,17 @@
  private void addSubentry(Entry entry) throws DirectoryException
  {
    SubEntry subEntry = new SubEntry(entry);
    SubtreeSpecification subSpec =
            subEntry.getSubTreeSpecification();
    SubtreeSpecification subSpec = subEntry.getSubTreeSpecification();
    DN subDN = subSpec.getBaseDN();
    List<SubEntry> subList = null;
    lock.writeLock().lock();
    try
    {
      if (subEntry.isCollective() || subEntry.isInheritedCollective())
      {
        subList = dn2CollectiveSubEntry.get(subDN);
      }
      else
      {
        subList = dn2SubEntry.get(subDN);
      }
      Map<DN, List<SubEntry>> subEntryMap = getSubEntryMap(subEntry);
      List<SubEntry> subList = subEntryMap.get(subDN);
      if (subList == null)
      {
        subList = new ArrayList<>();
        if (subEntry.isCollective() || subEntry.isInheritedCollective())
        {
          dn2CollectiveSubEntry.put(subDN, subList);
        }
        else
        {
          dn2SubEntry.put(subDN, subList);
        }
        subEntryMap.put(subDN, subList);
      }
      dit2SubEntry.put(entry.getName(), subEntry);
      subList.add(subEntry);
@@ -215,68 +202,25 @@
    }
  }
  private Map<DN, List<SubEntry>> getSubEntryMap(SubEntry subEntry)
  {
    return (subEntry.isCollective() || subEntry.isInheritedCollective()) ? dn2CollectiveSubEntry : dn2SubEntry;
  }
  /**
   * Remove a given entry from this subentry manager.
   * @param entry to remove.
   *
   * @param entry
   *          to remove.
   */
  private void removeSubentry(Entry entry)
  {
    lock.writeLock().lock();
    try
    {
      boolean removed = false;
      Iterator<Map.Entry<DN, List<SubEntry>>> setIterator =
              dn2SubEntry.entrySet().iterator();
      while (setIterator.hasNext())
      if (!removeSubEntry(dn2SubEntry, entry))
      {
        Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
        List<SubEntry> subList = mapEntry.getValue();
        Iterator<SubEntry> listIterator = subList.iterator();
        while (listIterator.hasNext())
        {
          SubEntry subEntry = listIterator.next();
          if (subEntry.getDN().equals(entry.getName()))
          {
            dit2SubEntry.remove(entry.getName());
            listIterator.remove();
            removed = true;
            break;
          }
        }
        if (subList.isEmpty())
        {
          setIterator.remove();
        }
        if (removed)
        {
          return;
        }
      }
      setIterator = dn2CollectiveSubEntry.entrySet().iterator();
      while (setIterator.hasNext())
      {
        Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
        List<SubEntry> subList = mapEntry.getValue();
        Iterator<SubEntry> listIterator = subList.iterator();
        while (listIterator.hasNext())
        {
          SubEntry subEntry = listIterator.next();
          if (subEntry.getDN().equals(entry.getName()))
          {
            dit2SubEntry.remove(entry.getName());
            listIterator.remove();
            removed = true;
            break;
          }
        }
        if (subList.isEmpty())
        {
          setIterator.remove();
        }
        if (removed)
        {
          return;
        }
        removeSubEntry(dn2CollectiveSubEntry, entry);
      }
    }
    finally
@@ -285,6 +229,31 @@
    }
  }
  private boolean removeSubEntry(Map<DN, List<SubEntry>> subEntryMap, Entry entry)
  {
    Iterator<List<SubEntry>> subEntryListsIt = subEntryMap.values().iterator();
    while (subEntryListsIt.hasNext())
    {
      List<SubEntry> subEntries = subEntryListsIt.next();
      Iterator<SubEntry> subEntriesIt = subEntries.iterator();
      while (subEntriesIt.hasNext())
      {
        SubEntry subEntry = subEntriesIt.next();
        if (subEntry.getDN().equals(entry.getName()))
        {
          dit2SubEntry.remove(entry.getName());
          subEntriesIt.remove();
          if (subEntries.isEmpty())
          {
            subEntryListsIt.remove();
          }
          return true;
        }
      }
    }
    return false;
  }
  /**
   * {@inheritDoc}  In this case, the server will search the backend to find
   * all subentries that it may contain and register them with this manager.
@@ -417,31 +386,33 @@
   * Return subentries applicable to specific DN.
   * Note that this getter will skip any collective subentries,
   * returning only applicable regular subentries.
   * @param  dn for which to retrieve applicable
   *         subentries.
   * @param  dn for which to retrieve applicable subentries.
   * @return applicable subentries.
   */
  public List<SubEntry> getSubentries(DN dn)
  {
    if (dn2SubEntry.isEmpty())
    return getSubentries(dn2SubEntry, dn);
  }
  private List<SubEntry> getSubentries(Map<DN, List<SubEntry>> subEntryMap, DN dn)
  {
    if (subEntryMap.isEmpty())
    {
      return Collections.emptyList();
    }
    List<SubEntry> subentries = new ArrayList<>();
    lock.readLock().lock();
    try
    {
      for (DN subDN = dn; subDN != null;
           subDN = subDN.parent())
      List<SubEntry> subentries = new ArrayList<>();
      for (DN subDN = dn; subDN != null; subDN = subDN.parent())
      {
        List<SubEntry> subList = dn2SubEntry.get(subDN);
        List<SubEntry> subList = subEntryMap.get(subDN);
        if (subList != null)
        {
          for (SubEntry subEntry : subList)
          {
            SubtreeSpecification subSpec =
                    subEntry.getSubTreeSpecification();
            SubtreeSpecification subSpec = subEntry.getSubTreeSpecification();
            if (subSpec.isDNWithinScope(dn))
            {
              subentries.add(subEntry);
@@ -449,13 +420,12 @@
          }
        }
      }
      return subentries;
    }
    finally
    {
      lock.readLock().unlock();
    }
    return subentries;
  }
  /**
@@ -468,26 +438,28 @@
   */
  public List<SubEntry> getSubentries(Entry entry)
  {
    if (dn2SubEntry.isEmpty())
    return getSubentries(dn2SubEntry, entry);
  }
  private List<SubEntry> getSubentries(Map<DN, List<SubEntry>> subEntryMap, Entry entry)
  {
    if (subEntryMap.isEmpty())
    {
      return Collections.emptyList();
    }
    List<SubEntry> subentries = new ArrayList<>();
    lock.readLock().lock();
    try
    {
      for (DN subDN = entry.getName(); subDN != null;
           subDN = subDN.parent())
      List<SubEntry> subentries = new ArrayList<>();
      for (DN subDN = entry.getName(); subDN != null; subDN = subDN.parent())
      {
        List<SubEntry> subList = dn2SubEntry.get(subDN);
        List<SubEntry> subList = subEntryMap.get(subDN);
        if (subList != null)
        {
          for (SubEntry subEntry : subList)
          {
            SubtreeSpecification subSpec =
                    subEntry.getSubTreeSpecification();
            SubtreeSpecification subSpec = subEntry.getSubTreeSpecification();
            if (subSpec.isWithinScope(entry))
            {
              subentries.add(subEntry);
@@ -495,13 +467,12 @@
          }
        }
      }
      return subentries;
    }
    finally
    {
      lock.readLock().unlock();
    }
    return subentries;
  }
  /**
@@ -514,40 +485,7 @@
   */
  public List<SubEntry> getCollectiveSubentries(DN dn)
  {
    if (dn2CollectiveSubEntry.isEmpty())
    {
      return Collections.emptyList();
    }
    List<SubEntry> subentries = new ArrayList<>();
    lock.readLock().lock();
    try
    {
      for (DN subDN = dn; subDN != null;
           subDN = subDN.parent())
      {
        List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN);
        if (subList != null)
        {
          for (SubEntry subEntry : subList)
          {
            SubtreeSpecification subSpec =
                    subEntry.getSubTreeSpecification();
            if (subSpec.isDNWithinScope(dn))
            {
              subentries.add(subEntry);
            }
          }
        }
      }
    }
    finally
    {
      lock.readLock().unlock();
    }
    return subentries;
    return getSubentries(dn2CollectiveSubEntry, dn);
  }
  /**
@@ -560,40 +498,7 @@
   */
  public List<SubEntry> getCollectiveSubentries(Entry entry)
  {
    if (dn2CollectiveSubEntry.isEmpty())
    {
      return Collections.emptyList();
    }
    List<SubEntry> subentries = new ArrayList<>();
    lock.readLock().lock();
    try
    {
      for (DN subDN = entry.getName(); subDN != null;
           subDN = subDN.parent())
      {
        List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN);
        if (subList != null)
        {
          for (SubEntry subEntry : subList)
          {
            SubtreeSpecification subSpec =
                    subEntry.getSubTreeSpecification();
            if (subSpec.isWithinScope(entry))
            {
              subentries.add(subEntry);
            }
          }
        }
      }
    }
    finally
    {
      lock.readLock().unlock();
    }
    return subentries;
    return getSubentries(dn2CollectiveSubEntry, entry);
  }
  /**
@@ -606,77 +511,8 @@
    lock.writeLock().lock();
    try
    {
      Iterator<Map.Entry<DN, List<SubEntry>>> setIterator =
              dn2SubEntry.entrySet().iterator();
      while (setIterator.hasNext())
      {
        Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
        List<SubEntry> subList = mapEntry.getValue();
        Iterator<SubEntry> listIterator = subList.iterator();
        while (listIterator.hasNext())
        {
          SubEntry subEntry = listIterator.next();
          if (backend.handlesEntry(subEntry.getDN()))
          {
            dit2SubEntry.remove(subEntry.getDN());
            listIterator.remove();
            // Notify change listeners.
            for (SubentryChangeListener changeListener :
              changeListeners)
            {
              try
              {
                changeListener.handleSubentryDelete(
                        subEntry.getEntry());
              }
              catch (Exception e)
              {
                logger.traceException(e);
              }
            }
          }
        }
        if (subList.isEmpty())
        {
          setIterator.remove();
        }
      }
      setIterator = dn2CollectiveSubEntry.entrySet().iterator();
      while (setIterator.hasNext())
      {
        Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next();
        List<SubEntry> subList = mapEntry.getValue();
        Iterator<SubEntry> listIterator = subList.iterator();
        while (listIterator.hasNext())
        {
          SubEntry subEntry = listIterator.next();
          if (backend.handlesEntry(subEntry.getDN()))
          {
            dit2SubEntry.remove(subEntry.getDN());
            listIterator.remove();
            // Notify change listeners.
            for (SubentryChangeListener changeListener :
              changeListeners)
            {
              try
              {
                changeListener.handleSubentryDelete(
                        subEntry.getEntry());
              }
              catch (Exception e)
              {
                logger.traceException(e);
              }
            }
          }
        }
        if (subList.isEmpty())
        {
          setIterator.remove();
        }
      }
      performBackendPostFinalizationProcessing(dn2SubEntry, backend);
      performBackendPostFinalizationProcessing(dn2CollectiveSubEntry, backend);
    }
    finally
    {
@@ -684,6 +520,42 @@
    }
  }
  private void performBackendPostFinalizationProcessing(Map<DN, List<SubEntry>> subEntryMap, Backend<?> backend)
  {
    Iterator<List<SubEntry>> subEntryListsIt = subEntryMap.values().iterator();
    while (subEntryListsIt.hasNext())
    {
      List<SubEntry> subEntryList = subEntryListsIt.next();
      Iterator<SubEntry> subEntriesIt = subEntryList.iterator();
      while (subEntriesIt.hasNext())
      {
        SubEntry subEntry = subEntriesIt.next();
        if (backend.handlesEntry(subEntry.getDN()))
        {
          dit2SubEntry.remove(subEntry.getDN());
          subEntriesIt.remove();
          // Notify change listeners.
          for (SubentryChangeListener changeListener : changeListeners)
          {
            try
            {
              changeListener.handleSubentryDelete(subEntry.getEntry());
            }
            catch (Exception e)
            {
              logger.traceException(e);
            }
          }
        }
      }
      if (subEntryList.isEmpty())
      {
        subEntryListsIt.remove();
      }
    }
  }
  @Override
  public void performBackendPostInitializationProcessing(Backend<?> backend) {
    // Nothing to do.
@@ -860,7 +732,6 @@
    }
  }
  /** {@inheritDoc} */
  @Override
  public PreOperation doPreOperation(
          PreOperationAddOperation addOperation)
@@ -898,7 +769,6 @@
    return PluginResult.PreOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PreOperation doPreOperation(
          PreOperationDeleteOperation deleteOperation)
@@ -950,7 +820,6 @@
    return PluginResult.PreOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PreOperation doPreOperation(
          PreOperationModifyOperation modifyOperation)
@@ -991,7 +860,6 @@
    return PluginResult.PreOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PreOperation doPreOperation(PreOperationModifyDNOperation modifyDNOperation)
  {
@@ -1049,7 +917,6 @@
    return PluginResult.PreOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PostOperation doPostOperation(
          PostOperationAddOperation addOperation)
@@ -1065,7 +932,6 @@
    return PluginResult.PostOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PostOperation doPostOperation(
          PostOperationDeleteOperation deleteOperation)
@@ -1081,7 +947,6 @@
    return PluginResult.PostOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PostOperation doPostOperation(
          PostOperationModifyOperation modifyOperation)
@@ -1098,7 +963,6 @@
    return PluginResult.PostOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public PostOperation doPostOperation(
          PostOperationModifyDNOperation modifyDNOperation)
@@ -1115,7 +979,6 @@
    return PluginResult.PostOperation.continueOperationProcessing();
  }
  /** {@inheritDoc} */
  @Override
  public void doPostSynchronization(
      PostSynchronizationAddOperation addOperation)
@@ -1127,7 +990,6 @@
    }
  }
  /** {@inheritDoc} */
  @Override
  public void doPostSynchronization(
      PostSynchronizationDeleteOperation deleteOperation)
@@ -1139,7 +1001,6 @@
    }
  }
  /** {@inheritDoc} */
  @Override
  public void doPostSynchronization(
      PostSynchronizationModifyOperation modifyOperation)
@@ -1152,7 +1013,6 @@
    }
  }
  /** {@inheritDoc} */
  @Override
  public void doPostSynchronization(
      PostSynchronizationModifyDNOperation modifyDNOperation)
opendj-server-legacy/src/main/java/org/opends/server/types/SubEntry.java
@@ -26,6 +26,7 @@
import org.opends.server.core.DirectoryServer;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.server.types.SubEntry.CollectiveConflictBehavior.*;
import static org.opends.server.util.ServerConstants.*;
/**
@@ -73,7 +74,6 @@
      this.name = name;
    }
    /** {@inheritDoc} */
    @Override
    public String toString()
    {
@@ -81,57 +81,26 @@
    }
  }
  /**
   * The name of the "collectiveConflictBehavior" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR =
          "collectiveconflictbehavior";
  /**
   * The name of the "inheritFromDNAttribute" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN =
          "inheritfromdnattribute";
  /**
   * The name of the "inheritFromRDNAttribute" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN =
          "inheritfromrdnattribute";
  /**
   * The name of the "inheritFromRDNType" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE =
          "inheritfromrdntype";
  /**
   * The name of the "inheritFromBaseRDN" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE =
          "inheritfrombaserdn";
  /**
   * The name of the "inheritAttribute" attribute type,
   * formatted in all lowercase characters.
   */
  public static final String ATTR_INHERIT_COLLECTIVE_ATTR =
          "inheritattribute";
  /** The lowercased name of the "collectiveConflictBehavior" attribute type. */
  public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC = "collectiveconflictbehavior";
  /** The lowercased name of the "inheritFromDNAttribute" attribute type. */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN_LC = "inheritfromdnattribute";
  /** The lowercased name of the "inheritFromRDNAttribute" attribute type. */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC = "inheritfromrdnattribute";
  /** The lowercased name of the "inheritFromRDNType" attribute type. */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC = "inheritfromrdntype";
  /** The lowercased name of the "inheritFromBaseRDN" attribute type. */
  public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC = "inheritfrombaserdn";
  /** The lowercased name of the "inheritAttribute" attribute type. */
  public static final String ATTR_INHERIT_COLLECTIVE_ATTR_LC = "inheritattribute";
  /** Attribute option to mark attributes collective. */
  private static final String ATTR_OPTION_COLLECTIVE =
          "collective";
  private static final String ATTR_OPTION_COLLECTIVE = "collective";
  /** Entry object. */
  private Entry entry;
  /** Subtree specification. */
  private SubtreeSpecification subTreeSpec;
  private final SubtreeSpecification subTreeSpec;
  /** Collective subentry flag. */
  private boolean isCollective;
@@ -158,11 +127,10 @@
  private DN inheritFromBaseDN;
  /** Collective attributes. */
  private List<Attribute> collectiveAttributes;
  private final List<Attribute> collectiveAttributes = new ArrayList<>();
  /** Conflict behavior. */
  private CollectiveConflictBehavior conflictBehavior =
          CollectiveConflictBehavior.REAL_OVERRIDES_VIRTUAL;
  private CollectiveConflictBehavior conflictBehavior = REAL_OVERRIDES_VIRTUAL;
  /**
   * Constructs a subentry object from a given entry object.
@@ -174,73 +142,17 @@
  {
    this.entry = entry;
    // Process subtree specification.
    this.subTreeSpec = null;
    String specString = null;
    boolean isValidSpec = true;
    AttributeType specAttrType = DirectoryServer.getAttributeType(ATTR_SUBTREE_SPEC_LC);
    for (Attribute attr : entry.getAttribute(specAttrType))
    {
      for (ByteString value : attr)
      {
        specString = value.toString();
        try
        {
          this.subTreeSpec = SubtreeSpecification.valueOf(entry.getName().parent(), specString);
          isValidSpec = true;
        }
        catch (DirectoryException de)
        {
          isValidSpec = false;
        }
        if (this.subTreeSpec != null)
        {
          break;
        }
      }
      if (this.subTreeSpec != null)
      {
        break;
      }
    }
    // Check that the subtree spec is flagged as valid. If it is not
    // that means all parsers have failed and it is invalid syntax.
    if (!isValidSpec)
    {
      LocalizableMessage message =
        ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
          specString);
      throw new DirectoryException(
              ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
    }
    // Subentry has to to have a subtree specification.
    if (this.subTreeSpec == null)
    {
      // There is none for some reason eg this could be
      // old Draft based ldapSubEntry so create a dummy.
      this.subTreeSpec = new SubtreeSpecification(entry.getName().parent(),
          null, -1, -1, null, null, null);
    }
    // Determine if this subentry is collective attribute subentry.
    this.subTreeSpec = buildSubTreeSpecification(entry);
    this.isCollective = entry.isCollectiveAttributeSubentry();
    // Determine if this subentry is inherited collective
    // attribute subentry and if so what kind.
    this.isInheritedCollective =
            entry.isInheritedCollectiveAttributeSubentry();
    this.isInheritedCollective = entry.isInheritedCollectiveAttributeSubentry();
    if (this.isInheritedCollective)
    {
      this.isInheritedFromDNCollective =
              entry.isInheritedFromDNCollectiveAttributeSubentry();
      this.isInheritedFromRDNCollective =
              entry.isInheritedFromRDNCollectiveAttributeSubentry();
      this.isInheritedFromDNCollective = entry.isInheritedFromDNCollectiveAttributeSubentry();
      this.isInheritedFromRDNCollective = entry.isInheritedFromRDNCollectiveAttributeSubentry();
    }
    // Process collective attributes.
    this.collectiveAttributes = new ArrayList<>();
    if (this.isCollective)
    {
      List<Attribute> subAttrList = entry.getAttributes();
@@ -249,9 +161,7 @@
        AttributeType attrType = subAttr.getAttributeDescription().getAttributeType();
        if (attrType.isCollective())
        {
          CollectiveVirtualAttribute collectiveAttr =
                  new CollectiveVirtualAttribute(subAttr);
          this.collectiveAttributes.add(collectiveAttr);
          this.collectiveAttributes.add(new CollectiveVirtualAttribute(subAttr));
        }
        else if (subAttr.hasOption(ATTR_OPTION_COLLECTIVE))
        {
@@ -259,14 +169,13 @@
          builder.addAll(subAttr);
          for (String option : subAttr.getAttributeDescription().getOptions())
          {
            if (!option.equals(ATTR_OPTION_COLLECTIVE))
            if (!ATTR_OPTION_COLLECTIVE.equals(option))
            {
              builder.setOption(option);
            }
          }
          Attribute attr = builder.toAttribute();
          CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(attr);
          this.collectiveAttributes.add(collectiveAttr);
          this.collectiveAttributes.add(new CollectiveVirtualAttribute(attr));
        }
      }
    }
@@ -276,7 +185,7 @@
    {
      if (this.isInheritedFromDNCollective)
      {
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_DN))
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_DN_LC))
        {
          for (ByteString value : attr)
          {
@@ -289,7 +198,7 @@
      if (this.isInheritedFromRDNCollective)
      {
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN))
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC))
        {
          for (ByteString value : attr)
          {
@@ -298,7 +207,7 @@
            break;
          }
        }
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE))
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC))
        {
          for (ByteString value : attr)
          {
@@ -306,7 +215,7 @@
            break;
          }
        }
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE))
        for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC))
        {
          for (ByteString value : attr)
          {
@@ -318,13 +227,12 @@
        }
      }
      for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_ATTR))
      for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_ATTR_LC))
      {
        for (ByteString value : attr)
        {
          CollectiveVirtualAttribute collectiveAttr =
              new CollectiveVirtualAttribute(Attributes.empty(value.toString()));
          this.collectiveAttributes.add(collectiveAttr);
          Attribute collectiveAttr = Attributes.empty(value.toString());
          this.collectiveAttributes.add(new CollectiveVirtualAttribute(collectiveAttr));
        }
      }
    }
@@ -332,7 +240,7 @@
    // Establish collective attribute conflict behavior.
    if (this.isCollective || this.isInheritedCollective)
    {
      for (Attribute attr : entry.getAttribute(ATTR_COLLECTIVE_CONFLICT_BEHAVIOR))
      for (Attribute attr : entry.getAttribute(ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC))
      {
        for (ByteString value : attr)
        {
@@ -349,6 +257,46 @@
    }
  }
  private SubtreeSpecification buildSubTreeSpecification(Entry entry) throws DirectoryException
  {
    String specString = null;
    boolean isValidSpec = true;
    AttributeType specAttrType = DirectoryServer.getAttributeType(ATTR_SUBTREE_SPEC_LC);
    for (Attribute attr : entry.getAttribute(specAttrType))
    {
      for (ByteString value : attr)
      {
        specString = value.toString();
        try
        {
          SubtreeSpecification subTreeSpec = SubtreeSpecification.valueOf(entry.getName().parent(), specString);
          if (subTreeSpec != null)
          {
            return subTreeSpec;
          }
          isValidSpec = true;
        }
        catch (DirectoryException ignored)
        {
          isValidSpec = false;
        }
      }
    }
    // Check that the subtree spec is flagged as valid. If it is not
    // that means all parsers have failed and it is invalid syntax.
    if (!isValidSpec)
    {
      LocalizableMessage message = ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(specString);
      throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
    }
    // Subentry has to have a subtree specification.
    // There is none for some reason eg this could be
    // old Draft based ldapSubEntry so create a dummy.
    return new SubtreeSpecification(entry.getName().parent(), null, -1, -1, null, null, null);
  }
  /**
   * Retrieves the distinguished name for this subentry.
   * @return  The distinguished name for this subentry.
@@ -359,8 +307,7 @@
  }
  /**
   * Getter to retrieve the actual entry object
   * for this subentry.
   * Getter to retrieve the actual entry object for this subentry.
   * @return entry object for this subentry.
   */
  public final Entry getEntry()
@@ -369,10 +316,8 @@
  }
  /**
   * Indicates whether or not this subentry is
   * a collective attribute subentry.
   * @return <code>true</code> if collective,
   *         <code>false</code> otherwise.
   * Indicates whether this subentry is a collective attribute subentry.
   * @return {@code true} if collective, {@code false} otherwise.
   */
  public boolean isCollective()
  {
@@ -380,11 +325,8 @@
  }
  /**
   * Indicates whether or not this subentry is
   * an inherited collective attribute subentry.
   * @return <code>true</code> if inherited
   *         collective, <code>false</code>
   *         otherwise.
   * Indicates whether this subentry is inherited collective attribute subentry.
   * @return {@code true} if inherited collective, {@code false} otherwise.
   */
  public boolean isInheritedCollective()
  {
@@ -392,12 +334,8 @@
  }
  /**
   * Indicates whether or not this subentry is
   * an inherited from DN collective attribute
   * subentry.
   * @return <code>true</code> if inherited
   *         from DN collective,
   *         <code>false</code> otherwise.
   * Indicates whether this subentry is inherited from DN collective attribute subentry.
   * @return {@code true} if inherited from DN collective, {@code false} otherwise.
   */
  public boolean isInheritedFromDNCollective()
  {
@@ -405,12 +343,8 @@
  }
  /**
   * Indicates whether or not this subentry is
   * an inherited from RDN collective attribute
   * subentry.
   * @return <code>true</code> if inherited
   *         from RDN collective,
   *         <code>false</code> otherwise.
   * Indicates whether this subentry is inherited from RDN collective attribute subentry.
   * @return {@code true} if inherited from RDN collective, {@code false} otherwise.
   */
  public boolean isInheritedFromRDNCollective()
  {
@@ -418,10 +352,8 @@
  }
  /**
   * Getter to retrieve inheritFromDNAttribute type
   * for inherited collective attribute subentry.
   * @return Type of inheritFromDNAttribute or,
   *         <code>null</code> if there is none.
   * Getter to retrieve inheritFromDNAttribute type for inherited collective attribute subentry.
   * @return Type of inheritFromDNAttribute, or {@code null} if there is none.
   */
  public AttributeType getInheritFromDNType()
  {
@@ -429,10 +361,8 @@
  }
  /**
   * Getter to retrieve inheritFromRDNAttribute type
   * for inherited collective attribute subentry.
   * @return Type of inheritFromRDNAttribute or,
   *         <code>null</code> if there is none.
   * Getter to retrieve inheritFromRDNAttribute type for inherited collective attribute subentry.
   * @return Type of inheritFromRDNAttribute, or {@code null} if there is none.
   */
  public AttributeType getInheritFromRDNAttrType()
  {
@@ -440,10 +370,8 @@
  }
  /**
   * Getter to retrieve inheritFromRDNAttribute value
   * for inherited collective attribute subentry.
   * @return ByteString of inheritFromRDNAttribute
   *         or, <code>null</code> if there is none.
   * Getter to retrieve inheritFromRDNAttribute value for inherited collective attribute subentry.
   * @return ByteString of inheritFromRDNAttribute, or {@code null} if there is none.
   */
  public ByteString getInheritFromRDNAttrValue()
  {
@@ -451,10 +379,8 @@
  }
  /**
   * Getter to retrieve RDN type of inheritFromRDNType
   * for inherited collective attribute subentry.
   * @return RDN Type of inheritFromRDNAttribute or,
   *         <code>null</code> if there is none.
   * Getter to retrieve RDN type of inheritFromRDNType for inherited collective attribute subentry.
   * @return RDN Type of inheritFromRDNAttribute, or {@code null} if there is none.
   */
  public AttributeType getInheritFromRDNType()
  {
@@ -462,10 +388,8 @@
  }
  /**
   * Getter to retrieve inheritFromDNAttribute value
   * for inherited collective attribute subentry.
   * @return ByteString of inheritFromDNAttribute
   *         or, <code>null</code> if there is none.
   * Getter to retrieve inheritFromDNAttribute value for inherited collective attribute subentry.
   * @return ByteString of inheritFromDNAttribute, or {@code null} if there is none.
   */
  public ByteString getInheritFromDNAttrValue()
  {
@@ -473,10 +397,8 @@
  }
  /**
   * Getter to retrieve inheritFromBaseRDN DN
   * for inherited collective attribute subentry.
   * @return DN of inheritFromBaseRDN or,
   *         <code>null</code> if there is none.
   * Getter to retrieve inheritFromBaseRDN DN for inherited collective attribute subentry.
   * @return DN of inheritFromBaseRDN, or {@code null} if there is none.
   */
  public DN getInheritFromBaseDN()
  {
@@ -502,13 +424,17 @@
  }
  /**
   * Getter for collective conflict behavior defined for this
   * collective attributes subentry.
   * @return conflict behavior for this collective attributes
   *         subentry.
   * Getter for collective conflict behavior defined for this collective attributes subentry.
   * @return conflict behavior for this collective attributes subentry.
   */
  public CollectiveConflictBehavior getConflictBehavior()
  {
    return this.conflictBehavior;
  }
  @Override
  public String toString()
  {
    return getClass().getSimpleName() + "(" + this.entry.getName() + ")";
  }
}
opendj-server-legacy/src/main/java/org/opends/server/types/SubtreeSpecification.java
@@ -16,7 +16,18 @@
 */
package org.opends.server.types;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import org.forgerock.i18n.LocalizableMessage;
@@ -61,8 +72,6 @@
    /** The set of refinements which must all be true. */
    private final Collection<Refinement> refinementSet;
    /**
     * Create a new AND refinement.
     *
@@ -75,9 +84,6 @@
      this.refinementSet = refinementSet;
    }
    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj)
    {
@@ -96,18 +102,12 @@
      return false;
    }
    /** {@inheritDoc} */
    @Override
    public int hashCode()
    {
      return refinementSet.hashCode();
    }
    /** {@inheritDoc} */
    @Override
    public boolean matches(final Entry entry)
    {
@@ -123,9 +123,6 @@
      return true;
    }
    /** {@inheritDoc} */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
@@ -155,18 +152,12 @@
    }
  }
  /**
   * A refinement which uses a search filter.
   */
  /** 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.
     *
@@ -178,9 +169,6 @@
      this.filter = filter;
    }
    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj)
    {
@@ -198,18 +186,12 @@
      return false;
    }
    /** {@inheritDoc} */
    @Override
    public int hashCode()
    {
      return filter.hashCode();
    }
    /** {@inheritDoc} */
    @Override
    public boolean matches(final Entry entry)
    {
@@ -225,9 +207,6 @@
      }
    }
    /** {@inheritDoc} */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
@@ -236,8 +215,6 @@
    }
  }
  /**
   * RFC 3672 subtree specification Item refinement. This type of
   * refinement filters entries based on the presence of a specified
@@ -251,8 +228,6 @@
    /** The item's normalized object class. */
    private final String normalizedObjectClass;
    /**
     * Create a new item refinement.
     *
@@ -266,9 +241,6 @@
          .toLowerCase(objectClass.trim());
    }
    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj)
    {
@@ -288,18 +260,12 @@
      return false;
    }
    /** {@inheritDoc} */
    @Override
    public int hashCode()
    {
      return normalizedObjectClass.hashCode();
    }
    /** {@inheritDoc} */
    @Override
    public boolean matches(final Entry entry)
    {
@@ -307,9 +273,6 @@
      return oc != null && entry.hasObjectClass(oc);
    }
    /** {@inheritDoc} */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
@@ -319,8 +282,6 @@
    }
  }
  /**
   * RFC 3672 subtree specification NOT refinement. This type of
   * refinement filters entries based on the underlying refinement
@@ -332,8 +293,6 @@
    /** The inverted refinement. */
    private final Refinement refinement;
    /**
     * Create a new NOT refinement.
     *
@@ -345,9 +304,6 @@
      this.refinement = refinement;
    }
    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj)
    {
@@ -366,27 +322,18 @@
      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)
    {
@@ -395,8 +342,6 @@
    }
  }
  /**
   * RFC 3672 subtree specification OR refinement. This type of
   * refinement filters entries based on at least one of the
@@ -407,8 +352,6 @@
    /** The set of refinements of which at least one must be true. */
    private final Collection<Refinement> refinementSet;
    /**
     * Create a new OR refinement.
     *
@@ -421,9 +364,6 @@
      this.refinementSet = refinementSet;
    }
    /** {@inheritDoc} */
    @Override
    public boolean equals(final Object obj)
    {
@@ -442,18 +382,12 @@
      return false;
    }
    /** {@inheritDoc} */
    @Override
    public int hashCode()
    {
      return refinementSet.hashCode();
    }
    /** {@inheritDoc} */
    @Override
    public boolean matches(final Entry entry)
    {
@@ -469,9 +403,6 @@
      return false;
    }
    /** {@inheritDoc} */
    @Override
    public StringBuilder toString(final StringBuilder builder)
    {
@@ -501,35 +432,21 @@
    }
  }
  /**
   * Abstract interface for RFC3672 specification filter refinements.
   */
  /** Abstract interface for RFC3672 specification filter refinements. */
  public static abstract class Refinement
  {
    /**
     * Create a new RFC3672 specification filter 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.
     *
@@ -540,9 +457,6 @@
     */
    public abstract boolean matches(Entry entry);
    /** {@inheritDoc} */
    @Override
    public final String toString()
    {
@@ -551,8 +465,6 @@
      return toString(builder).toString();
    }
    /**
     * Append the string representation of the refinement to the
     * provided strin builder.
@@ -564,8 +476,6 @@
    public abstract StringBuilder toString(StringBuilder builder);
  }
  /**
   * Internal utility class which can be used by sub-classes to help
   * parse string representations.
@@ -605,8 +515,6 @@
    private static Pattern STRING_VALUE_TOKEN = Pattern
        .compile("\"([^\"]|(\"\"))*\"");
    /**
     * Create a new parser for a subtree specification string value.
     *
@@ -618,8 +526,6 @@
      this.scanner = new Scanner(value);
    }
    /**
     * Determine if there are remaining tokens.
     *
@@ -631,8 +537,6 @@
      return scanner.hasNext();
    }
    /**
     * Determine if the next token is a right-brace character.
     *
@@ -644,8 +548,6 @@
      return scanner.hasNext(RBRACE);
    }
    /**
     * Scans the next token of the input as a non-negative
     * <code>int</code> value.
@@ -664,8 +566,6 @@
      return Integer.parseInt(s);
    }
    /**
     * Scans the next token of the input as a key value.
     *
@@ -681,8 +581,6 @@
      return StaticUtils.toLowerCase(scanner.next());
    }
    /**
     * Scans the next token of the input as a name value.
     * <p>
@@ -701,8 +599,6 @@
      return nextValue(NAME, NAME_TOKEN);
    }
    /**
     * Scans the next tokens of the input as a set of specific
     * exclusions encoded according to the SpecificExclusion
@@ -724,7 +620,6 @@
        final Set<DN> chopAfter) throws InputMismatchException,
        NoSuchElementException, DirectoryException
    {
      // Skip leading open-brace.
      skipLeftBrace();
@@ -754,11 +649,11 @@
        // <type>:<value>.
        final String type = StaticUtils.toLowerCase(nextName());
        skipColon();
        if (type.equals("chopbefore"))
        if ("chopbefore".equals(type))
        {
          chopBefore.add(DN.valueOf(nextStringValue()));
        }
        else if (type.equals("chopafter"))
        else if ("chopafter".equals(type))
        {
          chopAfter.add(DN.valueOf(nextStringValue()));
        }
@@ -769,8 +664,6 @@
      }
    }
    /**
     * Scans the next token of the input as a string quoted according
     * to the StringValue production in RFC 3641.
@@ -791,8 +684,6 @@
      return s.substring(1, s.length() - 1).replace("\"\"", "\"");
    }
    /**
     * Skip a colon separator.
     *
@@ -807,8 +698,6 @@
      nextValue(COLON, COLON_TOKEN);
    }
    /**
     * Skip a left-brace character.
     *
@@ -823,8 +712,6 @@
      nextValue(LBRACE, LBRACE_TOKEN);
    }
    /**
     * Skip a right-brace character.
     *
@@ -839,8 +726,6 @@
      nextValue(RBRACE, RBRACE_TOKEN);
    }
    /**
     * Skip a comma separator.
     *
@@ -855,8 +740,6 @@
      nextValue(SEP, SEP_TOKEN);
    }
    /**
     * Parse the next token from the string using the specified
     * patterns.
@@ -898,8 +781,6 @@
    }
  }
  /**
   * Parses the string argument as an RFC3672 subtree specification.
   *
@@ -916,7 +797,6 @@
  public static SubtreeSpecification valueOf(final DN rootDN,
      final String s) throws DirectoryException
  {
    // Default values.
    DN relativeBaseDN = null;
@@ -965,7 +845,7 @@
        }
        final String key = parser.nextKey();
        if (key.equals("base"))
        if ("base".equals(key))
        {
          if (relativeBaseDN != null)
          {
@@ -974,7 +854,7 @@
          }
          relativeBaseDN = DN.valueOf(parser.nextStringValue());
        }
        else if (key.equals("minimum"))
        else if ("minimum".equals(key))
        {
          if (minimum != -1)
          {
@@ -983,7 +863,7 @@
          }
          minimum = parser.nextInt();
        }
        else if (key.equals("maximum"))
        else if ("maximum".equals(key))
        {
          if (maximum != -1)
          {
@@ -992,7 +872,7 @@
          }
          maximum = parser.nextInt();
        }
        else if (key.equals("specificationfilter"))
        else if ("specificationfilter".equals(key))
        {
          if (refinement != null)
          {
@@ -1000,8 +880,7 @@
            throw new InputMismatchException();
          }
          // First try normal search filter before RFC3672
          // refinements.
          // First try normal search filter before RFC3672 refinements.
          try
          {
            final SearchFilter filter = SearchFilter
@@ -1013,7 +892,7 @@
            refinement = parseRefinement(parser);
          }
        }
        else if (key.equals("specificexclusions"))
        else if ("specificexclusions".equals(key))
        {
          if (!chopBefore.isEmpty() || !chopAfter.isEmpty())
          {
@@ -1046,22 +925,16 @@
      isValid = false;
    }
    if (isValid)
    {
      return new SubtreeSpecification(rootDN, relativeBaseDN,
          minimum, maximum, chopBefore, chopAfter, refinement);
    }
    else
    if (!isValid)
    {
      final LocalizableMessage message =
        ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID.get(s);
      throw new DirectoryException(
          ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
    }
    return new SubtreeSpecification(rootDN, relativeBaseDN, minimum, maximum, chopBefore, chopAfter, refinement);
  }
  /**
   * Parse a single refinement.
   *
@@ -1082,26 +955,21 @@
    // Skip the colon separator.
    parser.skipColon();
    if (type.equals("item"))
    if ("item".equals(type))
    {
      return new ItemRefinement(parser.nextName());
    }
    else if (type.equals("not"))
    else if ("not".equals(type))
    {
      final Refinement refinement = parseRefinement(parser);
      return new NotRefinement(refinement);
      return new NotRefinement(parseRefinement(parser));
    }
    else if (type.equals("and"))
    else if ("and".equals(type))
    {
      final ArrayList<Refinement> refinements =
        parseRefinementSet(parser);
      return new AndRefinement(refinements);
      return new AndRefinement(parseRefinementSet(parser));
    }
    else if (type.equals("or"))
    else if ("or".equals(type))
    {
      final ArrayList<Refinement> refinements =
        parseRefinementSet(parser);
      return new OrRefinement(refinements);
      return new OrRefinement(parseRefinementSet(parser));
    }
    else
    {
@@ -1110,8 +978,6 @@
    }
  }
  /**
   * Parse a list of refinements.
   *
@@ -1155,15 +1021,12 @@
      }
      // Parse each sub-refinement.
      final Refinement refinement = parseRefinement(parser);
      refinements.add(refinement);
      refinements.add(parseRefinement(parser));
    }
    return refinements;
  }
  /** The absolute base of the subtree. */
  private final DN baseDN;
@@ -1187,8 +1050,6 @@
  /** The optional specification filter refinements. */
  private final Refinement refinements;
  /**
   * Create a new RFC3672 subtree specification.
   *
@@ -1260,8 +1121,6 @@
    this.refinements = refinements;
  }
  /**
   * Indicates whether the provided object is logically equal to this
   * subtree specification object.
@@ -1275,7 +1134,6 @@
  @Override
  public boolean equals(final Object obj)
  {
    if (this == obj)
    {
      return true;
@@ -1285,31 +1143,17 @@
    {
      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 minimumDepth == other.minimumDepth
          && maximumDepth == other.maximumDepth
          && chopBefore.values().equals(other.chopBefore.values())
          && chopAfter.values().equals(other.chopAfter.values())
          && getBaseDN().equals(other.getBaseDN())
          && Objects.equals(refinements, other.refinements);
    }
    return false;
  }
  /**
   * Get the absolute base DN of the subtree specification.
   *
@@ -1321,8 +1165,6 @@
    return baseDN;
  }
  /**
   * Get the set of chop after relative DNs.
   *
@@ -1330,12 +1172,9 @@
   */
  public Iterable<DN> getChopAfter()
  {
    return chopAfter.values();
  }
  /**
   * Get the set of chop before relative DNs.
   *
@@ -1343,12 +1182,9 @@
   */
  public Iterable<DN> getChopBefore()
  {
    return chopBefore.values();
  }
  /**
   * Get the maximum depth of the subtree specification.
   *
@@ -1359,8 +1195,6 @@
    return maximumDepth;
  }
  /**
   * Get the minimum depth of the subtree specification.
   *
@@ -1372,8 +1206,6 @@
    return minimumDepth;
  }
  /**
   * Get the specification filter refinements.
   *
@@ -1385,8 +1217,6 @@
    return refinements;
  }
  /**
   * Get the relative base DN.
   *
@@ -1398,8 +1228,6 @@
    return relativeBaseDN;
  }
  /**
   * Get the root DN.
   *
@@ -1410,8 +1238,6 @@
    return rootDN;
  }
  /**
   * Retrieves the hash code for this subtree specification object.
   *
@@ -1420,9 +1246,9 @@
  @Override
  public int hashCode()
  {
    int hash = commonComponentsHashCode();
    int hash = minimumDepth * 31 + maximumDepth;
    hash = hash * 31 + chopBefore.values().hashCode();
    hash = hash * 31 + chopAfter.values().hashCode();
    hash = hash * 31 + getBaseDN().hashCode();
    if (refinements != null)
@@ -1433,8 +1259,6 @@
    return hash;
  }
  /**
   * Determine if the specified DN is within the scope of the subtree
   * specification.
@@ -1447,7 +1271,6 @@
   */
  public boolean isDNWithinScope(final DN dn)
  {
    if (!dn.isSubordinateOrEqualTo(baseDN))
    {
      return false;
@@ -1497,8 +1320,6 @@
    return true;
  }
  /**
   * Determine if an entry is within the scope of the subtree
   * specification.
@@ -1514,8 +1335,6 @@
        && (refinements == null || refinements.matches(entry));
  }
  /**
   * Retrieves a string representation of this subtree specification
   * object.
@@ -1530,8 +1349,6 @@
    return toString(builder).toString();
  }
  /**
   * Append the string representation of the subtree specification to
   * the provided string builder.
@@ -1542,7 +1359,6 @@
   */
  public StringBuilder toString(final StringBuilder builder)
  {
    boolean isFirstElement = true;
    // Output the optional base DN.
@@ -1550,8 +1366,7 @@
    if (relativeBaseDN != null && !relativeBaseDN.isRootDN())
    {
      builder.append(" base ");
      StaticUtils.toRFC3641StringValue(builder,
          relativeBaseDN.toString());
      StaticUtils.toRFC3641StringValue(builder, relativeBaseDN.toString());
      isFirstElement = false;
    }
@@ -1562,43 +1377,19 @@
    if (chopBefore.iterator().hasNext()
        || chopAfter.iterator().hasNext())
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" specificExclusions { ");
      isFirstElement = append2(builder, isFirstElement, " specificExclusions { ");
      boolean isFirst = true;
      for (final DN dn : chopBefore)
      {
        if (!isFirst)
        {
          builder.append(", chopBefore:");
        }
        else
        {
          builder.append("chopBefore:");
          isFirst = false;
        }
        isFirst = append(builder, isFirst, "chopBefore:");
        StaticUtils.toRFC3641StringValue(builder, dn.toString());
      }
      for (final DN dn : chopAfter)
      {
        if (!isFirst)
        {
          builder.append(", chopAfter:");
        }
        else
        {
          builder.append("chopAfter:");
          isFirst = false;
        }
        isFirst = append(builder, isFirst, "chopAfter:");
        StaticUtils.toRFC3641StringValue(builder, dn.toString());
      }
@@ -1608,45 +1399,21 @@
    // Output the optional minimum depth.
    if (getMinimumDepth() > 0)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" minimum ");
      isFirstElement = append2(builder, isFirstElement, " minimum ");
      builder.append(getMinimumDepth());
    }
    // Output the optional maximum depth.
    if (getMaximumDepth() >= 0)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" maximum ");
      isFirstElement = append2(builder, isFirstElement, " maximum ");
      builder.append(getMaximumDepth());
    }
    // Output the optional refinements.
    if (refinements != null)
    {
      if (!isFirstElement)
      {
        builder.append(",");
      }
      else
      {
        isFirstElement = false;
      }
      builder.append(" specificationFilter ");
      isFirstElement = append2(builder, isFirstElement, " specificationFilter ");
      refinements.toString(builder);
    }
@@ -1655,42 +1422,31 @@
    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)
  private boolean append2(final StringBuilder builder, boolean isFirst, String toAppend)
  {
    if (this == other)
    if (isFirst)
    {
      return true;
      isFirst = false;
    }
    return minimumDepth == other.minimumDepth
        && maximumDepth == other.maximumDepth
        && chopBefore.values().equals(other.chopBefore.values())
        && chopAfter.values().equals(other.chopAfter.values());
    else
    {
      builder.append(",");
    }
    builder.append(toAppend);
    return isFirst;
  }
  /**
   * Get a hash code of the subtree specification's common components.
   *
   * @return The computed hash code.
   */
  private int commonComponentsHashCode()
  private boolean append(final StringBuilder builder, boolean isFirst, String toAppend)
  {
    int hash = minimumDepth * 31 + maximumDepth;
    hash = hash * 31 + chopBefore.values().hashCode();
    hash = hash * 31 + chopAfter.values().hashCode();
    return hash;
    if (isFirst)
    {
      isFirst = false;
    }
    else
    {
      builder.append(", ");
    }
    builder.append(toAppend);
    return isFirst;
  }
}
opendj-server-legacy/src/test/java/org/opends/server/types/TestSubtreeSpecification.java
@@ -16,702 +16,107 @@
 */
package org.opends.server.types;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.Assert.*;
import org.opends.server.core.SubtreeSpecificationTestCase;
import org.opends.server.types.DN;
import org.opends.server.types.SubtreeSpecification;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
 * This class defines a set of tests for the
 * {@link org.opends.server.types.SubtreeSpecification} class.
 */
public final class TestSubtreeSpecification extends
    SubtreeSpecificationTestCase {
/** This class defines a set of tests for the {@link SubtreeSpecification} class. */
@SuppressWarnings("javadoc")
public final class TestSubtreeSpecification extends SubtreeSpecificationTestCase {
  /** Cached root DN. */
  private DN rootDN = DN.rootDN();
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf1() throws Exception {
    String input = "{}";
    String output = "{ }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  @DataProvider
  public Object[][] valueOfData() {
    return new Object[][] {
      { "{}", "{ }" },
      { "  {    }    ", "{ }" },
      { "{ base \"dc=sun, dc=com\" }",
        "{ base \"dc=sun,dc=com\" }" },
      { "{base \"dc=sun, dc=com\"}",
        "{ base \"dc=sun,dc=com\" }" },
      { "{ base \"dc=sun, dc=com\", " + "specificationFilter item:ds-config-rootDN }",
        "{ base \"dc=sun,dc=com\", " + "specificationFilter item:ds-config-rootDN }" },
      { "{ base \"dc=sun, dc=com\", minimum 0 , maximum 10, "
          + "specificExclusions {chopBefore:\"o=abc\", "
          + "chopAfter:\"o=xyz\"} , specificationFilter not:not:item:foo }",
        "{ base \"dc=sun,dc=com\", "
          + "specificExclusions { chopBefore:\"o=abc\", "
          + "chopAfter:\"o=xyz\" }, maximum 10, specificationFilter "
          + "not:not:item:foo }" },
      { "{ base \"\", minimum 0,maximum 10,"
          + "specificExclusions {chopBefore:\"o=abc\","
          + "chopAfter:\"o=xyz\"},specificationFilter not:not:item:foo}",
        "{ specificExclusions { chopBefore:\"o=abc\", "
          + "chopAfter:\"o=xyz\" }, "
          + "maximum 10, specificationFilter not:not:item:foo }" },
      { "{ specificationFilter and:{item:top, item:person} }",
        "{ specificationFilter and:{item:top, item:person} }" },
      { "{ specificationFilter or:{item:top, item:person} }",
        "{ specificationFilter or:{item:top, item:person} }" },
      { "{ specificationFilter or:{item:top, item:foo, and:{item:one, item:two}} }",
        "{ specificationFilter or:{item:top, item:foo, and:{item:one, item:two}} }" },
      { "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=*)\" }",
        "{ base \"dc=sun,dc=com\", specificationFilter \"(objectClass=*)\" }" },
    };
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf2() throws Exception {
    String input = "  {    }    ";
    String output = "{ }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  @Test(dataProvider = "valueOfData")
  public void testValueOf(String specification, String expected) throws Exception {
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, specification);
    assertEquals(ss.toString(), expected);
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf3() throws Exception {
    String input = "{ base \"dc=sun, dc=com\" }";
    String output = "{ base \"dc=sun,dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  @DataProvider
  public Object[][] isWithinScopeData() {
    return new Object[][] {
      { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\" }", true },
      { "dc=com", "{ base \"dc=sun, dc=com\" }", false },
      { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\" }", true },
      { "dc=foo, dc=bar, dc=com", "{ base \"dc=sun, dc=com\" }", false },
      { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", false },
      { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", true },
      { "dc=xyz, dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", true },
      { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 0 }", true },
      { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 0 }", false },
      { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 1 }", false },
      { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 2 }", true },
      { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"\" } }", true },
      { "dc=foo, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"\" } }", false },
      { "dc=foo, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"dc=foo\" } }", true },
      { "dc=bar, dc=foo, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"dc=foo\" } }", false },
      { "dc=foo, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", false },
      { "dc=bar, dc=foo, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", false },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", true },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter item:person }", true },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter item:organization }", false },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter not:item:person }", false },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter not:item:organization }", true },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=person)\" }", true },
      { "dc=abc, dc=sun, dc=com",
        "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=organization)\" }", false },
    };
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf4() throws Exception {
    String input = "{base \"dc=sun, dc=com\"}";
    String output = "{ base \"dc=sun,dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf5() throws Exception {
    String input = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter item:ds-config-rootDN }";
    String output = "{ base \"dc=sun,dc=com\", "
        + "specificationFilter item:ds-config-rootDN }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf6() throws Exception {
    String input = "{ base \"dc=sun, dc=com\", minimum 0 , maximum 10, "
        + "specificExclusions {chopBefore:\"o=abc\", "
        + "chopAfter:\"o=xyz\"} , specificationFilter not:not:item:foo }";
    String output = "{ base \"dc=sun,dc=com\", "
        + "specificExclusions { chopBefore:\"o=abc\", "
        + "chopAfter:\"o=xyz\" }, maximum 10, specificationFilter "
        + "not:not:item:foo }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf7() throws Exception {
    String input = "{ base \"\", minimum 0,maximum 10,"
        + "specificExclusions {chopBefore:\"o=abc\","
        + "chopAfter:\"o=xyz\"},specificationFilter not:not:item:foo}";
    String output = "{ specificExclusions { chopBefore:\"o=abc\", "
        + "chopAfter:\"o=xyz\" }, "
        + "maximum 10, specificationFilter not:not:item:foo }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf8() throws Exception {
    String input = "{ specificationFilter and:{item:top, item:person} }";
    String output = "{ specificationFilter and:{item:top, item:person} }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf9() throws Exception {
    String input = "{ specificationFilter or:{item:top, item:person} }";
    String output = "{ specificationFilter or:{item:top, item:person} }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * Tests the {@link SubtreeSpecification#valueOf(DN, String)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testValueOf10() throws Exception {
    String input = "{ specificationFilter "
        + "or:{item:top, item:foo, and:{item:one, item:two}} }";
    String output = "{ specificationFilter "
        + "or:{item:top, item:foo, and:{item:one, item:two}} }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        input);
    assertEquals(output, ss.toString());
  }
  /**
   * 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
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches1() throws Exception {
    DN dn = DN.valueOf("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches2() throws Exception {
    DN dn = DN.valueOf("dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches3() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches4() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=bar, dc=com");
    String value = "{ base \"dc=sun, dc=com\" }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches5() throws Exception {
    DN dn = DN.valueOf("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches6() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches7() throws Exception {
    DN dn = DN.valueOf("dc=xyz, dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", minimum 1 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches8() throws Exception {
    DN dn = DN.valueOf("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 0 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches9() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 0 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches10() throws Exception {
    DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 1 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches11() throws Exception {
    DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", maximum 2 }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches12() throws Exception {
    DN dn = DN.valueOf("dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches13() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches14() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"dc=foo\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches15() throws Exception {
    DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopAfter:\"dc=foo\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches16() throws Exception {
    DN dn = DN.valueOf("dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches17() throws Exception {
    DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches18() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificExclusions { chopBefore:\"dc=foo\" } }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches19() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter item:person }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(true, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches20() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter item:organization }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches21() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter not:item:person }";
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN,
        value);
    assertEquals(false, ss
        .isWithinScope(createEntry(dn, getObjectClasses())));
  }
  /**
   * Tests the {@link SubtreeSpecification#isWithinScope(Entry)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testMatches22() throws Exception {
    DN dn = DN.valueOf("dc=abc, dc=sun, dc=com");
    String value = "{ base \"dc=sun, dc=com\", "
        + "specificationFilter not:item:organization }";
    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.valueOf("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.valueOf("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())));
  /** Tests the {@link SubtreeSpecification#isWithinScope(Entry)} method. */
  @Test(dataProvider = "isWithinScopeData")
  public void testIsWithinScope(String dnString, String value, boolean expected) throws Exception {
    DN dn = DN.valueOf(dnString);
    SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value);
    assertEquals(ss.isWithinScope(createEntry(dn, getObjectClasses())), expected);
  }
}