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