From aa8dbe8ce1729e268d6bcf7503d172365e7c2705 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 02 Apr 2013 11:04:11 +0000
Subject: [PATCH] Additional change for OPENDJ-354: Implement a RequestHandler which provides an in-memory backend

---
 opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java |   12 ++++
 opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java             |   72 ++++++++++++-----------
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java         |    4 
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java       |   42 +++++++++++--
 4 files changed, 85 insertions(+), 45 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java
index c5102b9..1d4cf19 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java
@@ -22,6 +22,7 @@
  *
  *
  *      Copyright 2009-2010 Sun Microsystems, Inc.
+ *      Portions copyright 2013 ForgeRock AS.
  */
 
 package com.forgerock.opendj.util;
@@ -34,8 +35,14 @@
  * Utility methods for manipulating {@link Iterable}s.
  */
 public final class Iterables {
-    private static final class ArrayIterable<M> implements Iterable<M> {
+    private static abstract class AbstractIterable<M> implements Iterable<M> {
+        @Override
+        public String toString() {
+            return Iterables.toString(this);
+        }
+    }
 
+    private static final class ArrayIterable<M> extends AbstractIterable<M> {
         private final M[] a;
 
         // Constructed via factory methods.
@@ -43,28 +50,18 @@
             this.a = a;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public Iterator<M> iterator() {
             return Iterators.arrayIterator(a);
         }
-
     }
 
-    private static final class EmptyIterable<M> implements Iterable<M> {
-
-        /**
-         * {@inheritDoc}
-         */
+    private static final class EmptyIterable<M> extends AbstractIterable<M> {
         public Iterator<M> iterator() {
             return Iterators.emptyIterator();
         }
-
     }
 
-    private static final class FilteredIterable<M, P> implements Iterable<M> {
-
+    private static final class FilteredIterable<M, P> extends AbstractIterable<M> {
         private final Iterable<M> iterable;
         private final P parameter;
         private final Predicate<? super M, P> predicate;
@@ -77,17 +74,12 @@
             this.parameter = p;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public Iterator<M> iterator() {
             return Iterators.filteredIterator(iterable.iterator(), predicate, parameter);
         }
-
     }
 
-    private static final class SingletonIterable<M> implements Iterable<M> {
-
+    private static final class SingletonIterable<M> extends AbstractIterable<M> {
         private final M value;
 
         // Constructed via factory methods.
@@ -95,17 +87,12 @@
             this.value = value;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public Iterator<M> iterator() {
             return Iterators.singletonIterator(value);
         }
-
     }
 
-    private static final class TransformedIterable<M, N, P> implements Iterable<N> {
-
+    private static final class TransformedIterable<M, N, P> extends AbstractIterable<N> {
         private final Function<? super M, ? extends N, P> function;
         private final Iterable<M> iterable;
         private final P parameter;
@@ -118,17 +105,12 @@
             this.parameter = p;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public Iterator<N> iterator() {
             return Iterators.transformedIterator(iterable.iterator(), function, parameter);
         }
-
     }
 
-    private static final class UnmodifiableIterable<M> implements Iterable<M> {
-
+    private static final class UnmodifiableIterable<M> extends AbstractIterable<M> {
         private final Iterable<M> iterable;
 
         // Constructed via factory methods.
@@ -136,13 +118,9 @@
             this.iterable = iterable;
         }
 
-        /**
-         * {@inheritDoc}
-         */
         public Iterator<M> iterator() {
             return Iterators.unmodifiableIterator(iterable.iterator());
         }
-
     }
 
     private static final Iterable<Object> EMPTY_ITERABLE = new EmptyIterable<Object>();
@@ -302,6 +280,30 @@
         return new UnmodifiableIterable<M>(iterable);
     }
 
+    /**
+     * Returns a string representation of the provided iterable composed of an
+     * opening square bracket, followed by each element separated by commas, and
+     * then a closing square bracket.
+     *
+     * @param iterable
+     *            The iterable whose string representation is to be returned.
+     * @return A string representation of the provided iterable.
+     */
+    public static String toString(Iterable<?> iterable) {
+        final StringBuilder builder = new StringBuilder();
+        boolean firstValue = true;
+        builder.append('[');
+        for (Object value : iterable) {
+            if (!firstValue) {
+                builder.append(',');
+            }
+            builder.append(String.valueOf(value));
+            firstValue = false;
+        }
+        builder.append(']');
+        return builder.toString();
+    }
+
     // Prevent instantiation
     private Iterables() {
         // Do nothing.
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java
index f7ee890..cb66c19 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java
@@ -40,6 +40,8 @@
 import org.forgerock.opendj.ldap.schema.ObjectClass;
 import org.forgerock.opendj.ldap.schema.Schema;
 
+import com.forgerock.opendj.util.Iterables;
+
 /**
  * A configurable factory for filtering the attributes exposed by an entry. An
  * {@code AttributeFilter} is useful for performing fine-grained access control,
@@ -57,9 +59,10 @@
  * </ul>
  */
 public final class AttributeFilter {
-    // TODO: exclude specific attributes, matched values, types only, custom predicates, etc.
-    private boolean includeAllOperationalAttributes;
-    private boolean includeAllUserAttributes;
+    // TODO: exclude specific attributes, matched values, custom predicates, etc.
+    private boolean includeAllOperationalAttributes = false;
+    private boolean includeAllUserAttributes; // Depends on constructor.
+    private boolean typesOnly = false;
 
     /**
      * Use a map so that we can perform membership checks as well as recover the
@@ -74,7 +77,6 @@
      */
     public AttributeFilter() {
         includeAllUserAttributes = true;
-        includeAllOperationalAttributes = false;
     }
 
     /**
@@ -106,7 +108,6 @@
         if (attributeDescriptions == null || attributeDescriptions.isEmpty()) {
             // Fast-path for common case.
             includeAllUserAttributes = true;
-            includeAllOperationalAttributes = false;
         } else {
             for (final String attribute : attributeDescriptions) {
                 includeAttribute(attribute, schema);
@@ -212,7 +213,7 @@
                                     throw new NoSuchElementException();
                                 }
                                 hasNextMustIterate = true;
-                                return next;
+                                return filterAttribute(next);
                             }
 
                             @Override
@@ -221,6 +222,11 @@
                             }
                         };
                     }
+
+                    @Override
+                    public String toString() {
+                        return Iterables.toString(this);
+                    }
                 };
             }
 
@@ -237,10 +243,10 @@
                     final AttributeType at = ad.getAttributeType();
                     final AttributeDescription requestedAd = requestedAttributes.get(ad);
                     if (requestedAd != null) {
-                        return renameAttribute(attribute, requestedAd);
+                        return filterAttribute(renameAttribute(attribute, requestedAd));
                     } else if ((at.isOperational() && includeAllOperationalAttributes)
                             || (!at.isOperational() && includeAllUserAttributes)) {
-                        return attribute;
+                        return filterAttribute(attribute);
                     }
                 }
                 return null;
@@ -397,9 +403,29 @@
         }
     }
 
+    /**
+     * Specifies whether or not filtered attributes are to contain both
+     * attribute descriptions and values, or just attribute descriptions.
+     *
+     * @param typesOnly
+     *            {@code true} if only attribute descriptions (and not values)
+     *            are to be included, or {@code false} (the default) if both
+     *            attribute descriptions and values are to be included.
+     * @return A reference to this attribute filter.
+     */
+    public AttributeFilter typesOnly(final boolean typesOnly) {
+        this.typesOnly = typesOnly;
+        return this;
+    }
+
     private void allocatedRequestedAttributes() {
         if (requestedAttributes.isEmpty()) {
             requestedAttributes = new HashMap<AttributeDescription, AttributeDescription>();
         }
     }
+
+    private Attribute filterAttribute(final Attribute attribute) {
+        return typesOnly ? Attributes.emptyAttribute(attribute.getAttributeDescription())
+                : attribute;
+    }
 }
diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
index 794ee02..f7ce541 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
@@ -324,8 +324,8 @@
             final Filter filter = request.getFilter();
             final Matcher matcher = filter.matcher(schema);
             final AttributeFilter attributeFilter =
-                    new AttributeFilter(request.getAttributes(), schema);
-
+                    new AttributeFilter(request.getAttributes(), schema).typesOnly(request
+                            .isTypesOnly());
             if (scope.equals(SearchScope.BASE_OBJECT)) {
                 if (matcher.matches(baseEntry).toBoolean()) {
                     sendEntry(attributeFilter, resultHandler, baseEntry);
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java
index cdb7204..a682970 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java
@@ -42,6 +42,7 @@
 import org.forgerock.opendj.ldap.controls.PostReadResponseControl;
 import org.forgerock.opendj.ldap.controls.PreReadRequestControl;
 import org.forgerock.opendj.ldap.controls.PreReadResponseControl;
+import org.forgerock.opendj.ldap.requests.Requests;
 import org.forgerock.opendj.ldif.ConnectionEntryReader;
 import org.forgerock.opendj.ldif.LDIFEntryReader;
 import org.testng.annotations.Test;
@@ -346,6 +347,17 @@
     }
 
     @Test
+    public void testSearchAttributesSelectedTypesOnly() throws Exception {
+        final Connection connection = getConnection();
+        assertThat(
+                connection.searchSingleEntry(Requests.newSearchRequest(
+                        "uid=test1,ou=People,dc=example,dc=com", SearchScope.BASE_OBJECT,
+                        "(objectClass=*)", "uid", "entryDN").setTypesOnly(true))).isEqualTo(
+                new LinkedHashMapEntry("uid=test1,ou=People,dc=example,dc=com").addAttribute("uid")
+                        .addAttribute("entryDN"));
+    }
+
+    @Test
     public void testSearchAttributesRenamed() throws Exception {
         final Connection connection = getConnection();
         final Entry entry =

--
Gitblit v1.10.0