From 1df4f51adf614210ca4a9b9728327090ec5ea264 Mon Sep 17 00:00:00 2001
From: Gaetan Boismal <gaetan.boismal@forgerock.com>
Date: Fri, 11 Sep 2015 20:33:53 +0000
Subject: [PATCH] OPENDJ-1666 PR-19 CREST-3.0.0 Migration

---
 opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java |  330 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 169 insertions(+), 161 deletions(-)

diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
index a0f515c..f259cb2 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java
@@ -15,6 +15,12 @@
  */
 package org.forgerock.opendj.rest2ldap;
 
+import static org.forgerock.opendj.ldap.LdapException.newLdapException;
+import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.asResourceException;
+import static org.forgerock.opendj.rest2ldap.Utils.ensureNotNull;
+import static org.forgerock.opendj.rest2ldap.Utils.i18n;
+
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
@@ -23,19 +29,19 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.forgerock.json.fluent.JsonPointer;
-import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.JsonPointer;
+import org.forgerock.json.JsonValue;
 import org.forgerock.json.resource.BadRequestException;
 import org.forgerock.json.resource.ResourceException;
-import org.forgerock.json.resource.ResultHandler;
 import org.forgerock.opendj.ldap.Attribute;
 import org.forgerock.opendj.ldap.AttributeDescription;
 import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.Connection;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.Entry;
 import org.forgerock.opendj.ldap.EntryNotFoundException;
-import org.forgerock.opendj.ldap.LdapException;
 import org.forgerock.opendj.ldap.Filter;
+import org.forgerock.opendj.ldap.LdapException;
 import org.forgerock.opendj.ldap.LinkedAttribute;
 import org.forgerock.opendj.ldap.MultipleEntriesFoundException;
 import org.forgerock.opendj.ldap.ResultCode;
@@ -45,14 +51,13 @@
 import org.forgerock.opendj.ldap.responses.Result;
 import org.forgerock.opendj.ldap.responses.SearchResultEntry;
 import org.forgerock.opendj.ldap.responses.SearchResultReference;
+import org.forgerock.util.AsyncFunction;
 import org.forgerock.util.Function;
-import org.forgerock.util.promise.NeverThrowsException;
 import org.forgerock.util.promise.ExceptionHandler;
