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

Nicolas Capponi
16.01.2016 9a20087a7c428eabc2c9abb9c27f01f623dbe042
OPENDJ-2655 Move CompactDN class as inner class of StaticGroup and optimize its implementation
1 files renamed
7 files modified
320 ■■■■ changed files
opendj-core/clirr-ignored-api-changes.xml 12 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/DN.java 96 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/api/Group.java 7 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/FilteredStaticGroupMemberList.java 14 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/SimpleStaticGroupMemberList.java 16 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java 154 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/extensions/CompactDnTestCase.java 17 ●●●●● patch | view | raw | blame | history
opendj-core/clirr-ignored-api-changes.xml
@@ -86,5 +86,15 @@
    <to>org/forgerock/opendj/ldap/schema/**SchemaElement$SchemaElementBuilder</to>
    <justification>Renamed class SchemaElement to AbstractSchemaElement</justification>
  </difference>
   <difference>
    <className>org/forgerock/opendj/ldap/DN</className>
    <differenceType>7002</differenceType>
    <method>org.forgerock.opendj.ldap.DN$CompactDn compact()</method>
    <justification>CompactDN has been migrated to server</justification>
  </difference>
  <difference>
    <className>org/forgerock/opendj/ldap/DN$CompactDn</className>
    <differenceType>8001</differenceType>
    <justification>CompactDN has been migrated to server</justification>
  </difference>
</differences>
opendj-core/src/main/java/org/forgerock/opendj/ldap/DN.java
@@ -16,7 +16,6 @@
 */
package org.forgerock.opendj.ldap;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -35,7 +34,6 @@
import com.forgerock.opendj.util.SubstringReader;
import static com.forgerock.opendj.ldap.CoreMessages.*;
import static com.forgerock.opendj.util.StaticUtils.*;
/**
 * A distinguished name (DN) as defined in RFC 4512 section 2.3 is the
@@ -329,6 +327,7 @@
    private final RDN rdn;
    private DN parent;
    private final int size;
    private int hashCode = -1;
    /**
     * The normalized byte string representation of this DN, which is not
@@ -472,7 +471,10 @@
    @Override
    public int hashCode() {
        return toNormalizedByteString().hashCode();
        if (hashCode == -1) {
            hashCode = toNormalizedByteString().hashCode();
        }
        return hashCode;
    }
    /**
@@ -985,92 +987,4 @@
        return UUID.nameUUIDFromBytes(normDN.toByteArray());
    }
    /**
     * A compact representation of a DN, suitable for equality and comparisons, and providing a natural hierarchical
     * ordering.
     * <p>
     * This representation should be used when it is important to reduce memory usage. The memory consumption compared
     * to a regular DN object is minimal. Prototypical usage is for static groups implementation where large groups of
     * DNs must be recorded and must be converted back to DNs.
     * <p>
     * This representation can be created either eagerly or lazily.
     * <ul>
     *   <li>eagerly: the normalized value is computed immediately at creation time.</li>
     *   <li>lazily: the normalized value is computed only the first time it is needed.</li>
     * </ul>
     *
     * @deprecated This class will eventually be replaced by a compact implementation of a DN.
     */
    @Deprecated
    public static final class CompactDn implements Comparable<CompactDn> {
        /** Original string corresponding to the DN. */
        private final byte[] originalValue;
        /**
         * Normalized byte string, suitable for equality and comparisons, and providing a natural hierarchical ordering,
         * but not usable as a valid DN.
         */
        private volatile byte[] normalizedValue;
        private final Schema schema;
        private CompactDn(final DN dn) {
            this.originalValue = getBytes(dn.toString());
            this.schema = dn.schema;
        }
        @Override
        public int compareTo(final CompactDn other) {
            byte[] normValue = getNormalizedValue();
            byte[] otherNormValue = other.getNormalizedValue();
            return ByteString.compareTo(normValue, 0, normValue.length, otherNormValue, 0, otherNormValue.length);
        }
        /**
         * Returns the DN corresponding to this compact representation.
         *
         *  @return the DN
         */
        public DN toDn() {
            return DN.valueOf(ByteString.toString(originalValue, 0, originalValue.length), schema);
        }
        @Override
        public int hashCode() {
            return Arrays.hashCode(getNormalizedValue());
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            } else if (obj instanceof CompactDn) {
                final CompactDn other = (CompactDn) obj;
                return Arrays.equals(getNormalizedValue(), other.getNormalizedValue());
            } else {
                return false;
            }
        }
        @Override
        public String toString() {
            return ByteString.toString(originalValue, 0, originalValue.length);
        }
        private byte[] getNormalizedValue() {
            if (normalizedValue == null) {
                normalizedValue = toDn().toNormalizedByteString().toByteArray();
            }
            return normalizedValue;
        }
    }
    /**
     * Returns a compact representation of this DN, with lazy evaluation of the normalized value.
     *
     * @return the DN compact representation
     */
    public CompactDn compact() {
        return new CompactDn(this);
    }
}
opendj-server-legacy/src/main/java/org/opends/server/api/Group.java
@@ -16,7 +16,6 @@
 */
