From 507e00fb190713b1654579123d284bcd3d750abe Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 10 Apr 2013 10:31:19 +0000
Subject: [PATCH] Partial fix for OPENDJ-693: Implement modify/update support

---
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ObjectAttributeMapper.java |  105 +++++++++++++++++++++++++++++++++-------------------
 1 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ObjectAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ObjectAttributeMapper.java
index 0251974..d4ba83f 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ObjectAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ObjectAttributeMapper.java
@@ -17,6 +17,7 @@
 
 import static org.forgerock.opendj.ldap.Filter.alwaysFalse;
 import static org.forgerock.opendj.rest2ldap.Utils.accumulate;
+import static org.forgerock.opendj.rest2ldap.Utils.i18n;
 import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase;
 import static org.forgerock.opendj.rest2ldap.Utils.transform;
 
@@ -32,10 +33,10 @@
 import org.forgerock.json.fluent.JsonValue;
 import org.forgerock.json.resource.BadRequestException;
 import org.forgerock.json.resource.ResultHandler;
-import org.forgerock.opendj.ldap.Attribute;
 import org.forgerock.opendj.ldap.Entry;
 import org.forgerock.opendj.ldap.Filter;
 import org.forgerock.opendj.ldap.Function;
+import org.forgerock.opendj.ldap.Modification;
 
 /**
  * An attribute mapper which maps JSON objects to LDAP attributes.
@@ -50,6 +51,11 @@
             this.name = name;
             this.mapper = mapper;
         }
+
+        @Override
+        public String toString() {
+            return name + " -> " + mapper;
+        }
     }
 
     private final Map<String, Mapping> mappings = new LinkedHashMap<String, Mapping>();
@@ -74,43 +80,50 @@
     }
 
     @Override
-    void getLDAPAttributes(final Context c, final JsonPointer jsonAttribute,
+    void getLDAPAttributes(final Context c, final JsonPointer path, final JsonPointer subPath,
             final Set<String> ldapAttributes) {
-        if (jsonAttribute.isEmpty()) {
+        if (subPath.isEmpty()) {
             // Request all subordinate mappings.
             for (final Mapping mapping : mappings.values()) {
-                mapping.mapper.getLDAPAttributes(c, jsonAttribute, ldapAttributes);
+                mapping.mapper.getLDAPAttributes(c, path.child(mapping.name), subPath,
+                        ldapAttributes);
             }
         } else {
             // Request single subordinate mapping.
-            final Mapping mapping = getMapping(jsonAttribute);
+            final Mapping mapping = getMapping(subPath);
             if (mapping != null) {
-                final JsonPointer relativePointer = jsonAttribute.relativePointer();
-                mapping.mapper.getLDAPAttributes(c, relativePointer, ldapAttributes);
+                mapping.mapper.getLDAPAttributes(c, path.child(subPath.get(0)), subPath
+                        .relativePointer(), ldapAttributes);
             }
         }
     }
 
     @Override
-    void getLDAPFilter(final Context c, final FilterType type, final JsonPointer jsonAttribute,
-            final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
-        final Mapping mapping = getMapping(jsonAttribute);
+    void getLDAPFilter(final Context c, final JsonPointer path, final JsonPointer subPath,
+            final FilterType type, final String operator, final Object valueAssertion,
+            final ResultHandler<Filter> h) {
+        final Mapping mapping = getMapping(subPath);
         if (mapping != null) {
-            final JsonPointer relativePointer = jsonAttribute.relativePointer();
-            mapping.mapper.getLDAPFilter(c, type, relativePointer, operator, valueAssertion, h);
+            mapping.mapper.getLDAPFilter(c, path.child(subPath.get(0)), subPath.relativePointer(),
+                    type, operator, valueAssertion, h);
         } else {
-            // Either the filter targeted the entire object (i.e. it was "/"), or it targeted
-            // an unrecognized attribute within the object. Either way, the filter will
-            // never match.
+            /*
+             * Either the filter targeted the entire object (i.e. it was "/"),
+             * or it targeted an unrecognized attribute within the object.
+             * Either way, the filter will never match.
+             */
             h.handleResult(alwaysFalse());
         }
     }
 
     @Override
