From 60f3502563cd2c71a751b74f0b34bfe2f5d17330 Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Thu, 08 Nov 2012 15:40:09 +0000
Subject: [PATCH] Fix OPENDJ-619 : Reduce the memory utilization of LDIF.diff(EntryReader, EntryReader) in the SDK
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java | 136 ++++
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java | 1336 ++++++++++++++++++++++++++++++++++++++++++-
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java | 221 +++++-
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java | 135 ----
4 files changed, 1,614 insertions(+), 214 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
index e2ed752..a32ce02 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
@@ -27,19 +27,24 @@
package org.forgerock.opendj.ldap;
+import static com.forgerock.opendj.util.StaticUtils.getBytes;
import static org.forgerock.opendj.ldap.CoreMessages.ERR_DN_TYPE_NOT_FOUND;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.TreeSet;
import java.util.WeakHashMap;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.Syntax;
import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
+import com.forgerock.opendj.util.StaticUtils;
import com.forgerock.opendj.util.SubstringReader;
import com.forgerock.opendj.util.Validator;
@@ -799,4 +804,135 @@
}
return stringValue;
}
+
+ /**
+ * Returns the normalized string representation of a DN.
+ *
+ * @return The normalized string representation of the provided DN.
+ */
+ public String toNormalizedString() {
+ final StringBuilder builder = new StringBuilder(this.size());
+ if (rdn() == null) {
+ return builder.toString();
+ }
+
+ int i = this.size() - 1;
+ normalizeRDN(builder, parent(i).rdn());
+ for (i--; i >= 0; i--) {
+ final RDN rdn = parent(i).rdn();
+ // Only add a separator if the RDN is not RDN.maxValue().
+ if (rdn.size() != 0) {
+ builder.append('\u0000');
+ }
+ normalizeRDN(builder, rdn);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Returns the normalized string representation of a RDN.
+ *
+ * @param builder
+ * The StringBuilder to use to construct the normalized string.
+ * @param rdn
+ * The RDN.
+ * @return The normalized string representation of the provided RDN.
+ */
+ private static StringBuilder normalizeRDN(final StringBuilder builder, final RDN rdn) {
+ final int sz = rdn.size();
+ switch (sz) {
+ case 0:
+ // Handle RDN.maxValue().
+ builder.append('\u0001');
+ break;
+ case 1:
+ normalizeAVA(builder, rdn.getFirstAVA());
+ break;
+ default:
+ // Need to sort the AVAs before comparing.
+ TreeSet<AVA> a = new TreeSet<AVA>();
+ for (AVA ava : rdn) {
+ a.add(ava);
+ }
+ Iterator<AVA> i = a.iterator();
+ // Normalize the first AVA.
+ normalizeAVA(builder, i.next());
+ while (i.hasNext()) {
+ builder.append('\u0001');
+ normalizeAVA(builder, i.next());
+ }
+ break;
+ }
+ return builder;
+ }
+
+ /**
+ * Returns the normalized string representation of an AVA.
+ *
+ * @param builder
+ * The StringBuilder to use to construct the normalized string.
+ * @param ava
+ * The AVA.
+ * @return The normalized string representation of the provided AVA.
+ */
+ private static StringBuilder normalizeAVA(final StringBuilder builder, final AVA ava) {
+ ByteString value = ava.getAttributeValue();
+ final MatchingRule matchingRule = ava.getAttributeType().getEqualityMatchingRule();
+ if (matchingRule != null) {
+ try {
+ value = matchingRule.normalizeAttributeValue(ava.getAttributeValue());
+ } catch (final DecodeException de) {
+ // Ignore - we'll drop back to the user provided value.
+ }
+ }
+
+ if (!ava.getAttributeType().getNames().iterator().hasNext()) {
+ builder.append(ava.getAttributeType().getOID());
+ builder.append("=#");
+ StaticUtils.toHex(value, builder);
+ } else {
+ final String name = ava.getAttributeType().getNameOrOID();
+ // Normalizing.
+ StaticUtils.toLowerCase(name, builder);
+
+ builder.append("=");
+
+ final Syntax syntax = ava.getAttributeType().getSyntax();
+ if (!syntax.isHumanReadable()) {
+ builder.append("#");
+ StaticUtils.toHex(value, builder);
+ } else {
+ final String str = value.toString();
+ if (str.length() == 0) {
+ return builder;
+ }
+ char c = str.charAt(0);
+ int startPos = 0;
+ if ((c == ' ') || (c == '#')) {
+ builder.append('\\');
+ builder.append(c);
+ startPos = 1;
+ }
+ final int length = str.length();
+ for (int si = startPos; si < length; si++) {
+ c = str.charAt(si);
+ if (c < ' ') {
+ for (final byte b : getBytes(String.valueOf(c))) {
+ builder.append('\\');
+ builder.append(StaticUtils.byteToLowerHex(b));
+ }
+ } else {
+ if ((c == ' ' && si == length - 1)
+ || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
+ || c == '=' || c == '>' || c == '\\' || c == '\u0000')) {
+ builder.append('\\');
+ }
+ builder.append(c);
+ }
+ }
+ }
+ }
+ return builder;
+ }
+
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
index b005f62..b2a7fb0 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -22,151 +22,21 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011-2012 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.schema;
-import static com.forgerock.opendj.util.StaticUtils.getBytes;
-
-import java.util.Iterator;
-import java.util.TreeSet;
-
import org.forgerock.i18n.LocalizedIllegalArgumentException;
-import org.forgerock.opendj.ldap.AVA;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
-import org.forgerock.opendj.ldap.RDN;
-
-import com.forgerock.opendj.util.StaticUtils;
/**
* This class defines the distinguishedNameMatch matching rule defined in X.520
* and referenced in RFC 2252.
*/
final class DistinguishedNameEqualityMatchingRuleImpl extends AbstractMatchingRuleImpl {
- /**
- * Returns the normalized string representation of an AVA.
- *
- * @param builder
- * The StringBuilder to use to construct the normalized string.
- * @param ava
- * The AVA.
- * @return The normalized string representation of the provided AVA.
- */
- private static StringBuilder normalizeAVA(final StringBuilder builder, final AVA ava) {
- ByteString value = ava.getAttributeValue();
- final MatchingRule matchingRule = ava.getAttributeType().getEqualityMatchingRule();
- if (matchingRule != null) {
- try {
- value = matchingRule.normalizeAttributeValue(ava.getAttributeValue());
- } catch (final DecodeException de) {
- // Ignore - we'll drop back to the user provided value.
- }
- }
-
- if (!ava.getAttributeType().getNames().iterator().hasNext()) {
- builder.append(ava.getAttributeType().getOID());
- builder.append("=#");
- StaticUtils.toHex(value, builder);
- } else {
- final String name = ava.getAttributeType().getNameOrOID();
- // Normalizing.
- StaticUtils.toLowerCase(name, builder);
-
- builder.append("=");
-
- final Syntax syntax = ava.getAttributeType().getSyntax();
- if (!syntax.isHumanReadable()) {
- builder.append("#");
- StaticUtils.toHex(value, builder);
- } else {
- final String str = value.toString();
- if (str.length() == 0) {
- return builder;
- }
- char c = str.charAt(0);
- int startPos = 0;
- if ((c == ' ') || (c == '#')) {
- builder.append('\\');
- builder.append(c);
- startPos = 1;
- }
- final int length = str.length();
- for (int si = startPos; si < length; si++) {
- c = str.charAt(si);
- if (c < ' ') {
- for (final byte b : getBytes(String.valueOf(c))) {
- builder.append('\\');
- builder.append(StaticUtils.byteToLowerHex(b));
- }
- } else {
- if ((c == ' ' && si == length - 1)
- || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
- || c == '=' || c == '>' || c == '\\' || c == '\u0000')) {
- builder.append('\\');
- }
- builder.append(c);
- }
- }
- }
- }
- return builder;
- }
-
- /**
- * Returns the normalized string representation of a DN.
- *
- * @param builder
- * The StringBuilder to use to construct the normalized string.
- * @param dn
- * The DN.
- * @return The normalized string representation of the provided DN.
- */
- private static StringBuilder normalizeDN(final StringBuilder builder, final DN dn) {
- if (dn.rdn() == null) {
- return builder;
- }
-
- int i = dn.size() - 1;
- normalizeRDN(builder, dn.parent(i).rdn());
- for (i--; i >= 0; i--) {
- builder.append('\u0000');
- normalizeRDN(builder, dn.parent(i).rdn());
- }
- return builder;
- }
-
- /**
- * Returns the normalized string representation of a RDN.
- *
- * @param builder
- * The StringBuilder to use to construct the normalized string.
- * @param rdn
- * The RDN.
- * @return The normalized string representation of the provided RDN.
- */
- private static StringBuilder normalizeRDN(final StringBuilder builder, final RDN rdn) {
- final int sz = rdn.size();
- if (sz == 1) {
- return normalizeAVA(builder, rdn.getFirstAVA());
- } else {
- // Need to sort the AVAs before comparing.
- TreeSet<AVA> a = new TreeSet<AVA>();
- for (AVA ava : rdn) {
- a.add(ava);
- }
- Iterator<AVA> i = a.iterator();
- // Normalize the first AVA.
- normalizeAVA(builder, i.next());
- while (i.hasNext()) {
- builder.append('\u0001');
- normalizeAVA(builder, i.next());
- }
-
- return builder;
- }
- }
/**
* {@inheritDoc}
@@ -175,8 +45,7 @@
throws DecodeException {
try {
DN dn = DN.valueOf(value.toString(), schema.asNonStrictSchema());
- StringBuilder builder = new StringBuilder(value.length());
- return ByteString.valueOf(normalizeDN(builder, dn));
+ return ByteString.valueOf(dn.toNormalizedString());
} catch (final LocalizedIllegalArgumentException e) {
throw DecodeException.error(e.getMessageObject());
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java
index d6276db..ffa1db7 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIF.java
@@ -28,19 +28,29 @@
import static org.forgerock.opendj.ldap.CoreMessages.REJECTED_CHANGE_FAIL_DELETE;
import static org.forgerock.opendj.ldap.CoreMessages.REJECTED_CHANGE_FAIL_MODIFY;
import static org.forgerock.opendj.ldap.CoreMessages.REJECTED_CHANGE_FAIL_MODIFYDN;
+import static com.forgerock.opendj.util.StaticUtils.getBytes;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.SortedMap;
import java.util.TreeMap;
+import org.forgerock.opendj.asn1.ASN1;
+import org.forgerock.opendj.asn1.ASN1Reader;
+import org.forgerock.opendj.asn1.ASN1Writer;
import org.forgerock.opendj.ldap.AVA;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.Attributes;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ByteStringBuilder;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.DecodeOptions;
@@ -58,9 +68,13 @@
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.Responses;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.schema.AttributeUsage;
import org.forgerock.opendj.ldap.schema.Schema;
+import com.forgerock.opendj.ldap.LDAPUtils;
+
/**
* This class contains common utility methods for creating and manipulating
* readers and writers.
@@ -77,6 +91,26 @@
// @formatter:on
/**
+ * Comparator ordering the DN ASC.
+ */
+ private static final Comparator<byte[][]> DN_ORDER2 = new Comparator<byte[][]>() {
+ public int compare(byte[][] b1, byte[][] b2) {
+ return DN_ORDER.compare(b1[0], b2[0]);
+ }
+ };
+
+ /**
+ * Comparator ordering the DN ASC.
+ */
+ private static final Comparator<byte[]> DN_ORDER = new Comparator<byte[]>() {
+ public int compare(byte[] b1, byte[] b2) {
+ final ByteString bs = ByteString.valueOf(b1);
+ final ByteString bs2 = ByteString.valueOf(b2);
+ return bs.compareTo(bs2);
+ }
+ };
+
+ /**
* Copies the content of {@code input} to {@code output}. This method does
* not close {@code input} or {@code output}.
*
@@ -137,10 +171,11 @@
*/
public static ChangeRecordReader diff(final EntryReader source, final EntryReader target)
throws IOException {
- final SortedMap<DN, Entry> sourceEntries = readEntries(source);
- final SortedMap<DN, Entry> targetEntries = readEntries(target);
- final Iterator<Entry> sourceIterator = sourceEntries.values().iterator();
- final Iterator<Entry> targetIterator = targetEntries.values().iterator();
+
+ final List<byte[][]> source2 = readEntriesAsList(source);
+ final List<byte[][]> target2 = readEntriesAsList(target);
+ final Iterator<byte[][]> sourceIterator = source2.iterator();
+ final Iterator<byte[][]> targetIterator = target2.iterator();
return new ChangeRecordReader() {
private Entry sourceEntry = nextEntry(sourceIterator);
@@ -201,11 +236,13 @@
}
}
- private Entry nextEntry(final Iterator<Entry> i) {
- return i.hasNext() ? i.next() : null;
+ private Entry nextEntry(final Iterator<byte[][]> i) throws IOException {
+ if (i.hasNext()) {
+ return decodeEntry(i.next()[1]);
+ }
+ return null;
}
};
-
}
/**
@@ -240,6 +277,12 @@
* <b>NOTE:</b> this method reads the content of {@code input} into memory
* before applying the changes, and is therefore not suited for use in cases
* where a very large number of entries are to be patched.
+ * <p>
+ * <b>NOTE:</b> this method will not perform modifications required in order
+ * to maintain referential integrity. In particular, if an entry references
+ * another entry using a DN valued attribute and the referenced entry is
+ * deleted, then the DN reference will not be removed. The same applies to
+ * renamed entries and their references.
*
* @param input
* The entry reader containing the set of entries to be patched.
@@ -264,6 +307,12 @@
* <b>NOTE:</b> this method reads the content of {@code input} into memory
* before applying the changes, and is therefore not suited for use in cases
* where a very large number of entries are to be patched.
+ * <p>
+ * <b>NOTE:</b> this method will not perform modifications required in order
+ * to maintain referential integrity. In particular, if an entry references
+ * another entry using a DN valued attribute and the referenced entry is
+ * deleted, then the DN reference will not be removed. The same applies to
+ * renamed entries and their references.
*
* @param input
* The entry reader containing the set of entries to be patched.
@@ -278,10 +327,12 @@
*/
public static EntryReader patch(final EntryReader input, final ChangeRecordReader patch,
final RejectedChangeRecordListener listener) throws IOException {
- final SortedMap<DN, Entry> entries = readEntries(input);
+ final SortedMap<byte[], byte[]> entries = readEntriesAsMap(input);
while (patch.hasNext()) {
final ChangeRecord change = patch.readChangeRecord();
+ final DN changeDN = change.getName();
+ final byte[] changeNormDN = getBytes(change.getName().toNormalizedString());
final DecodeException de =
change.accept(new ChangeRecordVisitor<DecodeException, Void>() {
@@ -289,17 +340,19 @@
@Override
public DecodeException visitChangeRecord(final Void p,
final AddRequest change) {
- final Entry existingEntry = entries.get(change.getName());
- if (existingEntry != null) {
+
+ if (entries.get(changeNormDN) != null) {
+ final Entry existingEntry = decodeEntry(entries.get(changeNormDN));
try {
final Entry entry =
listener.handleDuplicateEntry(change, existingEntry);
- entries.put(entry.getName(), entry);
+ entries.put(getBytes(entry.getName().toNormalizedString()),
+ encodeEntry(entry)[1]);
} catch (final DecodeException e) {
return e;
}
} else {
- entries.put(change.getName(), change);
+ entries.put(changeNormDN, encodeEntry(change)[1]);
}
return null;
}
@@ -307,7 +360,7 @@
@Override
public DecodeException visitChangeRecord(final Void p,
final DeleteRequest change) {
- if (!entries.containsKey(change.getName())) {
+ if (entries.get(changeNormDN) == null) {
try {
listener.handleRejectedChangeRecord(change,
REJECTED_CHANGE_FAIL_DELETE.get(change.getName()
@@ -319,10 +372,12 @@
try {
if (change.getControl(SubtreeDeleteRequestControl.DECODER,
new DecodeOptions()) != null) {
- entries.subMap(change.getName(),
- change.getName().child(RDN.maxValue())).clear();
+ entries.subMap(
+ getBytes(change.getName().toNormalizedString()),
+ getBytes(change.getName().child(RDN.maxValue())
+ .toNormalizedString())).clear();
} else {
- entries.remove(change.getName());
+ entries.remove(changeNormDN);
}
} catch (final DecodeException e) {
return e;
@@ -335,7 +390,7 @@
@Override
public DecodeException visitChangeRecord(final Void p,
final ModifyDNRequest change) {
- if (!entries.containsKey(change.getName())) {
+ if (entries.get(changeNormDN) == null) {
try {
listener.handleRejectedChangeRecord(change,
REJECTED_CHANGE_FAIL_MODIFYDN.get(change.getName()
@@ -345,7 +400,7 @@
}
} else {
// Calculate the old and new DN.
- final DN oldDN = change.getName();
+ final DN oldDN = changeDN;
DN newSuperior = change.getNewSuperior();
if (newSuperior == null) {
@@ -357,51 +412,72 @@
final DN newDN = newSuperior.child(change.getNewRDN());
// Move the renamed entries into a separate map
- // in order to
- // avoid cases where the renamed subtree
- // overlaps.
- final SortedMap<DN, Entry> renamedEntries =
- new TreeMap<DN, Entry>();
- final Iterator<Map.Entry<DN, Entry>> i =
- entries.subMap(change.getName(),
- change.getName().child(RDN.maxValue())).entrySet()
- .iterator();
- while (i.hasNext()) {
- final Map.Entry<DN, Entry> e = i.next();
- i.remove();
+ // in order to avoid cases where the renamed subtree overlaps.
+ final SortedMap<byte[], byte[]> renamedEntries =
+ new TreeMap<byte[], byte[]>(DN_ORDER);
- final DN renamedDN = e.getKey().rename(oldDN, newDN);
- final Entry entry = e.getValue().setName(renamedDN);
- renamedEntries.put(renamedDN, entry);
+ // @formatter:off
+ final Iterator<Map.Entry<byte[], byte[]>> i =
+ entries.subMap(changeNormDN,
+ getBytes((changeDN.child(RDN.maxValue())).
+ toNormalizedString())).entrySet().iterator();
+ // @formatter:on
+
+ while (i.hasNext()) {
+ final Map.Entry<byte[], byte[]> e = i.next();
+ final Entry entry = decodeEntry(e.getValue());
+ final DN renamedDN = entry.getName().rename(oldDN, newDN);
+ entry.setName(renamedDN);
+ renamedEntries.put(getBytes(renamedDN.toNormalizedString()),
+ encodeEntry(entry)[1]);
+ i.remove();
}
- // Modify the target entry.
- final Entry entry = entries.values().iterator().next();
+ // Modify target entry
+ final Entry targetEntry =
+ decodeEntry(renamedEntries.values().iterator().next());
+
if (change.isDeleteOldRDN()) {
for (final AVA ava : oldDN.rdn()) {
- entry.removeAttribute(ava.toAttribute(), null);
+ targetEntry.removeAttribute(ava.toAttribute(), null);
}
}
for (final AVA ava : newDN.rdn()) {
- entry.addAttribute(ava.toAttribute());
+ targetEntry.addAttribute(ava.toAttribute());
}
+ renamedEntries.remove(getBytes(targetEntry.getName()
+ .toNormalizedString()));
+ renamedEntries.put(getBytes(targetEntry.getName()
+ .toNormalizedString()), encodeEntry(targetEntry)[1]);
+
// Add the renamed entries.
- for (final Entry renamedEntry : renamedEntries.values()) {
- final Entry existingEntry = entries.get(renamedEntry.getName());
- if (existingEntry != null) {
+ final Iterator<byte[]> j = renamedEntries.values().iterator();
+ while (j.hasNext()) {
+ final Entry renamedEntry = decodeEntry(j.next());
+ final byte[] existingEntryDn =
+ entries.get(getBytes(renamedEntry.getName()
+ .toNormalizedString()));
+
+ if (existingEntryDn != null) {
+ final Entry existingEntry = decodeEntry(existingEntryDn);
try {
final Entry tmp =
listener.handleDuplicateEntry(change,
existingEntry, renamedEntry);
- entries.put(tmp.getName(), tmp);
+ entries.put(
+ getBytes(tmp.getName().toNormalizedString()),
+ encodeEntry(tmp)[1]);
} catch (final DecodeException e) {
return e;
}
} else {
- entries.put(renamedEntry.getName(), renamedEntry);
+ entries.put(getBytes(renamedEntry.getName()
+ .toNormalizedString()),
+ encodeEntry(renamedEntry)[1]);
}
}
+ renamedEntries.clear();
}
return null;
}
@@ -409,7 +485,7 @@
@Override
public DecodeException visitChangeRecord(final Void p,
final ModifyRequest change) {
- if (!entries.containsKey(change.getName())) {
+ if (entries.get(changeNormDN) == null) {
try {
listener.handleRejectedChangeRecord(change,
REJECTED_CHANGE_FAIL_MODIFY.get(change.getName()
@@ -418,7 +494,7 @@
return e;
}
} else {
- final Entry entry = entries.get(change.getName());
+ final Entry entry = decodeEntry(entries.get(changeNormDN));
for (final Modification modification : change.getModifications()) {
final ModificationType modType =
modification.getModificationType();
@@ -434,6 +510,7 @@
+ "\": modification type not supported");
}
}
+ entries.put(changeNormDN, encodeEntry(entry)[1]);
}
return null;
}
@@ -446,7 +523,7 @@
}
return new EntryReader() {
- private final Iterator<Entry> iterator = entries.values().iterator();
+ private final Iterator<byte[]> iterator = entries.values().iterator();
@Override
public void close() throws IOException {
@@ -464,7 +541,7 @@
@Override
public Entry readEntry() throws IOException {
- return iterator.next();
+ return decodeEntry(iterator.next());
}
};
}
@@ -612,15 +689,61 @@
};
}
- private static SortedMap<DN, Entry> readEntries(final EntryReader reader) throws IOException {
- final SortedMap<DN, Entry> entries = new TreeMap<DN, Entry>();
+ private static List<byte[][]> readEntriesAsList(final EntryReader reader) throws IOException {
+ final List<byte[][]> entries = new ArrayList<byte[][]>();
+
while (reader.hasNext()) {
final Entry entry = reader.readEntry();
- entries.put(entry.getName(), entry);
+ entries.add(encodeEntry(entry));
}
+ // Sorting the list by DN
+ Collections.sort(entries, DN_ORDER2);
+
return entries;
}
+ private static TreeMap<byte[], byte[]> readEntriesAsMap(final EntryReader reader)
+ throws IOException {
+ final TreeMap<byte[], byte[]> entries = new TreeMap<byte[], byte[]>(DN_ORDER);
+
+ while (reader.hasNext()) {
+ final Entry entry = reader.readEntry();
+ final byte[][] bEntry = encodeEntry(entry);
+ entries.put(bEntry[0], bEntry[1]);
+ }
+
+ return entries;
+ }
+
+ private static SearchResultEntry decodeEntry(final byte[] asn1EntryFormat) {
+ final ASN1Reader readerASN1 = ASN1.getReader(asn1EntryFormat);
+ try {
+ final SearchResultEntry sr =
+ LDAPUtils.decodeSearchResultEntry(readerASN1, new DecodeOptions());
+ readerASN1.close();
+ return sr;
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ private static byte[][] encodeEntry(final Entry entry) {
+ final byte[][] bEntry = new byte[2][];
+
+ final ByteStringBuilder bsb = new ByteStringBuilder();
+ final ASN1Writer writer = ASN1.getWriter(bsb);
+ // Store normalized DN
+ bEntry[0] = getBytes(entry.getName().toNormalizedString());
+ try {
+ // Store ASN1 representation of the entry.
+ LDAPUtils.encodeSearchResultEntry(writer, Responses.newSearchResultEntry(entry));
+ bEntry[1] = bsb.toByteArray();
+ return bEntry;
+ } catch (final IOException ioe) {
+ throw new IllegalStateException(ioe);
+ }
+ }
+
// Prevent instantiation.
private LDIF() {
// Do nothing.
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java
index 0d614da..0a2302b 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldif/LDIFTestCase.java
@@ -29,6 +29,7 @@
import static org.fest.assertions.Assertions.assertThat;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -202,12 +203,12 @@
// @formatter:off
final EntryReader reader = new LDIFEntryReader(
- "dn: uid=user.0,ou=People,dc=example,dc=com",
- "objectClass: person",
- "objectClass: inetorgperson",
- "objectClass: organizationalperson",
- "objectClass: top",
- "uid: user.0"
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "objectClass: inetorgperson",
+ "objectClass: organizationalperson",
+ "objectClass: top",
+ "uid: user.0"
);
// @formatter:on
@@ -306,7 +307,7 @@
*
* @throws Exception
*/
- @Test()
+ @Test(expectedExceptions = NoSuchElementException.class)
public final void testLdifSearchWithSchemaMatchFullAttributesTypeOnly() throws Exception {
// @formatter:off
@@ -335,13 +336,8 @@
assertThat(entry.getAttribute("uid")).isNotNull();
assertThat(entry.getAttribute("uid").getAttributeDescription()).isNotNull();
assertThat(entry.getAttribute("uid")).isEmpty();
-
- try {
- assertThat(entry.getAttribute("uid").firstValueAsString()).isNull();
- } catch (NoSuchElementException ex) {
- // No values, only type.
- // Expected exception on entry.getAttribute("uid").firstValueAsString()
- }
+ // The following assert throws an exception because no values contained in, only type.
+ assertThat(entry.getAttribute("uid").firstValueAsString()).isNull();
}
resultReader.close();
}
@@ -470,7 +466,7 @@
*
* @throws Exception
*/
- @Test()
+ @Test(expectedExceptions = NoSuchElementException.class)
public final void testLdifSearchWithSchemaMatchSpecifiedAttributeTypeOnly() throws Exception {
// @formatter:off
@@ -496,12 +492,9 @@
assertThat(entry.getAttributeCount()).isEqualTo(1);
assertThat(entry.getAttribute("uid").getAttributeDescription()).isNotNull();
assertThat(entry.getAttribute("uid")).isEmpty();
- try {
- assertThat(entry.getAttribute("uid").firstValueAsString()).isNull();
- } catch (NoSuchElementException ex) {
- // No values, only type.
- // Expected exception on entry.getAttribute("uid").firstValueAsString()
- }
+ // The following assert throws an exception because no values contained in, only type.
+ assertThat(entry.getAttribute("uid").firstValueAsString()).isNull();
+
}
resultReader.close();
}
@@ -637,7 +630,10 @@
"objectClass: person",
"objectClass: inetorgperson"
);
- final Entry e1 = new LinkedHashMapEntry("dn: uid=user.1,ou=People,dc=example,dc=com", "objectClass: person");
+ final Entry e1 = new LinkedHashMapEntry(
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: person"
+ );
// @formatter:on
final SortedMap<DN, Entry> sourceEntries = new TreeMap<DN, Entry>();
@@ -646,10 +642,9 @@
final Iterator<Entry> sourceIterator = sourceEntries.values().iterator();
final EntryReader resultReader = LDIF.newEntryIteratorReader(sourceIterator);
- Entry entry = null;
int cCount = 0;
while (resultReader.hasNext()) {
- entry = resultReader.readEntry();
+ final Entry entry = resultReader.readEntry();
assertThat(entry.getName().toString()).isNotNull();
assertThat(entry.getName().toString()).contains("ou=People,dc=example,dc=com");
assertThat(entry.getAttributeCount()).isGreaterThanOrEqualTo(1);
@@ -862,7 +857,7 @@
assertThat(cr).isInstanceOf(ModifyRequest.class);
// @formatter:off
- /* Expected : 2 add / 1 delete.
+ /* Expected : 2 add / 1 delete - output :
* dn: uid=newuser,ou=People,dc=example,dc=com
* changetype: modify
* add: userPassword
@@ -1025,6 +1020,199 @@
}
/**
+ * Differences between two short ldif examples.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifDiffEntriesShortExamples() throws Exception {
+
+ // @formatter:off
+ final LDIFEntryReader source = new LDIFEntryReader(
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaccf",
+ "sn: Amar",
+ "cn: Aaccf Amar",
+ "initials: APA",
+ "employeeNumber: 0",
+ "uid: user.0",
+ "mail: user.0@example.com",
+ "description: This is the description for Aaccf Amar.",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaren",
+ "sn: Atp",
+ "cn: Aaren Atp",
+ "initials: AFA",
+ "employeeNumber: 1",
+ "uid: user.1",
+ "mail: user.1@example.com",
+ "description: This is the description for Aaren Atp.",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "initials: AVA",
+ "employeeNumber: 2",
+ "uid: user.2",
+ "mail: user.2@example.com",
+ "description: This is the description for Aarika Atpco.",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "initials: ATA",
+ "employeeNumber: 3",
+ "uid: user.3",
+ "mail: user.3@example.com",
+ "description: This is the description for Aaron Atrc.",
+ "",
+ "dn: uid=user.4,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aartjan",
+ "sn: Aalders",
+ "cn: Aartjan Aalders",
+ "initials: AAA",
+ "employeeNumber: 4",
+ "uid: user.4",
+ "mail: user.4@example.com",
+ "description: This is the description for Aartjan Aalders."
+ );
+
+ final LDIFEntryReader target = new LDIFEntryReader(
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Amar", // diff
+ "sn: Amar",
+ "cn: Aaccf Amar",
+ "initials: APA",
+ "employeeNumber: 55", // diff
+ "uid: user.0",
+ "mail: user.0@example.com",
+ "description: This is the description for Aaccf Amar.",
+ "work-phone: 650/506-0666", // diff
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaren",
+ "sn: Atp",
+ "cn: Aaren Atp",
+ "initials: AFA",
+ "employeeNumber: 1",
+ "uid: user.1",
+ "mail: aaren@example.com", // diff
+ "description: This is the description for Aaren Atp.",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "initials: AVA",
+ "employeeNumber: 2",
+ "uid: user.2",
+ "mail: user.2@example.com", // diff (delete description)
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "initials: ATA",
+ "employeeNumber: 3",
+ "uid: user.999", // diff
+ "mail: user.999@example.com", // diff
+ "description: This is the description for Aaron Atrc.",
+ "",
+ "dn: uid=user.4,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aartjan",
+ "sn: Aalders",
+ "cn: Aartjan Aalders",
+ "initials: AAA",
+ "employeeNumber: 4",
+ "uid: user.4",
+ "mail: user.4@example.com",
+ "description: This is the description for Aartjan Aalders."
+ );
+ // @formatter:on
+
+ final ChangeRecordReader reader = LDIF.diff(source, target);
+ assertThat(reader.hasNext()).isTrue();
+ ChangeRecord cr = reader.readChangeRecord();
+ assertThat(cr.getName().toString()).isEqualTo("uid=user.0,ou=People,dc=example,dc=com");
+ assertThat(cr instanceof ModifyRequest);
+ assertThat(((ModifyRequest) cr).getModifications()).isNotEmpty();
+ // 1st entry : 2 add/delete + 1 add(work-phone)
+ assertThat(((ModifyRequest) cr).getModifications().size()).isEqualTo(5);
+ // 2nd entry : 1 add/delete
+ cr = reader.readChangeRecord();
+ assertThat(cr.getName().toString()).isEqualTo("uid=user.1,ou=People,dc=example,dc=com");
+ assertThat(cr instanceof ModifyRequest);
+ assertThat(((ModifyRequest) cr).getModifications().size()).isEqualTo(2);
+ // 3rd entry : 1 delete
+ cr = reader.readChangeRecord();
+ assertThat(cr.getName().toString()).isEqualTo("uid=user.2,ou=People,dc=example,dc=com");
+ assertThat(cr instanceof ModifyRequest);
+ assertThat(((ModifyRequest) cr).getModifications().size()).isEqualTo(1);
+ assertThat(((ModifyRequest) cr).getModifications().get(0).getModificationType().toString())
+ .isEqualTo("delete");
+ assertThat(
+ ((ModifyRequest) cr).getModifications().get(0).getAttribute()
+ .getAttributeDescriptionAsString()).isEqualTo("description");
+ // 4th entry : 2 add/delete
+ cr = reader.readChangeRecord();
+ assertThat(cr.getName().toString()).isEqualTo("uid=user.3,ou=People,dc=example,dc=com");
+ assertThat(cr instanceof ModifyRequest);
+ assertThat(((ModifyRequest) cr).getModifications().size()).isEqualTo(4);
+ // 5th entry : 0 modifications
+ cr = reader.readChangeRecord();
+ assertThat(cr.getName().toString()).isEqualTo("uid=user.4,ou=People,dc=example,dc=com");
+ assertThat(cr instanceof ModifyRequest);
+ assertThat(((ModifyRequest) cr).getModifications().size()).isEqualTo(0);
+ assertThat(reader.hasNext()).isFalse();
+
+ reader.close();
+ target.close();
+ }
+
+ /**
* Diff between two same entries : no modifications expected.
*
* @throws Exception
@@ -1081,13 +1269,12 @@
}
/**
- * Test the patch function. Apply simple patch to replace/add data to the
- * input.
+ * Create a patch without any differences with the original.
*
* @throws Exception
*/
@Test()
- public final void testLdifPatch() throws Exception {
+ public final void testLdifPatchAddNoDiff() throws Exception {
// @formatter:off
final LDIFEntryReader input = new LDIFEntryReader(
"dn: uid=scarter,ou=People,dc=example,dc=com",
@@ -1095,6 +1282,1012 @@
"sn: new user",
"mail: mail@mailme.org"
);
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: add",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(3); // objectclass - sn - mail
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * The patch add successfully an attribute 'manager' to the entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchAddDiff() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: add",
+ "add: manager",
+ "manager: uid=joneill,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5); // objectclass - sn - mail
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * The patch add two new entries to the original.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchAddDiffNewEntry() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=joneill,ou=People,dc=example,dc=com",
+ "changetype: add",
+ "add: manager",
+ "manager: uid=hamond,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "",
+ "dn: uid=djackson,ou=People,dc=example,dc=com",
+ "changetype: add",
+ "add: manager",
+ "manager: uid=joneill,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString())
+ .isEqualTo("uid=djackson,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=joneill,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ reader.close();
+ }
+
+ /**
+ * Try to modify an nonexistent entry. The patch throw an error via the
+ * listener which is in RejectedChangeRecordListener.OVERWRITE.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchAddModifyNonExistantEntryDoNothing() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: cn=Lisa Jangles,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "add: telephonenumber",
+ "telephonenumber: (408) 555-2468"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Testing to delete in entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchDeleteEntry() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: delete"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Testing to delete in entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchDeleteEntryAmongSeveral() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "uid: user.1",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Eniko",
+ "sn: Eniko",
+ "cn: Eniko Atpco",
+ "uid: user.2",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "uid: user.3"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "changetype: delete"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.1,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.3,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Testing to delete attributes in an entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchDeleteAttributesEntry() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Carter",
+ "sn: Sam",
+ "cn: Sam Carter",
+ "uid: scarter",
+ "mail: user.1@mail.com",
+ "postalAdress: 42 Shepherd Street",
+ "work-phone: 650/506-7000",
+ "work-phone: 650/506-0666",
+ "home-fax: 650-7001"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "delete: work-phone",
+ "work-phone: 650/506-0666",
+ "-",
+ "delete: home-fax"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(8);
+ assertThat(entry.getAttribute("work-phone").firstValueAsString()).isEqualTo("650/506-7000");
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Modifying an entry : add
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyEntry() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "add: work-phone",
+ "work-phone: 650/506-7000"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * The patch attempts to modify the dn adding uppercase.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDNEntryUppercaseUid() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: scarter",
+ "",
+ "dn: uid=djackson,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: djackson"
+
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: uid=Scarter",
+ "deleteoldrdn: 1"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ // does not work with a single entry && ...
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString())
+ .isEqualTo("uid=djackson,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=Scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4); //The patch create uid attribute on the selected entry.
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Attemp to modify the entry adding uppercase in cn.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDNEntryUpperCaseDnNameSurname() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: cn=sam carter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: scarter",
+ "",
+ "dn: uid=djackson,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: djackson"
+
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: cn=sam carter,ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: cn=Sam Carter",
+ "deleteoldrdn: 1"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ // does not work with a single entry && ...
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "cn=Sam Carter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString())
+ .isEqualTo("uid=djackson,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4); //The patch create uid attribute on the selected entry.
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * The patch attempts to modify a rdn of a specific entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDNEntry() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: scarter",
+ "",
+ "dn: uid=djackson,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "uid: djackson"
+
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: uid=Susan Jacobs",
+ "deleteoldrdn: 1"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ // does not work with a single entry && ...
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString())
+ .isEqualTo("uid=djackson,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=Susan Jacobs,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4); //The patch create uid attribute on the selected entry.
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ @Test()
+ public final void testLdifPatchModifyDnEntry2() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "uid: user.1",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Eniko",
+ "sn: Eniko",
+ "cn: Eniko Atpco",
+ "uid: user.2",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "uid: user.3"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: uid=user.22",
+ "deleteoldrdn: 1"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.1,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.22,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.3,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Rename a branch : from ou=People,dc=example,dc=com to ou=Human
+ * Resources,dc=example,dc=com.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDnEntryBranch() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: organizationalunit",
+ "ou: People",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "uid: user.1",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Eniko",
+ "sn: Eniko",
+ "cn: Eniko Atpco",
+ "uid: user.2",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "uid: user.3",
+ "",
+ "dn: uid=user.4,ou=People,dc=example,dc=org",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Allan",
+ "sn: Zorg",
+ "cn: Allan Zorg",
+ "uid: user.4"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: ou=Human Resources,dc=example,dc=com",
+ "deleteoldrdn: 1"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAllAttributes("ou").iterator().next().firstValueAsString()).isEqualTo(
+ "Human Resources");
+ assertThat(entry.getAttributeCount()).isEqualTo(2);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.1,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.2,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.3,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.4,ou=People,dc=example,dc=org");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Rename a branch : from ou=People,dc=example,dc=com to ou=Human
+ * Resources,dc=example,dc=com. In this example deleteoldrdn is set to 0.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDnEntryBranchKeepsOldRdn() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: organizationalunit",
+ "ou: People",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "uid: user.1",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Eniko",
+ "sn: Eniko",
+ "cn: Eniko Atpco",
+ "uid: user.2",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaron",
+ "sn: Atrc",
+ "cn: Aaron Atrc",
+ "uid: user.3",
+ "",
+ "dn: uid=user.4,ou=People,dc=example,dc=org",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Allan",
+ "sn: Zorg",
+ "cn: Allan Zorg",
+ "uid: user.4"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: ou=Human Resources,dc=example,dc=com",
+ "deleteoldrdn: 0"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAllAttributes("ou").iterator().next().firstValueAsString()).isEqualTo(
+ "People");
+ assertThat(entry.getAttributeCount()).isEqualTo(2);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.1,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.2,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.3,ou=Human Resources,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.4,ou=People,dc=example,dc=org");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Moves an entry.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchModifyDnEntryNewSuperior() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "uid: user.1",
+ "mail: user.1@mail.com",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Eniko",
+ "sn: Eniko",
+ "cn: Eniko Atpco",
+ "uid: user.2"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "# moves the entry from ou=People, dc=example,dc=com to Marketing",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "changetype: modrdn",
+ "newrdn: uid=user.1",
+ "deleteoldrdn: 1",
+ "newsuperior: ou=Marketing,dc=example,dc=com"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo(
+ "uid=user.1,ou=Marketing,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(6);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.2,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Apply simple patch to replace/add data to the input.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchAddReplace() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace:sn",
+ "sn: scarter",
+ "-",
+ "add: manager",
+ "manager: uid=joneill,ou=People,dc=example,dc=com"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(4); // objectclass - sn - mail - manager
+ assertThat(entry.getAttribute("manager").firstValueAsString()).isEqualTo(
+ "uid=joneill,ou=People,dc=example,dc=com");
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Replace / add postalAdress.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchAddReplaceLanguageTagExample() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "postalAdress;lang-en: Shepherd Street"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace: postalAdress;lang-fr",
+ "postalAdress;lang-fr: 355 avenue Leon Blum",
+ "-",
+ "replace: postalAdress;lang-en",
+ "postalAdress;lang-en: 42 Shepherd Street"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttributeCount()).isEqualTo(5); // objectclass - sn - mail - manager - postalAdress
+ assertThat(entry.getAttribute("postalAdress;lang-fr").firstValueAsString()).isEqualTo(
+ "355 avenue Leon Blum");
+ assertThat(entry.getAttribute("postalAdress;lang-en").firstValueAsString()).isEqualTo(
+ "42 Shepherd Street");
+ assertThat(reader.hasNext()).isFalse();
+ reader.close();
+ }
+
+ /**
+ * Test some changes : add/replace/delete...
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchVariousChanges() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "",
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaccf",
+ "sn: Amar",
+ "cn: Aaccf Amar",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaren",
+ "sn: Atp",
+ "cn: Aaren Atp",
+ "mail: AarenAtp@mail.org",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco",
+ "description:: ZnVubnkgZGVzY3JpcHRpb24gISA6RA==",
+ "mail:: QWFyaWthQXRwY29AbWFpbC5vcmc=",
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Kadja",
+ "sn: Atpcol",
+ "cn: Kadja Atpcol"
+ );
+ // @formatter:on
+
+ final File file = File.createTempFile("sdk", ".png");
+ final String url = file.toURI().toURL().toString();
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace:sn",
+ "sn: scarter",
+ "-",
+ "add: manager",
+ "manager: uid=joneill,ou=People,dc=example,dc=com",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace:description",
+ "description:: QWFyaWthIEF0cGNvIGRlc2NyaXB0aW9uIDogbG9yZW0gaXBzdW0uLi4=",
+ "-",
+ "add: jpegphoto",
+ "jpegphoto:< " + url,
+ "",
+ "dn: uid=user.3,ou=People,dc=example,dc=com",
+ "changetype: delete"
+ );
+ // @formatter:on
+
+ final EntryReader reader = LDIF.patch(input, patch);
+
+ Entry entry = reader.readEntry();
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(entry.getAttribute("manager").firstValueAsString()).isEqualTo(
+ "uid=joneill,ou=People,dc=example,dc=com");
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.0,ou=People,dc=example,dc=com");
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getAttributeCount()).isEqualTo(5);
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.1,ou=People,dc=example,dc=com");
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getAttributeCount()).isEqualTo(7);
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.2,ou=People,dc=example,dc=com");
+ assertThat(entry.getAttribute("mail").firstValueAsString()).isEqualTo(
+ "AarikaAtpco@mail.org");
+ assertThat(entry.getAttribute("description").firstValueAsString()).isEqualTo(
+ "Aarika Atpco description : lorem ipsum...");
+ assertThat(entry.getAttribute("jpegphoto")).isNotEmpty();
+ assertThat(reader.hasNext()).isFalse();
+
+ file.delete();
+ reader.close();
+ }
+
+ /**
+ * An example for illustrate an LDIFChangeRecordReader containing changes on
+ * previous ldif.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testLdifPatchContainingChanges() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org",
+ "",
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaccf",
+ "sn: Amar",
+ "cn: Aaccf Amar",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aaren",
+ "sn: Atp",
+ "cn: Aaren Atp",
+ "",
+ "dn: uid=user.2,ou=People,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: person",
+ "objectClass: organizationalperson",
+ "objectClass: inetorgperson",
+ "givenName: Aarika",
+ "sn: Atpco",
+ "cn: Aarika Atpco"
+ );
+ // @formatter:on
// @formatter:off
final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
@@ -1104,21 +2297,101 @@
"sn: scarter",
"-",
"add: manager",
- "manager: uid=joneill,ou=People,dc=example,dc=com"
+ "manager: uid=joneill,ou=People,dc=example,dc=com",
+ "",
+ "dn: uid=user.0,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace:sn",
+ "sn: Amarr",
+ "-",
+ "delete: givenName",
+ "",
+ "dn: uid=user.1,ou=People,dc=example,dc=com",
+ "changetype: modify",
+ "replace:givenName",
+ "givenName: Aarwen",
+ "-",
+ "add: manager",
+ "manager: uid=joneill,ou=People,dc=example,dc=com",
+ "-",
+ "add: mail",
+ "mail: Aarwen@mail.com",
+ "-",
+ "add: fax",
+ "fax: 555 555-5555",
+ "-",
+ "add: description",
+ "description:: QWFyd2VuIGRlc2NyaXB0aW9uLg=="
);
// @formatter:on
- // @formatter:on
final EntryReader reader = LDIF.patch(input, patch);
+
Entry entry = reader.readEntry();
assertThat(entry.getName().toString()).isEqualTo("uid=scarter,ou=People,dc=example,dc=com");
- assertThat(entry.getAttributeCount()).isEqualTo(4); // objectclass - sn - mail - manager
+ // Attr. list : objectclass - sn - mail - manager
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
assertThat(entry.getAttribute("manager").firstValueAsString()).isEqualTo(
"uid=joneill,ou=People,dc=example,dc=com");
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ // Attr. list : objectclass - sn - cn
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ assertThat(reader.hasNext()).isTrue();
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.1,ou=People,dc=example,dc=com");
+ // Attr. list : objectclass - sn - cn - givenName - manager - mail - fax - description
+ assertThat(entry.getAttributeCount()).isEqualTo(8);
+ assertThat(entry.getAttribute("description").firstValueAsString()).isEqualTo(
+ "Aarwen description.");
+ assertThat(reader.hasNext()).isTrue();
+ // Last entry, no modification on it.
+ entry = reader.readEntry();
+ assertThat(entry.getName().toString()).isEqualTo("uid=user.2,ou=People,dc=example,dc=com");
+ // Attr. list : objectClass - givenname - sn - cn
+ assertThat(entry.getAttributeCount()).isEqualTo(4);
+ assertThat(reader.hasNext()).isFalse();
reader.close();
}
/**
+ * Try to apply a patch which data are not valid. Exception expected.
+ *
+ * @throws Exception
+ */
+ @SuppressWarnings("resource")
+ @Test(expectedExceptions = DecodeException.class)
+ public final void testLdifPatchInvalidChangeRecord() throws Exception {
+ // @formatter:off
+ final LDIFEntryReader input = new LDIFEntryReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "objectClass: person",
+ "sn: new user",
+ "mail: mail@mailme.org"
+ );
+ // @formatter:on
+
+ // @formatter:off
+ final LDIFChangeRecordReader patch = new LDIFChangeRecordReader(
+ "dn: uid=scarter,ou=People,dc=example,dc=com",
+ "changetype: modif\u0000",
+ "replace:sn",
+ "sn: scarter",
+ "-",
+ "add: manager\u0000",
+ "manager: uid=joneill,ou=People,dc=example,dc=com"
+ );
+ // @formatter:on
+ EntryReader reader = new LDIFEntryReader();
+ try {
+ reader = LDIF.patch(input, patch);
+ reader.readEntry();
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
* LDIF patch - EntryReader/ChangeRecordReader doesn't allow null. Exception
* expected.
*
@@ -1128,5 +2401,4 @@
public final void testLdifPatchDoesntAllowNull() throws Exception {
LDIF.patch(null, null);
}
-
}
--
Gitblit v1.10.0