From fbea82c15cf5f1d069e5aa00dcdfdd5172a2cc7b Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Fri, 15 Feb 2013 13:58:25 +0000
Subject: [PATCH] Final fix for OPENDJ-758 : Implement configurable update policy for simple and default mappers
---
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/WritabilityPolicy.java | 50 ++++++++++++++--
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java | 59 ++++++++-----------
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java | 24 ++++++++
opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java | 18 +++---
4 files changed, 102 insertions(+), 49 deletions(-)
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
index 9546963..9360506 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
@@ -20,11 +20,12 @@
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.forgerock.opendj.ldap.Functions.fixedFunction;
+import static org.forgerock.opendj.rest2ldap.Utils.base64ToByteString;
+import static org.forgerock.opendj.rest2ldap.Utils.byteStringToBase64;
import static org.forgerock.opendj.rest2ldap.Utils.byteStringToJson;
import static org.forgerock.opendj.rest2ldap.Utils.jsonToAttribute;
import static org.forgerock.opendj.rest2ldap.Utils.jsonToByteString;
import static org.forgerock.opendj.rest2ldap.Utils.toFilter;
-import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_ONLY;
import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_WRITE;
import java.util.Collection;
@@ -55,7 +56,6 @@
private Collection<Object> defaultJSONValues = Collections.emptySet();
private ByteString defaultLDAPValue = null;
private Function<Object, ByteString, Void> encoder = null;
- private boolean isIgnoreUpdates = true;
private boolean isRequired = false;
private boolean isSingleValued = false;
private final AttributeDescription ldapAttributeName;
@@ -119,45 +119,41 @@
}
/**
- * Indicates whether or not an attempt to update the LDAP attribute should
- * be ignored when the update is incompatible with the writability policy.
- * The default is {@code true}.
+ * Indicates that JSON values are base 64 encodings of binary data. Calling
+ * this method is equivalent to the following:
*
- * @param ignore
- * {@code true} an attempt to update the LDAP attribute should be
- * ignored.
+ * <pre>
+ * mapper.decoder(...); // function that converts binary data to base 64
+ * mapper.encoder(...); // function that converts base 64 to binary data
+ * </pre>
+ *
* @return This attribute mapper.
*/
- public SimpleAttributeMapper ignoreUpdates(final boolean ignore) {
- this.isIgnoreUpdates = ignore;
+ public SimpleAttributeMapper isBinary() {
+ decoder = byteStringToBase64();
+ encoder = base64ToByteString();
return this;
}
/**
* Indicates that the LDAP attribute is mandatory and must be provided
- * during create requests. The default is {@code false}.
+ * during create requests.
*
- * @param isRequired
- * {@code true} if the LDAP attribute is mandatory and must be
- * provided during create requests.
* @return This attribute mapper.
*/
- public SimpleAttributeMapper required(final boolean isRequired) {
- this.isRequired = isRequired;
+ public SimpleAttributeMapper isRequired() {
+ this.isRequired = true;
return this;
}
/**
- * Forces a multi-valued LDAP attribute to be represented as a single-valued
- * JSON value, rather than an array of values. The default is {@code false}.
+ * Indicates that multi-valued LDAP attribute should be represented as a
+ * single-valued JSON value, rather than an array of values.
*
- * @param isSingleValued
- * {@code true} if the LDAP attribute should be treated as a
- * single-valued attribute.
* @return This attribute mapper.
*/
- public SimpleAttributeMapper singleValued(final boolean isSingleValued) {
- this.isSingleValued = isSingleValued;
+ public SimpleAttributeMapper isSingleValued() {
+ this.isSingleValued = true;
return this;
}
@@ -209,7 +205,7 @@
try {
final List<Attribute> result;
if (v == null || v.isNull()) {
- if (isRequired()) {
+ if (attributeIsRequired()) {
// FIXME: improve error message.
throw new BadRequestException("no value provided");
} else if (defaultLDAPValue != null) {
@@ -219,11 +215,11 @@
} else {
result = emptyList();
}
- } else if (v.isList() && isSingleValued()) {
+ } else if (v.isList() && attributeIsSingleValued()) {
// FIXME: improve error message.
throw new BadRequestException("expected single value, but got multiple values");
- } else if (isCreate()) {
- if (isIgnoreUpdates) {
+ } else if (!writabilityPolicy.canCreate(ldapAttributeName)) {
+ if (writabilityPolicy.discardWrites()) {
result = emptyList();
} else {
// FIXME: improve error message.
@@ -253,16 +249,11 @@
}
}
- private boolean isCreate() {
- return writabilityPolicy != READ_ONLY
- && ldapAttributeName.getAttributeType().isNoUserModification();
- }
-
- private boolean isRequired() {
+ private boolean attributeIsRequired() {
return isRequired && defaultJSONValue == null;
}
- private boolean isSingleValued() {
+ private boolean attributeIsSingleValued() {
return isSingleValued || ldapAttributeName.getAttributeType().isSingleValue();
}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
index 559c92f..19d9a38 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java
@@ -91,6 +91,22 @@
}
+ private static final Function<ByteString, String, Void> BYTESTRING_TO_BASE64 =
+ new Function<ByteString, String, Void>() {
+ @Override
+ public String apply(ByteString value, Void p) {
+ return value.toBase64String();
+ }
+ };
+
+ private static final Function<Object, ByteString, Void> BASE64_TO_BYTESTRING =
+ new Function<Object, ByteString, Void>() {
+ @Override
+ public ByteString apply(Object value, Void p) {
+ return ByteString.valueOfBase64(String.valueOf(value));
+ }
+ };
+
private static final Function<ByteString, Object, AttributeDescription> BYTESTRING_TO_JSON =
new Function<ByteString, Object, AttributeDescription>() {
@Override
@@ -144,6 +160,14 @@
return BYTESTRING_TO_JSON;
}
+ static Function<ByteString, String, Void> byteStringToBase64() {
+ return BYTESTRING_TO_BASE64;
+ }
+
+ static Function<Object, ByteString, Void> base64ToByteString() {
+ return BASE64_TO_BYTESTRING;
+ }
+
static <T> T ensureNotNull(final T object) {
if (object == null) {
throw new NullPointerException();
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/WritabilityPolicy.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/WritabilityPolicy.java
index 2b062bd..d300b62 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/WritabilityPolicy.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/WritabilityPolicy.java
@@ -16,26 +16,64 @@
package org.forgerock.opendj.rest2ldap;
+import org.forgerock.opendj.ldap.AttributeDescription;
+
/**
* The writability policy determines whether or not an attribute supports
* updates.
*/
public enum WritabilityPolicy {
+ // @formatter:off
/**
- * The attribute may be provided when creating a new resource, but cannot be
- * modified afterwards.
+ * The attribute cannot be provided when creating a new resource, nor
+ * modified afterwards. Attempts to update the attribute will result in an
+ * error.
*/
- CREATE_ONLY,
+ READ_ONLY(false),
/**
* The attribute cannot be provided when creating a new resource, nor
- * modified afterwards.
+ * modified afterwards. Attempts to update the attribute will not result in
+ * an error (the new values will be ignored).
*/
- READ_ONLY,
+ READ_ONLY_DISCARD_WRITES(true),
+
+ /**
+ * The attribute may be provided when creating a new resource, but cannot be
+ * modified afterwards. Attempts to update the attribute will result in an
+ * error.
+ */
+ CREATE_ONLY(false),
+
+ /**
+ * The attribute may be provided when creating a new resource, but cannot be
+ * modified afterwards. Attempts to update the attribute will not result in
+ * an error (the new values will be ignored).
+ */
+ CREATE_ONLY_DISCARD_WRITES(true),
/**
* The attribute may be provided when creating a new resource, and modified
* afterwards.
*/
- READ_WRITE;
+ READ_WRITE(false);
+ // @formatter:on
+
+ private final boolean discardWrites;
+
+ private WritabilityPolicy(final boolean discardWrites) {
+ this.discardWrites = discardWrites;
+ }
+
+ boolean canCreate(final AttributeDescription attribute) {
+ return this != READ_ONLY && !attribute.getAttributeType().isNoUserModification();
+ }
+
+ boolean canWrite(final AttributeDescription attribute) {
+ return this == READ_WRITE && !attribute.getAttributeType().isNoUserModification();
+ }
+
+ boolean discardWrites() {
+ return discardWrites;
+ }
}
diff --git a/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java b/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
index 070a2f5..96ac80c 100644
--- a/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
+++ b/opendj3/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -68,16 +68,16 @@
CollectionResourceProvider users =
builder().factory(ldapFactory).baseDN("ou=people,dc=example,dc=com")
.attribute("schemas", constant(Arrays.asList("urn:scim:schemas:core:1.0")))
- .attribute("id", simple("uid").singleValued(true).required(true).writability(CREATE_ONLY))
- .attribute("rev", simple("etag").singleValued(true).writability(READ_ONLY))
- .attribute("userName", simple("mail").singleValued(true).writability(READ_ONLY))
- .attribute("displayName", simple("cn").singleValued(true).required(true))
+ .attribute("id", simple("uid").isSingleValued().isRequired().writability(CREATE_ONLY))
+ .attribute("rev", simple("etag").isSingleValued().writability(READ_ONLY))
+ .attribute("userName", simple("mail").isSingleValued().writability(READ_ONLY))
+ .attribute("displayName", simple("cn").isSingleValued().isRequired())
.attribute("name", object()
- .attribute("givenName", simple("givenName").singleValued(true))
- .attribute("familyName", simple("sn").singleValued(true).required(true)))
+ .attribute("givenName", simple("givenName").isSingleValued())
+ .attribute("familyName", simple("sn").isSingleValued().isRequired()))
.attribute("contactInformation", object()
- .attribute("telephoneNumber", simple("telephoneNumber").singleValued(true))
- .attribute("emailAddress", simple("mail").singleValued(true)))
+ .attribute("telephoneNumber", simple("telephoneNumber").isSingleValued())
+ .attribute("emailAddress", simple("mail").isSingleValued()))
.additionalLDAPAttribute("objectClass", "top", "person", "organizationalPerson", "inetOrgPerson")
.build();
router.addRoute("/users", users);
@@ -85,7 +85,7 @@
// Create group resource.
CollectionResourceProvider groups =
builder().factory(ldapFactory).baseDN("ou=groups,dc=example,dc=com")
- .attribute("cn", simple("cn").singleValued(true))
+ .attribute("cn", simple("cn").isSingleValued())
.attribute("description", simple("description"))
.attribute("member", simple("uniquemember"))
.build();
--
Gitblit v1.10.0