From 9cb4730adfb2ad5fcf171c48a4d0aee46777902e Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 23 May 2012 10:06:17 +0000
Subject: [PATCH] * simplify example code and add groups container * allow AttributeMappers to throw ResourceExceptions instead of LDAP ErrorResultExceptions * rename IdentityAttributeMapper -> SimpleAttributeMapper.

---
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java |   29 +++++
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java            |   25 ++--
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java                     |   22 ++--
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java                  |   41 ++++----
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java         |   30 +++---
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java                          |  129 ++++++-------------------
 6 files changed, 118 insertions(+), 158 deletions(-)

diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
index 9387131..47acac8 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
@@ -16,7 +16,6 @@
 
 package org.forgerock.opendj.rest2ldap;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -25,7 +24,6 @@
 import org.forgerock.json.fluent.JsonValue;
 import org.forgerock.opendj.ldap.Attribute;
 import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.ResultHandler;
 import org.forgerock.resource.provider.Context;
 
 /**
@@ -34,30 +32,33 @@
 public interface AttributeMapper {
 
     /**
-     * Returns an unmodifiable collection containing the names of the LDAP
-     * attributes required by this attribute mapper. The returned collection
-     * should only contain the names of attributes found in the LDAP entry
-     * directly associated with the resource.
-     *
-     * @return An unmodifiable collection containing the names of the LDAP
-     *         attributes required by this attribute mapper.
-     */
-    Collection<String> getAllLDAPAttributes();
-
-    /**
-     * Adds the names of the LDAP attributes required by this attribute mapper
-     * which are associated with the provided resource attribute.
+     * Adds the names of the all the LDAP attributes required by this attribute
+     * mapper to the provided set.
      * <p>
      * Implementations should only add the names of attributes found in the LDAP
      * entry directly associated with the resource.
      *
-     * @param resourceAttribute
-     *            The name of the resource attribute requested by the client.
      * @param ldapAttributes
      *            The set into which the required LDAP attribute names should be
      *            put.
      */
-    void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes);
+    void getLDAPAttributes(Set<String> ldapAttributes);
+
+    /**
+     * Adds the names of the LDAP attributes required by this attribute mapper
+     * which are associated with the provided resource attribute to the provided
+     * set.
+     * <p>
+     * Implementations should only add the names of attributes found in the LDAP
+     * entry directly associated with the resource.
+     *
+     * @param ldapAttributes
+     *            The set into which the required LDAP attribute names should be
+     *            put.
+     * @param resourceAttribute
+     *            The name of the resource attribute requested by the client.
+     */
+    void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute);
 
     /**
      * Transforms attributes contained in the provided LDAP entry to JSON
@@ -72,7 +73,7 @@
      * @param e
      * @param h
      */
-    void toJson(Context c, Entry e, ResultHandler<Map<String, Object>> h);
+    void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h);
 
     /**
      * Transforms JSON content in the provided JSON value to LDAP attributes,
@@ -86,7 +87,7 @@
      * @param v
      * @param h
      */
-    void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h);
+    void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h);
 
     // TODO: methods for obtaining schema information (e.g. name, description,
     // type information).
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java
new file mode 100644
index 0000000..a6e92c9
--- /dev/null
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java
@@ -0,0 +1,29 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyrighted [year] [name of copyright owner]".
+ *
+ * Copyright 2012 ForgeRock AS. All rights reserved.
+ */
+
+package org.forgerock.opendj.rest2ldap;
+
+import org.forgerock.resource.exception.ResourceException;
+
+/**
+ *
+ */
+public interface AttributeMapperCompletionHandler<T> {
+
+    void onSuccess(T result);
+
+    void onFailure(ResourceException e);
+}
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
index 1bcfee1..3bb818d 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
@@ -29,8 +29,7 @@
 import org.forgerock.json.fluent.JsonValue;
 import org.forgerock.opendj.ldap.Attribute;
 import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.ResultHandler;
+import org.forgerock.resource.exception.ResourceException;
 import org.forgerock.resource.provider.Context;
 
 /**
@@ -50,7 +49,7 @@
         this.attributeMappers = new ArrayList<AttributeMapper>(attributeMappers);
         Set<String> tmp = new LinkedHashSet<String>(attributeMappers.size());
         for (final AttributeMapper mapper : attributeMappers) {
-            tmp.addAll(mapper.getAllLDAPAttributes());
+            mapper.getLDAPAttributes(tmp);
         }
         allLDAPAttributes = Collections.unmodifiableSet(tmp);
     }
@@ -58,37 +57,38 @@
     /**
      * {@inheritDoc}
      */
