From a08c81f677247ec9eb7721a86250c663065e9930 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 22 Jun 2016 22:12:03 +0000
Subject: [PATCH] OPENDJ-2871 Add support for sub-resources and inheritance

---
 opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractLdapPropertyMapper.java |   79 +++++++++++++++++++--------------------
 1 files changed, 38 insertions(+), 41 deletions(-)

diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractLdapPropertyMapper.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractLdapPropertyMapper.java
index 66fb8d1..23f37fd 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractLdapPropertyMapper.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractLdapPropertyMapper.java
@@ -24,6 +24,8 @@
 import static org.forgerock.opendj.rest2ldap.Utils.newBadRequestException;
 import static org.forgerock.opendj.rest2ldap.Utils.newNotSupportedException;
 import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_WRITE;
+import static org.forgerock.util.promise.Promises.newExceptionPromise;
+import static org.forgerock.util.promise.Promises.newResultPromise;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -54,7 +56,7 @@
     List<Object> defaultJsonValues = emptyList();
     final AttributeDescription ldapAttributeName;
     private boolean isRequired;
-    private boolean isSingleValued;
+    private boolean isMultiValued;
     private WritabilityPolicy writabilityPolicy = READ_WRITE;
 
     AbstractLdapPropertyMapper(final AttributeDescription ldapAttributeName) {
@@ -62,30 +64,29 @@
     }
 
     /**
-     * Indicates that the LDAP attribute is mandatory and must be provided
-     * during create requests.
+     * Indicates that the LDAP attribute is mandatory and must be provided during create requests.
      *
+     * @param isRequired {@code true} if this property is required.
      * @return This property mapper.
      */
-    public final T isRequired() {
-        this.isRequired = true;
+    public final T isRequired(final boolean isRequired) {
+        this.isRequired = isRequired;
         return getThis();
     }
 
     /**
-     * Indicates that multi-valued LDAP attribute should be represented as a
-     * single-valued JSON value, rather than an array of values.
+     * Indicates that the LDAP attribute is multi-valued and should be represented in JSON using an array of values.
      *
+     * @param isMultiValued {@code true} if this property is multi-valued.
      * @return This property mapper.
      */
-    public final T isSingleValued() {
-        this.isSingleValued = true;
+    public final T isMultiValued(final boolean isMultiValued) {
+        this.isMultiValued = isMultiValued;
         return getThis();
     }
 
     /**
-     * Indicates whether the LDAP attribute supports updates.
-     * The default is {@link WritabilityPolicy#READ_WRITE}.
+     * Indicates whether the LDAP attribute supports updates. The default is {@link WritabilityPolicy#READ_WRITE}.
      *
      * @param policy
      *            The writability policy.
@@ -97,13 +98,14 @@
     }
 
     boolean attributeIsSingleValued() {
-        return isSingleValued || ldapAttributeName.getAttributeType().isSingleValue();
+        return !isMultiValued || ldapAttributeName.getAttributeType().isSingleValue();
     }
 
     @Override
-    Promise<List<Attribute>, ResourceException> create(
-            final Connection connection, final JsonPointer path, final JsonValue v) {
-        return getNewLdapAttributes(connection, path, v).then(
+    Promise<List<Attribute>, ResourceException> create(final Connection connection,
+                                                       final Resource resource, final JsonPointer path,
+                                                       final JsonValue v) {
+        return getNewLdapAttributes(connection, resource, path, v).then(
             new Function<Attribute, List<Attribute>, ResourceException>() {
                 @Override
                 public List<Attribute> apply(Attribute newLDAPAttribute) throws ResourceException {
@@ -114,38 +116,33 @@
                         return Collections.emptyList();
                     } else if (newLDAPAttribute.isEmpty()) {
                         if (isRequired) {
-                            throw newBadRequestException(ERR_REMOVE_REQUIRED_FIELD.get("create", path));
+                            throw newBadRequestException(ERR_MISSING_REQUIRED_FIELD.get(path));
                         }
                         return Collections.emptyList();
                     }
-
                     return singletonList(newLDAPAttribute);
                 }
             });
     }
 
     @Override
-    void getLdapAttributes(final Connection connection, final JsonPointer path,
-                           final JsonPointer subPath, final Set<String> ldapAttributes) {
+    void getLdapAttributes(final JsonPointer path, final JsonPointer subPath, final Set<String> ldapAttributes) {
         ldapAttributes.add(ldapAttributeName.toString());
     }
 
-    abstract Promise<Attribute, ResourceException> getNewLdapAttributes(Connection connection, JsonPointer path,
-                                                                        List<Object> newValues);
+    abstract Promise<Attribute, ResourceException> getNewLdapAttributes(Connection connection, Resource resource,
+                                                                        JsonPointer path, List<Object> newValues);
 
     abstract T getThis();
 
     @Override
-    Promise<List<Modification>, ResourceException> patch(
-                final Connection connection, final JsonPointer path, final PatchOperation operation) {
+    Promise<List<Modification>, ResourceException> patch(final Connection connection, final Resource resource,
+                                                         final JsonPointer path, final PatchOperation operation) {
         try {
             final JsonPointer field = operation.getField();
             final JsonValue v = operation.getValue();
 
-            /*
-             * Reject any attempts to patch this field if it is read-only, even
-             * if it is configured to discard writes.
-             */
+            // Reject any attempts to patch this field if it is read-only, even if it is configured to discard writes.
             if (!writabilityPolicy.canWrite(ldapAttributeName)) {
                 throw newBadRequestException(ERR_MODIFY_READ_ONLY_FIELD.get("patch", path));
             }
@@ -211,8 +208,7 @@
                  * LDAP attribute is multi-valued, or the attribute already
                  * contains a value.
                  */
-                modType =
-                        attributeIsSingleValued() ? ModificationType.REPLACE : ModificationType.ADD;
+                modType = attributeIsSingleValued() ? ModificationType.REPLACE : ModificationType.ADD;
                 if (newValues.isEmpty()) {
                     throw newBadRequestException(ERR_PATCH_ADD_NO_VALUE_FOR_FIELD.get(path.child(field.get(0))));
                 }
@@ -233,11 +229,11 @@
                     return Promises.<List<Modification>, ResourceException> newExceptionPromise(
                             newBadRequestException(ERR_REMOVE_REQUIRED_FIELD.get("update", path)));
                 } else {
-                    return Promises.newResultPromise(
+                    return newResultPromise(
                         singletonList(new Modification(modType, emptyAttribute(ldapAttributeName))));
                 }
             } else {
-                return getNewLdapAttributes(connection, path, newValues)
+                return getNewLdapAttributes(connection, resource, path, newValues)
                         .then(new Function<Attribute, List<Modification>, ResourceException>() {
                             @Override
                             public List<Modification> apply(final Attribute value) {
@@ -246,16 +242,16 @@
                         });
             }
         } catch (final RuntimeException e) {
-            return Promises.newExceptionPromise(asResourceException(e));
+            return asResourceException(e).asPromise();
         } catch (final ResourceException e) {
-            return Promises.newExceptionPromise(e);
+            return newExceptionPromise(e);
         }
     }
 
     @Override