-
-import static org.forgerock.opendj.ldap.LdapException.*;
-import static org.forgerock.opendj.ldap.requests.Requests.*;
-import static org.forgerock.opendj.rest2ldap.Rest2LDAP.*;
-import static org.forgerock.opendj.rest2ldap.Utils.*;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.forgerock.util.promise.Promises;
+import org.forgerock.util.promise.ResultHandler;
 
 /**
  * An attribute mapper which provides a mapping from a JSON value to a single DN
@@ -125,64 +130,67 @@
     }
 
     @Override
-    void getLDAPFilter(final Context c, final JsonPointer path, final JsonPointer subPath, final FilterType type,
-        final String operator, final Object valueAssertion, final ResultHandler<Filter> h) {
-        // Construct a filter which can be used to find referenced resources.
-        mapper.getLDAPFilter(c, path, subPath, type, operator, valueAssertion, new ResultHandler<Filter>() {
-            @Override
-            public void handleError(final ResourceException error) {
-                h.handleError(error); // Propagate.
-            }
+    Promise<Filter, ResourceException> getLDAPFilter(final RequestState requestState, final JsonPointer path,
+            final JsonPointer subPath, final FilterType type, final String operator, final Object valueAssertion) {
 
-            @Override
-            public void handleResult(final Filter result) {
-                // Search for all referenced entries and construct a filter.
-                final SearchRequest request = createSearchRequest(result);
-                final List<Filter> subFilters = new LinkedList<>();
+        return mapper.getLDAPFilter(requestState, path, subPath, type, operator, valueAssertion)
+                .thenAsync(new AsyncFunction<Filter, Filter, ResourceException>() {
+                    @Override
+                    public Promise<Filter, ResourceException> apply(final Filter result) {
+                        // Search for all referenced entries and construct a filter.
+                        final SearchRequest request = createSearchRequest(result);
+                        final List<Filter> subFilters = new LinkedList<>();
 
-                final ExceptionHandler<LdapException> exceptionHandler = new ExceptionHandler<LdapException>() {
-                    @Override
-                    public void handleException(LdapException exception) {
-                        h.handleError(asResourceException(exception)); // Propagate.
-                    }
-                };
+                        return requestState.getConnection().thenAsync(
+                                new AsyncFunction<Connection, Filter, ResourceException>() {
+                                    @Override
+                                    public Promise<Filter, ResourceException> apply(final Connection connection)
+                                            throws ResourceException {
+                                        return connection.searchAsync(request, new SearchResultHandler() {
+                                            @Override
+                                            public boolean handleEntry(final SearchResultEntry entry) {
+                                                if (subFilters.size() < SEARCH_MAX_CANDIDATES) {
+                                                    subFilters.add(Filter.equality(
+                                                            ldapAttributeName.toString(), entry.getName()));
+                                                    return true;
+                                                } else {
+                                                    // No point in continuing - maximum candidates reached.
+                                                    return false;
+                                                }
+                                            }
 
-                c.getConnection().searchAsync(request, new SearchResultHandler() {
-                    @Override
-                    public boolean handleEntry(final SearchResultEntry entry) {
-                        if (subFilters.size() < SEARCH_MAX_CANDIDATES) {
-                            subFilters.add(Filter.equality(ldapAttributeName.toString(), entry.getName()));
-                            return true;
-                        } else {
-                            // No point in continuing - maximum candidates reached.
-                            return false;
-                        }
+                                            @Override
+                                            public boolean handleReference(final SearchResultReference reference) {
+                                                // Ignore references.
+                                                return true;
+                                            }
+                                        }).then(new Function<Result, Filter, ResourceException>() {
+                                            @Override
+                                            public Filter apply(Result result) throws ResourceException {
+                                                if (subFilters.size() >= SEARCH_MAX_CANDIDATES) {
+                                                    throw asResourceException(
+                                                            newLdapException(ResultCode.ADMIN_LIMIT_EXCEEDED));
+                                                } else if (subFilters.size() == 1) {
+                                                    return subFilters.get(0);
+                                                } else {
+                                                    return Filter.or(subFilters);
+                                                }
+                                            }
+                                        }, new Function<LdapException, Filter, ResourceException>() {
+                                            @Override
+                                            public Filter apply(LdapException exception) throws ResourceException {
+                                                throw asResourceException(exception);
+                                            }
+                                        });
+                                    }
+                                });
                     }
-
-                    @Override
-                    public boolean handleReference(final SearchResultReference reference) {
-                        // Ignore references.
-                        return true;
-                    }
-                }).thenOnResult(new org.forgerock.util.promise.ResultHandler<Result>() {
-                    @Override
-                    public void handleResult(Result result) {
-                        if (subFilters.size() >= SEARCH_MAX_CANDIDATES) {
-                            exceptionHandler.handleException(newLdapException(ResultCode.ADMIN_LIMIT_EXCEEDED));
-                        } else if (subFilters.size() == 1) {
-                            h.handleResult(subFilters.get(0));
-                        } else {
-                            h.handleResult(Filter.or(subFilters));
-                        }
-                    }
-                }).thenOnException(exceptionHandler);
-            }
-        });
+                });
     }
 
     @Override
-    void getNewLDAPAttributes(final Context c, final JsonPointer path, final List<Object> newValues,
-        final ResultHandler<Attribute> h) {
+    Promise<Attribute, ResourceException> getNewLDAPAttributes(
+            final RequestState requestState, final JsonPointer path, final List<Object> newValues) {
         /*
          * For each value use the subordinate mapper to obtain the LDAP primary
          * key, the perform a search for each one to find the corresponding entries.
@@ -190,17 +198,12 @@
         final Attribute newLDAPAttribute = new LinkedAttribute(ldapAttributeName);
         final AtomicInteger pendingSearches = new AtomicInteger(newValues.size());
         final AtomicReference<ResourceException> exception = new AtomicReference<>();
+        final PromiseImpl<Attribute, ResourceException> promise = PromiseImpl.create();
 
         for (final Object value : newValues) {
-            mapper.create(c, path, new JsonValue(value), new ResultHandler<List<Attribute>>() {
-
+            mapper.create(requestState, path, new JsonValue(value)).thenOnResult(new ResultHandler<List<Attribute>>() {
                 @Override
-                public void handleError(final ResourceException error) {
-                    h.handleError(error);
-                }
-
-                @Override
-                public void handleResult(final List<Attribute> result) {
+                public void handleResult(List<Attribute> result) {
                     Attribute primaryKeyAttribute = null;
                     for (final Attribute attribute : result) {
                         if (attribute.getAttributeDescription().equals(primaryKey)) {
@@ -210,68 +213,72 @@
                     }
 
                     if (primaryKeyAttribute == null || primaryKeyAttribute.isEmpty()) {
-                        h.handleError(new BadRequestException(i18n(
-                            "The request cannot be processed because the reference "
-                                + "field '%s' contains a value which does not contain " + "a primary key", path)));
-                        return;
+                        promise.handleException(new BadRequestException(
+                                i18n("The request cannot be processed because the reference field '%s' contains "
+                                        + "a value which does not contain a primary key", path)));
                     }
 
                     if (primaryKeyAttribute.size() > 1) {
-                        h.handleError(new BadRequestException(i18n(
-                            "The request cannot be processed because the reference "
-                                + "field '%s' contains a value which contains multiple " + "primary keys", path)));
-                        return;
+                        promise.handleException(new BadRequestException(
+                                i18n("The request cannot be processed because the reference field '%s' contains "
+                                        + "a value which contains multiple primary keys", path)));
                     }
 
                     // Now search for the referenced entry in to get its DN.
                     final ByteString primaryKeyValue = primaryKeyAttribute.firstValue();
                     final Filter filter = Filter.equality(primaryKey.toString(), primaryKeyValue);
                     final SearchRequest search = createSearchRequest(filter);
-                    c.getConnection().searchSingleEntryAsync(search).thenOnResult(
-                            new org.forgerock.util.promise.ResultHandler<SearchResultEntry>() {
-                            @Override
-                            public void handleResult(final SearchResultEntry result) {
-                                synchronized (newLDAPAttribute) {
-                                    newLDAPAttribute.add(result.getName());
-                                }
-                                completeIfNecessary();
-                            }
-                        }).thenOnException(new ExceptionHandler<LdapException>() {
-                            @Override
-                            public void handleException(final LdapException error) {
-                                ResourceException re;
-                                try {
-                                    throw error;
-                                } catch (final EntryNotFoundException e) {
-                                    re = new BadRequestException(i18n(
-                                            "The request cannot be processed " + "because the resource '%s' "
-                                                    + "referenced in field '%s' does " + "not exist",
-                                            primaryKeyValue.toString(), path));
-                                } catch (final MultipleEntriesFoundException e) {
-                                    re = new BadRequestException(i18n(
-                                            "The request cannot be processed " + "because the resource '%s' "
-                                                    + "referenced in field '%s' is " + "ambiguous",
-                                            primaryKeyValue.toString(), path));
-                                } catch (final LdapException e) {
-                                    re = asResourceException(e);
-                                }
-                                exception.compareAndSet(null, re);
-                                completeIfNecessary();
-                            }
-                        });
+                    requestState.getConnection().thenOnResult(new ResultHandler<Connection>() {
+                        @Override
+                        public void handleResult(Connection connection) {
+                            connection.searchSingleEntryAsync(search)
+                                      .thenOnResult(new ResultHandler<SearchResultEntry>() {
+                                          @Override
+                                          public void handleResult(final SearchResultEntry result) {
+                                              synchronized (newLDAPAttribute) {
+                                                  newLDAPAttribute.add(result.getName());
+                                              }
+                                              completeIfNecessary();
+                                          }
+                                      }).thenOnException(new ExceptionHandler<LdapException>() {
+                                          @Override
+                                          public void handleException(final LdapException error) {
+                                              ResourceException re;
+                                              try {
+                                                  throw error;
+                                              } catch (final EntryNotFoundException e) {
+                                                  re = new BadRequestException(i18n(
+                                                          "The request cannot be processed because the resource "
+                                                          + "'%s' referenced in field '%s' does not exist",
+                                                          primaryKeyValue.toString(), path));
+                                              } catch (final MultipleEntriesFoundException e) {
+                                                  re = new BadRequestException(i18n(
+                                                          "The request cannot be processed because the resource "
+                                                          + "'%s' referenced in field '%s' is ambiguous",
+                                                          primaryKeyValue.toString(), path));
+                                              } catch (final LdapException e) {
+                                                  re = asResourceException(e);
+                                              }
+                                              exception.compareAndSet(null, re);
+                                              completeIfNecessary();
+                                          }
+                                      });
+                        }
+                    });
                 }
 
                 private void completeIfNecessary() {
                     if (pendingSearches.decrementAndGet() == 0) {
                         if (exception.get() != null) {
-                            h.handleError(exception.get());
+                            promise.handleException(exception.get());
                         } else {
-                            h.handleResult(newLDAPAttribute);
+                            promise.handleResult(newLDAPAttribute);
                         }
                     }
                 }
             });
         }
+        return promise;
     }
 
     @Override
@@ -280,47 +287,47 @@
     }
 
     @Override
-    void read(final Context c, final JsonPointer path, final Entry e, final ResultHandler<JsonValue> h) {
+    Promise<JsonValue, ResourceException> read(final RequestState c, final JsonPointer path, final Entry e) {
         final Attribute attribute = e.getAttribute(ldapAttributeName);
         if (attribute == null || attribute.isEmpty()) {
-            h.handleResult(null);
+            return Promises.newResultPromise(null);
         } else if (attributeIsSingleValued()) {
             try {
                 final DN dn = attribute.parse().usingSchema(c.getConfig().schema()).asDN();
-                readEntry(c, path, dn, h);
+                return readEntry(c, path, dn);
             } catch (final Exception ex) {
                 // The LDAP attribute could not be decoded.
-                h.handleError(asResourceException(ex));
+                return Promises.newExceptionPromise(asResourceException(ex));
             }
         } else {
             try {
                 final Set<DN> dns = attribute.parse().usingSchema(c.getConfig().schema()).asSetOfDN();
-                final ResultHandler<JsonValue> handler =
-                    accumulate(dns.size(), transform(new Function<List<JsonValue>, JsonValue, NeverThrowsException>() {
-                        @Override
-                        public JsonValue apply(final List<JsonValue> value) {
-                            if (value.isEmpty()) {
-                                /*
-                                 * No values, so omit the entire JSON object
-                                 * from the resource.
-                                 */
-                                return null;
-                            } else {
-                                // Combine values into a single JSON array.
-                                final List<Object> result = new ArrayList<>(value.size());
-                                for (final JsonValue e : value) {
-                                    result.add(e.getObject());
-                                }
-                                return new JsonValue(result);
-                            }
-                        }
-                    }, h));
+
+                final List<Promise<JsonValue, ResourceException>> promises = new ArrayList<>(dns.size());
                 for (final DN dn : dns) {
-                    readEntry(c, path, dn, handler);
+                    promises.add(readEntry(c, path, dn));
                 }
