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); } } }