From b362d9da285a8dc1b86db29b945feb3bc245b03b Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 22 May 2012 16:28:29 +0000
Subject: [PATCH] Checkpoint basic GET functionality, including example gateway for testing.

---
 /dev/null                                                                                          |   41 ----
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/IdentityAttributeMapper.java |    3 
 opendj3/opendj-rest2ldap/pom.xml                                                                   |  173 ++++++++++------
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Utils.java                   |   22 +
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java            |   21 -
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java          |  169 ++++++++++++++--
 opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java                 |  160 ++++++++++++++++
 7 files changed, 434 insertions(+), 155 deletions(-)

diff --git a/opendj3/opendj-rest2ldap/pom.xml b/opendj3/opendj-rest2ldap/pom.xml
index 8c52fc1..fa1dd8a 100644
--- a/opendj3/opendj-rest2ldap/pom.xml
+++ b/opendj3/opendj-rest2ldap/pom.xml
@@ -24,47 +24,86 @@
  !      Copyright 2012 ForgeRock AS
  !    
  -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <parent>
-    <artifactId>opendj-project</artifactId>
-    <groupId>org.forgerock.opendj</groupId>
-    <version>3.0.0-SNAPSHOT</version>
-  </parent>
-  <artifactId>opendj-rest2ldap</artifactId>
-  <name>OpenDJ REST to LDAP Gateway</name>
-  <description>
-    This module includes APIs for implementing REST to LDAP gateways.
-  </description>
-  <packaging>jar</packaging>
-  <dependencies>
-    <dependency>
-      <groupId>org.forgerock.opendj</groupId>
-      <artifactId>opendj-ldap-sdk</artifactId>
-      <version>${project.version}</version>
-      <scope>compile</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.forgerock.opendj</groupId>
-      <artifactId>opendj-build-tools</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-    	<groupId>org.forgerock.commons</groupId>
-    	<artifactId>json-fluent</artifactId>
-    	<version>1.1.0</version>
-    	<scope>compile</scope>
-    </dependency>
-    <dependency>
-        <groupId>org.forgerock.commons</groupId>
-        <artifactId>org.forgerock.json.resource</artifactId>
-        <version>1.3.0-SNAPSHOT</version>
-        <scope>compile</scope>
-    </dependency>
-  </dependencies>
-  <build>
-    <plugins>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>opendj-project</artifactId>
+        <groupId>org.forgerock.opendj</groupId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>opendj-rest2ldap</artifactId>
+    <name>OpenDJ REST to LDAP Gateway</name>
+    <description>
+        This module includes APIs for implementing REST to LDAP gateways.
+    </description>
+    <packaging>jar</packaging>
+    <repositories>
+        <repository>
+            <id>maven-restlet</id>
+            <name>Public online Restlet repository</name>
+            <url>http://maven.restlet.org</url>
+        </repository>
+    </repositories>
+    <dependencies>
+        <dependency>
+            <groupId>org.forgerock.opendj</groupId>
+            <artifactId>opendj-ldap-sdk</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.opendj</groupId>
+            <artifactId>opendj-build-tools</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.commons</groupId>
+            <artifactId>json-fluent</artifactId>
+            <version>1.1.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+            <version>2.5</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.commons</groupId>
+            <artifactId>org.forgerock.json.resource</artifactId>
+            <version>1.3.0-SNAPSHOT</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.commons</groupId>
+            <artifactId>org.forgerock.json.resource.restlet</artifactId>
+            <version>1.3.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.commons</groupId>
+            <artifactId>org.forgerock.restlet</artifactId>
+            <version>1.1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.forgerock.commons</groupId>
+            <artifactId>json-patch</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.restlet.jse</groupId>
+            <artifactId>org.restlet</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.restlet.jse</groupId>
+            <artifactId>org.restlet.ext.jackson</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
       <!--
       <plugin>
         <groupId>org.forgerock.commons</groupId>
@@ -84,30 +123,30 @@
         </executions>
       </plugin>
       -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-surefire-plugin</artifactId>
