From a2d67f674f7e80dcd9ca901ea63df41ef47f4214 Mon Sep 17 00:00:00 2001
From: vharseko <vharseko@openam.org.ru>
Date: Wed, 22 Nov 2017 05:08:57 +0000
Subject: [PATCH] Merge pull request #3 from GuyPaddock/wren/feature/subtree-flattening

---
 opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java |   72 +++++++++++++++++++++++++++++++++++-
 1 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
index 7cec13f..f731a1b 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceImpl.java
@@ -12,6 +12,7 @@
  * information: "Portions Copyright [year] [name of copyright owner]".
  *
  * Copyright 2012-2016 ForgeRock AS.
+ * Portions Copyright 2017 Rosie Applications, Inc.
  */
 package org.forgerock.opendj.rest2ldap;
 
@@ -31,7 +32,6 @@
 import static org.forgerock.opendj.ldap.ByteString.valueOfBytes;
 import static org.forgerock.opendj.ldap.Filter.alwaysFalse;
 import static org.forgerock.opendj.ldap.Filter.alwaysTrue;
-import static org.forgerock.opendj.ldap.SearchScope.SINGLE_LEVEL;
 import static org.forgerock.opendj.ldap.requests.Requests.*;
 import static org.forgerock.opendj.rest2ldap.ReadOnUpdatePolicy.CONTROLS;
 import static org.forgerock.opendj.rest2ldap.RoutingContext.newCollectionRoutingContext;
@@ -140,9 +140,17 @@
     private final boolean usePermissiveModify;
     private final Resource resource;
     private final Attribute glueObjectClasses;
+    private final boolean flattenSubtree;
+    private final Filter baseSearchFilter;
 
     SubResourceImpl(final Rest2Ldap rest2Ldap, final DN baseDn, final Attribute glueObjectClasses,
                     final NamingStrategy namingStrategy, final Resource resource) {
+        this(rest2Ldap, baseDn, glueObjectClasses, namingStrategy, resource, false, null);
+    }
+
+    SubResourceImpl(final Rest2Ldap rest2Ldap, final DN baseDn, final Attribute glueObjectClasses,
+                    final NamingStrategy namingStrategy, final Resource resource,
+                    final boolean flattenSubtree, final Filter baseSearchFilter) {
         this.readOnUpdatePolicy = rest2Ldap.getOptions().get(READ_ON_UPDATE_POLICY);
         this.useSubtreeDelete = rest2Ldap.getOptions().get(USE_SUBTREE_DELETE);
         this.usePermissiveModify = rest2Ldap.getOptions().get(USE_PERMISSIVE_MODIFY);
@@ -153,6 +161,8 @@
         this.glueObjectClasses = glueObjectClasses;
         this.namingStrategy = namingStrategy;
         this.resource = resource;
+        this.flattenSubtree = flattenSubtree;
+        this.baseSearchFilter = baseSearchFilter;
     }
 
     Promise<ActionResponse, ResourceException> action(
@@ -504,9 +514,34 @@
     Promise<QueryResponse, ResourceException> query(
             final Context context, final QueryRequest request, final QueryResourceHandler resourceHandler) {
         return getLdapFilter(context, request.getQueryFilter())
+                .then(applyBaseSearchFilter())
                 .thenAsync(runQuery(context, request, resourceHandler));
     }
 
+    /**
+     * Generates a function that applies any base filter that this sub-resource may have been
+     * initialized with.
+     *
+     * @return  The function to invoke to apply a base filter, if one has been specified.
+     */
+    private Function<Filter, Filter, ResourceException> applyBaseSearchFilter() {
+        return new Function<Filter, Filter, ResourceException>() {
+            @Override
+            public Filter apply(final Filter requestFilter) throws ResourceException {
+                final Filter baseSearchFilter = SubResourceImpl.this.baseSearchFilter,
+                             searchFilter;
+
+                if (baseSearchFilter != null) {
+                    searchFilter = Filter.and(baseSearchFilter, requestFilter);
+                } else {
+                    searchFilter = requestFilter;
+                }
+
+                return searchFilter;
+            }
+        };
+    }
+
     // FIXME: supporting assertions against sub-type properties.
     private Promise<Filter, ResourceException> getLdapFilter(
             final Context context, final QueryFilter<JsonPointer> queryFilter) {
@@ -523,6 +558,7 @@
                     public Promise<Filter, ResourceException> visitAndFilter(
                             final Void unused, final List<QueryFilter<JsonPointer>> subFilters) {
                         final List<Promise<Filter, ResourceException>> promises = new ArrayList<>(subFilters.size());
+
                         for (final QueryFilter<JsonPointer> subFilter : subFilters) {
                             promises.add(subFilter.accept(this, unused));
                         }
@@ -532,14 +568,17 @@
                             public Filter apply(final List<Filter> value) {
                                 // Check for unmapped filter components and optimize.
                                 final Iterator<Filter> i = value.iterator();
+
                                 while (i.hasNext()) {
                                     final Filter f = i.next();
+
                                     if (f == alwaysFalse()) {
                                         return alwaysFalse();
                                     } else if (f == alwaysTrue()) {
                                         i.remove();
                                     }
                                 }
+
                                 switch (value.size()) {
                                 case 0:
                                     return alwaysTrue();
@@ -673,6 +712,7 @@
                                 parentDnAndType, resource, ROOT, field, STARTS_WITH, null, valueAssertion);
                     }
                 };
+        
         // Note that the returned LDAP filter may be null if it could not be mapped by any property mappers.
         return queryFilter.accept(visitor, null);
     }
@@ -700,7 +740,7 @@
                 final String[] attributes = getLdapAttributesForUnknownType(request.getFields()).toArray(new String[0]);
                 final Filter searchFilter = ldapFilter == Filter.alwaysTrue() ? Filter.objectClassPresent()
                         : ldapFilter;
-                final SearchRequest searchRequest = newSearchRequest(baseDn, SINGLE_LEVEL, searchFilter, attributes);
+                final SearchRequest searchRequest = createSearchRequest(searchFilter, attributes);
 
                 // Add the page results control. We can support the page offset by reading the next offset pages, or
                 // offset x page size resources.
@@ -1064,6 +1104,34 @@
         return namingStrategy.createSearchRequest(baseDn, resourceId).addAttribute(attributes);
     }
 
+    /**
+     * Creates a request to search LDAP for entries that match the provided search filter, and
+     * the specified attributes.
+     *
+     * If the subtree flattening is enabled, the search request will encompass the whole subtree.
+     *
+     * @param   searchFilter
+     *          The filter that entries must match to be returned.
+     * @param   desiredAttributes
+     *          The names of the attributes to be included with each entry.
+     *
+     * @return  The resulting search request.
+     */
+    private SearchRequest createSearchRequest(Filter searchFilter, String[] desiredAttributes) {
+        final SearchScope searchScope;
+        final SearchRequest searchRequest;
+
+        if (SubResourceImpl.this.flattenSubtree) {
+            searchScope = SearchScope.SUBORDINATES;
+        } else {
+            searchScope = SearchScope.SINGLE_LEVEL;
+        }
+
+        searchRequest = newSearchRequest(baseDn, searchScope, searchFilter, desiredAttributes);
+
+        return searchRequest;
+    }
+
     @SuppressWarnings("unused")
     private static <R> AsyncFunction<LdapException, R, ResourceException> adaptLdapException(final Class<R> clazz) {
         return new AsyncFunction<LdapException, R, ResourceException>() {

--
Gitblit v1.10.0