mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
02.04.2013 69f741af9ff3315cf4a18f4893a87f468e33a537
Additional change for OPENDJ-354: Implement a RequestHandler which provides an in-memory backend

* add types only support for searches
* make attribute filtering easier to debug by adding toString() method to returned iterables.
4 files modified
130 ■■■■■ changed files
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/util/Iterables.java 72 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/AttributeFilter.java 42 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/MemoryBackendTestCase.java 12 ●●●●● patch | view | raw | blame | history
opendj-sdk/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.
opendj-sdk/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;
    }
}
opendj-sdk/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);
opendj-sdk/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 =