-    void toJSON(final Context c, final Entry e, final ResultHandler<JsonValue> h) {
-        // Use an accumulator which will aggregate the results from the subordinate mappers into
-        // a single list. On completion, the accumulator combines the results into a single JSON
-        // map object.
+    void toJSON(final Context c, final JsonPointer path, final Entry e,
+            final ResultHandler<JsonValue> h) {
+        /*
+         * Use an accumulator which will aggregate the results from the
+         * subordinate mappers into a single list. On completion, the
+         * accumulator combines the results into a single JSON map object.
+         */
         final ResultHandler<Map.Entry<String, JsonValue>> handler =
                 accumulate(mappings.size(), transform(
                         new Function<List<Map.Entry<String, JsonValue>>, JsonValue, Void>() {
@@ -118,11 +131,16 @@
                             public JsonValue apply(final List<Map.Entry<String, JsonValue>> value,
                                     final Void p) {
                                 if (value.isEmpty()) {
-                                    // No subordinate attributes, so omit the entire JSON object
-                                    // from the resource.
+                                    /*
+                                     * No subordinate attributes, so omit the
+                                     * entire JSON object from the resource.
+                                     */
                                     return null;
                                 } else {
-                                    // Combine the sub-attributes into a single JSON object.
+                                    /*
+                                     * Combine the sub-attributes into a single
+                                     * JSON object.
+                                     */
                                     final Map<String, Object> result =
                                             new LinkedHashMap<String, Object>(value.size());
                                     for (final Map.Entry<String, JsonValue> e : value) {
@@ -134,7 +152,7 @@
                         }, h));
 
         for (final Mapping mapping : mappings.values()) {
-            mapping.mapper.toJSON(c, e, transform(
+            mapping.mapper.toJSON(c, path.child(mapping.name), e, transform(
                     new Function<JsonValue, Map.Entry<String, JsonValue>, Void>() {
                         @Override
                         public Map.Entry<String, JsonValue> apply(final JsonValue value,
@@ -147,30 +165,39 @@
     }
 
     @Override
-    void toLDAP(final Context c, final JsonValue v, final ResultHandler<List<Attribute>> h) {
-        // Fail immediately if the JSON value has the wrong type or contains unknown attributes.
+    void toLDAP(final Context c, final JsonPointer path, final Entry e, final JsonValue v,
+            final ResultHandler<List<Modification>> h) {
+        /*
+         * Fail immediately if the JSON value has the wrong type or contains
+         * unknown attributes.
+         */
         final Map<String, Mapping> missingMappings = new LinkedHashMap<String, Mapping>(mappings);
         if (v != null && !v.isNull()) {
             if (v.isMap()) {
                 for (final String attribute : v.asMap().keySet()) {
                     if (missingMappings.remove(toLowerCase(attribute)) == null) {
-                        h.handleError(new BadRequestException("unrecognized attribute '"
-                                + attribute + "'"));
+                        h.handleError(new BadRequestException(i18n(
+                                "The request cannot be processed because the JSON resource "
+                                        + "contains an unrecognized field '%s'", path
+                                        .child(attribute))));
                         return;
                     }
                 }
             } else {
-                h.handleError(new BadRequestException("JSON object expected"));
+                h.handleError(new BadRequestException(i18n(
+                        "The request cannot be processed because the JSON resource "
+                                + "contains the field '%s' whose value is the wrong type: "
+                                + "an object is expected", path)));
                 return;
             }
         }
 
         // Accumulate the results of the subordinate mappings.
-        final ResultHandler<List<Attribute>> handler =
+        final ResultHandler<List<Modification>> handler =
                 accumulate(mappings.size(), transform(
-                        new Function<List<List<Attribute>>, List<Attribute>, Void>() {
+                        new Function<List<List<Modification>>, List<Modification>, Void>() {
                             @Override
-                            public List<Attribute> apply(final List<List<Attribute>> value,
+                            public List<Modification> apply(final List<List<Modification>> value,
                                     final Void p) {
                                 switch (value.size()) {
                                 case 0:
@@ -178,9 +205,9 @@
                                 case 1:
                                     return value.get(0);
                                 default:
-                                    final List<Attribute> attributes =
-                                            new ArrayList<Attribute>(value.size());
-                                    for (final List<Attribute> a : value) {
+                                    final List<Modification> attributes =
+                                            new ArrayList<Modification>(value.size());
+                                    for (final List<Modification> a : value) {
                                         attributes.addAll(a);
                                     }
                                     return attributes;
@@ -190,16 +217,16 @@
 
         // Invoke mappings for which there are values provided.
         if (v != null && !v.isNull()) {
-            for (final Map.Entry<String, Object> e : v.asMap().entrySet()) {
-                final Mapping mapping = getMapping(e.getKey());
-                final JsonValue subValue = new JsonValue(e.getValue());
-                mapping.mapper.toLDAP(c, subValue, handler);
+            for (final Map.Entry<String, Object> me : v.asMap().entrySet()) {
+                final Mapping mapping = getMapping(me.getKey());
+                final JsonValue subValue = new JsonValue(me.getValue());
+                mapping.mapper.toLDAP(c, path.child(me.getKey()), e, subValue, handler);
             }
         }
 
         // Invoke mappings for which there were no values provided.
         for (final Mapping mapping : missingMappings.values()) {
-            mapping.mapper.toLDAP(c, null, handler);
+            mapping.mapper.toLDAP(c, path.child(mapping.name), e, null, handler);
         }
     }
 

--
Gitblit v1.10.0