-    public Set<String> getAllLDAPAttributes() {
-        return allLDAPAttributes;
+    public void getLDAPAttributes(Set<String> ldapAttributes) {
+        ldapAttributes.addAll(allLDAPAttributes);
     }
 
     /**
      * {@inheritDoc}
      */
-    public void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes) {
+    public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) {
         for (AttributeMapper attribute : attributeMappers) {
-            attribute.getLDAPAttributesFor(resourceAttribute, ldapAttributes);
+            attribute.getLDAPAttributes(ldapAttributes, resourceAttribute);
         }
     }
 
     /**
      * {@inheritDoc}
      */
-    public void toJson(Context c, Entry e, final ResultHandler<Map<String, Object>> h) {
-        ResultHandler<Map<String, Object>> resultAccumulater =
-                new ResultHandler<Map<String, Object>>() {
+    public void toJson(Context c, Entry e,
+            final AttributeMapperCompletionHandler<Map<String, Object>> h) {
+        AttributeMapperCompletionHandler<Map<String, Object>> resultAccumulater =
+                new AttributeMapperCompletionHandler<Map<String, Object>>() {
                     private final AtomicInteger latch = new AtomicInteger(attributeMappers.size());
                     private final List<Map<String, Object>> results =
                             new ArrayList<Map<String, Object>>(latch.get());
 
-                    public void handleErrorResult(ErrorResultException error) {
+                    public void onFailure(ResourceException e) {
                         // Ensure that handler is only invoked once.
                         if (latch.getAndSet(0) > 0) {
-                            h.handleErrorResult(error);
+                            h.onFailure(e);
                         }
                     }
 
-                    public void handleResult(Map<String, Object> result) {
+                    public void onSuccess(Map<String, Object> result) {
                         synchronized (this) {
                             results.add(result);
                         }
@@ -106,7 +106,7 @@
                                 mergeJsonValues(results, mergeResult);
                                 break;
                             }
-                            h.handleResult(mergeResult);
+                            h.onSuccess(mergeResult);
                         }
                     }
                 };
@@ -119,7 +119,7 @@
     /**
      * {@inheritDoc}
      */
-    public void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h) {
+    public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
         // TODO Auto-generated method stub
 
     }
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
index eeaefd9..2994682 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -16,10 +16,6 @@
 
 package org.forgerock.opendj.rest2ldap;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import org.forgerock.json.fluent.JsonValue;
 import org.forgerock.json.resource.restlet.JsonResourceRestlet;
 import org.forgerock.opendj.ldap.ConnectionFactory;
 import org.forgerock.opendj.ldap.Connections;
@@ -30,7 +26,6 @@
 import org.forgerock.resource.framework.impl.ResourceInvoker;
 import org.restlet.Application;
 import org.restlet.Component;
-import org.restlet.Request;
 import org.restlet.Restlet;
 import org.restlet.data.Protocol;
 import org.restlet.routing.Router;
@@ -41,115 +36,53 @@
  */
 public class Example {
 
-    private static final String PATH_PROPERTY = "rest2ldap.restlet.path";
-
     private Application application = new Application();
     private final Router router = new Router();
-    private HashMap<JsonResourceProvider, Restlet> restlets =
-            new HashMap<JsonResourceProvider, Restlet>();
 
-    protected synchronized void bindRestlet(Restlet restlet, Map<String, Object> properties) {
-        Object path = properties.get(PATH_PROPERTY);
-        if (path != null && path instanceof String) { // service is specified as
-                                                      // internally routable
-            attach((String) path, restlet);
-        }
-    }
-
-    protected synchronized void unbindRestlet(Restlet restlet, Map<String, Object> properties) {
-        Object path = properties.get(PATH_PROPERTY);
-        if (path != null && path instanceof String) { // service is specified as
-                                                      // internally routable
-            detach(restlet);
-        }
-    }
-
-    /**
-     * Attaches a target Restlet to the Restlet router based on a given URI
-     * prefix.
-     *
-     * @param path
-     *            the path to attach it to.
-     * @param restlet
-     *            the restlet to route to if path matches.
-     * @throws IllegalArgumentException
-     *             if path does not begin with a '/' character.
-     */
-    public void attach(String path, Restlet restlet) {
+    private void bindJsonResource(JsonResourceProvider resource, String path) {
+        Restlet restlet = new JsonResourceRestlet(resource);
         restlet.setContext(application.getContext());
         router.attach(path, restlet, Template.MODE_EQUALS);
         router.attach(path + (path.equals("/") ? "" : "/"), restlet, Template.MODE_STARTS_WITH);
     }
 
-    /**
-     * Remove a restlet from restlet router
-     *
-     * @param restlet
-     *            the restlet to remove
-     */
-    public void detach(Restlet restlet) {
-        router.detach(restlet); // all routes to restlet are removed
-    }
-
-    protected synchronized void bindJsonResource(JsonResourceProvider resource,
-            Map<String, Object> properties) {
-        Restlet restlet = new CustomRestlet(resource);
-        restlets.put(resource, restlet);
-        bindRestlet(restlet, properties);
-    }
-
-    protected synchronized void unbindJsonResource(JsonResourceProvider resource,
-            Map<String, Object> properties) {
-        Restlet restlet = restlets.get(resource);
-        if (restlet != null) {
-            unbindRestlet(restlet, properties);
-            restlets.remove(resource);
-        }
-    }
-
-    private class CustomRestlet extends JsonResourceRestlet {
-        public CustomRestlet(JsonResourceProvider resource) {
-            super(resource);
-        }
-
-        @Override
-        public JsonValue newContext(Request request) {
-            JsonValue result = super.newContext(request);
-            JsonValue security = result.get("security");
-            security.put("openidm-roles", request.getAttributes().get("openidm.roles"));
-            return result;
-        }
-    }
-
     public void start() throws Exception {
-        Component component = new Component();
-
-        // Add http listener
-        component.getServers().add(Protocol.HTTP, 8080);
-        application.getTunnelService().setQueryTunnel(false); // query string
-                                                              // purism
-        application.setInboundRoot(router);
-
-        // Attach the json resource at the root path
-        Map<String, Object> props = new HashMap<String, Object>();
-        props.put(PATH_PROPERTY, "");
-
-        AttributeMapper mapper = new IdentityAttributeMapper().excludeAttribute("entryUUID", "etag");
+        // All LDAP resources will use this connection factory.
         ConnectionFactory factory =
                 Connections.newAuthenticatedConnectionFactory(new LDAPConnectionFactory(
                         "localhost", 1389), Requests.newSimpleBindRequest("cn=directory manager",
                         "password".toCharArray()));
-        EntryContainer container =
+
+        // Create two entry containers whose members reference each other.
+        EntryContainer userContainer =
                 new EntryContainer(DN.valueOf("ou=people,dc=example,dc=com"), factory);
-        LDAPResource resource = new LDAPResource(container, mapper);
-        ResourceInvoker invoker = new ResourceInvoker();
-        invoker.resource = resource;
-        bindJsonResource(invoker, props);
+        EntryContainer groupContainer =
+                new EntryContainer(DN.valueOf("ou=groups,dc=example,dc=com"), factory);
 
-        // Attach the sample application.
-        component.getDefaultHost().attach("/example", application);
+        // Create user resource.
+        AttributeMapper userMapper =
+                new SimpleAttributeMapper().includeAttribute("uid", "cn", "sn", "mail",
+                        "isMemberOf", "modifyTimestamp");
+        LDAPResource userResource = new LDAPResource(userContainer, userMapper);
+        ResourceInvoker userResourceInvoker = new ResourceInvoker();
+        userResourceInvoker.resource = userResource; // FIXME: Yuk!
+        bindJsonResource(userResourceInvoker, "/users");
 
-        // Start the component.
+        // Create group resource.
+        AttributeMapper groupMapper =
+                new SimpleAttributeMapper().includeAttribute("cn", "ou", "description",
+                        "uniquemember");
+        LDAPResource groupResource = new LDAPResource(groupContainer, groupMapper);
+        ResourceInvoker groupResourceInvoker = new ResourceInvoker();
+        groupResourceInvoker.resource = groupResource; // FIXME: Yuk!
+        bindJsonResource(groupResourceInvoker, "/groups");
+
+        // Configure and start the application.
+        application.getTunnelService().setQueryTunnel(false);
+        application.setInboundRoot(router);
+        Component component = new Component();
+        component.getServers().add(Protocol.HTTP, 8080);
+        component.getDefaultHost().attach("", application);
         component.start();
     }
 
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
index 58fdbc8..a0fe6f0 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
@@ -160,14 +160,13 @@
 
                         public void handleResult(final SearchResultEntry entry) {
                             final String revision = entryContainer.getEtagFromEntry(entry);
-                            final ResultHandler<Map<String, Object>> mapHandler =
-                                    new ResultHandler<Map<String, Object>>() {
-                                        public void handleErrorResult(
-                                                final ErrorResultException error) {
-                                            out.setFailure(adaptErrorResult(error));
+                            final AttributeMapperCompletionHandler<Map<String, Object>> mapHandler =
+                                    new AttributeMapperCompletionHandler<Map<String, Object>>() {
+                                        public void onFailure(final ResourceException e) {
+                                            out.setFailure(e);
                                         }
 
-                                        public void handleResult(final Map<String, Object> result) {
+                                        public void onSuccess(final Map<String, Object> result) {
                                             out.setResult(id, revision, new JsonValue(result));
                                         }
                                     };
@@ -227,18 +226,19 @@
      *         attributes.
      */
     private Collection<String> getRequestedLDAPAttributes(final Set<JsonPointer> requestedAttributes) {
+        final Set<String> requestedLDAPAttributes;
         if (requestedAttributes.isEmpty()) {
             // Full read.
-            return attributeMapper.getAllLDAPAttributes();
+            requestedLDAPAttributes = new LinkedHashSet<String>();
+            attributeMapper.getLDAPAttributes(requestedLDAPAttributes);
         } else {
             // Partial read.
-            final Set<String> requestedLDAPAttributes =
-                    new LinkedHashSet<String>(requestedAttributes.size());
+            requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size());
             for (final JsonPointer requestedAttribute : requestedAttributes) {
-                attributeMapper.getLDAPAttributesFor(requestedAttribute, requestedLDAPAttributes);
+                attributeMapper.getLDAPAttributes(requestedLDAPAttributes, requestedAttribute);
             }
-            return requestedLDAPAttributes;
         }
+        return requestedLDAPAttributes;
     }
 
 }
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/IdentityAttributeMapper.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
similarity index 79%
rename from opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/IdentityAttributeMapper.java
rename to opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
index 3d2fca7..43bdf36 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/IdentityAttributeMapper.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
@@ -19,8 +19,6 @@
 import static org.forgerock.opendj.rest2ldap.Utils.getAttributeName;
 import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase;
 
-import java.util.Collection;
-import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -30,46 +28,45 @@
 import org.forgerock.json.fluent.JsonValue;
 import org.forgerock.opendj.ldap.Attribute;
 import org.forgerock.opendj.ldap.Entry;
-import org.forgerock.opendj.ldap.ResultHandler;
 import org.forgerock.resource.provider.Context;
 
 /**
  *
  */
-public final class IdentityAttributeMapper implements AttributeMapper {
+public final class SimpleAttributeMapper implements AttributeMapper {
 
     // All user attributes by default.
     private final Map<String, String> includedAttributes = new LinkedHashMap<String, String>();
     private final Map<String, String> excludedAttributes = new LinkedHashMap<String, String>();
 
-    public IdentityAttributeMapper() {
+    public SimpleAttributeMapper() {
         // No implementation required.
     }
 
-    public IdentityAttributeMapper includeAttribute(String... attributes) {
+    public SimpleAttributeMapper includeAttribute(String... attributes) {
         for (String attribute : attributes) {
             includedAttributes.put(toLowerCase(attribute), attribute);
         }
         return this;
     }
 
-    public IdentityAttributeMapper excludeAttribute(String... attributes) {
+    public SimpleAttributeMapper excludeAttribute(String... attributes) {
         for (String attribute : attributes) {
             excludedAttributes.put(toLowerCase(attribute), attribute);
         }
         return this;
     }
 
-    public Collection<String> getAllLDAPAttributes() {
+    public void getLDAPAttributes(Set<String> ldapAttributes) {
         if (!includedAttributes.isEmpty()) {
-            return includedAttributes.values();
+            ldapAttributes.addAll(includedAttributes.values());
         } else {
             // All user attributes.
-            return Collections.singleton("*");
+            ldapAttributes.add("*");
         }
     }
 
-    public void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes) {
+    public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) {
         String name = resourceAttribute.leaf();
         if (name != null) {
             if (isIncludedAttribute(name)) {
@@ -80,7 +77,7 @@
         }
     }
 
-    public void toJson(Context c, Entry e, ResultHandler<Map<String, Object>> h) {
+    public void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h) {
         Map<String, Object> result = new LinkedHashMap<String, Object>(e.getAttributeCount());
         for (Attribute a : e.getAllAttributes()) {
             String name = getAttributeName(a);
@@ -88,7 +85,7 @@
                 result.put(name, Utils.attributeToJson(a));
             }
         }
-        h.handleResult(result);
+        h.onSuccess(result);
     }
 
     private boolean isIncludedAttribute(String name) {
@@ -107,7 +104,7 @@
         return false;
     }
 
-    public void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h) {
+    public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) {
         // TODO:
     }
 }

--
Gitblit v1.10.0