-      </plugin>
-    </plugins>
-  </build>
-  <reporting>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-project-info-reports-plugin</artifactId>
-        <reportSets>
-          <reportSet>
-            <reports>
-              <report>mailing-list</report>
-              <report>issue-tracking</report>
-              <report>license</report>
-              <report>scm</report>
-              <report>cim</report>
-              <report>distribution-management</report>
-            </reports>
-          </reportSet>
-        </reportSets>
-      </plugin>
-    </plugins>
-  </reporting>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+                <reportSets>
+                    <reportSet>
+                        <reports>
+                            <report>mailing-list</report>
+                            <report>issue-tracking</report>
+                            <report>license</report>
+                            <report>scm</report>
+                            <report>cim</report>
+                            <report>distribution-management</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+        </plugins>
+    </reporting>
 </project>
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
index 5b4e80d..b2ff886 100644
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EntryContainer.java
@@ -18,50 +18,167 @@
 
 import java.util.Collection;
 
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.ConnectionFactory;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.Filter;
 import org.forgerock.opendj.ldap.ResultHandler;
 import org.forgerock.opendj.ldap.SearchResultHandler;
+import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.Result;
 import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.opendj.ldap.responses.SearchResultReference;
 import org.forgerock.resource.provider.Context;
 
 /**
  *
  */
 public final class EntryContainer {
+    // FIXME: make this configurable, also allow use of DN.
+    private static final String UUID_ATTRIBUTE = "entryUUID";
 
-    /**
-     * @param entry
-     * @return
-     */
-    public String getIDFromEntry(final SearchResultEntry entry) {
-        // TODO Auto-generated method stub
-        return null;
+    // FIXME: make this configurable.
+    private static final String ETAG_ATTRIBUTE = "etag";
+
+    private final ConnectionFactory factory;
+    private final DN baseDN;
+
+    private abstract class AbstractRequestCompletionHandler<R, H extends ResultHandler<? super R>>
+            implements ResultHandler<R> {
+        final H resultHandler;
+        final Connection connection;
+
+        AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
+            this.connection = connection;
+            this.resultHandler = resultHandler;
+        }
+
+        @Override
+        public final void handleErrorResult(final ErrorResultException error) {
+            connection.close();
+            resultHandler.handleErrorResult(error);
+        }
+
+        @Override
+        public final void handleResult(final R result) {
+            connection.close();
+            resultHandler.handleResult(result);
+        }
+
     }
 
-    /**
-     * @param context
-     * @param handler
-     */
+    private abstract class ConnectionCompletionHandler<R> implements ResultHandler<Connection> {
+        private final ResultHandler<? super R> resultHandler;
+
+        ConnectionCompletionHandler(final ResultHandler<? super R> resultHandler) {
+            this.resultHandler = resultHandler;
+        }
+
+        @Override
+        public final void handleErrorResult(final ErrorResultException error) {
+            resultHandler.handleErrorResult(error);
+        }
+
+        @Override
+        public abstract void handleResult(Connection connection);
+
+    }
+
+    private final class RequestCompletionHandler<R> extends
+            AbstractRequestCompletionHandler<R, ResultHandler<? super R>> {
+        RequestCompletionHandler(final Connection connection,
+                final ResultHandler<? super R> resultHandler) {
+            super(connection, resultHandler);
+        }
+    }
+
+    private final class SearchRequestCompletionHandler extends
+            AbstractRequestCompletionHandler<Result, SearchResultHandler> implements
+            SearchResultHandler {
+
+        SearchRequestCompletionHandler(final Connection connection,
+                final SearchResultHandler resultHandler) {
+            super(connection, resultHandler);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final boolean handleEntry(final SearchResultEntry entry) {
+            return resultHandler.handleEntry(entry);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public final boolean handleReference(final SearchResultReference reference) {
+            return resultHandler.handleReference(reference);
+        }
+
+    }
+
+    public EntryContainer(DN baseDN, ConnectionFactory factory) {
+        this.baseDN = baseDN;
+        this.factory = factory;
+    }
+
     public void listEntries(final Context context, final SearchResultHandler handler) {
-        // TODO Auto-generated method stub
+        final ConnectionCompletionHandler<Result> outerHandler =
+                new ConnectionCompletionHandler<Result>(handler) {
 
+                    @Override
+                    public void handleResult(final Connection connection) {
+                        final SearchRequestCompletionHandler innerHandler =
+                                new SearchRequestCompletionHandler(connection, handler);
+                        SearchRequest request =
+                                Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
+                                        .objectClassPresent(), UUID_ATTRIBUTE, ETAG_ATTRIBUTE);
+                        connection.searchAsync(request, null, innerHandler);
+                    }
+
+                };
+
+        factory.getConnectionAsync(outerHandler);
     }
 
-    /**
-     * Reads the entry having the specified resource ID.
-     *
-     * @param c
-     *            The request context.
-     * @param id
-     *            The resource ID.
-     * @param attributes
-     *            The set of LDAP attributes to be read.
-     * @param h
-     *            The result handler.
-     */
     public void readEntry(final Context c, final String id, final Collection<String> attributes,
-            final ResultHandler<SearchResultEntry> h) {
-        // TODO Auto-generated method stub
+            final ResultHandler<SearchResultEntry> handler) {
+        final ConnectionCompletionHandler<SearchResultEntry> outerHandler =
+                new ConnectionCompletionHandler<SearchResultEntry>(handler) {
 
+                    @Override
+                    public void handleResult(final Connection connection) {
+                        final RequestCompletionHandler<SearchResultEntry> innerHandler =
+                                new RequestCompletionHandler<SearchResultEntry>(connection, handler);
+                        // FIXME: who is responsible for adding the UUID and
+                        // etag attributes to this search?
+                        String[] tmp = attributes.toArray(new String[attributes.size() + 2]);
+                        tmp[tmp.length - 2] = UUID_ATTRIBUTE;
+                        tmp[tmp.length - 1] = ETAG_ATTRIBUTE;
+
+                        SearchRequest request =
+                                Requests.newSearchRequest(baseDN, SearchScope.SINGLE_LEVEL, Filter
+                                        .equality(UUID_ATTRIBUTE, id), tmp);
+                        connection.searchSingleEntryAsync(request, innerHandler);
+                    }
+
+                };
+
+        factory.getConnectionAsync(outerHandler);
+    }
+
+    public String getIDFromEntry(final Entry entry) {
+        return entry.parseAttribute(UUID_ATTRIBUTE).asString();
+    }
+
+    public String getEtagFromEntry(final Entry entry) {
+        return entry.parseAttribute(ETAG_ATTRIBUTE).asString();
     }
 
 }
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EtagStrategy.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EtagStrategy.java
deleted file mode 100644
index 5071e2c..0000000
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/EtagStrategy.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.opendj.ldap.Entry;
-
-/**
- *
- */
-public interface EtagStrategy {
-    String getEtagFromEntry(final Entry entry);
-}
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
new file mode 100644
index 0000000..94256a3
--- /dev/null
+++ b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -0,0 +1,160 @@
+/*
+ * 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 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;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.LDAPConnectionFactory;
+import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.resource.framework.JsonResourceProvider;
+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;
+import org.restlet.routing.Template;
+
+/**
+ * Example
+ */
+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) {
+        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();
+        ConnectionFactory factory =
+                Connections.newAuthenticatedConnectionFactory(new LDAPConnectionFactory(
+                        "localhost", 1389), Requests.newSimpleBindRequest("cn=directory manager",
+                        "password".toCharArray()));
+        EntryContainer container =
+                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);
+
+        // Attach the sample application.
+        component.getDefaultHost().attach("/example", application);
+
+        // Start the component.
+        component.start();
+    }
+
+    public static void main(String[] args) throws Exception {
+        Example instance = new Example();
+        instance.start();
+    }
+}
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/IdentityAttributeMapper.java
index 0ea36f9..3d2fca7 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/IdentityAttributeMapper.java
@@ -65,7 +65,7 @@
             return includedAttributes.values();
         } else {
             // All user attributes.
-            return Collections.emptySet();
+            return Collections.singleton("*");
         }
     }
 