package org.opends.server.api;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -288,6 +287,9 @@
   *                         its DN should be added to the list, and
   *                         any DN already contained in the list
   *                         should be skipped.
   *                         The use of an atomic reference allow to
   *                         lazily create the Set to optimize memory
   *                         when there is no nested groups.
   *
   * @return  {@code true} if the specified user is currently a member
   *          of this group, or {@code false} if not.
@@ -339,6 +341,9 @@
   *                         its DN should be added to the list, and
   *                         any DN already contained in the list
   *                         should be skipped.
   *                         The use of an atomic reference allow to
   *                         lazily create the Set to optimize memory
   *                         when there is no nested groups.
   *
   * @return  {@code true} if the specified user is currently a member
   *          of this group, or {@code false} if not.
opendj-server-legacy/src/main/java/org/opends/server/core/GroupManager.java
@@ -579,7 +579,7 @@
          {
            try
            {
              Group<?> groupInstance = groupImplementation.newInstance(null, entry);
              Group<?> groupInstance = groupImplementation.newInstance(serverContext, entry);
              groupInstances.put(entry.getName(), groupInstance);
              refreshToken++;
            }
@@ -937,7 +937,7 @@
      {
        if (groupImplementation.isGroupDefinition(entry))
        {
          Group<?> groupInstance = groupImplementation.newInstance(null, entry);
          Group<?> groupInstance = groupImplementation.newInstance(serverContext, entry);
          lock.writeLock().lock();
          try
opendj-server-legacy/src/main/java/org/opends/server/extensions/FilteredStaticGroupMemberList.java
@@ -25,9 +25,10 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.DN.CompactDn;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.StaticGroup.CompactDn;
import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
@@ -65,10 +66,14 @@
  /** The search scope to apply against the base DN for the member subset. */
  private SearchScope scope;
  private final ServerContext serverContext;
  /**
   * Creates a new filtered static group member list with the provided
   * information.
   *
   * @param serverContext
   *            The server context.
   * @param  groupDN    The DN of the static group with which this member list
   *                    is associated.
   * @param  memberDNs  The set of DNs for the users that are members of the
@@ -82,11 +87,12 @@
   *                    match.  If this is {@code null}, then all members will
   *                    be considered eligible.
   */
  public FilteredStaticGroupMemberList(DN groupDN, Set<CompactDn> memberDNs, DN baseDN, SearchScope scope,
      SearchFilter filter)
  public FilteredStaticGroupMemberList(ServerContext serverContext, DN groupDN, Set<CompactDn> memberDNs, DN baseDN,
      SearchScope scope, SearchFilter filter)
  {
    ifNull(groupDN, memberDNs);
    this.serverContext = serverContext;
    this.groupDN   = groupDN;
    this.memberDNIterator = memberDNs.iterator();
    this.baseDN = baseDN;
@@ -112,7 +118,7 @@
      DN nextDN = null;
      try
      {
        nextDN = StaticGroup.fromCompactDn(memberDNIterator.next());
        nextDN = memberDNIterator.next().toDn(serverContext);
      }
      catch (LocalizedIllegalArgumentException e)
      {
opendj-server-legacy/src/main/java/org/opends/server/extensions/SimpleStaticGroupMemberList.java
@@ -16,13 +16,13 @@
 */
package org.opends.server.extensions;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import java.util.Iterator;
import java.util.Set;
import org.forgerock.opendj.ldap.DN.CompactDn;
import org.opends.server.core.ServerContext;
import org.opends.server.extensions.StaticGroup.CompactDn;
import org.opends.server.types.DirectoryConfig;
import org.opends.server.types.DirectoryException;
import org.forgerock.opendj.ldap.DN;
@@ -32,7 +32,6 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.extensions.StaticGroup.*;
import static org.forgerock.util.Reject.*;
/**
@@ -50,18 +49,23 @@
  /** The iterator used to traverse the set of member DNs. */
  private Iterator<CompactDn> memberDNIterator;
  private final ServerContext serverContext;
  /**
   * Creates a new simple static group member list with the provided set of
   * member DNs.
   *
   * @param serverContext
   *            The server context.
   * @param  groupDN    The DN of the static group with which this member list
   *                    is associated.
   * @param  memberDNs  The set of DNs for the users that are members of the
   *                    associated static group.
   */
  public SimpleStaticGroupMemberList(DN groupDN, Set<CompactDn> memberDNs)
  public SimpleStaticGroupMemberList(ServerContext serverContext, DN groupDN, Set<CompactDn> memberDNs)
  {
    ifNull(groupDN, memberDNs);
    this.serverContext = serverContext;
    this.groupDN   = groupDN;
    this.memberDNIterator = memberDNs.iterator();
  }
@@ -81,7 +85,7 @@
    {
      try
      {
        dn = fromCompactDn(memberDNIterator.next());
        dn = memberDNIterator.next().toDn(serverContext);
      }
      catch (LocalizedIllegalArgumentException e)
      {
@@ -104,7 +108,7 @@
      try
      {
        Entry memberEntry = DirectoryConfig.getEntry(fromCompactDn(memberDN));
        Entry memberEntry = DirectoryConfig.getEntry(memberDN.toDn(serverContext));
        if (memberEntry == null)
        {
          LocalizableMessage message = ERR_STATICMEMBERS_NO_SUCH_ENTRY.get(memberDN, groupDN);
opendj-server-legacy/src/main/java/org/opends/server/extensions/StaticGroup.java
@@ -16,7 +16,12 @@
 */
package org.opends.server.extensions;
import static com.forgerock.opendj.util.StaticUtils.getBytes;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
@@ -30,7 +35,6 @@
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DN.CompactDn;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
@@ -38,6 +42,7 @@
import org.forgerock.opendj.server.config.server.GroupImplementationCfg;
import org.forgerock.opendj.server.config.server.StaticGroupImplementationCfg;
import org.forgerock.util.Reject;
import org.forgerock.util.annotations.VisibleForTesting;
import org.opends.server.api.Group;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
@@ -88,7 +93,7 @@
  private DN groupEntryDN;
  /** The set of the DNs of the members for this group. */
  private LinkedHashSet<CompactDn> memberDNs;
  private HashSet<CompactDn> memberDNs;
  /** The list of nested group DNs for this group. */
  private LinkedList<DN> nestedGroups = new LinkedList<>();
@@ -202,7 +207,7 @@
      {
        try
        {
          someMemberDNs.add(DN.valueOf(v.toString()).compact());
          someMemberDNs.add(new CompactDn(DN.valueOf(v.toString())));
        }
        catch (LocalizedIllegalArgumentException e)
        {
@@ -333,8 +338,8 @@
      newNestedGroups.add(nestedGroupDN);
      nestedGroups = newNestedGroups;
      //Add it to the member DN list.
      LinkedHashSet<CompactDn> newMemberDNs = new LinkedHashSet<>(memberDNs);
      newMemberDNs.add(toCompactDn(nestedGroupDN));
      HashSet<CompactDn> newMemberDNs = new HashSet<>(memberDNs);
      newMemberDNs.add(new CompactDn(nestedGroupDN));
      memberDNs = newMemberDNs;
    }
    finally
@@ -372,7 +377,7 @@
      nestedGroups = newNestedGroups;
      //Remove it from the member DN list.
      LinkedHashSet<CompactDn> newMemberDNs = new LinkedHashSet<>(memberDNs);
      newMemberDNs.remove(toCompactDn(nestedGroupDN));
      newMemberDNs.remove(new CompactDn(nestedGroupDN));
      memberDNs = newMemberDNs;
    }
    finally
@@ -385,7 +390,7 @@
  public boolean isMember(DN userDN, Set<DN> examinedGroups) throws DirectoryException
  {
    reloadIfNeeded();
    CompactDn compactUserDN = toCompactDn(userDN);
    CompactDn compactUserDN = new CompactDn(userDN);
    lock.readLock().lock();
    try
    {
@@ -440,8 +445,8 @@
        // Check if the group itself has been removed
        if (thisGroup == null)
        {
          throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE,
                  ERR_STATICGROUP_GROUP_INSTANCE_INVALID.get(groupEntryDN));
          throw new DirectoryException(ResultCode.NO_SUCH_ATTRIBUTE, ERR_STATICGROUP_GROUP_INSTANCE_INVALID
              .get(groupEntryDN));
        }
        else if (thisGroup != this)
        {
@@ -451,7 +456,7 @@
          {
            try
            {
              newMemberDNs.add(toCompactDn(memberList.nextMemberDN()));
              newMemberDNs.add(new CompactDn(memberList.nextMemberDN()));
            }
            catch (MembershipException ex)
            {
@@ -463,7 +468,7 @@
        nestedGroups.clear();
        for (CompactDn compactDn : memberDNs)
        {
          DN dn = fromCompactDn(compactDn);
          DN dn = compactDn.toDn(serverContext);
          Group<?> group = DirectoryServer.getGroupManager().getGroupInstance(dn);
          if (group != null)
          {
@@ -486,7 +491,7 @@
    lock.readLock().lock();
    try
    {
      return new SimpleStaticGroupMemberList(groupEntryDN, memberDNs);
      return new SimpleStaticGroupMemberList(serverContext, groupEntryDN, memberDNs);
    }
    finally
    {
@@ -503,9 +508,9 @@
    {
      if (baseDN == null && filter == null)
      {
        return new SimpleStaticGroupMemberList(groupEntryDN, memberDNs);
        return new SimpleStaticGroupMemberList(serverContext, groupEntryDN, memberDNs);
      }
      return new FilteredStaticGroupMemberList(groupEntryDN, memberDNs, baseDN, scope, filter);
      return new FilteredStaticGroupMemberList(serverContext, groupEntryDN, memberDNs, baseDN, scope, filter);
    }
    finally
    {
@@ -541,7 +546,7 @@
              for (ByteString v : attribute)
              {
                DN member = DN.valueOf(v);
                memberDNs.add(toCompactDn(member));
                memberDNs.add(new CompactDn(member));
                if (DirectoryServer.getGroupManager().getGroupInstance(member) != null)
                {
                  nestedGroups.add(member);
@@ -559,7 +564,7 @@
                for (ByteString v : attribute)
                {
                  DN member = DN.valueOf(v);
                  memberDNs.remove(toCompactDn(member));
                  memberDNs.remove(new CompactDn(member));
                  nestedGroups.remove(member);
                }
              }
@@ -570,7 +575,7 @@
              for (ByteString v : attribute)
              {
                DN member = DN.valueOf(v);
                memberDNs.add(toCompactDn(member));
                memberDNs.add(new CompactDn(member));
                if (DirectoryServer.getGroupManager().getGroupInstance(member) != null)
                {
                  nestedGroups.add(member);
@@ -595,7 +600,7 @@
    try
    {
      DN userDN = userEntry.getName();
      CompactDn compactUserDN = toCompactDn(userDN);
      CompactDn compactUserDN = new CompactDn(userDN);
      if (memberDNs.contains(compactUserDN))
      {
@@ -626,7 +631,7 @@
  {
    Reject.ifNull(userDN);
    CompactDn compactUserDN = toCompactDn(userDN);
    CompactDn compactUserDN = new CompactDn(userDN);
    lock.writeLock().lock();
    try
    {
@@ -680,26 +685,99 @@
  }
  /**
   * Convert the provided DN to a compact DN.
   *
   * @param dn
   *            The DN
   * @return the compact representation of the DN
   * A compact representation of a DN, suitable for equality and comparisons, and providing a natural hierarchical
   * ordering.
   * <p>
   * The memory consumption compared to a regular DN object is minimal.
   */
  private CompactDn toCompactDn(DN dn)
  static final class CompactDn implements Comparable<CompactDn>
  {
    return dn.compact();
  }
    /** Original string corresponding to the DN. */
    private final byte[] originalValue;
  /**
   * Convert the provided compact DN to a DN.
   *
   * @param compactDn
   *            Compact representation of a DN
   * @return the regular DN
   */
  static DN fromCompactDn(CompactDn compactDn)
  {
    return compactDn.toDn();
    /**
     * Normalized byte string, suitable for equality and comparisons, and providing a natural
     * hierarchical ordering, but not usable as a valid DN.
     */
    private final byte[] normalizedValue;
    @VisibleForTesting
    CompactDn(DN dn)
    {
      this.originalValue = getBytes(dn.toString());
      this.normalizedValue = dn.toNormalizedByteString().toByteArray();
    }
    @Override
    public int compareTo(final CompactDn other)
    {
      final int length1 = normalizedValue.length;
      final int length2 = other.normalizedValue.length;
      int count = Math.min(length1, length2);
      int i = 0;
      int j = 0;
      while (count-- != 0)
      {
        final int firstByte = 0xFF & normalizedValue[i++];
        final int secondByte = 0xFF & other.normalizedValue[j++];
        if (firstByte != secondByte)
        {
          return firstByte - secondByte;
        }
      }
      return length1 - length2;
    }
    /**
     * Returns the DN corresponding to this compact representation.
     *
     * @param serverContext
     *          The server context.
     *
     * @return the DN
     */
    public DN toDn(ServerContext serverContext)
    {
      return DN.valueOf(toString(), serverContext.getSchemaNG());
    }
    @Override
    public int hashCode()
    {
      return Arrays.hashCode(normalizedValue);
    }
    @Override
    public boolean equals(Object obj)
    {
      if (this == obj)
      {
        return true;
      }
      else if (obj instanceof CompactDn)
      {
        final CompactDn other = (CompactDn) obj;
        return Arrays.equals(normalizedValue, other.normalizedValue);
      }
      else
      {
        return false;
      }
    }
    @Override
    public String toString()
    {
      final int length = originalValue.length;
      if (length == 0) {
          return "";
      }
      try {
          return new String(originalValue, 0, length, "UTF-8");
      } catch (final UnsupportedEncodingException e) {
          // TODO: I18N
          throw new RuntimeException("Unable to decode bytes as UTF-8 string", e);
      }
    }
  }
}
}
opendj-server-legacy/src/test/java/org/opends/server/extensions/CompactDnTestCase.java
File was renamed from opendj-core/src/test/java/org/forgerock/opendj/ldap/CompactDnTestCase.java
@@ -11,20 +11,23 @@
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2014 ForgeRock AS.
 * Copyright 2014-2016 ForgeRock AS.
 */
package org.forgerock.opendj.ldap;
package org.opends.server.extensions;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.extensions.StaticGroup.CompactDn;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.fest.assertions.Assertions.*;
/**
 * This class defines a set of tests for the org.forgerock.opendj.ldap.DN.CompactDn class.
 * This class defines a set of tests for the inner class StaticGroup.CompactDn.
 */
@SuppressWarnings("javadoc")
public class CompactDnTestCase extends SdkTestCase {
public class CompactDnTestCase extends DirectoryServerTestCase {
    /**
     * DN test data provider.
@@ -80,11 +83,11 @@
    @Test(dataProvider = "equivalentDnRepresentations")
    public void testEquals(String dn, String otherDn) throws Exception {
        assertThat(DN.valueOf(dn).compact()).isEqualTo(DN.valueOf(otherDn).compact());
      assertThat(new CompactDn(DN.valueOf(dn))).isEqualTo(new CompactDn(DN.valueOf(otherDn)));
    }
    @Test(dataProvider = "equivalentDnRepresentations")
    public void testCompareTo(String dn, String otherDn) throws Exception {
        assertThat(DN.valueOf(dn).compact().compareTo(DN.valueOf(otherDn).compact())).isEqualTo(0);
        assertThat(new CompactDn(DN.valueOf(dn)).compareTo(new CompactDn(DN.valueOf(otherDn)))).isEqualTo(0);
    }
}
}