From 0dc1115939d4eda4ad6559d64e2628b86ad29119 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Thu, 28 Mar 2013 11:50:36 +0000
Subject: [PATCH] Fix OPENDJ-354: Implement a RequestHandler which provides an in-memory backend
---
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 200 insertions(+), 9 deletions(-)
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
index de5fcb4..7511b6b 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/Entries.java
@@ -22,13 +22,21 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2012 ForgeRock AS
+ * Portions copyright 2011-2013 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
import static org.forgerock.opendj.ldap.AttributeDescription.objectClass;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_DUPLICATE_VALUES;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_INCREMENT_INVALID_VALUE_COUNT;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_NO_SUCH_VALUE;
+import static org.forgerock.opendj.ldap.CoreMessages.ERR_ENTRY_UNKNOWN_MODIFICATION_TYPE;
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -37,6 +45,7 @@
import java.util.Set;
import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.ldap.controls.PermissiveModifyRequestControl;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.schema.ObjectClass;
@@ -179,14 +188,16 @@
/**
* {@inheritDoc}
*/
- public AttributeParser parseAttribute(AttributeDescription attributeDescription) {
+ @Override
+ public AttributeParser parseAttribute(final AttributeDescription attributeDescription) {
return entry.parseAttribute(attributeDescription);
}
/**
* {@inheritDoc}
*/
- public AttributeParser parseAttribute(String attributeDescription) {
+ @Override
+ public AttributeParser parseAttribute(final String attributeDescription) {
return entry.parseAttribute(attributeDescription);
}
@@ -251,6 +262,13 @@
}
+ private static final Comparator<Entry> COMPARATOR = new Comparator<Entry>() {
+ @Override
+ public int compare(final Entry o1, final Entry o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
private static final Function<Attribute, Attribute, Void> UNMODIFIABLE_ATTRIBUTE_FUNCTION =
new Function<Attribute, Attribute, Void>() {
@@ -261,12 +279,6 @@
};
- private static final Comparator<Entry> COMPARATOR = new Comparator<Entry>() {
- public int compare(Entry o1, Entry o2) {
- return o1.getName().compareTo(o2.getName());
- }
- };
-
/**
* Returns a {@code Comparator} which can be used to compare entries by name
* using the natural order for DN comparisons (parent before children).
@@ -576,6 +588,126 @@
}
/**
+ * Applies the provided modification to an entry. This method implements
+ * "permissive" modify semantics, ignoring attempts to add duplicate values
+ * or attempts to remove values which do not exist.
+ *
+ * @param entry
+ * The entry to be modified.
+ * @param change
+ * The modification to be applied to the entry.
+ * @return A reference to the updated entry.
+ * @throws ErrorResultException
+ * If an error occurred while performing the change such as an
+ * attempt to increment a value which is not a number. The entry
+ * will not have been modified.
+ */
+ public static Entry modifyEntry(final Entry entry, final Modification change)
+ throws ErrorResultException {
+ return modifyEntry(entry, change, null);
+ }
+
+ /**
+ * Applies the provided modification to an entry. This method implements
+ * "permissive" modify semantics, recording attempts to add duplicate values
+ * or attempts to remove values which do not exist in the provided
+ * collection if provided.
+ *
+ * @param entry
+ * The entry to be modified.
+ * @param change
+ * The modification to be applied to the entry.
+ * @param conflictingValues
+ * A collection into which duplicate or missing values will be
+ * added, or {@code null} if conflicting values should not be
+ * saved.
+ * @return A reference to the updated entry.
+ * @throws ErrorResultException
+ * If an error occurred while performing the change such as an
+ * attempt to increment a value which is not a number. The entry
+ * will not have been modified.
+ */
+ public static Entry modifyEntry(final Entry entry, final Modification change,
+ final Collection<? super ByteString> conflictingValues) throws ErrorResultException {
+ final ModificationType modType = change.getModificationType();
+ if (modType.equals(ModificationType.ADD)) {
+ entry.addAttribute(change.getAttribute(), conflictingValues);
+ } else if (modType.equals(ModificationType.DELETE)) {
+ entry.removeAttribute(change.getAttribute(), conflictingValues);
+ } else if (modType.equals(ModificationType.REPLACE)) {
+ entry.replaceAttribute(change.getAttribute());
+ } else if (modType.equals(ModificationType.INCREMENT)) {
+ incrementAttribute(entry, change.getAttribute());
+ } else {
+ throw newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
+ ERR_ENTRY_UNKNOWN_MODIFICATION_TYPE.get(String.valueOf(modType)).toString());
+ }
+ return entry;
+ }
+
+ /**
+ * Applies the provided modification request to an entry. This method will
+ * utilize "permissive" modify semantics if the request contains the
+ * {@link PermissiveModifyRequestControl}.
+ *
+ * @param entry
+ * The entry to be modified.
+ * @param changes
+ * The modification request to be applied to the entry.
+ * @return A reference to the updated entry.
+ * @throws ErrorResultException
+ * If an error occurred while performing the changes such as an
+ * attempt to add duplicate values, remove values which do not
+ * exist, or increment a value which is not a number. The entry
+ * may have been modified.
+ */
+ public static Entry modifyEntry(final Entry entry, final ModifyRequest changes)
+ throws ErrorResultException {
+ final boolean isPermissive = changes.containsControl(PermissiveModifyRequestControl.OID);
+ return modifyEntry0(entry, changes.getModifications(), isPermissive);
+ }
+
+ /**
+ * Applies the provided modifications to an entry using "permissive" modify
+ * semantics.
+ *
+ * @param entry
+ * The entry to be modified.
+ * @param changes
+ * The modification request to be applied to the entry.
+ * @return A reference to the updated entry.
+ * @throws ErrorResultException
+ * If an error occurred while performing the changes such as an
+ * attempt to increment a value which is not a number. The entry
+ * may have been modified.
+ */
+ public static Entry modifyEntryPermissive(final Entry entry,
+ final Collection<Modification> changes) throws ErrorResultException {
+ return modifyEntry0(entry, changes, true);
+ }
+
+ /**
+ * Applies the provided modifications to an entry using "strict" modify
+ * semantics. Attempts to add duplicate values or attempts to remove values
+ * which do not exist will cause the update to fail.
+ *
+ * @param entry
+ * The entry to be modified.
+ * @param changes
+ * The modification request to be applied to the entry.
+ * @return A reference to the updated entry.
+ * @throws ErrorResultException
+ * If an error occurred while performing the changes such as an
+ * attempt to add duplicate values, remove values which do not
+ * exist, or increment a value which is not a number. The entry
+ * may have been modified.
+ */
+ public static Entry modifyEntryStrict(final Entry entry, final Collection<Modification> changes)
+ throws ErrorResultException {
+ return modifyEntry0(entry, changes, false);
+ }
+
+ /**
* Returns a read-only view of {@code entry} and its attributes. Query
* operations on the returned entry and its attributes "read-through" to the
* underlying entry or attribute, and attempts to modify the returned entry
@@ -596,6 +728,65 @@
}
}
+ private static void incrementAttribute(final Entry entry, final Attribute change)
+ throws ErrorResultException {
+ // First parse the change.
+ final AttributeDescription deltaAd = change.getAttributeDescription();
+ if (change.size() != 1) {
+ throw newErrorResult(ResultCode.CONSTRAINT_VIOLATION,
+ ERR_ENTRY_INCREMENT_INVALID_VALUE_COUNT.get(deltaAd.toString()).toString());
+ }
+ final long delta;
+ try {
+ delta = change.parse().asLong();
+ } catch (final Exception e) {
+ throw newErrorResult(ResultCode.CONSTRAINT_VIOLATION,
+ ERR_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT.get(deltaAd.toString()).toString());
+ }
+
+ // Now apply the increment to the attribute.
+ final Attribute oldAttribute = entry.getAttribute(deltaAd);
+ if (oldAttribute == null) {
+ throw newErrorResult(ResultCode.NO_SUCH_ATTRIBUTE,
+ ERR_ENTRY_INCREMENT_NO_SUCH_ATTRIBUTE.get(deltaAd.toString()).toString());
+ }
+
+ // Re-use existing attribute description in case it differs in case, etc.
+ final Attribute newAttribute = new LinkedAttribute(oldAttribute.getAttributeDescription());
+ try {
+ for (final Long value : oldAttribute.parse().asSetOfLong()) {
+ newAttribute.add(value + delta);
+ }
+ } catch (final Exception e) {
+ throw newErrorResult(ResultCode.CONSTRAINT_VIOLATION,
+ ERR_ENTRY_INCREMENT_CANNOT_PARSE_AS_INT.get(deltaAd.toString()).toString());
+ }
+ entry.replaceAttribute(newAttribute);
+ }
+
+ private static Entry modifyEntry0(final Entry entry, final Collection<Modification> changes,
+ final boolean isPermissive) throws ErrorResultException {
+ final Collection<ByteString> conflictingValues =
+ isPermissive ? null : new ArrayList<ByteString>(0);
+ for (final Modification change : changes) {
+ modifyEntry(entry, change, conflictingValues);
+ if (!isPermissive && !conflictingValues.isEmpty()) {
+ if (change.getModificationType().equals(ModificationType.ADD)) {
+ // Duplicate values.
+ throw newErrorResult(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS,
+ ERR_ENTRY_DUPLICATE_VALUES.get(
+ change.getAttribute().getAttributeDescriptionAsString())
+ .toString());
+ } else {
+ // Missing values.
+ throw newErrorResult(ResultCode.NO_SUCH_ATTRIBUTE, ERR_ENTRY_NO_SUCH_VALUE.get(
+ change.getAttribute().getAttributeDescriptionAsString()).toString());
+ }
+ }
+ }
+ return entry;
+ }
+
// Prevent instantiation.
private Entries() {
// Nothing to do.
--
Gitblit v1.10.0