From 8d673dd2b125d0b974eb1e8376e053731c628354 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 19 Sep 2012 22:52:22 +0000
Subject: [PATCH] Fix OPENDJ-157: Make methods like Entry.getAttribute(String) more user friendly
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java | 217 ++++---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java | 2
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java | 41
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java | 56
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java | 100 ++-
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java | 115 +++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java | 50 +
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java | 220 +++++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java | 2
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java | 794 ++++++++++++++++++++++++++-
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java | 109 +-
11 files changed, 1,402 insertions(+), 304 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java
index 9aa3359..0112e4c 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractEntry.java
@@ -28,6 +28,7 @@
package org.forgerock.opendj.ldap;
import java.util.Collection;
+import java.util.Iterator;
import com.forgerock.opendj.util.Iterables;
import com.forgerock.opendj.util.Predicate;
@@ -43,6 +44,7 @@
private static final Predicate<Attribute, AttributeDescription> FIND_ATTRIBUTES_PREDICATE =
new Predicate<Attribute, AttributeDescription>() {
+ @Override
public boolean matches(final Attribute value, final AttributeDescription p) {
return value.getAttributeDescription().isSubTypeOf(p);
}
@@ -50,94 +52,6 @@
};
/**
- * Returns {@code true} if {@code object} is an entry which is equal to
- * {@code entry}. Two entry are considered equal if their distinguished
- * names are equal, they both have the same number of attributes, and every
- * attribute contained in the first entry is also contained in the second
- * entry.
- *
- * @param entry
- * The entry to be tested for equality.
- * @param object
- * The object to be tested for equality with the entry.
- * @return {@code true} if {@code object} is an entry which is equal to
- * {@code entry}, or {@code false} if not.
- */
- static boolean equals(final Entry entry, final Object object) {
- if (entry == object) {
- return true;
- }
-
- if (!(object instanceof Entry)) {
- return false;
- }
-
- final Entry other = (Entry) object;
- if (!entry.getName().equals(other.getName())) {
- return false;
- }
-
- // Distinguished name is the same, compare attributes.
- if (entry.getAttributeCount() != other.getAttributeCount()) {
- return false;
- }
-
- for (final Attribute attribute : entry.getAllAttributes()) {
- final Attribute otherAttribute =
- other.getAttribute(attribute.getAttributeDescription());
-
- if (!attribute.equals(otherAttribute)) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the hash code for {@code entry}. It will be calculated as the sum
- * of the hash codes of the distinguished name and all of the attributes.
- *
- * @param entry
- * The entry whose hash code should be calculated.
- * @return The hash code for {@code entry}.
- */
- static int hashCode(final Entry entry) {
- int hashCode = entry.getName().hashCode();
- for (final Attribute attribute : entry.getAllAttributes()) {
- hashCode += attribute.hashCode();
- }
- return hashCode;
- }
-
- /**
- * Returns a string representation of {@code entry}.
- *
- * @param entry
- * The entry whose string representation should be returned.
- * @return The string representation of {@code entry}.
- */
- static String toString(final Entry entry) {
- final StringBuilder builder = new StringBuilder();
- builder.append("Entry(");
- builder.append(entry.getName());
- builder.append(", {");
-
- boolean firstValue = true;
- for (final Attribute attribute : entry.getAllAttributes()) {
- if (!firstValue) {
- builder.append(", ");
- }
-
- builder.append(attribute);
- firstValue = false;
- }
-
- builder.append("})");
- return builder.toString();
- }
-
- /**
* Sole constructor.
*/
protected AbstractEntry() {
@@ -147,6 +61,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean addAttribute(final Attribute attribute) {
return addAttribute(attribute, null);
}
@@ -154,6 +69,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public Entry addAttribute(final String attributeDescription, final Object... values) {
addAttribute(new LinkedAttribute(attributeDescription, values), null);
return this;
@@ -162,6 +78,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean containsAttribute(final Attribute attribute,
final Collection<ByteString> missingValues) {
final Attribute a = getAttribute(attribute.getAttributeDescription());
@@ -187,6 +104,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean containsAttribute(final String attributeDescription, final Object... values) {
return containsAttribute(new LinkedAttribute(attributeDescription, values), null);
}
@@ -196,12 +114,34 @@
*/
@Override
public boolean equals(final Object object) {
- return equals(this, object);
+ if (this == object) {
+ return true;
+ } else if (object instanceof Entry) {
+ final Entry other = (Entry) object;
+ if (!this.getName().equals(other.getName())) {
+ return false;
+ }
+ // Distinguished name is the same, compare attributes.
+ if (this.getAttributeCount() != other.getAttributeCount()) {
+ return false;
+ }
+ for (final Attribute attribute : this.getAllAttributes()) {
+ final Attribute otherAttribute =
+ other.getAttribute(attribute.getAttributeDescription());
+ if (!attribute.equals(otherAttribute)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
}
/**
* {@inheritDoc}
*/
+ @Override
public Iterable<Attribute> getAllAttributes(final AttributeDescription attributeDescription) {
Validator.ensureNotNull(attributeDescription);
@@ -212,6 +152,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public Iterable<Attribute> getAllAttributes(final String attributeDescription) {
return getAllAttributes(AttributeDescription.valueOf(attributeDescription));
}
@@ -219,6 +160,21 @@
/**
* {@inheritDoc}
*/
+ @Override
+ public Attribute getAttribute(final AttributeDescription attributeDescription) {
+ for (final Attribute attribute : getAllAttributes()) {
+ final AttributeDescription ad = attribute.getAttributeDescription();
+ if (isAssignable(attributeDescription, ad)) {
+ return attribute;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public Attribute getAttribute(final String attributeDescription) {
return getAttribute(AttributeDescription.valueOf(attributeDescription));
}
@@ -228,26 +184,64 @@
*/
@Override
public int hashCode() {
- return hashCode(this);
+ int hashCode = this.getName().hashCode();
+ for (final Attribute attribute : this.getAllAttributes()) {
+ hashCode += attribute.hashCode();
+ }
+ return hashCode;
}
/**
* {@inheritDoc}
*/
- public AttributeParser parseAttribute(AttributeDescription attributeDescription) {
+ @Override
+ public AttributeParser parseAttribute(final AttributeDescription attributeDescription) {
return AttributeParser.parseAttribute(getAttribute(attributeDescription));
}
/**
* {@inheritDoc}
*/
- public AttributeParser parseAttribute(String attributeDescription) {
+ @Override
+ public AttributeParser parseAttribute(final String attributeDescription) {
return AttributeParser.parseAttribute(getAttribute(attributeDescription));
}
/**
* {@inheritDoc}
*/
+ @Override
+ public boolean removeAttribute(final Attribute attribute,
+ final Collection<ByteString> missingValues) {
+ final Iterator<Attribute> i = getAllAttributes().iterator();
+ final AttributeDescription attributeDescription = attribute.getAttributeDescription();
+ while (i.hasNext()) {
+ final Attribute oldAttribute = i.next();
+ if (isAssignable(attributeDescription, oldAttribute.getAttributeDescription())) {
+ if (attribute.isEmpty()) {
+ i.remove();
+ return true;
+ } else {
+ final boolean modified = oldAttribute.removeAll(attribute, missingValues);
+ if (oldAttribute.isEmpty()) {
+ i.remove();
+ return true;
+ }
+ return modified;
+ }
+ }
+ }
+ // Not found.
+ if (missingValues != null) {
+ missingValues.addAll(attribute);
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public boolean removeAttribute(final AttributeDescription attributeDescription) {
return removeAttribute(Attributes.emptyAttribute(attributeDescription), null);
}
@@ -255,6 +249,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public Entry removeAttribute(final String attributeDescription, final Object... values) {
removeAttribute(new LinkedAttribute(attributeDescription, values), null);
return this;
@@ -263,12 +258,20 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean replaceAttribute(final Attribute attribute) {
if (attribute.isEmpty()) {
return removeAttribute(attribute.getAttributeDescription());
} else {
- removeAttribute(attribute.getAttributeDescription());
- addAttribute(attribute, null);
+ // For consistency with addAttribute and removeAttribute, preserve
+ // the existing attribute if it already exists.
+ final Attribute oldAttribute = getAttribute(attribute.getAttributeDescription());
+ if (oldAttribute != null) {
+ oldAttribute.clear();
+ oldAttribute.addAll(attribute);
+ } else {
+ addAttribute(attribute, null);
+ }
return true;
}
}
@@ -276,6 +279,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public Entry replaceAttribute(final String attributeDescription, final Object... values) {
replaceAttribute(new LinkedAttribute(attributeDescription, values));
return this;
@@ -284,6 +288,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public Entry setName(final String dn) {
return setName(DN.valueOf(dn));
}
@@ -293,7 +298,29 @@
*/
@Override
public String toString() {
- return toString(this);
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Entry(");
+ builder.append(this.getName());
+ builder.append(", {");
+ boolean firstValue = true;
+ for (final Attribute attribute : this.getAllAttributes()) {
+ if (!firstValue) {
+ builder.append(", ");
+ }
+
+ builder.append(attribute);
+ firstValue = false;
+ }
+ builder.append("})");
+ return builder.toString();
+ }
+
+ private boolean isAssignable(final AttributeDescription from, final AttributeDescription to) {
+ if (!from.isPlaceHolder()) {
+ return from.equals(to);
+ } else {
+ return from.matches(to);
+ }
}
}
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java
index 9825e45..e6d23e1 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AbstractMapEntry.java
@@ -37,7 +37,6 @@
*/
abstract class AbstractMapEntry extends AbstractEntry {
private final Map<AttributeDescription, Attribute> attributes;
-
private DN name;
/**
@@ -57,12 +56,11 @@
/**
* {@inheritDoc}
*/
+ @Override
public final boolean addAttribute(final Attribute attribute,
final Collection<ByteString> duplicateValues) {
- Validator.ensureNotNull(attribute);
-
final AttributeDescription attributeDescription = attribute.getAttributeDescription();
- final Attribute oldAttribute = attributes.get(attributeDescription);
+ final Attribute oldAttribute = getAttribute(attributeDescription);
if (oldAttribute != null) {
return oldAttribute.addAll(attribute, duplicateValues);
} else {
@@ -74,6 +72,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public final Entry clearAttributes() {
attributes.clear();
return this;
@@ -82,6 +81,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public final Iterable<Attribute> getAllAttributes() {
return attributes.values();
}
@@ -89,15 +89,21 @@
/**
* {@inheritDoc}
*/
+ @Override
public final Attribute getAttribute(final AttributeDescription attributeDescription) {
- Validator.ensureNotNull(attributeDescription);
-
- return attributes.get(attributeDescription);
+ final Attribute attribute = attributes.get(attributeDescription);
+ if (attribute == null && attributeDescription.isPlaceHolder()) {
+ // Fall-back to inefficient search using place-holder.
+ return super.getAttribute(attributeDescription);
+ } else {
+ return attribute;
+ }
}
/**
* {@inheritDoc}
*/
+ @Override
public final int getAttributeCount() {
return attributes.size();
}
@@ -105,6 +111,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public final DN getName() {
return name;
}
@@ -112,20 +119,27 @@
/**
* {@inheritDoc}
*/
+ @Override
public final boolean removeAttribute(final Attribute attribute,
final Collection<ByteString> missingValues) {
- Validator.ensureNotNull(attribute);
-
final AttributeDescription attributeDescription = attribute.getAttributeDescription();
-
if (attribute.isEmpty()) {
- return attributes.remove(attributeDescription) != null;
+ if (attributes.remove(attributeDescription) != null) {
+ return true;
+ } else if (attributeDescription.isPlaceHolder()) {
+ // Fall-back to inefficient remove using place-holder.
+ return super.removeAttribute(attribute, missingValues);
+ } else {
+ return false;
+ }
} else {
- final Attribute oldAttribute = attributes.get(attributeDescription);
+ final Attribute oldAttribute = getAttribute(attributeDescription);
if (oldAttribute != null) {
final boolean modified = oldAttribute.removeAll(attribute, missingValues);
if (oldAttribute.isEmpty()) {
- attributes.remove(attributeDescription);
+ // Use old attribute's description in case it is different
+ // (e.g. this may be the case when using place-holders).
+ attributes.remove(oldAttribute.getAttributeDescription());
return true;
}
return modified;
@@ -141,6 +155,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public final Entry setName(final DN dn) {
Validator.ensureNotNull(dn);
this.name = dn;
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
index ebefad2..d7c9d6b 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -67,7 +67,7 @@
public abstract int compareTo(Impl other);
- public abstract boolean containsOption(String normalizedOption);
+ public abstract boolean hasOption(String normalizedOption);
public abstract boolean equals(Impl other);
@@ -128,7 +128,7 @@
}
@Override
- public boolean containsOption(final String normalizedOption) {
+ public boolean hasOption(final String normalizedOption) {
final int sz = normalizedOptions.length;
for (int i = 0; i < sz; i++) {
if (normalizedOptions[i].equals(normalizedOption)) {
@@ -169,7 +169,7 @@
if (other == ZERO_OPTION_IMPL) {
return true;
} else if (other.size() == 1) {
- return containsOption(other.firstNormalizedOption());
+ return hasOption(other.firstNormalizedOption());
} else if (other.size() > size()) {
return false;
} else {
@@ -179,7 +179,7 @@
// not worth it.
final MultiOptionImpl tmp = (MultiOptionImpl) other;
for (final String normalizedOption : tmp.normalizedOptions) {
- if (!containsOption(normalizedOption)) {
+ if (!hasOption(normalizedOption)) {
return false;
}
}
@@ -191,7 +191,7 @@
public boolean isSuperTypeOf(final Impl other) {
// Must contain a sub-set of other's options.
for (final String normalizedOption : normalizedOptions) {
- if (!other.containsOption(normalizedOption)) {
+ if (!other.hasOption(normalizedOption)) {
return false;
}
}
@@ -235,13 +235,13 @@
}
@Override
- public boolean containsOption(final String normalizedOption) {
+ public boolean hasOption(final String normalizedOption) {
return this.normalizedOption.equals(normalizedOption);
}
@Override
public boolean equals(final Impl other) {
- return other.size() == 1 && other.containsOption(normalizedOption);
+ return other.size() == 1 && other.hasOption(normalizedOption);
}
@Override
@@ -272,7 +272,7 @@
@Override
public boolean isSuperTypeOf(final Impl other) {
// Other must have this option.
- return other.containsOption(normalizedOption);
+ return other.hasOption(normalizedOption);
}
public Iterator<String> iterator() {
@@ -298,7 +298,7 @@
}
@Override
- public boolean containsOption(final String normalizedOption) {
+ public boolean hasOption(final String normalizedOption) {
return false;
}
@@ -391,7 +391,7 @@
Validator.ensureNotNull(option);
final String normalizedOption = toLowerCase(option);
- if (pimpl.containsOption(normalizedOption)) {
+ if (pimpl.hasOption(normalizedOption)) {
return this;
}
@@ -480,7 +480,7 @@
Validator.ensureNotNull(option);
final String normalizedOption = toLowerCase(option);
- if (!pimpl.containsOption(normalizedOption)) {
+ if (!pimpl.hasOption(normalizedOption)) {
return this;
}
@@ -489,8 +489,7 @@
new StringBuilder(oldAttributeDescription.length() - option.length() - 1);
final String normalizedOldAttributeDescription = toLowerCase(oldAttributeDescription);
- final int index =
- normalizedOldAttributeDescription.indexOf(normalizedOption);
+ final int index = normalizedOldAttributeDescription.indexOf(normalizedOption);
builder.append(oldAttributeDescription, 0, index - 1 /* to semi-colon */);
builder.append(oldAttributeDescription, index + option.length(), oldAttributeDescription
.length());
@@ -1033,15 +1032,16 @@
* @throws NullPointerException
* If {@code option} was {@code null}.
*/
- public boolean containsOption(final String option) {
+ public boolean hasOption(final String option) {
final String normalizedOption = toLowerCase(option);
- return pimpl.containsOption(normalizedOption);
+ return pimpl.hasOption(normalizedOption);
}
/**
* Indicates whether the provided object is an attribute description which
* is equal to this attribute description. It will be considered equal if
- * the attribute type and normalized sorted list of options are identical.
+ * the attribute types are {@link AttributeType#equals equal} and normalized
+ * sorted list of options are identical.
*
* @param o
* The object for which to make the determination.
@@ -1053,19 +1053,12 @@
public boolean equals(final Object o) {
if (this == o) {
return true;
- }
-
- if (!(o instanceof AttributeDescription)) {
+ } else if (o instanceof AttributeDescription) {
+ final AttributeDescription other = (AttributeDescription) o;
+ return attributeType.equals(other.attributeType) && pimpl.equals(other.pimpl);
+ } else {
return false;
}
-
- final AttributeDescription other = (AttributeDescription) o;
- if (!attributeType.equals(other.attributeType)) {
- return false;
- }
-
- // Attribute type is the same, compare options.
- return pimpl.equals(other.pimpl);
}
/**
@@ -1125,14 +1118,34 @@
}
/**
+ * Indicates whether this attribute description is a temporary place-holder
+ * allocated dynamically by a non-strict schema when no corresponding
+ * registered attribute type was found.
+ * <p>
+ * Place holder attribute descriptions have an attribute type whose OID is
+ * the normalized attribute name with the string {@code -oid} appended. In
+ * addition, they will use the directory string syntax and case ignore
+ * matching rule.
+ *
+ * @return {@code true} if this is a temporary place-holder attribute
+ * description allocated dynamically by a non-strict schema when no
+ * corresponding registered attribute type was found.
+ * @see Schema#getAttributeType(String)
+ * @see AttributeType#isPlaceHolder()
+ */
+ public boolean isPlaceHolder() {
+ return attributeType.isPlaceHolder();
+ }
+
+ /**
* Indicates whether or not this attribute description is a sub-type of the
* provided attribute description as defined in RFC 4512 section 2.5.
* Specifically, this method will return {@code true} if and only if the
* following conditions are both {@code true}:
* <ul>
- * <li>This attribute description has an attribute type which is equal to,
- * or is a sub-type of, the attribute type in the provided attribute
- * description.
+ * <li>This attribute description has an attribute type which
+ * {@link AttributeType#matches matches}, or is a sub-type of, the attribute
+ * type in the provided attribute description.
* <li>This attribute description contains all of the options contained in
* the provided attribute description.
* </ul>
@@ -1160,9 +1173,9 @@
* Specifically, this method will return {@code true} if and only if the
* following conditions are both {@code true}:
* <ul>
- * <li>This attribute description has an attribute type which is equal to,
- * or is a super-type of, the attribute type in the provided attribute
- * description.
+ * <li>This attribute description has an attribute type which
+ * {@link AttributeType#matches matches}, or is a super-type of, the
+ * attribute type in the provided attribute description.
* <li>This attribute description contains a sub-set of the options
* contained in the provided attribute description.
* </ul>
@@ -1177,7 +1190,7 @@
* If {@code name} was {@code null}.
*/
public boolean isSuperTypeOf(final AttributeDescription other) {
- if (!other.attributeType.isSubTypeOf(attributeType)) {
+ if (!attributeType.isSuperTypeOf(other.attributeType)) {
return false;
} else {
return pimpl.isSuperTypeOf(other.pimpl);
@@ -1185,6 +1198,25 @@
}
/**
+ * Indicates whether the provided attribute description matches this
+ * attribute description. It will be considered a match if the attribute
+ * types {@link AttributeType#matches match} and the normalized sorted list
+ * of options are identical.
+ *
+ * @param other
+ * The attribute description for which to make the determination.
+ * @return {@code true} if the provided attribute description matches this
+ * attribute description, or {@code false} if not.
+ */
+ public boolean matches(final AttributeDescription other) {
+ if (this == other) {
+ return true;
+ } else {
+ return attributeType.matches(other.attributeType) && pimpl.equals(other.pimpl);
+ }
+ }
+
+ /**
* Returns the string representation of this attribute description as
* defined in RFC4512 section 2.5.
*
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java
index ff43d3d..49360e3 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Attributes.java
@@ -30,6 +30,8 @@
import java.util.Collection;
import java.util.Iterator;
+import org.forgerock.i18n.LocalizedIllegalArgumentException;
+
import com.forgerock.opendj.util.Iterators;
import com.forgerock.opendj.util.Validator;
@@ -97,7 +99,6 @@
private static final class RenamedAttribute implements Attribute {
private final Attribute attribute;
-
private final AttributeDescription attributeDescription;
private RenamedAttribute(final Attribute attribute,
@@ -106,31 +107,38 @@
this.attributeDescription = attributeDescription;
}
+ @Override
public boolean add(final ByteString value) {
return attribute.add(value);
}
+ @Override
public boolean add(final Object firstValue, final Object... remainingValues) {
return attribute.add(firstValue, remainingValues);
}
+ @Override
public boolean addAll(final Collection<? extends ByteString> values) {
return attribute.addAll(values);
}
+ @Override
public boolean addAll(final Collection<? extends ByteString> values,
final Collection<? super ByteString> duplicateValues) {
return attribute.addAll(values, duplicateValues);
}
+ @Override
public void clear() {
attribute.clear();
}
+ @Override
public boolean contains(final Object value) {
return attribute.contains(value);
}
+ @Override
public boolean containsAll(final Collection<?> values) {
return attribute.containsAll(values);
}
@@ -140,18 +148,22 @@
return AbstractAttribute.equals(this, object);
}
+ @Override
public ByteString firstValue() {
return attribute.firstValue();
}
+ @Override
public String firstValueAsString() {
return attribute.firstValueAsString();
}
+ @Override
public AttributeDescription getAttributeDescription() {
return attributeDescription;
}
+ @Override
public String getAttributeDescriptionAsString() {
return attributeDescription.toString();
}
@@ -161,48 +173,59 @@
return AbstractAttribute.hashCode(this);
}
- public AttributeParser parse() {
- return attribute.parse();
- }
-
+ @Override
public boolean isEmpty() {
return attribute.isEmpty();
}
+ @Override
public Iterator<ByteString> iterator() {
return attribute.iterator();
}
+ @Override
+ public AttributeParser parse() {
+ return attribute.parse();
+ }
+
+ @Override
public boolean remove(final Object value) {
return attribute.remove(value);
}
+ @Override
public boolean removeAll(final Collection<?> values) {
return attribute.removeAll(values);
}
+ @Override
public <T> boolean removeAll(final Collection<T> values,
final Collection<? super T> missingValues) {
return attribute.removeAll(values, missingValues);
}
+ @Override
public boolean retainAll(final Collection<?> values) {
return attribute.retainAll(values);
}
+ @Override
public <T> boolean retainAll(final Collection<T> values,
final Collection<? super T> missingValues) {
return attribute.retainAll(values, missingValues);
}
+ @Override
public int size() {
return attribute.size();
}
+ @Override
public ByteString[] toArray() {
return attribute.toArray();
}
+ @Override
public <T> T[] toArray(final T[] array) {
return attribute.toArray(array);
}
@@ -215,6 +238,72 @@
}
/**
+ * Singleton attribute.
+ */
+ private static final class SingletonAttribute extends AbstractAttribute {
+
+ private final AttributeDescription attributeDescription;
+ private ByteString normalizedValue;
+ private final ByteString value;
+
+ private SingletonAttribute(final AttributeDescription attributeDescription,
+ final Object value) {
+ this.attributeDescription = attributeDescription;
+ this.value = ByteString.valueOf(value);
+ }
+
+ @Override
+ public boolean add(final ByteString value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean contains(final Object value) {
+ final ByteString normalizedValue = normalizeValue(this, ByteString.valueOf(value));
+ return normalizedSingleValue().equals(normalizedValue);
+ }
+
+ @Override
+ public AttributeDescription getAttributeDescription() {
+ return attributeDescription;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public Iterator<ByteString> iterator() {
+ return Iterators.singletonIterator(value);
+ }
+
+ @Override
+ public boolean remove(final Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int size() {
+ return 1;
+ }
+
+ // Lazily computes the normalized single value.
+ private ByteString normalizedSingleValue() {
+ if (normalizedValue == null) {
+ normalizedValue = normalizeValue(this, value);
+ }
+ return normalizedValue;
+ }
+
+ }
+
+ /**
* Unmodifiable attribute.
*/
private static final class UnmodifiableAttribute implements Attribute {
@@ -225,31 +314,38 @@
this.attribute = attribute;
}
+ @Override
public boolean add(final ByteString value) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean add(final Object firstValue, final Object... remainingValues) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean addAll(final Collection<? extends ByteString> values) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean addAll(final Collection<? extends ByteString> values,
final Collection<? super ByteString> duplicateValues) {
throw new UnsupportedOperationException();
}
+ @Override
public void clear() {
throw new UnsupportedOperationException();
}
+ @Override
public boolean contains(final Object value) {
return attribute.contains(value);
}
+ @Override
public boolean containsAll(final Collection<?> values) {
return attribute.containsAll(values);
}
@@ -259,18 +355,22 @@
return (object == this || attribute.equals(object));
}
+ @Override
public ByteString firstValue() {
return attribute.firstValue();
}
+ @Override
public String firstValueAsString() {
return attribute.firstValueAsString();
}
+ @Override
public AttributeDescription getAttributeDescription() {
return attribute.getAttributeDescription();
}
+ @Override
public String getAttributeDescriptionAsString() {
return attribute.getAttributeDescriptionAsString();
}
@@ -280,48 +380,59 @@
return attribute.hashCode();
}
+ @Override
public boolean isEmpty() {
return attribute.isEmpty();
}
+ @Override
public Iterator<ByteString> iterator() {
return Iterators.unmodifiableIterator(attribute.iterator());
}
+ @Override
public AttributeParser parse() {
return attribute.parse();
}
+ @Override
public boolean remove(final Object value) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean removeAll(final Collection<?> values) {
throw new UnsupportedOperationException();
}
+ @Override
public <T> boolean removeAll(final Collection<T> values,
final Collection<? super T> missingValues) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean retainAll(final Collection<?> values) {
throw new UnsupportedOperationException();
}
+ @Override
public <T> boolean retainAll(final Collection<T> values,
final Collection<? super T> missingValues) {
throw new UnsupportedOperationException();
}
+ @Override
public int size() {
return attribute.size();
}
+ @Override
public ByteString[] toArray() {
return attribute.toArray();
}
+ @Override
public <T> T[] toArray(final T[] array) {
return attribute.toArray(array);
}
@@ -330,12 +441,13 @@
public String toString() {
return attribute.toString();
}
-
}
/**
* Returns a read-only empty attribute having the specified attribute
- * description.
+ * description. Attempts to modify the returned attribute either directly,
+ * or indirectly via an iterator, result in an
+ * {@code UnsupportedOperationException}.
*
* @param attributeDescription
* The attribute description.
@@ -348,6 +460,26 @@
}
/**
+ * Returns a read-only empty attribute having the specified attribute
+ * description. The attribute description will be decoded using the default
+ * schema. Attempts to modify the returned attribute either directly, or
+ * indirectly via an iterator, result in an
+ * {@code UnsupportedOperationException}.
+ *
+ * @param attributeDescription
+ * The attribute description.
+ * @return The empty attribute.
+ * @throws LocalizedIllegalArgumentException
+ * If {@code attributeDescription} could not be decoded using
+ * the default schema.
+ * @throws NullPointerException
+ * If {@code attributeDescription} was {@code null}.
+ */
+ public static final Attribute emptyAttribute(final String attributeDescription) {
+ return emptyAttribute(AttributeDescription.valueOf(attributeDescription));
+ }
+
+ /**
* Returns a view of {@code attribute} having a different attribute
* description. All operations on the returned attribute "pass-through" to
* the underlying attribute.
@@ -368,6 +500,80 @@
}
/**
+ * Returns a view of {@code attribute} having a different attribute
+ * description. All operations on the returned attribute "pass-through" to
+ * the underlying attribute. The attribute description will be decoded using
+ * the default schema.
+ *
+ * @param attribute
+ * The attribute to be renamed.
+ * @param attributeDescription
+ * The new attribute description for {@code attribute}.
+ * @return A renamed view of {@code attribute}.
+ * @throws LocalizedIllegalArgumentException
+ * If {@code attributeDescription} could not be decoded using
+ * the default schema.
+ * @throws NullPointerException
+ * If {@code attribute} or {@code attributeDescription} was
+ * {@code null}.
+ */
+ public static final Attribute renameAttribute(final Attribute attribute,
+ final String attributeDescription) {
+ Validator.ensureNotNull(attribute, attributeDescription);
+ return renameAttribute(attribute, AttributeDescription.valueOf(attributeDescription));
+ }
+
+ /**
+ * Returns a read-only single-valued attribute having the specified
+ * attribute description and value. Attempts to modify the returned
+ * attribute either directly, or indirectly via an iterator, result in an
+ * {@code UnsupportedOperationException}.
+ * <p>
+ * If {@code value} is not an instance of {@code ByteString} then it will be
+ * converted using the {@link ByteString#valueOf(Object)} method.
+ *
+ * @param attributeDescription
+ * The attribute description.
+ * @param value
+ * The single attribute value.
+ * @return The single-valued attribute.
+ * @throws NullPointerException
+ * If {@code attributeDescription} or {@code value} was
+ * {@code null}.
+ */
+ public static final Attribute singletonAttribute(
+ final AttributeDescription attributeDescription, final Object value) {
+ return new SingletonAttribute(attributeDescription, value);
+ }
+
+ /**
+ * Returns a read-only single-valued attribute having the specified
+ * attribute description. The attribute description will be decoded using
+ * the default schema. Attempts to modify the returned attribute either
+ * directly, or indirectly via an iterator, result in an
+ * {@code UnsupportedOperationException}.
+ * <p>
+ * If {@code value} is not an instance of {@code ByteString} then it will be
+ * converted using the {@link ByteString#valueOf(Object)} method.
+ *
+ * @param attributeDescription
+ * The attribute description.
+ * @param value
+ * The single attribute value.
+ * @return The single-valued attribute.
+ * @throws LocalizedIllegalArgumentException
+ * If {@code attributeDescription} could not be decoded using
+ * the default schema.
+ * @throws NullPointerException
+ * If {@code attributeDescription} or {@code value} was
+ * {@code null}.
+ */
+ public static final Attribute singletonAttribute(final String attributeDescription,
+ final Object value) {
+ return singletonAttribute(AttributeDescription.valueOf(attributeDescription), value);
+ }
+
+ /**
* Returns a read-only view of {@code attribute}. Query operations on the
* returned attribute "read-through" to the underlying attribute, and
* attempts to modify the returned attribute either directly or indirectly
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java
index 3c1c382..0688857 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entry.java
@@ -38,8 +38,12 @@
* {@link #addAttribute(String, Object...)} and {@link #setName(String)}). In
* these cases the default schema is used unless an alternative schema is
* specified in the {@code Entry} constructor. The default schema is not used
- * for any other purpose. In particular, an {@code Entry} will permit attributes
- * to be added which have been decoded using multiple schemas.
+ * for any other purpose. In particular, an {@code Entry} may contain attributes
+ * which have been decoded using different schemas.
+ * <p>
+ * When determining whether or not an entry already contains a particular
+ * attribute, attribute descriptions will be compared using
+ * {@link AttributeDescription#matches}.
* <p>
* Full LDAP modify semantics are provided via the {@link #addAttribute},
* {@link #removeAttribute}, and {@link #replaceAttribute} methods.
@@ -64,12 +68,14 @@
* Ensures that this entry contains the provided attribute and values
* (optional operation). This method has the following semantics:
* <ul>
- * <li>If this entry does not already contain an attribute with the same
- * attribute description, then this entry will be modified such that it
- * contains {@code attribute}, even if it is empty.
- * <li>If this entry already contains an attribute with the same attribute
- * description, then the attribute values contained in {@code attribute}
- * will be merged with the existing attribute values.
+ * <li>If this entry does not already contain an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * this entry will be modified such that it contains {@code attribute}, even
+ * if it is empty.
+ * <li>If this entry already contains an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * the attribute values contained in {@code attribute} will be merged with
+ * the existing attribute values.
* </ul>
* <p>
* <b>NOTE:</b> When {@code attribute} is non-empty, this method implements
@@ -91,12 +97,14 @@
* Ensures that this entry contains the provided attribute and values
* (optional operation). This method has the following semantics:
* <ul>
- * <li>If this entry does not already contain an attribute with the same
- * attribute description, then this entry will be modified such that it
- * contains {@code attribute}, even if it is empty.
- * <li>If this entry already contains an attribute with the same attribute
- * description, then the attribute values contained in {@code attribute}
- * will be merged with the existing attribute values.
+ * <li>If this entry does not already contain an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * this entry will be modified such that it contains {@code attribute}, even
+ * if it is empty.
+ * <li>If this entry already contains an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * the attribute values contained in {@code attribute} will be merged with
+ * the existing attribute values.
* </ul>
* <p>
* <b>NOTE:</b> When {@code attribute} is non-empty, this method implements
@@ -121,12 +129,14 @@
* Ensures that this entry contains the provided attribute and values
* (optional operation). This method has the following semantics:
* <ul>
- * <li>If this entry does not already contain an attribute with the same
- * attribute description, then this entry will be modified such that it
- * contains {@code attribute}, even if it is empty.
- * <li>If this entry already contains an attribute with the same attribute
- * description, then the attribute values contained in {@code attribute}
- * will be merged with the existing attribute values.
+ * <li>If this entry does not already contain an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * this entry will be modified such that it contains {@code attribute}, even
+ * if it is empty.
+ * <li>If this entry already contains an attribute with a
+ * {@link AttributeDescription#matches matching} attribute description, then
+ * the attribute values contained in {@code attribute} will be merged with
+ * the existing attribute values.
* </ul>
* <p>
* The attribute description will be decoded using the schema associated
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
index 589d1db..e5aa80b 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/AttributeType.java
@@ -74,6 +74,9 @@
// Indicates whether this definition is declared "obsolete".
private final boolean isObsolete;
+ // Indicates whether this definition is a temporary place-holder.
+ private final boolean isPlaceHolder;
+
// Indicates whether this attribute type is declared "single-value".
private final boolean isSingleValue;
@@ -162,34 +165,45 @@
}
this.isObjectClassType = oid.equals("2.5.4.0");
+ this.isPlaceHolder = false;
this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
}
- AttributeType(final String oid, final List<String> names, final String description,
- final MatchingRule equalityMatchingRule, final Syntax syntax) {
- super(description, Collections.<String, List<String>> emptyMap());
+ /**
+ * Creates a new place-holder attribute type having the specified name,
+ * default syntax, and default matching rule. The OID of the place-holder
+ * attribute will be the normalized attribute type name followed by the
+ * suffix "-oid".
+ *
+ * @param name
+ * The name of the place-holder attribute type.
+ */
+ AttributeType(final String name) {
+ super("", Collections.<String, List<String>> emptyMap());
- Validator.ensureNotNull(oid, names, description);
+ final StringBuilder builder = new StringBuilder(name.length() + 4);
+ StaticUtils.toLowerCase(name, builder);
+ builder.append("-oid");
- this.oid = oid;
- this.names = names;
+ this.oid = builder.toString();
+ this.names = Collections.singletonList(name);
this.isObsolete = false;
this.superiorTypeOID = null;
this.superiorType = null;
+ this.equalityMatchingRule = Schema.getDefaultMatchingRule();
this.equalityMatchingRuleOID = equalityMatchingRule.getOID();
- this.equalityMatchingRule = equalityMatchingRule;
this.orderingMatchingRuleOID = null;
this.substringMatchingRuleOID = null;
this.approximateMatchingRuleOID = null;
+ this.syntax = Schema.getDefaultSyntax();
this.syntaxOID = syntax.getOID();
- this.syntax = syntax;
this.isSingleValue = false;
this.isCollective = false;
this.isNoUserModification = false;
this.attributeUsage = AttributeUsage.USER_APPLICATIONS;
this.definition = buildDefinition();
-
- this.isObjectClassType = oid.equals("2.5.4.0");
+ this.isObjectClassType = false;
+ this.isPlaceHolder = true;
this.normalizedName = StaticUtils.toLowerCase(getNameOrOID());
}
@@ -200,7 +214,8 @@
* <li>The {@code objectClass} attribute is less than all other attribute
* types.
* <li>User attributes are less than operational attributes.
- * <li>Lexicographic comparison of the primary name or OID.
+ * <li>Lexicographic comparison of the primary name and then, if equal, the
+ * OID.
* </ul>
*
* @param type
@@ -219,9 +234,13 @@
} else {
final boolean isOperational = getUsage().isOperational();
final boolean typeIsOperational = type.getUsage().isOperational();
-
if (isOperational == typeIsOperational) {
- return normalizedName.compareTo(type.normalizedName);
+ final int tmp = normalizedName.compareTo(type.normalizedName);
+ if (tmp == 0) {
+ return oid.compareTo(type.oid);
+ } else {
+ return tmp;
+ }
} else {
return isOperational ? 1 : -1;
}
@@ -452,6 +471,24 @@
}
/**
+ * Indicates whether this attribute type is a temporary place-holder
+ * allocated dynamically by a non-strict schema when no registered attribute
+ * type was found.
+ * <p>
+ * Place holder attribute types have an OID which is the normalized
+ * attribute name with the string {@code -oid} appended. In addition, they
+ * will use the directory string syntax and case ignore matching rule.
+ *
+ * @return {@code true} if this is a temporary place-holder attribute type
+ * allocated dynamically by a non-strict schema when no registered
+ * attribute type was found.
+ * @see Schema#getAttributeType(String)
+ */
+ public boolean isPlaceHolder() {
+ return isPlaceHolder;
+ }
+
+ /**
* Indicates whether this attribute type is declared "single-value".
*
* @return {@code true} if this attribute type is declared "single-value",
@@ -475,7 +512,7 @@
public boolean isSubTypeOf(final AttributeType type) {
AttributeType tmp = this;
do {
- if (tmp.equals(type)) {
+ if (tmp.matches(type)) {
return true;
}
tmp = tmp.getSuperiorType();
@@ -484,6 +521,50 @@
}
/**
+ * Indicates whether or not this attribute type is a super-type of the
+ * provided attribute type.
+ *
+ * @param type
+ * The attribute type for which to make the determination.
+ * @return {@code true} if this attribute type is a super-type of the
+ * provided attribute type, or {@code false} if not.
+ * @throws NullPointerException
+ * If {@code type} was {@code null}.
+ */
+ public boolean isSuperTypeOf(final AttributeType type) {
+ return type.isSubTypeOf(this);
+ }
+
+ /**
+ * Implements a place-holder tolerant version of {@link #equals}. This
+ * method returns {@true} in the following cases:
+ * <ul>
+ * <li>this attribute type is equal to the provided attribute type as
+ * specified by {@link #equals}
+ * <li>this attribute type is a place-holder and the provided attribute type
+ * has a name which matches the name of this attribute type
+ * <li>the provided attribute type is a place-holder and this attribute type
+ * has a name which matches the name of the provided attribute type.
+ * </ul>
+ *
+ * @param type
+ * The attribute type for which to make the determination.
+ * @return {@code true} if the provided attribute type matches this
+ * attribute type.
+ */
+ public boolean matches(final AttributeType type) {
+ if (this == type) {
+ return true;
+ } else if (oid.equals(type.oid)) {
+ return true;
+ } else if (isPlaceHolder != type.isPlaceHolder) {
+ return isPlaceHolder ? type.hasName(normalizedName) : hasName(type.normalizedName);
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Returns the string representation of this schema definition in the form
* specified in RFC 2252.
*
@@ -591,8 +672,7 @@
boolean validate(final Schema schema, final List<AttributeType> invalidSchemaElements,
final List<LocalizableMessage> warnings) {
// Avoid validating this schema element more than once. This may occur
- // if
- // multiple attributes specify the same superior.
+ // if multiple attributes specify the same superior.
if (!needsValidating) {
return isValid;
}
@@ -612,8 +692,7 @@
}
// First ensure that the superior has been validated and fail if it
- // is
- // invalid.
+ // is invalid.
if (!superiorType.validate(schema, invalidSchemaElements, warnings)) {
final LocalizableMessage message =
WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_TYPE.get(getNameOrOID(),
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index ad4db1e..8ccd84a 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -73,8 +73,10 @@
public final class Schema {
private static final class EmptyImpl implements Impl {
- private EmptyImpl() {
- // Nothing to do.
+ private final boolean isStrict;
+
+ private EmptyImpl(final boolean isStrict) {
+ this.isStrict = isStrict;
}
public boolean allowMalformedNamesAndOptions() {
@@ -95,17 +97,12 @@
@Override
public AttributeType getAttributeType(final String name) {
- // Construct an placeholder attribute type with the given name,
- // the default matching rule, and the default syntax. The OID of
- // the attribute will be the normalized OID alias with "-oid"
- // appended to the given name.
- final StringBuilder builder = new StringBuilder(name.length() + 4);
- StaticUtils.toLowerCase(name, builder);
- builder.append("-oid");
- final String noid = builder.toString();
-
- return new AttributeType(noid, Collections.singletonList(name), "", Schema
- .getDefaultMatchingRule(), Schema.getDefaultSyntax());
+ if (isStrict) {
+ throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name));
+ } else {
+ // Return a place-holder.
+ return new AttributeType(name);
+ }
}
@Override
@@ -298,7 +295,7 @@
@Override
public boolean isStrict() {
- return false;
+ return isStrict;
}
}
@@ -389,9 +386,9 @@
}
private static final class NonStrictImpl implements Impl {
- private final Impl strictImpl;
+ private final StrictImpl strictImpl;
- private NonStrictImpl(final Impl strictImpl) {
+ private NonStrictImpl(final StrictImpl strictImpl) {
this.strictImpl = strictImpl;
}
@@ -413,20 +410,8 @@
@Override
public AttributeType getAttributeType(final String name) {
- if (!strictImpl.hasAttributeType(name)) {
- // Construct an placeholder attribute type with the given name,
- // the default matching rule, and the default syntax. The OID of
- // the attribute will be the normalized OID alias with "-oid"
- // appended to the given name.
- final StringBuilder builder = new StringBuilder(name.length() + 4);
- StaticUtils.toLowerCase(name, builder);
- builder.append("-oid");
- final String noid = builder.toString();
-
- return new AttributeType(noid, Collections.singletonList(name), "", Schema
- .getDefaultMatchingRule(), Schema.getDefaultSyntax());
- }
- return strictImpl.getAttributeType(name);
+ final AttributeType type = strictImpl.getAttributeType0(name);
+ return type != null ? type : new AttributeType(name);
}
@Override
@@ -735,19 +720,12 @@
@Override
public AttributeType getAttributeType(final String name) {
- final AttributeType type = numericOID2AttributeTypes.get(name);
+ final AttributeType type = getAttributeType0(name);
if (type != null) {
return type;
+ } else {
+ throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name));
}
- final List<AttributeType> attributes =
- name2AttributeTypes.get(StaticUtils.toLowerCase(name));
- if (attributes != null) {
- if (attributes.size() == 1) {
- return attributes.get(0);
- }
- throw new UnknownSchemaElementException(WARN_ATTR_TYPE_AMBIGIOUS.get(name));
- }
- throw new UnknownSchemaElementException(WARN_ATTR_TYPE_UNKNOWN.get(name));
}
@Override
@@ -1073,28 +1051,37 @@
public boolean isStrict() {
return true;
}
+
+ AttributeType getAttributeType0(final String name) {
+ final AttributeType type = numericOID2AttributeTypes.get(name);
+ if (type != null) {
+ return type;
+ }
+ final List<AttributeType> attributes =
+ name2AttributeTypes.get(StaticUtils.toLowerCase(name));
+ if (attributes != null) {
+ if (attributes.size() == 1) {
+ return attributes.get(0);
+ }
+ throw new UnknownSchemaElementException(WARN_ATTR_TYPE_AMBIGIOUS.get(name));
+ }
+ return null;
+ }
}
/*
* WARNING: do not reference the core schema in the following declarations.
*/
- private static final Schema EMPTY_SCHEMA = new Schema(new EmptyImpl());
-
+ private static final Schema EMPTY_STRICT_SCHEMA = new Schema(new EmptyImpl(true));
+ private static final Schema EMPTY_NON_STRICT_SCHEMA = new Schema(new EmptyImpl(false));
static final String ATTR_ATTRIBUTE_TYPES = "attributeTypes";
-
static final String ATTR_DIT_CONTENT_RULES = "dITContentRules";
-
static final String ATTR_DIT_STRUCTURE_RULES = "dITStructureRules";
-
static final String ATTR_LDAP_SYNTAXES = "ldapSyntaxes";
-
static final String ATTR_MATCHING_RULE_USE = "matchingRuleUse";
-
static final String ATTR_MATCHING_RULES = "matchingRules";
-
static final String ATTR_NAME_FORMS = "nameForms";
-
static final String ATTR_OBJECT_CLASSES = "objectClasses";
/**
@@ -1138,7 +1125,7 @@
* @return The empty schema.
*/
public static Schema getEmptySchema() {
- return EMPTY_SCHEMA;
+ return EMPTY_NON_STRICT_SCHEMA;
}
/**
@@ -1457,10 +1444,13 @@
* @see Schema#isStrict()
*/
public Schema asNonStrictSchema() {
- if (impl.isStrict()) {
- return new Schema(new NonStrictImpl(impl));
- } else {
+ if (!impl.isStrict()) {
return this;
+ } else if (impl instanceof StrictImpl) {
+ return new Schema(new NonStrictImpl((StrictImpl) impl));
+ } else {
+ // EmptyImpl
+ return EMPTY_NON_STRICT_SCHEMA;
}
}
@@ -1475,13 +1465,23 @@
public Schema asStrictSchema() {
if (impl.isStrict()) {
return this;
- } else {
+ } else if (impl instanceof NonStrictImpl) {
return new Schema(((NonStrictImpl) impl).strictImpl);
+ } else {
+ // EmptyImpl
+ return EMPTY_STRICT_SCHEMA;
}
}
/**
* Returns the attribute type with the specified name or numeric OID.
+ * <p>
+ * If the requested attribute type is not registered in this schema and this
+ * schema is non-strict then a temporary "place-holder" attribute type will
+ * be created and returned. Place holder attribute types have an OID which
+ * is the normalized attribute name with the string {@code -oid} appended.
+ * In addition, they will use the directory string syntax and case ignore
+ * matching rule.
*
* @param name
* The name or OID of the attribute type to retrieve.
@@ -1489,6 +1489,7 @@
* @throws UnknownSchemaElementException
* If this is a strict schema and the requested attribute type
* was not found or if the provided name is ambiguous.
+ * @see AttributeType#isPlaceHolder()
*/
public AttributeType getAttributeType(final String name) {
return impl.getAttributeType(name);
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
index 0b6caf2..b455c06 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/AbstractLDIFReader.java
@@ -501,7 +501,7 @@
// Ensure that the binary option is present if required.
if (!syntax.isBEREncodingRequired()) {
if (schemaValidationPolicy.checkAttributeValues().needsChecking()
- && attributeDescription.containsOption("binary")) {
+ && attributeDescription.hasOption("binary")) {
final LocalizableMessage message =
ERR_LDIF_UNEXPECTED_BINARY_OPTION.get(record.lineNumber, entry.getName()
.toString(), attrDescr);
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
index 57af7f8..8f3edde 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldif/LDIFChangeRecordReader.java
@@ -538,7 +538,7 @@
// Ensure that the binary option is present if required.
if (!syntax.isBEREncodingRequired()) {
if (schemaValidationPolicy.checkAttributeValues().needsChecking()
- && attributeDescription.containsOption("binary")) {
+ && attributeDescription.hasOption("binary")) {
final LocalizableMessage message =
ERR_LDIF_UNEXPECTED_BINARY_OPTION.get(record.lineNumber, entryDN
.toString(), pair.value);
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
index 1f6d5b2..619c7a2 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/AttributeDescriptionTestCase.java
@@ -219,7 +219,7 @@
assertEquals(attributeDescription.isObjectClass(), isObjectClass);
assertFalse(attributeDescription.hasOptions());
- assertFalse(attributeDescription.containsOption("dummy"));
+ assertFalse(attributeDescription.hasOption("dummy"));
final Iterator<String> iterator = attributeDescription.getOptions().iterator();
assertFalse(iterator.hasNext());
@@ -250,19 +250,19 @@
assertTrue(attributeDescription.hasOptions());
}
- assertFalse(attributeDescription.containsOption("dummy"));
+ assertFalse(attributeDescription.hasOption("dummy"));
if (containsFoo) {
- assertTrue(attributeDescription.containsOption("foo"));
- assertTrue(attributeDescription.containsOption("FOO"));
- assertTrue(attributeDescription.containsOption("FoO"));
+ assertTrue(attributeDescription.hasOption("foo"));
+ assertTrue(attributeDescription.hasOption("FOO"));
+ assertTrue(attributeDescription.hasOption("FoO"));
} else {
- assertFalse(attributeDescription.containsOption("foo"));
- assertFalse(attributeDescription.containsOption("FOO"));
- assertFalse(attributeDescription.containsOption("FoO"));
+ assertFalse(attributeDescription.hasOption("foo"));
+ assertFalse(attributeDescription.hasOption("FOO"));
+ assertFalse(attributeDescription.hasOption("FoO"));
}
for (final String option : options) {
- assertTrue(attributeDescription.containsOption(option));
+ assertTrue(attributeDescription.hasOption(option));
}
final Iterator<String> iterator = attributeDescription.getOptions().iterator();
@@ -278,8 +278,8 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn");
AttributeDescription ad2 = ad1.withOption("test");
assertTrue(ad2.hasOptions());
- assertTrue(ad2.containsOption("test"));
- assertFalse(ad2.containsOption("dummy"));
+ assertTrue(ad2.hasOption("test"));
+ assertFalse(ad2.hasOption("dummy"));
assertEquals(ad2.toString(), "cn;test");
assertEquals(ad2.getOptions().iterator().next(), "test");
}
@@ -296,9 +296,9 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1");
AttributeDescription ad2 = ad1.withOption("test2");
assertTrue(ad2.hasOptions());
- assertTrue(ad2.containsOption("test1"));
- assertTrue(ad2.containsOption("test2"));
- assertFalse(ad2.containsOption("dummy"));
+ assertTrue(ad2.hasOption("test1"));
+ assertTrue(ad2.hasOption("test2"));
+ assertFalse(ad2.hasOption("dummy"));
assertEquals(ad2.toString(), "cn;test1;test2");
Iterator<String> i = ad2.getOptions().iterator();
assertEquals(i.next(), "test1");
@@ -326,7 +326,7 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test");
AttributeDescription ad2 = ad1.withoutOption("test");
assertFalse(ad2.hasOptions());
- assertFalse(ad2.containsOption("test"));
+ assertFalse(ad2.hasOption("test"));
assertEquals(ad2.toString(), "cn");
assertFalse(ad2.getOptions().iterator().hasNext());
}
@@ -343,8 +343,8 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
AttributeDescription ad2 = ad1.withoutOption("test1");
assertTrue(ad2.hasOptions());
- assertFalse(ad2.containsOption("test1"));
- assertTrue(ad2.containsOption("test2"));
+ assertFalse(ad2.hasOption("test1"));
+ assertTrue(ad2.hasOption("test2"));
assertEquals(ad2.toString(), "cn;test2");
assertEquals(ad2.getOptions().iterator().next(), "test2");
}
@@ -354,8 +354,8 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2");
AttributeDescription ad2 = ad1.withoutOption("test2");
assertTrue(ad2.hasOptions());
- assertTrue(ad2.containsOption("test1"));
- assertFalse(ad2.containsOption("test2"));
+ assertTrue(ad2.hasOption("test1"));
+ assertFalse(ad2.hasOption("test2"));
assertEquals(ad2.toString(), "cn;test1");
assertEquals(ad2.getOptions().iterator().next(), "test1");
}
@@ -372,9 +372,9 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
AttributeDescription ad2 = ad1.withoutOption("test1");
assertTrue(ad2.hasOptions());
- assertFalse(ad2.containsOption("test1"));
- assertTrue(ad2.containsOption("test2"));
- assertTrue(ad2.containsOption("test3"));
+ assertFalse(ad2.hasOption("test1"));
+ assertTrue(ad2.hasOption("test2"));
+ assertTrue(ad2.hasOption("test3"));
assertEquals(ad2.toString(), "cn;test2;test3");
Iterator<String> i = ad2.getOptions().iterator();
assertEquals(i.next(), "test2");
@@ -386,9 +386,9 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
AttributeDescription ad2 = ad1.withoutOption("test2");
assertTrue(ad2.hasOptions());
- assertTrue(ad2.containsOption("test1"));
- assertFalse(ad2.containsOption("test2"));
- assertTrue(ad2.containsOption("test3"));
+ assertTrue(ad2.hasOption("test1"));
+ assertFalse(ad2.hasOption("test2"));
+ assertTrue(ad2.hasOption("test3"));
assertEquals(ad2.toString(), "cn;test1;test3");
Iterator<String> i = ad2.getOptions().iterator();
assertEquals(i.next(), "test1");
@@ -400,9 +400,9 @@
AttributeDescription ad1 = AttributeDescription.valueOf("cn;test1;test2;test3");
AttributeDescription ad2 = ad1.withoutOption("test3");
assertTrue(ad2.hasOptions());
- assertTrue(ad2.containsOption("test1"));
- assertTrue(ad2.containsOption("test2"));
- assertFalse(ad2.containsOption("test3"));
+ assertTrue(ad2.hasOption("test1"));
+ assertTrue(ad2.hasOption("test2"));
+ assertFalse(ad2.hasOption("test3"));
assertEquals(ad2.toString(), "cn;test1;test2");
Iterator<String> i = ad2.getOptions().iterator();
assertEquals(i.next(), "test1");
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java
index 5476659..5721f28 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/EntryTestCase.java
@@ -22,11 +22,21 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
+ * Portions copyright 2012 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
-import org.testng.Assert;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.forgerock.opendj.ldap.Attributes.emptyAttribute;
+import static org.forgerock.opendj.ldap.Attributes.singletonAttribute;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.SchemaBuilder;
+import org.forgerock.opendj.ldif.LDIFEntryReader;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -35,60 +45,778 @@
*/
@SuppressWarnings("javadoc")
public final class EntryTestCase extends SdkTestCase {
+
private static interface EntryFactory {
- Entry newEntry(String... ldifLines);
+ Entry newEntry(String... ldifLines) throws Exception;
}
private static final class LinkedHashMapEntryFactory implements EntryFactory {
- public Entry newEntry(final String... ldifLines) {
- return new LinkedHashMapEntry(ldifLines);
+ @Override
+ public Entry newEntry(final String... ldifLines) throws Exception {
+ final LDIFEntryReader reader = new LDIFEntryReader(ldifLines).setSchema(SCHEMA);
+ final Entry entry = reader.readEntry();
+ assertThat(reader.hasNext()).isFalse();
+ return new LinkedHashMapEntry(entry);
}
}
private static final class TreeMapEntryFactory implements EntryFactory {
- public Entry newEntry(final String... ldifLines) {
- return new TreeMapEntry(ldifLines);
+ @Override
+ public Entry newEntry(final String... ldifLines) throws Exception {
+ final LDIFEntryReader reader = new LDIFEntryReader(ldifLines).setSchema(SCHEMA);
+ final Entry entry = reader.readEntry();
+ assertThat(reader.hasNext()).isFalse();
+ return new TreeMapEntry(entry);
}
}
+ private static final AttributeDescription AD_CN;
+ private static final AttributeDescription AD_CUSTOM1;
+ private static final AttributeDescription AD_CUSTOM2;
+ private static final AttributeDescription AD_NAME;
+
+ private static final AttributeDescription AD_SN;
+
+ private static final Schema SCHEMA;
+
+ static {
+ final SchemaBuilder builder = new SchemaBuilder(Schema.getCoreSchema());
+ builder.addAttributeType("( 9.9.9.1 NAME 'custom1' SUP name )", false);
+ builder.addAttributeType("( 9.9.9.2 NAME 'custom2' SUP name )", false);
+ SCHEMA = builder.toSchema();
+ AD_CUSTOM1 = AttributeDescription.valueOf("custom1", SCHEMA);
+ AD_CUSTOM2 = AttributeDescription.valueOf("custom2", SCHEMA);
+ AD_CN = AttributeDescription.valueOf("cn");
+ AD_SN = AttributeDescription.valueOf("sn");
+ AD_NAME = AttributeDescription.valueOf("name");
+ }
+
@DataProvider(name = "EntryFactory")
- public Object[][] entryFactory() {
+ Object[][] entryFactory() {
// Value, type, options, containsOptions("foo")
return new Object[][] { { new TreeMapEntryFactory() }, { new LinkedHashMapEntryFactory() } };
}
@Test(dataProvider = "EntryFactory")
- public void smokeTest(final EntryFactory factory) throws Exception {
- final Entry entry1 =
- factory.newEntry("dn: cn=Joe Bloggs,dc=example,dc=com", "objectClass: top",
- "objectClass: person", "cn: Joe Bloggs", "sn: Bloggs", "givenName: Joe",
- "description: A description");
+ public void testAddAttributeAttribute(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute(new LinkedAttribute("sn", "sn"))).isTrue();
+ assertThat(entry.getAttribute(AD_SN)).hasSize(1);
+ }
- final Entry entry2 =
- factory.newEntry("dn: cn=Joe Bloggs,dc=example,dc=com", "changetype: add",
- "objectClass: top", "objectClass: person", "cn: Joe Bloggs", "sn: Bloggs",
- "givenName: Joe", "description: A description");
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeAttributeCollection(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> duplicateValues = new LinkedList<ByteString>();
+ assertThat(entry.addAttribute(new LinkedAttribute("sn", "sn"), duplicateValues)).isTrue();
+ assertThat(entry.getAttribute(AD_SN)).hasSize(1);
+ assertThat(duplicateValues).hasSize(0);
+ }
- Assert.assertEquals(entry1, entry2);
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeAttributeCollectionValueMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> duplicateValues = new LinkedList<ByteString>();
+ assertThat(entry.addAttribute(new LinkedAttribute("cn", "newcn"), duplicateValues))
+ .isTrue();
+ assertThat(entry.getAttribute(AD_CN)).hasSize(2);
+ assertThat(duplicateValues).hasSize(0);
+ }
- for (final Entry e : new Entry[] { entry1, entry2 }) {
- Assert.assertEquals(e.getName(), DN.valueOf("cn=Joe Bloggs,dc=example,dc=com"));
- Assert.assertEquals(e.getAttributeCount(), 5);
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeAttributeCollectionValuePresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> duplicateValues = new LinkedList<ByteString>();
+ assertThat(entry.addAttribute(new LinkedAttribute("cn", "test"), duplicateValues))
+ .isFalse();
+ assertThat(entry.getAttribute(AD_CN)).hasSize(1);
+ assertThat(duplicateValues).hasSize(1);
+ assertThat(duplicateValues).contains(ByteString.valueOf("test"));
+ }
- Assert.assertEquals(e.getAttribute("objectClass").size(), 2);
- Assert.assertTrue(e.containsAttribute("objectClass", "top", "person"));
- Assert.assertFalse(e.containsAttribute("objectClass", "top", "person", "foo"));
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeAttributeValueMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute(new LinkedAttribute("cn", "newcn"))).isTrue();
+ assertThat(entry.getAttribute(AD_CN)).hasSize(2);
+ }
- Assert.assertTrue(e.containsAttribute("objectClass"));
- Assert.assertTrue(e.containsAttribute("cn"));
- Assert.assertTrue(e.containsAttribute("cn", "Joe Bloggs"));
- Assert.assertFalse(e.containsAttribute("cn", "Jane Bloggs"));
- Assert.assertTrue(e.containsAttribute("sn"));
- Assert.assertTrue(e.containsAttribute("givenName"));
- Assert.assertTrue(e.containsAttribute("description"));
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeAttributeValuePresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute(new LinkedAttribute("cn", "test"))).isFalse();
+ assertThat(entry.getAttribute(AD_CN)).hasSize(1);
+ }
- Assert.assertEquals(e.getAttribute("cn").firstValueAsString(), "Joe Bloggs");
- Assert.assertEquals(e.getAttribute("sn").firstValueAsString(), "Bloggs");
- }
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeString(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("sn", "sn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_SN)).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeStringCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("custom2", "custom2")).isSameAs(entry);
+ // This is expected to be null since the type was decoded using the
+ // default schema and a temporary oid was allocated.
+ assertThat(entry.getAttribute(AD_CUSTOM2)).isNull();
+ assertThat(entry.getAttribute("custom2")).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeStringCustomValueMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("custom1", "xxxx")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CUSTOM1)).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeStringCustomValuePresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("custom1", "custom1")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CUSTOM1)).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeStringValueMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("cn", "newcn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testAddAttributeStringValuePresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.addAttribute("cn", "test")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testClearAttributes(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.clearAttributes()).isSameAs(entry);
+ assertThat(entry.getAttributeCount()).isEqualTo(0);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeCustomMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute(AD_CUSTOM2), missingValues)).isFalse();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeCustomPresent1(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute(AD_CUSTOM1), missingValues)).isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeCustomPresent2(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute("custom1"), missingValues)).isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeCustomValueMissing1(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(
+ entry.containsAttribute(singletonAttribute(AD_CUSTOM2, "missing"), missingValues))
+ .isFalse();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute(AD_SN), missingValues)).isFalse();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributePresent1(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute(AD_CN), missingValues)).isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributePresent2(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(emptyAttribute("cn"), missingValues)).isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeValueCustomMissing2(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(
+ entry.containsAttribute(singletonAttribute(AD_CUSTOM1, "missing"), missingValues))
+ .isFalse();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeValueCustomPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(
+ entry.containsAttribute(singletonAttribute(AD_CUSTOM1, "custom1"), missingValues))
+ .isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeValueMissing1(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(singletonAttribute(AD_SN, "missing"), missingValues))
+ .isFalse();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeValueMissing2(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(singletonAttribute(AD_CN, "missing"), missingValues))
+ .isFalse();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeAttributeValuePresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.containsAttribute(singletonAttribute(AD_CN, "test"), missingValues))
+ .isTrue();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringCustomMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("custom2")).isFalse();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringCustomPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("custom1")).isTrue();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("sn")).isFalse();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringPresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("cn")).isTrue();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringValueCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("custom1", "custom1")).isTrue();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringValueMissing1(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("cn", "missing")).isFalse();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringValueMissing2(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("sn", "missing")).isFalse();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testContainsAttributeStringValuePresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.containsAttribute("cn", "test")).isTrue();
+ }
+
+ @Test
+ public void testEqualsHashCodeDifferentContentDifferentTypes1() throws Exception {
+ final Entry e1 = createTestEntry(new TreeMapEntryFactory());
+ // Extra attributes.
+ final Entry e2 = createTestEntry(new LinkedHashMapEntryFactory()).addAttribute("sn", "sn");
+ assertThat(e1).isNotEqualTo(e2);
+ assertThat(e2).isNotEqualTo(e1);
+ assertThat(e1.hashCode()).isNotEqualTo(e2.hashCode());
+ }
+
+ @Test
+ public void testEqualsHashCodeDifferentContentDifferentTypes2() throws Exception {
+ final Entry e1 = createTestEntry(new TreeMapEntryFactory());
+ // Same attributes, extra values.
+ final Entry e2 =
+ createTestEntry(new LinkedHashMapEntryFactory()).addAttribute("cn", "newcn");
+ assertThat(e1).isNotEqualTo(e2);
+ assertThat(e2).isNotEqualTo(e1);
+ assertThat(e1.hashCode()).isNotEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testEqualsHashCodeDifferentContentSameTypes1(final EntryFactory factory)
+ throws Exception {
+ final Entry e1 = createTestEntry(factory);
+ // Extra attributes.
+ final Entry e2 = createTestEntry(factory).addAttribute("sn", "sn");
+ assertThat(e1).isNotEqualTo(e2);
+ assertThat(e2).isNotEqualTo(e1);
+ assertThat(e1.hashCode()).isNotEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testEqualsHashCodeDifferentContentSameTypes2(final EntryFactory factory)
+ throws Exception {
+ final Entry e1 = createTestEntry(factory);
+ // Same attributes, extra values.
+ final Entry e2 = createTestEntry(factory).addAttribute("cn", "newcn");
+ assertThat(e1).isNotEqualTo(e2);
+ assertThat(e2).isNotEqualTo(e1);
+ assertThat(e1.hashCode()).isNotEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testEqualsHashCodeDifferentDN(final EntryFactory factory) throws Exception {
+ final Entry e1 = createTestEntry(factory);
+ final Entry e2 = createTestEntry(factory).setName("cn=foobar");
+ assertThat(e1).isNotEqualTo(e2);
+ assertThat(e1.hashCode()).isNotEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testEqualsHashCodeMutates(final EntryFactory factory) throws Exception {
+ final Entry e = createTestEntry(factory);
+ final int hc1 = e.hashCode();
+ e.addAttribute("sn", "sn");
+ final int hc2 = e.hashCode();
+ assertThat(hc1).isNotEqualTo(hc2);
+ }
+
+ @Test
+ public void testEqualsHashCodeSameContentDifferentTypes() throws Exception {
+ final Entry e1 = createTestEntry(new TreeMapEntryFactory());
+ final Entry e2 = createTestEntry(new LinkedHashMapEntryFactory());
+ assertThat(e1).isEqualTo(e2);
+ assertThat(e2).isEqualTo(e1);
+ assertThat(e1.hashCode()).isEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testEqualsHashCodeSameContentSameTypes(final EntryFactory factory) throws Exception {
+ final Entry e1 = createTestEntry(factory);
+ final Entry e2 = createTestEntry(factory);
+ assertThat(e1).isEqualTo(e1);
+ assertThat(e1).isEqualTo(e2);
+ assertThat(e1.hashCode()).isEqualTo(e2.hashCode());
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributes(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes().iterator()).hasSize(3);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesAttributeDescriptionMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes(AD_SN)).hasSize(0);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesAttributeDescriptionPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes(AD_CN)).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesAttributeDescriptionPresentOptions(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ entry.addAttribute(singletonAttribute(AD_CN.withOption("lang-fr"), "xxxx"));
+ assertThat(entry.getAllAttributes(AD_CN)).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesAttributeDescriptionSupertype(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes(AD_NAME)).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesStringCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ entry.addAttribute(singletonAttribute(AD_CUSTOM1.withOption("lang-fr"), "xxxx"));
+ assertThat(entry.getAllAttributes("custom1")).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesStringCustomOptions(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ entry.addAttribute("custom2", "value1");
+ entry.addAttribute("custom2;lang-fr", "value2");
+ assertThat(entry.getAllAttributes("custom2")).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesStringMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes("sn")).hasSize(0);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesStringPresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes("cn")).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAllAttributesStringSupertype(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAllAttributes("name")).hasSize(2);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeAttributeDescriptionMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttribute(AD_SN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeAttributeDescriptionPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttribute(AD_CN)).isNotNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeCount(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeStringCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttribute("custom1")).isNotNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeStringMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttribute("sn")).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetAttributeStringPresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.getAttribute("cn")).isNotNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testGetName(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat((Object) entry.getName()).isEqualTo(DN.valueOf("cn=test"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeAttributeDescriptionCustom(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute(AD_CUSTOM1).asString()).isEqualTo("custom1");
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeAttributeDescriptionMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute(AD_SN).asString()).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeAttributeDescriptionPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute(AD_CN).asString()).isEqualTo("test");
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeStringCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute("custom1").asString()).isEqualTo("custom1");
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeStringMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute("sn").asString()).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testParseAttributeStringPresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.parseAttribute("cn").asString()).isEqualTo("test");
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeDescriptionMissing(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute(AD_SN)).isFalse();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeDescriptionPresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute(AD_CN)).isTrue();
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.removeAttribute(emptyAttribute(AD_SN), missingValues)).isFalse();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributePresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.removeAttribute(emptyAttribute(AD_CN), missingValues)).isTrue();
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeValueMissing1(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.removeAttribute(singletonAttribute(AD_CN, "missing"), missingValues))
+ .isFalse();
+ assertThat(entry.getAttribute(AD_CN)).isNotNull();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeValueMissing2(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.removeAttribute(singletonAttribute(AD_SN, "missing"), missingValues))
+ .isFalse();
+ assertThat(missingValues).hasSize(1);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeAttributeValuePresent(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ final List<ByteString> missingValues = new LinkedList<ByteString>();
+ assertThat(entry.removeAttribute(singletonAttribute(AD_CN, "test"), missingValues))
+ .isTrue();
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ assertThat(missingValues).isEmpty();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringCustom(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("custom1")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CUSTOM1)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringMissing(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("sn")).isSameAs(entry);
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringPresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("cn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringValueMissing1(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("cn", "missing")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).isNotNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringValueMissing2(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("sn", "missing")).isSameAs(entry);
+ assertThat(entry.getAttributeCount()).isEqualTo(3);
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testRemoveAttributeStringValuePresent(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.removeAttribute("cn", "test")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeAttributeMissingEmpty(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute(emptyAttribute(AD_SN))).isFalse();
+ assertThat(entry.getAttribute(AD_SN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeAttributeMissingValue(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute(singletonAttribute(AD_SN, "sn"))).isTrue();
+ assertThat(entry.getAttribute(AD_SN)).isEqualTo(singletonAttribute(AD_SN, "sn"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeAttributePresentEmpty(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute(emptyAttribute(AD_CN))).isTrue();
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeAttributePresentValue(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute(singletonAttribute(AD_CN, "newcn"))).isTrue();
+ assertThat(entry.getAttribute(AD_CN)).isEqualTo(singletonAttribute(AD_CN, "newcn"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringCustomEmpty(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("custom1")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CUSTOM1)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringCustomMissingValue(final EntryFactory factory)
+ throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("custom2", "xxxx")).isSameAs(entry);
+ // This is expected to be null since the type was decoded using the
+ // default schema and a temporary oid was allocated.
+ assertThat(entry.getAttribute(AD_CUSTOM2)).isNull();
+ assertThat(entry.getAttribute("custom2")).isEqualTo(singletonAttribute("custom2", "xxxx"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringCustomValue(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("custom1", "xxxx")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CUSTOM1))
+ .isEqualTo(singletonAttribute(AD_CUSTOM1, "xxxx"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringMissingEmpty(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("sn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_SN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringMissingValue(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("sn", "sn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_SN)).isEqualTo(singletonAttribute(AD_SN, "sn"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringPresentEmpty(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("cn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).isNull();
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testReplaceAttributeStringPresentValue(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.replaceAttribute("cn", "newcn")).isSameAs(entry);
+ assertThat(entry.getAttribute(AD_CN)).isEqualTo(singletonAttribute(AD_CN, "newcn"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testSetNameDN(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.setName(DN.valueOf("cn=foobar"))).isSameAs(entry);
+ assertThat((Object) entry.getName()).isEqualTo(DN.valueOf("cn=foobar"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testSetNameString(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ assertThat(entry.setName("cn=foobar")).isSameAs(entry);
+ assertThat((Object) entry.getName()).isEqualTo(DN.valueOf("cn=foobar"));
+ }
+
+ @Test(dataProvider = "EntryFactory")
+ public void testToString(final EntryFactory factory) throws Exception {
+ final Entry entry = createTestEntry(factory);
+ // The String representation is unspecified but we should at least
+ // expect the DN to be present.
+ assertThat(entry.toString()).contains("cn=test");
+ }
+
+ private Entry createTestEntry(final EntryFactory factory) throws Exception {
+ return factory.newEntry("dn: cn=test", "objectClass: top", "objectClass: extensibleObject",
+ "cn: test", "custom1: custom1");
}
}
--
Gitblit v1.10.0