-    Promise<List<Modification>, ResourceException> update(final Connection connection, final JsonPointer path,
-            final Entry e, final JsonValue v) {
-        return getNewLdapAttributes(connection, path, v).then(
+    Promise<List<Modification>, ResourceException> update(final Connection connection, final Resource resource,
+                                                          final JsonPointer path, final Entry e, final JsonValue v) {
+        return getNewLdapAttributes(connection, resource, path, v).then(
             new Function<Attribute, List<Modification>, ResourceException>() {
                 @Override
                 public List<Modification> apply(final Attribute newLDAPAttribute) throws ResourceException {
@@ -338,19 +334,20 @@
     }
 
     private Promise<Attribute, ResourceException> getNewLdapAttributes(final Connection connection,
-                                                                       final JsonPointer path, final JsonValue v) {
+                                                                       final Resource resource, final JsonPointer path,
+                                                                       final JsonValue v) {
         try {
             // Ensure that the value is of the correct type.
             checkSchema(path, v);
             final List<Object> newValues = asList(v, defaultJsonValues);
             if (newValues.isEmpty()) {
                 // Skip sub-class implementation if there are no values.
-                return Promises.newResultPromise(emptyAttribute(ldapAttributeName));
+                return newResultPromise(emptyAttribute(ldapAttributeName));
             } else {
-                return getNewLdapAttributes(connection, path, newValues);
+                return getNewLdapAttributes(connection, resource, path, newValues);
             }
-        } catch (final Exception ex) {
-            return Promises.newExceptionPromise(asResourceException(ex));
+        } catch (final Exception e) {
+            return asResourceException(e).asPromise();
         }
     }
 

--
Gitblit v1.10.0