@@ -88,6 +88,7 @@
                 result.put(name, Utils.attributeToJson(a));
             }
         }
+        h.handleResult(result);
     }
 
     private boolean isIncludedAttribute(String name) {
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 d67d9d4..58fdbc8 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
@@ -63,25 +63,13 @@
 public class LDAPResource implements Resource {
     private final EntryContainer entryContainer;
     private final AttributeMapper attributeMapper;
-    private final EtagStrategy etagStrategy;
 
     /**
      * Creates a new LDAP resource.
-     *
-     * @param entryContainer
-     *            The entry container which will be used to interact with the
-     *            LDAP server.
-     * @param etagStrategy
-     *            The algorithm which should be used to obtain a resource's etag
-     *            from an entry.
-     * @param attributeMapper
-     *            The attribute mapper.
      */
-    public LDAPResource(final EntryContainer entryContainer, final EtagStrategy etagStrategy,
-            final AttributeMapper attributeMapper) {
-        this.entryContainer = entryContainer;
-        this.etagStrategy = etagStrategy;
-        this.attributeMapper = attributeMapper;
+    public LDAPResource(final EntryContainer container, final AttributeMapper mapper) {
+        this.entryContainer = container;
+        this.attributeMapper = mapper;
     }
 
     /**
@@ -171,7 +159,7 @@
                         }
 
                         public void handleResult(final SearchResultEntry entry) {
-                            final String revision = etagStrategy.getEtagFromEntry(entry);
+                            final String revision = entryContainer.getEtagFromEntry(entry);
                             final ResultHandler<Map<String, Object>> mapHandler =
                                     new ResultHandler<Map<String, Object>>() {
                                         public void handleErrorResult(
@@ -252,4 +240,5 @@
             return requestedLDAPAttributes;
         }
     }
+
 }
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 676562d..e0cdf90 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
@@ -36,7 +36,7 @@
 /**
  *
  */
-public final class Utils {
+final class Utils {
 
     private static final Function<ByteString, Object, Syntax> BYTESTRING_TO_JSON =
             new Function<ByteString, Object, Syntax>() {
@@ -72,18 +72,32 @@
         }
     }
 
-    public static Object attributeToJson(Attribute a) {
+    static Object attributeToJson(Attribute a) {
         Syntax syntax = a.getAttributeDescription().getAttributeType().getSyntax();
         Function<ByteString, Object, Void> f = Functions.fixedFunction(BYTESTRING_TO_JSON, syntax);
         boolean isSingleValued = a.getAttributeDescription().getAttributeType().isSingleValue();
         return isSingleValued ? a.parse().as(f) : asList(a.parse().asSetOf(f));
     }
 
-    public static String getAttributeName(Attribute a) {
+    static String getAttributeName(Attribute a) {
         return a.getAttributeDescription().withoutOption("binary").toString();
     }
 
-    public static String toLowerCase(String s) {
+    static String toLowerCase(String s) {
         return s != null ? s.toLowerCase(Locale.ENGLISH) : null;
     }
+
+    static <T> T ensureNotNull(final T object) {
+        if (object == null) {
+            throw new NullPointerException();
+        }
+        return object;
+    }
+
+    static <T> T ensureNotNull(final T object, final String message) {
+        if (object == null) {
+            throw new NullPointerException(message);
+        }
+        return object;
+    }
 }
diff --git a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Validator.java b/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Validator.java
deleted file mode 100644
index 6812619..0000000
--- a/opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Validator.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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;
-
-/**
- *
- */
-final class Validator {
-
-    static <T> T ensureNotNull(final T object) {
-        if (object == null) {
-            throw new NullPointerException();
-        }
-        return object;
-    }
-
-    static <T> T ensureNotNull(final T object, final String message) {
-        if (object == null) {
-            throw new NullPointerException(message);
-        }
-        return object;
-    }
-
-    private Validator() {
-        // Prevent instantiation.
-    }
-}

--
Gitblit v1.10.0