+
+                return Promises.when(promises)
+                               .then(new Function<List<JsonValue>, JsonValue, ResourceException>() {
+                                   @Override
+                                   public JsonValue apply(final List<JsonValue> value) {
+                                       if (value.isEmpty()) {
+                                           // No values, so omit the entire JSON object from the resource.
+                                           return null;
+                                       } else {
+                                           // Combine values into a single JSON array.
+                                           final List<Object> result = new ArrayList<>(value.size());
+                                           for (final JsonValue e : value) {
+                                               result.add(e.getObject());
+                                           }
+                                           return new JsonValue(result);
+                                       }
+                                   }
+                               });
             } catch (final Exception ex) {
                 // The LDAP attribute could not be decoded.
-                h.handleError(asResourceException(ex));
+                return Promises.newExceptionPromise(asResourceException(ex));
             }
         }
     }
@@ -330,30 +337,31 @@
         return newSearchRequest(baseDN, scope, searchFilter, "1.1");
     }
 
-    private void readEntry(final Context c, final JsonPointer path, final DN dn,
-        final ResultHandler<JsonValue> handler) {
+    private Promise<JsonValue, ResourceException> readEntry(
+            final RequestState requestState, final JsonPointer path, final DN dn) {
         final Set<String> requestedLDAPAttributes = new LinkedHashSet<>();
-        mapper.getLDAPAttributes(c, path, new JsonPointer(), requestedLDAPAttributes);
-        c.getConnection().readEntryAsync(dn, requestedLDAPAttributes)
-                .thenOnResult(new org.forgerock.util.promise.ResultHandler<SearchResultEntry>() {
-                    @Override
-                    public void handleResult(final SearchResultEntry result) {
-                        mapper.read(c, path, result, handler);
-                    }
-                }).thenOnException(new ExceptionHandler<LdapException>() {
-                    @Override
-                    public void handleException(final LdapException error) {
-                        if (!(error instanceof EntryNotFoundException)) {
-                            handler.handleError(asResourceException(error));
-                        } else {
-                            /*
-                             * The referenced entry does not exist so ignore it
-                             * since it cannot be mapped.
-                             */
-                            handler.handleResult(null);
-                        }
-                    }
-                });
+        mapper.getLDAPAttributes(requestState, path, new JsonPointer(), requestedLDAPAttributes);
+        return requestState.getConnection().thenAsync(new AsyncFunction<Connection, JsonValue, ResourceException>() {
+            @Override
+            public Promise<JsonValue, ResourceException> apply(Connection connection) throws ResourceException {
+                return connection.readEntryAsync(dn, requestedLDAPAttributes)
+                        .thenAsync(new AsyncFunction<SearchResultEntry, JsonValue, ResourceException>() {
+                            @Override
+                            public Promise<JsonValue, ResourceException> apply(final SearchResultEntry result) {
+                                return mapper.read(requestState, path, result);
+                            }
+                        }, new AsyncFunction<LdapException, JsonValue, ResourceException>() {
+                            @Override
+                            public Promise<JsonValue, ResourceException> apply(final LdapException error) {
+                                if (!(error instanceof EntryNotFoundException)) {
+                                    return Promises.newExceptionPromise(asResourceException(error));
+                                } else {
+                                    // The referenced entry does not exist so ignore it since it cannot be mapped.
+                                    return Promises.newResultPromise(null);
+                                }
+                            }
+                        });
+            }
+        });
     }
-
 }

--
Gitblit v1.10.0