From 45141fb11ef698b11c6fb3becca82ca10e11505a Mon Sep 17 00:00:00 2001
From: Gaetan Boismal <gaetan.boismal@forgerock.com>
Date: Mon, 15 Sep 2014 12:50:50 +0000
Subject: [PATCH] OPENDJ-1285 CR-4409 Migrate SDK from Futures to Promises
---
opendj-core/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java | 39
opendj-core/src/main/java/org/forgerock/opendj/ldap/Connection.java | 282 +
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java | 175
opendj-core/clirr-ignored-api-changes.xml | 56
opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java | 36
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java | 34
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java | 79
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactoryTestCase.java | 187
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/AbstractLDAPFutureResultImpl.java | 72
opendj-core/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java | 17
opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java | 8
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java | 25
opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractSynchronousConnection.java | 82
opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java | 9
opendj-core/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java | 8
opendj-core/src/main/java/org/forgerock/opendj/ldap/RootDSE.java | 29
opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java | 118
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java | 165
opendj-core/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java | 62
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java | 34
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReferenceAttributeMapper.java | 270 +-
opendj-core/src/test/java/org/forgerock/opendj/ldif/ConnectionEntryReaderTestCase.java | 60
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java | 20
opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResult.java | 87
opendj-core/src/test/java/org/forgerock/opendj/ldap/ConnectionPoolTestCase.java | 58
opendj-core/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java | 533 +--
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java | 55
opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java | 50
opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java | 72
opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java | 18
opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java | 25
opendj-core/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java | 5
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java | 117
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java | 383 +--
opendj-core/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java | 16
opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultWrapper.java | 281 ++
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java | 66
opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPAuthnFilter.java | 192
opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java | 10
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AddRate.java | 29
opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java | 458 +--
opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultImpl.java | 64
opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnection.java | 75
opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java | 299 +-
opendj-server3x-adapter/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java | 21
pom.xml | 2
opendj-core/src/main/java/org/forgerock/opendj/ldap/Connections.java | 12
opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java | 263 -
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java | 10
opendj-core/src/test/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactoryTestCase.java | 158
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java | 62
opendj-core/src/main/java/org/forgerock/opendj/ldap/CachedConnectionPool.java | 229 +
opendj-server2x-adapter/src/main/java/org/forgerock/opendj/adapter/server2x/Adapters.java | 23
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPFutureResultImpl.java | 8
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java | 144
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java | 20
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPBindFutureResultImpl.java | 11
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPCompareFutureResultImpl.java | 12
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java | 78
opendj-core/src/test/java/org/forgerock/opendj/ldap/spi/BasicLDAPConnectionFactory.java | 21
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java | 44
opendj-core/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java | 105
opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java | 13
opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java | 17
opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java | 18
/dev/null | 132 -
opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnectionWrapper.java | 179 +
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPExtendedFutureResultImpl.java | 14
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java | 762 +++---
opendj-cli/src/main/java/com/forgerock/opendj/cli/AuthenticatedConnectionFactory.java | 165
opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java | 75
opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPSearchFutureResultImpl.java | 12
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionTestCase.java | 11
73 files changed, 3,441 insertions(+), 3,940 deletions(-)
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/AuthenticatedConnectionFactory.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/AuthenticatedConnectionFactory.java
index 82c61d5..2e11886 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/AuthenticatedConnectionFactory.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/AuthenticatedConnectionFactory.java
@@ -26,20 +26,24 @@
*/
package com.forgerock.opendj.cli;
-import org.forgerock.opendj.ldap.Connection;
+import java.util.concurrent.atomic.AtomicReference;
+
import org.forgerock.opendj.ldap.AbstractConnectionWrapper;
+import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Function;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
-
+import static org.forgerock.util.Utils.*;
/**
* An authenticated connection factory can be used to create pre-authenticated
* connections to a Directory Server.
@@ -83,19 +87,21 @@
* These methods will always throw {@code UnsupportedOperationException}.
*/
/** {@inheritDoc} */
+ @Override
public BindResult bind(BindRequest request) throws ErrorResultException {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
+ @Override
public BindResult bind(String name, char[] password) throws ErrorResultException {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
+ @Override
public FutureResult<BindResult> bindAsync(BindRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super BindResult> resultHandler) {
+ IntermediateResponseHandler intermediateResponseHandler) {
throw new UnsupportedOperationException();
}
@@ -115,10 +121,6 @@
* associated with this connection. If re-authentication fails for some
* reason then this connection will be automatically closed.
*
- * @param handler
- * A result handler which can be used to asynchronously
- * process the operation result when it is received, may be
- * {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support rebind operations.
@@ -126,45 +128,27 @@
* If this connection has already been closed, i.e. if
* {@code isClosed() == true}.
*/
- public FutureResult<BindResult> rebindAsync(final ResultHandler<? super BindResult> handler) {
+ public FutureResult<BindResult> rebindAsync() {
if (request == null) {
throw new UnsupportedOperationException();
}
- /*
- * Wrap the client handler so that we can update the connection
- * state.
- */
- final ResultHandler<? super BindResult> clientHandler = handler;
-
- final ResultHandler<BindResult> handlerWrapper = new ResultHandler<BindResult>() {
-
- /** {@inheritDoc} */
- public void handleErrorResult(final ErrorResultException error) {
- /*
- * This connection is now unauthenticated so prevent further
- * use.
- */
- connection.close();
-
- if (clientHandler != null) {
- clientHandler.handleErrorResult(error);
- }
- }
-
- /** {@inheritDoc} */
- public void handleResult(final BindResult result) {
- // Save the result.
- AuthenticatedConnection.this.result = result;
-
- if (clientHandler != null) {
- clientHandler.handleResult(result);
- }
- }
-
- };
-
- return connection.bindAsync(request, null, handlerWrapper);
+ return (FutureResult<BindResult>) connection.bindAsync(request)
+ .onSuccess(new SuccessHandler<BindResult>() {
+ @Override
+ public void handleResult(final BindResult result) {
+ // Save the result.
+ AuthenticatedConnection.this.result = result;
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ /*
+ * This connection is now unauthenticated so prevent further use.
+ */
+ connection.close();
+ }
+ });
}
/**
@@ -172,6 +156,7 @@
*
* @return The string representation of this authenticated connection factory.
*/
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AuthenticatedConnection(");
@@ -182,56 +167,9 @@
}
- private static final class FutureResultImpl {
- private final FutureResultTransformer<BindResult, Connection> futureBindResult;
- private final RecursiveFutureResult<Connection, BindResult> futureConnectionResult;
- private final BindRequest bindRequest;
- private Connection connection;
-
- private FutureResultImpl(final BindRequest request,
- final ResultHandler<? super Connection> handler) {
- this.bindRequest = request;
- this.futureBindResult = new FutureResultTransformer<BindResult, Connection>(handler) {
-
- @Override
- protected ErrorResultException transformErrorResult(
- final ErrorResultException errorResult) {
- // Ensure that the connection is closed.
- if (connection != null) {
- connection.close();
- connection = null;
- }
- return errorResult;
- }
-
- @Override
- protected AuthenticatedConnection transformResult(final BindResult result)
- throws ErrorResultException {
- // FIXME: should make the result unmodifiable.
- return new AuthenticatedConnection(connection, bindRequest, result);
- }
-
- };
- this.futureConnectionResult =
- new RecursiveFutureResult<Connection, BindResult>(futureBindResult) {
-
- @Override
- protected FutureResult<? extends BindResult> chainResult(
- final Connection innerResult,
- final ResultHandler<? super BindResult> handler)
- throws ErrorResultException {
- connection = innerResult;
- return connection.bindAsync(bindRequest, null, handler);
- }
- };
- futureBindResult.setFutureResult(futureConnectionResult);
- }
-
- }
-
private final BindRequest request;
private final ConnectionFactory parentFactory;
- private boolean allowRebinds = false;
+ private boolean allowRebinds;
/**
* Creates a new authenticated connection factory which will obtain
@@ -260,6 +198,7 @@
}
/** {@inheritDoc} */
+ @Override
public Connection getConnection() throws ErrorResultException {
final Connection connection = parentFactory.getConnection();
BindResult bindResult = null;
@@ -279,12 +218,35 @@
}
/** {@inheritDoc} */
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
- final FutureResultImpl future = new FutureResultImpl(request, handler);
- future.futureConnectionResult.setFutureResult(parentFactory
- .getConnectionAsync(future.futureConnectionResult));
- return future.futureBindResult;
+ @Override
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ return parentFactory.getConnectionAsync()
+ .thenAsync(
+ new AsyncFunction<Connection, BindResult, ErrorResultException>() {
+ @Override
+ public Promise<BindResult, ErrorResultException> apply(final Connection connection)
+ throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.bindAsync(request);
+ }
+ }
+ ).then(
+ new Function<BindResult, Connection, ErrorResultException>() {
+ @Override
+ public Connection apply(BindResult result) throws ErrorResultException {
+ // FIXME: should make the result unmodifiable.
+ return new AuthenticatedConnection(connectionHolder.get(), request, result);
+ }
+ },
+ new Function<ErrorResultException, Connection, ErrorResultException>() {
+ @Override
+ public Connection apply(ErrorResultException errorResult) throws ErrorResultException {
+ closeSilently(connectionHolder.get());
+ throw errorResult;
+ }
+ }
+ );
}
/**
@@ -325,10 +287,11 @@
*
* @return The string representation of this authenticated connection factory.
*/
+ @Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("AuthenticatedConnectionFactory(");
- builder.append(String.valueOf(parentFactory));
+ builder.append(parentFactory);
builder.append(')');
return builder.toString();
}
diff --git a/opendj-core/clirr-ignored-api-changes.xml b/opendj-core/clirr-ignored-api-changes.xml
index e32115d..458dcca 100644
--- a/opendj-core/clirr-ignored-api-changes.xml
+++ b/opendj-core/clirr-ignored-api-changes.xml
@@ -222,5 +222,59 @@
<method>boolean isIndexingSupported()</method>
<justification>OPENDJ-1308 Migrate schema support: allows decoupling indexing from a specific backend</justification>
</difference>
-
+ <difference>
+ <className>org/forgerock/opendj/ldap/*Connection*</className>
+ <differenceType>7004</differenceType>
+ <method>org.forgerock.opendj.ldap.FutureResult *Async(*org.forgerock.opendj.ldap.ResultHandler)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/schema/Schema</className>
+ <differenceType>7004</differenceType>
+ <method>org.forgerock.opendj.ldap.FutureResult readSchema*Async*(org.forgerock.opendj.ldap.Connection, org.forgerock.opendj.ldap.DN, org.forgerock.opendj.ldap.ResultHandler)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/*Connection*</className>
+ <differenceType>7006</differenceType>
+ <method>org.forgerock.opendj.ldap.FutureResult *Async(*org.forgerock.opendj.ldap.ResultHandler)</method>
+ <to>org.forgerock.util.promise.Promise</to>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/Connection</className>
+ <differenceType>7012</differenceType>
+ <method>org.forgerock.opendj.ldap.FutureResult *Async(org.forgerock.opendj.*)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>%regex[org/forgerock/opendj/ldap/(RequestHandler|MemoryBackend)]</className>
+ <differenceType>7004</differenceType>
+ <method>*handleSearch(*)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/ResultHandler</className>
+ <differenceType>7012</differenceType>
+ <method>*handleError(org.forgerock.opendj.ldap.ErrorResultException)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/ResultHandler</className>
+ <differenceType>7002</differenceType>
+ <method>*handleErrorResult(org.forgerock.opendj.ldap.ErrorResultException)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/SearchResultHandler</className>
+ <differenceType>4001</differenceType>
+ <to>org/forgerock/opendj/ldap/ResultHandler</to>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/schema/SchemaBuilder</className>
+ <differenceType>7004</differenceType>
+ <method>org.forgerock.opendj.ldap.FutureResult addSchema*Async(*)</method>
+ <justification>OPENDJ-1285 Migrate SDK from Futures to Promises</justification>
+ </difference>
</differences>
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/AsynchronousFutureResult.java b/opendj-core/src/main/java/com/forgerock/opendj/util/AsynchronousFutureResult.java
deleted file mode 100644
index 3e76e12..0000000
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/AsynchronousFutureResult.java
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2013-2014 ForgeRock AS.
- */
-
-package com.forgerock.opendj.util;
-
-import static org.forgerock.opendj.ldap.ErrorResultException.*;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer;
-
-import org.forgerock.opendj.ldap.CancelledResultException;
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
-
-/**
- * This class provides a skeletal implementation of the {@code FutureResult}
- * interface, to minimize the effort required to implement this interface.
- * <p>
- * This {@code FutureResult} implementation provides the following features:
- * <ul>
- * <li>The {@link #get} methods throw {@link ErrorResultException}s instead of
- * the more generic {@code ExecutionException}s.
- * <li>The {@link #get} methods never throw {@code CancellationException} since
- * requests in this SDK can usually be cancelled via other external means (e.g.
- * the {@code Cancel} extended operation) for which there are well defined error
- * results. Therefore cancellation is always signalled by throwing a
- * {@link CancelledResultException} in order to be consistent with other error
- * results.
- * <li>A {@link ResultHandler} can be provided to the constructor. The result
- * handler will be invoked immediately after the result or error is received but
- * before threads blocked on {@link #get} are released. More specifically,
- * result handler invocation <i>happens-before</i> a call to {@link #get}.
- * <b>NOTE:</b> a result handler which attempts to call {@link #get} will
- * deadlock.
- * <li>Sub-classes may choose to implement specific cancellation cleanup by
- * implementing the {@link #handleCancelRequest} method.
- * </ul>
- *
- * @param <M>
- * The type of result returned by this future.
- * @param <H>
- * The type of {@link ResultHandler} associated to this future.
- */
-public class AsynchronousFutureResult<M, H extends ResultHandler<? super M>> implements
- FutureResult<M>, ResultHandler<M> {
-
- @SuppressWarnings("serial")
- private final class Sync extends AbstractQueuedSynchronizer {
- // State value representing the initial state before a result has
- // been received.
- private static final int WAITING = 0;
-
- // State value representing that a result has been received and is
- // being processed.
- private static final int PENDING = 1;
-
- // State value representing that the request was cancelled.
- private static final int CANCELLED = 2;
-
- // State value representing that the request has failed.
- private static final int FAIL = 3;
-
- // State value representing that the request has succeeded.
- private static final int SUCCESS = 4;
-
- // These do not need to be volatile since their values are published
- // by updating the state after they are set and reading the state
- // immediately before they are read.
- private ErrorResultException errorResult = null;
-
- private M result = null;
-
- /**
- * Allow all threads to acquire if future has completed.
- */
- @Override
- protected int tryAcquireShared(final int ignore) {
- return innerIsDone() ? 1 : -1;
- }
-
- /**
- * Signal that the future has completed and threads waiting on get() can
- * be released.
- */
- @Override
- protected boolean tryReleaseShared(final int finalState) {
- // Ensures that errorResult/result is published.
- setState(finalState);
- return true;
- }
-
- boolean innerCancel(final boolean mayInterruptIfRunning) {
- if (!isCancelable() || !setStatePending()) {
- return false;
- }
-
- // Perform implementation defined cancellation.
- ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning);
- if (errorResult == null) {
- errorResult = newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
- }
- this.errorResult = errorResult;
-
- try {
- // Invoke error result completion handler.
- if (handler != null) {
- handler.handleErrorResult(errorResult);
- }
- } finally {
- releaseShared(CANCELLED); // Publishes errorResult.
- }
-
- return true;
- }
-
- M innerGet() throws ErrorResultException, InterruptedException {
- acquireSharedInterruptibly(0);
- return get0();
- }
-
- M innerGet(final long nanosTimeout) throws ErrorResultException, TimeoutException,
- InterruptedException {
- if (!tryAcquireSharedNanos(0, nanosTimeout)) {
- throw new TimeoutException();
- } else {
- return get0();
- }
- }
-
- boolean innerIsCancelled() {
- return getState() == CANCELLED;
- }
-
- boolean innerIsDone() {
- return getState() > 1;
- }
-
- boolean innerSetErrorResult(final ErrorResultException errorResult) {
- if (!setStatePending()) {
- return false;
- }
- this.errorResult = errorResult;
- try {
- // Invoke error result completion handler.
- if (handler != null) {
- handler.handleErrorResult(errorResult);
- }
- } finally {
- releaseShared(FAIL); // Publishes errorResult.
- }
- return true;
- }
-
- boolean innerSetResult(final M result) {
- if (!setStatePending()) {
- return false;
- }
- this.result = result;
- try {
- // Invoke result completion handler.
- if (handler != null) {
- handler.handleResult(result);
- }
- } finally {
- releaseShared(SUCCESS); // Publishes result.
- }
- return true;
- }
-
- private M get0() throws ErrorResultException {
- if (errorResult != null) {
- // State must be FAILED or CANCELLED.
- throw errorResult;
- } else {
- // State must be SUCCESS.
- return result;
- }
- }
-
- private boolean setStatePending() {
- return compareAndSetState(WAITING, PENDING);
- }
- }
-
- private final Sync sync = new Sync();
-
- private final H handler;
-
- private final int requestID;
-
- /**
- * Creates a new asynchronous future result with the provided result handler
- * and a request ID of -1.
- *
- * @param handler
- * A result handler which will be forwarded the result or error
- * when it arrives, may be {@code null}.
- */
- public AsynchronousFutureResult(final H handler) {
- this(handler, -1);
- }
-
- /**
- * Creates a new asynchronous future result with the provided result handler
- * and request ID.
- *
- * @param handler
- * A result handler which will be forwarded the result or error
- * when it arrives, may be {@code null}.
- * @param requestID
- * The request ID which will be returned by the default
- * implementation of {@link #getRequestID}.
- */
- public AsynchronousFutureResult(final H handler, final int requestID) {
- this.handler = handler;
- this.requestID = requestID;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean cancel(final boolean mayInterruptIfRunning) {
- return sync.innerCancel(mayInterruptIfRunning);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final M get() throws ErrorResultException, InterruptedException {
- return sync.innerGet();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final M get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- return sync.innerGet(unit.toNanos(timeout));
- }
-
- /**
- * Returns the result handler associated to this FutureResult.
- *
- * @return the result handler associated to this FutureResult.
- */
- public H getResultHandler() {
- return handler;
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * The default implementation returns the request ID passed in during
- * construction, or -1 if none was provided.
- */
- @Override
- public int getRequestID() {
- return requestID;
- }
-
- /**
- * Sets the error result associated with this future. If ({@code isDone() ==
- * true}) then the error result will be ignored, otherwise the result
- * handler will be invoked if one was provided and, on return, any threads
- * waiting on {@link #get} will be released and the provided error result
- * will be thrown.
- *
- * @param errorResult
- * The error result.
- */
- @Override
- public final void handleErrorResult(final ErrorResultException errorResult) {
- sync.innerSetErrorResult(errorResult);
- }
-
- /**
- * Sets the result associated with this future. If ({@code isDone() == true}
- * ) then the result will be ignored, otherwise the result handler will be
- * invoked if one was provided and, on return, any threads waiting on
- * {@link #get} will be released and the provided result will be returned.
- *
- * @param result
- * The result.
- */
- @Override
- public final void handleResult(final M result) {
- sync.innerSetResult(result);
- }
-
- /**
- * Attempts to set the error result associated with this future. If (i.e.
- * {@code isDone() == true}) then the error result will be ignored and
- * {@code false} will be returned, otherwise the result handler will be
- * invoked if one was provided and, on returning {@code true}, any threads
- * waiting on {@link #get} will be released and the provided error result
- * will be thrown.
- *
- * @param errorResult
- * The error result.
- * @return {@code false} if this future has already been completed, either
- * due to normal termination, an exception, or cancellation (i.e.
- * {@code isDone() == true}).
- */
- public final boolean tryHandleErrorResult(final ErrorResultException errorResult) {
- return sync.innerSetErrorResult(errorResult);
- }
-
- /**
- * Attempts to set the result associated with this future. If (i.e.
- * {@code isDone() == true}) then the result will be ignored and
- * {@code false} will be returned, otherwise the result handler will be
- * invoked if one was provided and, on returning {@code true}, any threads
- * waiting on {@link #get} will be released and the provided result will be
- * returned.
- *
- * @param result
- * The result.
- * @return {@code false} if this future has already been completed, either
- * due to normal termination, an exception, or cancellation (i.e.
- * {@code isDone() == true}).
- */
- public final boolean tryHandleResult(final M result) {
- return sync.innerSetResult(result);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean isCancelled() {
- return sync.innerIsCancelled();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean isDone() {
- return sync.innerIsDone();
- }
-
- /**
- * Invoked when {@link #cancel} is called and {@code isDone() == false} and
- * immediately before any threads waiting on {@link #get} are released.
- * Implementations may choose to return a custom error result if needed or
- * return {@code null} if the following default error result is acceptable:
- *
- * <pre>
- * Result result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
- * </pre>
- *
- * In addition, implementations may perform other cleanup, for example, by
- * issuing an LDAP abandon request. The default implementation is to do
- * nothing.
- *
- * @param mayInterruptIfRunning
- * {@code true} if the thread executing executing the response
- * handler should be interrupted; otherwise, in-progress response
- * handlers are allowed to complete.
- * @return The custom error result, or {@code null} if the default is
- * acceptable.
- */
- protected ErrorResultException handleCancelRequest(final boolean mayInterruptIfRunning) {
- // Do nothing by default.
- return null;
- }
-
- /**
- * Indicates whether this future result can be canceled.
- *
- * @return {@code true} if this future result is cancelable or {@code false}
- * otherwise.
- */
- protected boolean isCancelable() {
- // Return true by default.
- return true;
- }
-
- /**
- * Appends a string representation of this future's state to the provided
- * builder.
- *
- * @param sb
- * The string builder.
- */
- protected void toString(final StringBuilder sb) {
- sb.append(" state = ");
- sb.append(sync);
- }
-
-}
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/CompletedFutureResult.java b/opendj-core/src/main/java/com/forgerock/opendj/util/CompletedFutureResult.java
deleted file mode 100644
index 285e30d..0000000
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/CompletedFutureResult.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Copyright 2009 Sun Microsystems, Inc.
- * Portions copyright 2012 ForgeRock AS.
- */
-
-package com.forgerock.opendj.util;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
-import org.forgerock.util.Reject;
-
-/**
- * An implementation of {@code FutureResult} which can be used in cases where
- * the result is known in advance, for example, if the result is obtained
- * synchronously.
- *
- * @param <S>
- * The type of result returned by this future.
- */
-public final class CompletedFutureResult<S> implements FutureResult<S> {
- private final S result;
-
- private final ErrorResultException errorResult;
-
- private final int requestID;
-
- /**
- * Creates a new completed future which will throw the provided error result
- * and request ID of {@code -1}.
- *
- * @param errorResult
- * The error result.
- * @throws NullPointerException
- * If {@code errorResult} was {@code null}.
- */
- public CompletedFutureResult(final ErrorResultException errorResult) {
- this(errorResult, -1);
- }
-
- /**
- * Creates a new completed future which will throw the provided error result
- * and request ID.
- *
- * @param errorResult
- * The error result.
- * @param requestID
- * The request ID.
- * @throws NullPointerException
- * If {@code errorResult} was {@code null}.
- */
- public CompletedFutureResult(final ErrorResultException errorResult, final int requestID) {
- Reject.ifNull(errorResult);
- this.result = null;
- this.errorResult = errorResult;
- this.requestID = requestID;
- }
-
- /**
- * Creates a new completed future which will return the provided result and
- * request ID of {@code -1}.
- *
- * @param result
- * The result, which may be {@code null}.
- */
- public CompletedFutureResult(final S result) {
- this(result, -1);
- }
-
- /**
- * Creates a new completed future which will return the provided result and
- * request ID.
- *
- * @param result
- * The result, which may be {@code null}.
- * @param requestID
- * The request ID.
- */
- public CompletedFutureResult(final S result, final int requestID) {
- this.result = result;
- this.errorResult = null;
- this.requestID = requestID;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean cancel(final boolean mayInterruptIfRunning) {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public S get() throws ErrorResultException, InterruptedException {
- if (errorResult == null) {
- // May be null.
- return result;
- } else {
- throw errorResult;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public S get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- return get();
- }
-
- /**
- * {@inheritDoc}
- */
- public int getRequestID() {
- return requestID;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isCancelled() {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isDone() {
- return true;
- }
-
-}
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/FutureResultTransformer.java b/opendj-core/src/main/java/com/forgerock/opendj/util/FutureResultTransformer.java
deleted file mode 100644
index 83914d4..0000000
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/FutureResultTransformer.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Copyright 2009 Sun Microsystems, Inc.
- * Portions copyright 2013 ForgeRock AS.
- */
-
-package com.forgerock.opendj.util;
-
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
-import org.forgerock.opendj.ldap.ResultHandler;
-
-/**
- * An implementation of the {@code FutureResult} interface which transforms the
- * result of an asynchronous operation from one type to another. The
- * implementation ensures that the transformed is computed only once.
- *
- * @param <M>
- * The type of the inner result.
- * @param <N>
- * The type of the outer result.
- */
-public abstract class FutureResultTransformer<M, N> implements FutureResult<N>, ResultHandler<M> {
- private final ResultHandler<? super N> handler;
- private volatile FutureResult<? extends M> future = null;
-
- // These do not need to be volatile since the future acts as a memory
- // barrier.
- private N transformedResult = null;
- private ErrorResultException transformedErrorResult = null;
-
- /**
- * Creates a new result transformer which will transform the results of an
- * inner asynchronous request.
- *
- * @param handler
- * The outer result handler.
- */
- protected FutureResultTransformer(final ResultHandler<? super N> handler) {
- this.handler = handler;
- }
-
- /**
- * {@inheritDoc}
- */
- public final boolean cancel(final boolean mayInterruptIfRunning) {
- return future.cancel(mayInterruptIfRunning);
- }
-
- /**
- * {@inheritDoc}
- */
- public final N get() throws ErrorResultException, InterruptedException {
- try {
- future.get();
- } catch (ErrorResultException ignored) {
- // Ignore untransformed error.
- }
- // The handlers are guaranteed to have been invoked at this point.
- return get0();
- }
-
- /**
- * {@inheritDoc}
- */
- public final N get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- try {
- future.get(timeout, unit);
- } catch (ErrorResultException ignored) {
- // Ignore untransformed error.
- }
- // The handlers are guaranteed to have been invoked at this point.
- return get0();
- }
-
- /**
- * {@inheritDoc}
- */
- public final int getRequestID() {
- return future.getRequestID();
- }
-
- /**
- * {@inheritDoc}
- */
- public final void handleErrorResult(final ErrorResultException error) {
- transformedErrorResult = transformErrorResult(error);
- if (handler != null) {
- handler.handleErrorResult(transformedErrorResult);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public final void handleResult(final M result) {
- try {
- transformedResult = transformResult(result);
- if (handler != null) {
- handler.handleResult(transformedResult);
- }
- } catch (final ErrorResultException e) {
- transformedErrorResult = e;
- if (handler != null) {
- handler.handleErrorResult(transformedErrorResult);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public final boolean isCancelled() {
- return future.isCancelled();
- }
-
- /**
- * {@inheritDoc}
- */
- public final boolean isDone() {
- return future.isDone();
- }
-
- /**
- * Sets the inner future for this result transformer. This must be done
- * before this future is published.
- *
- * @param future
- * The inner future.
- */
- public final void setFutureResult(final FutureResult<? extends M> future) {
- this.future = future;
- }
-
- /**
- * Transforms the inner error result to an outer error result. The default
- * implementation is to return the inner error result.
- *
- * @param errorResult
- * The inner error result.
- * @return The outer error result.
- */
- protected ErrorResultException transformErrorResult(final ErrorResultException errorResult) {
- return errorResult;
- }
-
- /**
- * Transforms the inner result to an outer result, possibly throwing an
- * {@code ErrorResultException} if the transformation fails for some reason.
- *
- * @param result
- * The inner result.
- * @return The outer result.
- * @throws ErrorResultException
- * If the transformation fails for some reason.
- */
- protected abstract N transformResult(M result) throws ErrorResultException;
-
- private N get0() throws ErrorResultException {
- if (transformedErrorResult != null) {
- throw transformedErrorResult;
- } else {
- return transformedResult;
- }
- }
-
-}
diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/RecursiveFutureResult.java b/opendj-core/src/main/java/com/forgerock/opendj/util/RecursiveFutureResult.java
deleted file mode 100644
index 9aa3085..0000000
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/RecursiveFutureResult.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- * Copyright 2009-2010 Sun Microsystems, Inc.
- */
-
-package com.forgerock.opendj.util;
-
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
-import org.forgerock.opendj.ldap.ResultHandler;
-
-/**
- * An implementation of the {@code FutureResult} interface which can be used to
- * combine a sequence of two asynchronous operations into a single future
- * result. Implementations should override the methods {@link #chainResult} and
- * {@link #chainErrorResult} in order to define the second asynchronous
- * operation.
- *
- * @param <M>
- * The type of the inner result.
- * @param <N>
- * The type of the outer result.
- */
-public abstract class RecursiveFutureResult<M, N> implements FutureResult<N>, ResultHandler<M> {
-
- private final class FutureResultImpl extends AsynchronousFutureResult<N, ResultHandler<? super N>> {
-
- private FutureResultImpl(final ResultHandler<? super N> handler) {
- super(handler);
- }
-
- @Override
- public int getRequestID() {
- if (innerFuture instanceof FutureResult<?>) {
- final FutureResult<?> tmp = (FutureResult<?>) innerFuture;
- return tmp.getRequestID();
- } else {
- return -1;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected ErrorResultException handleCancelRequest(final boolean mayInterruptIfRunning) {
- innerFuture.cancel(mayInterruptIfRunning);
- if (outerFuture != null) {
- outerFuture.cancel(mayInterruptIfRunning);
- }
- return null;
- }
-
- }
-
- private final FutureResultImpl impl;
-
- private volatile Future<?> innerFuture = null;
-
- // This does not need to be volatile since the inner future acts as a
- // memory barrier.
- private FutureResult<? extends N> outerFuture = null;
-
- /**
- * Creates a new asynchronous result chain which will chain an outer
- * asynchronous request once the inner asynchronous request completes.
- *
- * @param handler
- * The outer result handler.
- */
- protected RecursiveFutureResult(final ResultHandler<? super N> handler) {
- this.impl = new FutureResultImpl(handler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean cancel(final boolean mayInterruptIfRunning) {
- return impl.cancel(mayInterruptIfRunning);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final N get() throws ErrorResultException, InterruptedException {
- return impl.get();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final N get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- return impl.get(timeout, unit);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final int getRequestID() {
- return impl.getRequestID();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- try {
- outerFuture = chainErrorResult(error, impl);
- } catch (final ErrorResultException e) {
- impl.handleErrorResult(e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final void handleResult(final M result) {
- try {
- outerFuture = chainResult(result, impl);
- } catch (final ErrorResultException e) {
- impl.handleErrorResult(e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean isCancelled() {
- return impl.isCancelled();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean isDone() {
- return impl.isDone();
- }
-
- /**
- * Sets the inner future for this result chain. This must be done before
- * this future is published.
- *
- * @param future
- * The inner future.
- */
- public final void setFutureResult(final Future<?> future) {
- this.innerFuture = future;
- }
-
- /**
- * Invokes the outer request based on the error result of the inner request
- * and returns a future representing the result of the outer request.
- * <p>
- * The default implementation is to terminate further processing by
- * re-throwing the inner error result.
- *
- * @param innerError
- * The error result of the inner request.
- * @param handler
- * The result handler to be used for the outer request.
- * @return A future representing the result of the outer request.
- * @throws ErrorResultException
- * If the outer request could not be invoked and processing
- * should terminate.
- */
- protected FutureResult<? extends N> chainErrorResult(final ErrorResultException innerError,
- final ResultHandler<? super N> handler) throws ErrorResultException {
- throw innerError;
- }
-
- /**
- * Invokes the outer request based on the result of the inner request and
- * returns a future representing the result of the outer request.
- *
- * @param innerResult
- * The result of the inner request.
- * @param handler
- * The result handler to be used for the outer request.
- * @return A future representing the result of the outer request.
- * @throws ErrorResultException
- * If the outer request could not be invoked and processing
- * should terminate.
- */
- protected abstract FutureResult<? extends N> chainResult(M innerResult,
- ResultHandler<? super N> handler) throws ErrorResultException;
-
-}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
index 235e173..dfeaac4 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnection.java
@@ -22,13 +22,11 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2012 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.CompareRequest;
@@ -42,6 +40,8 @@
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.responses.Result;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+
/**
* An abstract connection whose synchronous methods are implemented in terms of
* asynchronous methods.
@@ -55,133 +55,61 @@
// No implementation required.
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public Result add(final AddRequest request) throws ErrorResultException {
- final FutureResult<Result> future = addAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(addAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public BindResult bind(final BindRequest request) throws ErrorResultException {
- final FutureResult<BindResult> future = bindAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(bindAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public CompareResult compare(final CompareRequest request) throws ErrorResultException {
- final FutureResult<CompareResult> future = compareAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(compareAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public Result delete(final DeleteRequest request) throws ErrorResultException {
- final FutureResult<Result> future = deleteAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(deleteAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request,
final IntermediateResponseHandler handler) throws ErrorResultException {
- final FutureResult<R> future = extendedRequestAsync(request, handler, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(extendedRequestAsync(request, handler));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public Result modify(final ModifyRequest request) throws ErrorResultException {
- final FutureResult<Result> future = modifyAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(modifyAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public Result modifyDN(final ModifyDNRequest request) throws ErrorResultException {
- final FutureResult<Result> future = modifyDNAsync(request, null, null);
- try {
- return future.get();
- } catch (InterruptedException e) {
- throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
- }
+ return blockingGetOrThrow(modifyDNAsync(request));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public Result search(final SearchRequest request, final SearchResultHandler handler)
throws ErrorResultException {
- final FutureResult<Result> future = searchAsync(request, null, handler);
+ return blockingGetOrThrow(searchAsync(request, handler));
+ }
+
+ private <T extends Result> T blockingGetOrThrow(FutureResult<T> future) throws ErrorResultException {
try {
- return future.get();
+ return future.getOrThrow();
} catch (InterruptedException e) {
throw interrupted(e);
- } finally {
- // Cancel the request if it hasn't completed.
- future.cancel(false);
}
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
index 2629a53..0da2912 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnection.java
@@ -22,23 +22,17 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
-import static com.forgerock.opendj.ldap.CoreMessages.ERR_NO_SEARCH_RESULT_ENTRIES;
-import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES;
-import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT;
-import static com.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.util.Collection;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import org.forgerock.opendj.ldap.controls.SubtreeDeleteRequestControl;
import org.forgerock.opendj.ldap.requests.AddRequest;
+import org.forgerock.opendj.ldap.requests.BindRequest;
+import org.forgerock.opendj.ldap.requests.CompareRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ExtendedRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
@@ -56,6 +50,12 @@
import org.forgerock.opendj.ldif.ChangeRecordVisitor;
import org.forgerock.opendj.ldif.ConnectionEntryReader;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Function;
+
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+
+import static com.forgerock.opendj.ldap.CoreMessages.*;
/**
* This class provides a skeletal implementation of the {@code Connection}
@@ -63,108 +63,10 @@
*/
public abstract class AbstractConnection implements Connection {
- private static final class SingleEntryFuture implements FutureResult<SearchResultEntry>,
- SearchResultHandler {
- private final ResultHandler<? super SearchResultEntry> handler;
-
- private final SingleEntryHandler singleEntryHandler = new SingleEntryHandler();
-
- private volatile FutureResult<Result> future = null;
-
- private SingleEntryFuture(final ResultHandler<? super SearchResultEntry> handler) {
- this.handler = handler;
- }
-
- @Override
- public boolean cancel(final boolean mayInterruptIfRunning) {
- return future.cancel(mayInterruptIfRunning);
- }
-
- @Override
- public SearchResultEntry get() throws ErrorResultException, InterruptedException {
- try {
- future.get();
- } catch (ErrorResultException e) {
- throw singleEntryHandler.filterError(e);
- }
- return get0();
- }
-
- @Override
- public SearchResultEntry get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- try {
- future.get(timeout, unit);
- } catch (ErrorResultException e) {
- throw singleEntryHandler.filterError(e);
- }
- return get0();
- }
-
- @Override
- public int getRequestID() {
- return future.getRequestID();
- }
-
- @Override
- public boolean handleEntry(final SearchResultEntry entry) {
- return singleEntryHandler.handleEntry(entry);
- }
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- if (handler != null) {
- ErrorResultException finalError = singleEntryHandler.filterError(error);
- handler.handleErrorResult(finalError);
- }
- }
-
- @Override
- public boolean handleReference(final SearchResultReference reference) {
- return singleEntryHandler.handleReference(reference);
- }
-
- @Override
- public void handleResult(final Result result) {
- if (handler != null) {
- try {
- handler.handleResult(get0());
- } catch (final ErrorResultException e) {
- handler.handleErrorResult(e);
- }
- }
- }
-
- @Override
- public boolean isCancelled() {
- return future.isCancelled();
- }
-
- @Override
- public boolean isDone() {
- return future.isDone();
- }
-
- private SearchResultEntry get0() throws ErrorResultException {
- ErrorResultException exception = singleEntryHandler.checkForClientSideError();
- if (exception == null) {
- return singleEntryHandler.firstEntry;
- } else {
- throw exception;
- }
- }
-
- private void setResultFuture(final FutureResult<Result> future) {
- this.future = future;
- }
- }
-
private static final class SingleEntryHandler implements SearchResultHandler {
- private volatile SearchResultEntry firstEntry = null;
-
- private volatile SearchResultReference firstReference = null;
-
- private volatile int entryCount = 0;
+ private volatile SearchResultEntry firstEntry;
+ private volatile SearchResultReference firstReference;
+ private volatile int entryCount;
@Override
public boolean handleEntry(final SearchResultEntry entry) {
@@ -175,14 +77,6 @@
return true;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- // Ignore
- }
-
@Override
public boolean handleReference(final SearchResultReference reference) {
if (firstReference == null) {
@@ -192,22 +86,17 @@
}
/**
- * {@inheritDoc}
- */
- @Override
- public void handleResult(final Result result) {
- // Ignore.
- }
-
- /**
- * Filter the provided error in order to transform size limit exceeded error to a client side error,
- * or leave it as is for any other error.
+ * Filter the provided error in order to transform size limit exceeded
+ * error to a client side error, or leave it as is for any other error.
*
- * @param error to filter
- * @return provided error in most case, or <code>ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED</code>
- * error if provided error is <code>ResultCode.SIZE_LIMIT_EXCEEDED</code>
+ * @param error
+ * to filter
+ * @return provided error in most case, or
+ * <code>ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED</code>
+ * error if provided error is
+ * <code>ResultCode.SIZE_LIMIT_EXCEEDED</code>
*/
- public ErrorResultException filterError(final ErrorResultException error) {
+ private ErrorResultException filterError(final ErrorResultException error) {
if (error.getResult().getResultCode().equals(ResultCode.SIZE_LIMIT_EXCEEDED)) {
return newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES_NO_COUNT.get().toString());
@@ -217,35 +106,35 @@
}
/**
- * Check for any error related to number of search result at client-side level: no result,
- * too many result, search result reference.
+ * Check for any error related to number of search result at client-side
+ * level: no result, too many result, search result reference. This
+ * method should be called only after search operation is finished.
*
- * This method should be called only after search operation is finished.
- *
- * @return an <code>ErrorResultException</code> if an error is detected, <code>null</code> otherwise
+ * @return The single search result entry.
+ * @throws ErrorResultException
+ * If an error is detected.
*/
- public ErrorResultException checkForClientSideError() {
- ErrorResultException exception = null;
+ private SearchResultEntry getSingleEntry() throws ErrorResultException {
if (entryCount == 0) {
// Did not find any entries.
- exception = newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, ERR_NO_SEARCH_RESULT_ENTRIES
- .get().toString());
+ throw newErrorResult(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED,
+ ERR_NO_SEARCH_RESULT_ENTRIES.get().toString());
} else if (entryCount > 1) {
// Got more entries than expected.
- exception = newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
+ throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString());
} else if (firstReference != null) {
// Got an unexpected search result reference.
- exception = newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
+ throw newErrorResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED,
ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get(firstReference.getURIs().iterator().next())
- .toString());
+ .toString());
+ } else {
+ return firstEntry;
}
- return exception;
}
-
}
- // Visitor used for processing synchronous change requests.
+ /** Visitor used for processing synchronous change requests. */
private static final ChangeRecordVisitor<Object, Connection> SYNC_VISITOR =
new ChangeRecordVisitor<Object, Connection>() {
@@ -268,18 +157,18 @@
}
@Override
- public Object visitChangeRecord(final Connection p, final ModifyRequest change) {
+ public Object visitChangeRecord(final Connection p, final ModifyDNRequest change) {
try {
- return p.modify(change);
+ return p.modifyDN(change);
} catch (final ErrorResultException e) {
return e;
}
}
@Override
- public Object visitChangeRecord(final Connection p, final ModifyDNRequest change) {
+ public Object visitChangeRecord(final Connection p, final ModifyRequest change) {
try {
- return p.modifyDN(change);
+ return p.modify(change);
} catch (final ErrorResultException e) {
return e;
}
@@ -293,25 +182,21 @@
// No implementation required.
}
- /**
- * {@inheritDoc}
- */
@Override
public Result add(final Entry entry) throws ErrorResultException {
return add(Requests.newAddRequest(entry));
}
- /**
- * {@inheritDoc}
- */
@Override
public Result add(final String... ldifLines) throws ErrorResultException {
return add(Requests.newAddRequest(ldifLines));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<Result> addAsync(final AddRequest request) {
+ return addAsync(request, null);
+ }
+
@Override
public Result applyChange(final ChangeRecord request) throws ErrorResultException {
final Object result = request.accept(SYNC_VISITOR, this);
@@ -322,200 +207,166 @@
}
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<Result> applyChangeAsync(ChangeRecord request) {
+ return applyChangeAsync(request, null);
+ }
+
@Override
public FutureResult<Result> applyChangeAsync(final ChangeRecord request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final ChangeRecordVisitor<FutureResult<Result>, Connection> visitor =
- new ChangeRecordVisitor<FutureResult<Result>, Connection>() {
+ new ChangeRecordVisitor<FutureResult<Result>, Connection>() {
- @Override
- public FutureResult<Result> visitChangeRecord(final Connection p,
- final AddRequest change) {
- return p.addAsync(change, intermediateResponseHandler, resultHandler);
- }
+ @Override
+ public FutureResult<Result> visitChangeRecord(final Connection p, final AddRequest change) {
+ return p.addAsync(change, intermediateResponseHandler);
+ }
- @Override
- public FutureResult<Result> visitChangeRecord(final Connection p,
- final DeleteRequest change) {
- return p.deleteAsync(change, intermediateResponseHandler, resultHandler);
- }
+ @Override
+ public FutureResult<Result> visitChangeRecord(final Connection p, final DeleteRequest change) {
+ return p.deleteAsync(change, intermediateResponseHandler);
+ }
- @Override
- public FutureResult<Result> visitChangeRecord(final Connection p,
- final ModifyRequest change) {
- return p.modifyAsync(change, intermediateResponseHandler, resultHandler);
- }
+ @Override
+ public FutureResult<Result> visitChangeRecord(final Connection p, final ModifyDNRequest change) {
+ return p.modifyDNAsync(change, intermediateResponseHandler);
+ }
- @Override
- public FutureResult<Result> visitChangeRecord(final Connection p,
- final ModifyDNRequest change) {
- return p.modifyDNAsync(change, intermediateResponseHandler, resultHandler);
- }
- };
+ @Override
+ public FutureResult<Result> visitChangeRecord(final Connection p, final ModifyRequest change) {
+ return p.modifyAsync(change, intermediateResponseHandler);
+ }
+ };
return request.accept(visitor, this);
}
- /**
- * {@inheritDoc}
- */
@Override
public BindResult bind(final String name, final char[] password) throws ErrorResultException {
return bind(Requests.newSimpleBindRequest(name, password));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<BindResult> bindAsync(final BindRequest request) {
+ return bindAsync(request, null);
+ }
+
@Override
public void close() {
close(Requests.newUnbindRequest(), null);
}
- /**
- * {@inheritDoc}
- */
@Override
- public CompareResult compare(final String name, final String attributeDescription,
- final String assertionValue) throws ErrorResultException {
+ public CompareResult compare(final String name, final String attributeDescription, final String assertionValue)
+ throws ErrorResultException {
return compare(Requests.newCompareRequest(name, attributeDescription, assertionValue));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<CompareResult> compareAsync(final CompareRequest request) {
+ return compareAsync(request, null);
+ }
+
@Override
public Result delete(final String name) throws ErrorResultException {
return delete(Requests.newDeleteRequest(name));
}
- /**
- * {@inheritDoc}
- */
@Override
- public Result deleteSubtree(final String name) throws ErrorResultException {
- return delete(Requests.newDeleteRequest(name).addControl(
- SubtreeDeleteRequestControl.newControl(true)));
+ public FutureResult<Result> deleteAsync(final DeleteRequest request) {
+ return deleteAsync(request, null);
}
- /**
- * {@inheritDoc}
- */
@Override
- public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request)
- throws ErrorResultException {
+ public Result deleteSubtree(final String name) throws ErrorResultException {
+ return delete(Requests.newDeleteRequest(name).addControl(SubtreeDeleteRequestControl.newControl(true)));
+ }
+
+ @Override
+ public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request) throws ErrorResultException {
return extendedRequest(request, null);
}
- /**
- * {@inheritDoc}
- */
@Override
- public GenericExtendedResult extendedRequest(final String requestName,
- final ByteString requestValue) throws ErrorResultException {
+ public GenericExtendedResult extendedRequest(final String requestName, final ByteString requestValue)
+ throws ErrorResultException {
return extendedRequest(Requests.newGenericExtendedRequest(requestName, requestValue));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request) {
+ return extendedRequestAsync(request, null);
+ }
+
@Override
public Result modify(final String... ldifLines) throws ErrorResultException {
return modify(Requests.newModifyRequest(ldifLines));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<Result> modifyAsync(final ModifyRequest request) {
+ return modifyAsync(request, null);
+ }
+
@Override
public Result modifyDN(final String name, final String newRDN) throws ErrorResultException {
return modifyDN(Requests.newModifyDNRequest(name, newRDN));
}
- /**
- * {@inheritDoc}
- */
+ @Override
+ public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request) {
+ return modifyDNAsync(request, null);
+ }
+
@Override
public SearchResultEntry readEntry(final DN baseObject, final String... attributeDescriptions)
throws ErrorResultException {
final SearchRequest request =
- Requests.newSingleEntrySearchRequest(baseObject, SearchScope.BASE_OBJECT, Filter
- .objectClassPresent(), attributeDescriptions);
+ Requests.newSingleEntrySearchRequest(baseObject, SearchScope.BASE_OBJECT, Filter.objectClassPresent(),
+ attributeDescriptions);
return searchSingleEntry(request);
}
- /**
- * {@inheritDoc}
- */
@Override
- public SearchResultEntry readEntry(final String baseObject,
- final String... attributeDescriptions) throws ErrorResultException {
+ public SearchResultEntry readEntry(final String baseObject, final String... attributeDescriptions)
+ throws ErrorResultException {
return readEntry(DN.valueOf(baseObject), attributeDescriptions);
}
- /**
- * {@inheritDoc}
- */
@Override
public FutureResult<SearchResultEntry> readEntryAsync(final DN name,
- final Collection<String> attributeDescriptions,
- final ResultHandler<? super SearchResultEntry> handler) {
- final SearchRequest request =
- Requests.newSingleEntrySearchRequest(
- name, SearchScope.BASE_OBJECT,
- Filter.objectClassPresent());
+ final Collection<String> attributeDescriptions) {
+ final SearchRequest request = Requests.newSingleEntrySearchRequest(name, SearchScope.BASE_OBJECT,
+ Filter.objectClassPresent());
if (attributeDescriptions != null) {
request.getAttributes().addAll(attributeDescriptions);
}
- return searchSingleEntryAsync(request, handler);
+ return searchSingleEntryAsync(request);
}
- /**
- * {@inheritDoc}
- */
@Override
public ConnectionEntryReader search(final SearchRequest request) {
return new ConnectionEntryReader(this, request);
}
- /**
- * {@inheritDoc}
- */
@Override
- public Result search(final SearchRequest request,
- final Collection<? super SearchResultEntry> entries) throws ErrorResultException {
+ public Result search(final SearchRequest request, final Collection<? super SearchResultEntry> entries)
+ throws ErrorResultException {
return search(request, entries, null);
}
- /**
- * {@inheritDoc}
- */
@Override
- public Result search(final SearchRequest request,
- final Collection<? super SearchResultEntry> entries,
- final Collection<? super SearchResultReference> references) throws ErrorResultException {
+ public Result search(final SearchRequest request, final Collection<? super SearchResultEntry> entries,
+ final Collection<? super SearchResultReference> references) throws ErrorResultException {
Reject.ifNull(request, entries);
-
// FIXME: does this need to be thread safe?
final SearchResultHandler handler = new SearchResultHandler() {
-
@Override
public boolean handleEntry(final SearchResultEntry entry) {
entries.add(entry);
return true;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- // Ignore.
- }
-
@Override
public boolean handleReference(final SearchResultReference reference) {
if (references != null) {
@@ -523,72 +374,56 @@
}
return true;
}
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleResult(final Result result) {
- // Ignore.
- }
};
return search(request, handler);
}
- /**
- * {@inheritDoc}
- */
@Override
- public ConnectionEntryReader search(final String baseObject, final SearchScope scope,
- final String filter, final String... attributeDescriptions) {
- final SearchRequest request =
- Requests.newSearchRequest(baseObject, scope, filter, attributeDescriptions);
- return search(request);
+ public ConnectionEntryReader search(final String baseObject, final SearchScope scope, final String filter,
+ final String... attributeDescriptions) {
+ return search(newSearchRequest(baseObject, scope, filter, attributeDescriptions));
}
- /**
- * {@inheritDoc}
- */
@Override
- public SearchResultEntry searchSingleEntry(final SearchRequest request)
- throws ErrorResultException {
+ public FutureResult<Result> searchAsync(final SearchRequest request, final SearchResultHandler resultHandler) {
+ return searchAsync(request, null, resultHandler);
+ }
+
+ @Override
+ public SearchResultEntry searchSingleEntry(final SearchRequest request) throws ErrorResultException {
final SingleEntryHandler handler = new SingleEntryHandler();
try {
search(enforceSingleEntrySearchRequest(request), handler);
- } catch (ErrorResultException e) {
+ return handler.getSingleEntry();
+ } catch (final ErrorResultException e) {
throw handler.filterError(e);
}
- ErrorResultException error = handler.checkForClientSideError();
- if (error == null) {
- return handler.firstEntry;
- } else {
- throw error;
- }
}
- /**
- * {@inheritDoc}
- */
@Override
- public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope,
- final String filter, final String... attributeDescriptions) throws ErrorResultException {
+ public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope, final String filter,
+ final String... attributeDescriptions) throws ErrorResultException {
final SearchRequest request =
- Requests.newSingleEntrySearchRequest(baseObject, scope, filter, attributeDescriptions);
+ Requests.newSingleEntrySearchRequest(baseObject, scope, filter, attributeDescriptions);
return searchSingleEntry(request);
}
- /**
- * {@inheritDoc}
- */
@Override
- public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request,
- final ResultHandler<? super SearchResultEntry> handler) {
- final SingleEntryFuture innerFuture = new SingleEntryFuture(handler);
- final FutureResult<Result> future =
- searchAsync(enforceSingleEntrySearchRequest(request), null, innerFuture);
- innerFuture.setResultFuture(future);
- return innerFuture;
+ public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request) {
+ final SingleEntryHandler handler = new SingleEntryHandler();
+ return FutureResultWrapper.asFutureResult(searchAsync(enforceSingleEntrySearchRequest(request), handler).then(
+ new Function<Result, SearchResultEntry, ErrorResultException>() {
+ @Override
+ public SearchResultEntry apply(final Result value) throws ErrorResultException {
+ return handler.getSingleEntry();
+ }
+ }, new Function<ErrorResultException, SearchResultEntry, ErrorResultException>() {
+ @Override
+ public SearchResultEntry apply(final ErrorResultException error) throws ErrorResultException {
+ throw handler.filterError(error);
+ }
+ }));
}
/**
@@ -611,6 +446,7 @@
* <p>
* Sub-classes should provide an implementation which returns an appropriate
* description of the connection which may be used for debugging purposes.
+ * </p>
*/
@Override
public abstract String toString();
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnectionWrapper.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnectionWrapper.java
index dafbd75..1223522 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnectionWrapper.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractConnectionWrapper.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
@@ -122,10 +122,19 @@
* The default implementation is to delegate.
*/
@Override
+ public FutureResult<Result> addAsync(final AddRequest request) {
+ return connection.addAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.addAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.addAsync(request, intermediateResponseHandler);
}
/**
@@ -154,10 +163,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<Result> applyChangeAsync(final ChangeRecord request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.applyChangeAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<Result> applyChangeAsync(ChangeRecord request) {
+ return connection.applyChangeAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<Result> applyChangeAsync(ChangeRecord request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.applyChangeAsync(request, intermediateResponseHandler);
}
/**
@@ -186,10 +204,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
- return connection.bindAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<BindResult> bindAsync(final BindRequest request) {
+ return connection.bindAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<BindResult> bindAsync(BindRequest request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.bindAsync(request, intermediateResponseHandler);
}
/**
@@ -228,8 +255,8 @@
* The default implementation is to delegate.
*/
@Override
- public CompareResult compare(final String name, final String attributeDescription,
- final String assertionValue) throws ErrorResultException {
+ public CompareResult compare(final String name, final String attributeDescription, final String assertionValue)
+ throws ErrorResultException {
return connection.compare(name, attributeDescription, assertionValue);
}
@@ -239,10 +266,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
- return connection.compareAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<CompareResult> compareAsync(final CompareRequest request) {
+ return connection.compareAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<CompareResult> compareAsync(CompareRequest request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.compareAsync(request, intermediateResponseHandler);
}
/**
@@ -271,10 +307,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.deleteAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<Result> deleteAsync(final DeleteRequest request) {
+ return connection.deleteAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<Result> deleteAsync(DeleteRequest request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.deleteAsync(request, intermediateResponseHandler);
}
/**
@@ -293,8 +338,7 @@
* The default implementation is to delegate.
*/
@Override
- public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request)
- throws ErrorResultException {
+ public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request) throws ErrorResultException {
return connection.extendedRequest(request);
}
@@ -315,8 +359,8 @@
* The default implementation is to delegate.
*/
@Override
- public GenericExtendedResult extendedRequest(final String requestName,
- final ByteString requestValue) throws ErrorResultException {
+ public GenericExtendedResult extendedRequest(final String requestName, final ByteString requestValue)
+ throws ErrorResultException {
return connection.extendedRequest(requestName, requestValue);
}
@@ -326,11 +370,19 @@
* The default implementation is to delegate.
*/
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
- return connection.extendedRequestAsync(request, intermediateResponseHandler, resultHandler);
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request) {
+ return connection.extendedRequestAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(ExtendedRequest<R> request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.extendedRequestAsync(request, intermediateResponseHandler);
}
/**
@@ -379,10 +431,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.modifyAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<Result> modifyAsync(final ModifyRequest request) {
+ return connection.modifyAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<Result> modifyAsync(ModifyRequest request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.modifyAsync(request, intermediateResponseHandler);
}
/**
@@ -411,10 +472,19 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.modifyDNAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request) {
+ return connection.modifyDNAsync(request);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public FutureResult<Result> modifyDNAsync(ModifyDNRequest request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return modifyDNAsync(request, intermediateResponseHandler);
}
/**
@@ -446,9 +516,8 @@
*/
@Override
public FutureResult<SearchResultEntry> readEntryAsync(final DN name,
- final Collection<String> attributeDescriptions,
- final ResultHandler<? super SearchResultEntry> handler) {
- return connection.readEntryAsync(name, attributeDescriptions, handler);
+ final Collection<String> attributeDescriptions) {
+ return connection.readEntryAsync(name, attributeDescriptions);
}
/**
@@ -523,9 +592,8 @@
*/
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
final SearchResultHandler resultHandler) {
- return connection.searchAsync(request, intermediateResponseHandler, resultHandler);
+ return connection.searchAsync(request, resultHandler);
}
/**
@@ -534,8 +602,18 @@
* The default implementation is to delegate.
*/
@Override
- public SearchResultEntry searchSingleEntry(final SearchRequest request)
- throws ErrorResultException {
+ public FutureResult<Result> searchAsync(SearchRequest request,
+ IntermediateResponseHandler intermediateResponseHandler, SearchResultHandler entryHandler) {
+ return connection.searchAsync(request, intermediateResponseHandler, entryHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default implementation is to delegate.
+ */
+ @Override
+ public SearchResultEntry searchSingleEntry(final SearchRequest request) throws ErrorResultException {
return connection.searchSingleEntry(request);
}
@@ -545,8 +623,8 @@
* The default implementation is to delegate.
*/
@Override
- public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope,
- final String filter, final String... attributeDescriptions) throws ErrorResultException {
+ public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope, final String filter,
+ final String... attributeDescriptions) throws ErrorResultException {
return connection.searchSingleEntry(baseObject, scope, filter, attributeDescriptions);
}
@@ -556,9 +634,8 @@
* The default implementation is to delegate.
*/
@Override
- public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request,
- final ResultHandler<? super SearchResultEntry> handler) {
- return connection.searchSingleEntryAsync(request, handler);
+ public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request) {
+ return connection.searchSingleEntryAsync(request);
}
/**
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
index c65ad4f..37ac6d9 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithm.java
@@ -26,9 +26,6 @@
*/
package org.forgerock.opendj.ldap;
-import static com.forgerock.opendj.util.StaticUtils.DEFAULT_SCHEDULER;
-import static org.forgerock.opendj.ldap.ErrorResultException.*;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -40,10 +37,16 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.Promise;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
import com.forgerock.opendj.util.ReferenceCountedObject;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.util.promise.Promises.*;
+
+import static com.forgerock.opendj.util.StaticUtils.*;
+
/**
* An abstract load balancing algorithm providing monitoring and failover
* capabilities.
@@ -58,7 +61,7 @@
private final ConnectionFactory factory;
private final AtomicBoolean isOperational = new AtomicBoolean(true);
- private volatile FutureResult<?> pendingConnectFuture = null;
+ private volatile Promise<?, ErrorResultException> pendingConnectPromise;
private final int index;
private MonitoredConnectionFactory(final ConnectionFactory factory, final int index) {
@@ -90,43 +93,35 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> resultHandler) {
- final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future =
- new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(
- resultHandler);
-
- final ResultHandler<Connection> failoverHandler = new ResultHandler<Connection>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- // Attempt failed - try next factory.
- notifyOffline(error);
- final int nextIndex = (index + 1) % monitoredFactories.size();
- try {
- final MonitoredConnectionFactory nextFactory =
- getMonitoredConnectionFactory(nextIndex);
- nextFactory.getConnectionAsync(future);
- } catch (final ErrorResultException e) {
- future.handleErrorResult(e);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ return factory.getConnectionAsync().thenAsync(
+ new AsyncFunction<Connection, Connection, ErrorResultException>() {
+ @Override
+ public Promise<Connection, ErrorResultException> apply(Connection value)
+ throws ErrorResultException {
+ notifyOnline();
+ return newSuccessfulPromise(value);
}
- }
-
- @Override
- public void handleResult(final Connection result) {
- notifyOnline();
- future.handleResult(result);
- }
- };
-
- factory.getConnectionAsync(failoverHandler);
- return future;
+ },
+ new AsyncFunction<ErrorResultException, Connection, ErrorResultException>() {
+ @Override
+ public Promise<Connection, ErrorResultException> apply(ErrorResultException error)
+ throws ErrorResultException {
+ // Attempt failed - try next factory.
+ notifyOffline(error);
+ final int nextIndex = (index + 1) % monitoredFactories.size();
+ return getMonitoredConnectionFactory(nextIndex).getConnectionAsync();
+ }
+ });
}
+
+
/**
* Handle monitoring connection request failure.
*/
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
notifyOffline(error);
}
@@ -150,10 +145,9 @@
* pending monitoring request.
*/
private synchronized void checkIfAvailable() {
- if (!isOperational.get()
- && (pendingConnectFuture == null || pendingConnectFuture.isDone())) {
+ if (!isOperational.get() && (pendingConnectPromise == null || pendingConnectPromise.isDone())) {
logger.debug(LocalizableMessage.raw("Attempting reconnect to offline factory '%s'", this));
- pendingConnectFuture = factory.getConnectionAsync(this);
+ pendingConnectPromise = factory.getConnectionAsync().onSuccess(this).onFailure(this);
}
}
@@ -279,7 +273,7 @@
* Guarded by stateLock.
*/
private ScheduledFuture<?> monitoringFuture;
- private AtomicBoolean isClosed = new AtomicBoolean();
+ private final AtomicBoolean isClosed = new AtomicBoolean();
AbstractLoadBalancingAlgorithm(final Collection<? extends ConnectionFactory> factories,
final LoadBalancerEventListener listener, final long interval, final TimeUnit unit,
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractSynchronousConnection.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractSynchronousConnection.java
index c03967e..db438dd 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractSynchronousConnection.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AbstractSynchronousConnection.java
@@ -21,7 +21,7 @@
* CDDL HEADER END
*
*
- * Copyright 2012 ForgeRock AS
+ * Copyright 2012-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
@@ -40,7 +40,7 @@
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.responses.Result;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
/**
* An abstract connection whose asynchronous methods are implemented in terms of
@@ -74,113 +74,95 @@
*/
@Override
public FutureResult<Void> abandonAsync(final AbandonRequest request) {
- throw new UnsupportedOperationException(
- "Abandon requests are not supported for synchronous connections");
+ throw new UnsupportedOperationException("Abandon requests are not supported for synchronous connections");
}
@Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(add(request), resultHandler);
+ return onSuccess(add(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(bind(request), resultHandler);
+ return onSuccess(bind(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(compare(request), resultHandler);
+ return onSuccess(compare(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(delete(request), resultHandler);
+ return onSuccess(delete(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(extendedRequest(request, intermediateResponseHandler), resultHandler);
+ return onSuccess(extendedRequest(request, intermediateResponseHandler));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(modify(request), resultHandler);
+ return onSuccess(modify(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
try {
- return onSuccess(modifyDN(request), resultHandler);
+ return onSuccess(modifyDN(request));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler) {
try {
- return onSuccess(search(request, resultHandler), resultHandler);
+ return onSuccess(search(request, entryHandler));
} catch (final ErrorResultException e) {
- return onFailure(e, resultHandler);
+ return onFailure(e);
}
}
- private <R extends Result> FutureResult<R> onFailure(final ErrorResultException e,
- final ResultHandler<? super R> resultHandler) {
- if (resultHandler != null) {
- resultHandler.handleErrorResult(e);
- }
- return new CompletedFutureResult<R>(e);
+ private <R extends Result> FutureResult<R> onFailure(final ErrorResultException e) {
+ return newFailedFutureResult(e);
}
- private <R extends Result> FutureResult<R> onSuccess(final R result,
- final ResultHandler<? super R> resultHandler) {
- if (resultHandler != null) {
- resultHandler.handleResult(result);
- }
- return new CompletedFutureResult<R>(result);
+ private <R extends Result> FutureResult<R> onSuccess(final R result) {
+ return newSuccessfulFutureResult(result);
}
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java
index d0eb99d..e3fa07b 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AuthenticatedConnectionFactory.java
@@ -22,16 +22,20 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
+import java.util.concurrent.atomic.AtomicReference;
+
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.Function;
+import org.forgerock.util.promise.Promise;
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
+import static org.forgerock.util.Utils.*;
/**
* An authenticated connection factory can be used to create pre-authenticated
@@ -57,28 +61,27 @@
super(connection);
}
- /*
+ /**
* Bind operations are not supported by pre-authenticated connections.
* These methods will always throw {@code UnsupportedOperationException}.
*/
-
public FutureResult<BindResult> bindAsync(final BindRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<? super BindResult> resultHandler) {
throw new UnsupportedOperationException();
}
-
+ @Override
public BindResult bind(BindRequest request) throws ErrorResultException {
throw new UnsupportedOperationException();
}
-
+ @Override
public BindResult bind(String name, char[] password) throws ErrorResultException {
throw new UnsupportedOperationException();
}
-
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("AuthenticatedConnection(");
@@ -89,52 +92,6 @@
}
- private static final class FutureResultImpl {
- private final FutureResultTransformer<BindResult, Connection> futureBindResult;
- private final RecursiveFutureResult<Connection, BindResult> futureConnectionResult;
- private final BindRequest bindRequest;
- private Connection connection;
-
- private FutureResultImpl(final BindRequest request,
- final ResultHandler<? super Connection> handler) {
- this.bindRequest = request;
- this.futureBindResult = new FutureResultTransformer<BindResult, Connection>(handler) {
-
- @Override
- protected ErrorResultException transformErrorResult(
- final ErrorResultException errorResult) {
- // Ensure that the connection is closed.
- if (connection != null) {
- connection.close();
- connection = null;
- }
- return errorResult;
- }
-
- @Override
- protected Connection transformResult(final BindResult result)
- throws ErrorResultException {
- return new AuthenticatedConnection(connection);
- }
-
- };
- this.futureConnectionResult =
- new RecursiveFutureResult<Connection, BindResult>(futureBindResult) {
-
- @Override
- protected FutureResult<? extends BindResult> chainResult(
- final Connection innerResult,
- final ResultHandler<? super BindResult> handler)
- throws ErrorResultException {
- connection = innerResult;
- return connection.bindAsync(bindRequest, null, handler);
- }
- };
- futureBindResult.setFutureResult(futureConnectionResult);
- }
-
- }
-
private final BindRequest request;
private final ConnectionFactory parentFactory;
@@ -162,6 +119,7 @@
parentFactory.close();
}
+ @Override
public Connection getConnection() throws ErrorResultException {
final Connection connection = parentFactory.getConnection();
boolean bindSucceeded = false;
@@ -181,25 +139,44 @@
return new AuthenticatedConnection(connection);
}
-
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
- final FutureResultImpl future = new FutureResultImpl(request, handler);
- future.futureConnectionResult.setFutureResult(parentFactory
- .getConnectionAsync(future.futureConnectionResult));
- return future.futureBindResult;
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ return parentFactory.getConnectionAsync()
+ .thenAsync(
+ new AsyncFunction<Connection, BindResult, ErrorResultException>() {
+ @Override
+ public Promise<BindResult, ErrorResultException> apply(final Connection connection)
+ throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.bindAsync(request);
+ }
+ }
+ ).then(
+ new Function<BindResult, Connection, ErrorResultException>() {
+ @Override
+ public Connection apply(BindResult result) throws ErrorResultException {
+ return new AuthenticatedConnection(connectionHolder.get());
+ }
+ },
+ new Function<ErrorResultException, Connection, ErrorResultException>() {
+ @Override
+ public Connection apply(ErrorResultException error) throws ErrorResultException {
+ closeSilently(connectionHolder.get());
+ throw error;
+ }
+ }
+ );
}
-
+ @Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("AuthenticatedConnectionFactory(");
- builder.append(String.valueOf(parentFactory));
+ builder.append(parentFactory);
builder.append(", ");
builder.append(request);
builder.append(')');
return builder.toString();
}
-
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/CachedConnectionPool.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/CachedConnectionPool.java
index 769b8cf..3d7319b 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/CachedConnectionPool.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/CachedConnectionPool.java
@@ -26,13 +26,6 @@
*/
package org.forgerock.opendj.ldap;
-import static com.forgerock.opendj.util.StaticUtils.DEBUG_ENABLED;
-import static com.forgerock.opendj.util.StaticUtils.DEFAULT_SCHEDULER;
-import static com.forgerock.opendj.util.StaticUtils.getStackTraceIfDebugEnabled;
-import static com.forgerock.opendj.util.StaticUtils.logIfDebugEnabled;
-import static com.forgerock.opendj.ldap.CoreMessages.ERR_CONNECTION_POOL_CLOSING;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@@ -66,12 +59,19 @@
import org.forgerock.opendj.ldif.ChangeRecord;
import org.forgerock.opendj.ldif.ConnectionEntryReader;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
-import com.forgerock.opendj.util.CompletedFutureResult;
import com.forgerock.opendj.util.ReferenceCountedObject;
import com.forgerock.opendj.util.TimeSource;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.util.promise.Promises.*;
+
+import static com.forgerock.opendj.ldap.CoreMessages.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
+
/**
* A connection pool implementation which maintains a cache of pooled
* connections with a configurable core pool size, maximum size, and expiration
@@ -80,13 +80,27 @@
final class CachedConnectionPool implements ConnectionPool {
/**
- * This result handler is invoked when an attempt to add a new connection to
- * the pool completes.
+ * This success handler is invoked when an attempt to add a new connection
+ * to the pool completes.
*/
- private final class ConnectionResultHandler implements ResultHandler<Connection> {
-
+ private final class ConnectionSuccessHandler implements SuccessHandler<Connection> {
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleResult(final Connection connection) {
+ logger.debug(LocalizableMessage.raw(
+ "Connection attempt succeeded: availableConnections=%d, maxPoolSize=%d",
+ currentPoolSize(), maxPoolSize));
+ pendingConnectionAttempts.decrementAndGet();
+ publishConnection(connection);
+ }
+ }
+
+ /**
+ * This failure handler is invoked when an attempt to add a new connection
+ * to the pool ended in error.
+ */
+ private final class ConnectionFailureHandler implements FailureHandler<ErrorResultException> {
+ @Override
+ public void handleError(final ErrorResultException error) {
// Connection attempt failed, so decrease the pool size.
pendingConnectionAttempts.decrementAndGet();
availableConnections.release();
@@ -114,18 +128,9 @@
}
}
for (QueueElement waitingFuture : waitingFutures) {
- waitingFuture.getWaitingFuture().handleErrorResult(error);
+ waitingFuture.getWaitingFuture().handleError(error);
}
}
-
- @Override
- public void handleResult(final Connection connection) {
- logger.debug(LocalizableMessage.raw(
- "Connection attempt succeeded: availableConnections=%d, maxPoolSize=%d",
- currentPoolSize(), maxPoolSize));
- pendingConnectionAttempts.decrementAndGet();
- publishConnection(connection);
- }
}
/**
@@ -167,10 +172,14 @@
}
@Override
+ public FutureResult<Result> addAsync(AddRequest request) {
+ return addAsync(request, null);
+ }
+
+ @Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return checkState().addAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().addAsync(request, intermediateResponseHandler);
}
@Override
@@ -211,11 +220,14 @@
}
@Override
+ public FutureResult<Result> applyChangeAsync(final ChangeRecord request) {
+ return checkState().applyChangeAsync(request, null);
+ }
+
+ @Override
public FutureResult<Result> applyChangeAsync(final ChangeRecord request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return checkState().applyChangeAsync(request, intermediateResponseHandler,
- resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().applyChangeAsync(request, intermediateResponseHandler);
}
@Override
@@ -230,10 +242,14 @@
}
@Override
+ public FutureResult<BindResult> bindAsync(BindRequest request) {
+ return bindAsync(request, null);
+ }
+
+ @Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
- return checkState().bindAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().bindAsync(request, intermediateResponseHandler);
}
@Override
@@ -268,7 +284,7 @@
*/
connection.close();
pendingConnectionAttempts.incrementAndGet();
- factory.getConnectionAsync(connectionResultHandler);
+ factory.getConnectionAsync().onSuccess(connectionSuccessHandler).onFailure(connectionFailureHandler);
logger.debug(LocalizableMessage.raw(
"Connection no longer valid: availableConnections=%d, maxPoolSize=%d",
@@ -300,10 +316,14 @@
}
@Override
+ public FutureResult<CompareResult> compareAsync(CompareRequest request) {
+ return compareAsync(request, null);
+ }
+
+ @Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
- return checkState().compareAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().compareAsync(request, intermediateResponseHandler);
}
@Override
@@ -317,10 +337,14 @@
}
@Override
+ public FutureResult<Result> deleteAsync(DeleteRequest request) {
+ return deleteAsync(request, null);
+ }
+
+ @Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return checkState().deleteAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().deleteAsync(request, intermediateResponseHandler);
}
@Override
@@ -347,12 +371,14 @@
}
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
- return checkState().extendedRequestAsync(request, intermediateResponseHandler,
- resultHandler);
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(ExtendedRequest<R> request) {
+ return extendedRequestAsync(request, null);
+ }
+
+ @Override
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().extendedRequestAsync(request, intermediateResponseHandler);
}
@Override
@@ -367,8 +393,7 @@
}
@Override
- public void handleConnectionError(final boolean isDisconnectNotification,
- final ErrorResultException error) {
+ public void handleConnectionError(final boolean isDisconnectNotification, final ErrorResultException error) {
final List<ConnectionEventListener> tmpListeners;
synchronized (stateLock) {
tmpListeners = listeners;
@@ -416,10 +441,14 @@
}
@Override
+ public FutureResult<Result> modifyAsync(ModifyRequest request) {
+ return modifyAsync(request, null);
+ }
+
+ @Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return checkState().modifyAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().modifyAsync(request, intermediateResponseHandler);
}
@Override
@@ -433,10 +462,14 @@
}
@Override
+ public FutureResult<Result> modifyDNAsync(ModifyDNRequest request) {
+ return modifyDNAsync(request, null);
+ }
+
+ @Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return checkState().modifyDNAsync(request, intermediateResponseHandler, resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return checkState().modifyDNAsync(request, intermediateResponseHandler);
}
@Override
@@ -453,9 +486,8 @@
@Override
public FutureResult<SearchResultEntry> readEntryAsync(final DN name,
- final Collection<String> attributeDescriptions,
- final ResultHandler<? super SearchResultEntry> handler) {
- return checkState().readEntryAsync(name, attributeDescriptions, handler);
+ final Collection<String> attributeDescriptions) {
+ return checkState().readEntryAsync(name, attributeDescriptions);
}
@Override
@@ -474,16 +506,14 @@
}
@Override
- public Result search(final SearchRequest request,
- final Collection<? super SearchResultEntry> entries) throws ErrorResultException {
+ public Result search(final SearchRequest request, final Collection<? super SearchResultEntry> entries)
+ throws ErrorResultException {
return checkState().search(request, entries);
}
@Override
- public Result search(final SearchRequest request,
- final Collection<? super SearchResultEntry> entries,
- final Collection<? super SearchResultReference> references)
- throws ErrorResultException {
+ public Result search(final SearchRequest request, final Collection<? super SearchResultEntry> entries,
+ final Collection<? super SearchResultReference> references) throws ErrorResultException {
return checkState().search(request, entries, references);
}
@@ -494,35 +524,36 @@
}
@Override
- public ConnectionEntryReader search(final String baseObject, final SearchScope scope,
- final String filter, final String... attributeDescriptions) {
+ public ConnectionEntryReader search(final String baseObject, final SearchScope scope, final String filter,
+ final String... attributeDescriptions) {
return checkState().search(baseObject, scope, filter, attributeDescriptions);
}
@Override
- public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
- return checkState().searchAsync(request, intermediateResponseHandler, resultHandler);
+ public FutureResult<Result> searchAsync(SearchRequest request, SearchResultHandler resultHandler) {
+ return searchAsync(request, null, resultHandler);
}
@Override
- public SearchResultEntry searchSingleEntry(final SearchRequest request)
- throws ErrorResultException {
+ public FutureResult<Result> searchAsync(final SearchRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler) {
+ return checkState().searchAsync(request, intermediateResponseHandler, entryHandler);
+ }
+
+ @Override
+ public SearchResultEntry searchSingleEntry(final SearchRequest request) throws ErrorResultException {
return checkState().searchSingleEntry(request);
}
@Override
- public SearchResultEntry searchSingleEntry(final String baseObject,
- final SearchScope scope, final String filter, final String... attributeDescriptions)
- throws ErrorResultException {
+ public SearchResultEntry searchSingleEntry(final String baseObject, final SearchScope scope,
+ final String filter, final String... attributeDescriptions) throws ErrorResultException {
return checkState().searchSingleEntry(baseObject, scope, filter, attributeDescriptions);
}
@Override
- public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request,
- final ResultHandler<? super SearchResultEntry> handler) {
- return checkState().searchSingleEntryAsync(request, handler);
+ public FutureResult<SearchResultEntry> searchSingleEntryAsync(final SearchRequest request) {
+ return checkState().searchSingleEntryAsync(request);
}
@Override
@@ -623,11 +654,9 @@
this.stack = null;
}
- QueueElement(final ResultHandler<? super Connection> handler, final long timestampMillis,
- final StackTraceElement[] stack) {
- this.value =
- new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(
- handler);
+ QueueElement(final long timestampMillis,
+ final StackTraceElement[] stack) {
+ this.value = new FutureResultImpl<Connection>();
this.timestampMillis = timestampMillis;
this.stack = stack;
}
@@ -650,8 +679,8 @@
}
@SuppressWarnings("unchecked")
- AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> getWaitingFuture() {
- return (AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>) value;
+ FutureResultImpl<Connection> getWaitingFuture() {
+ return (FutureResultImpl<Connection>) value;
}
boolean hasTimedOut(final long timeLimitMillis) {
@@ -659,7 +688,7 @@
}
boolean isWaitingFuture() {
- return value instanceof AsynchronousFutureResult;
+ return value instanceof FutureResultImpl;
}
}
@@ -672,7 +701,8 @@
TimeSource timeSource = TimeSource.DEFAULT;
private final Semaphore availableConnections;
- private final ResultHandler<Connection> connectionResultHandler = new ConnectionResultHandler();
+ private final SuccessHandler<Connection> connectionSuccessHandler = new ConnectionSuccessHandler();
+ private final FailureHandler<ErrorResultException> connectionFailureHandler = new ConnectionFailureHandler();
private final int corePoolSize;
private final ConnectionFactory factory;
private boolean isClosed = false;
@@ -760,15 +790,14 @@
@Override
public Connection getConnection() throws ErrorResultException {
try {
- return getConnectionAsync(null).get();
+ return getConnectionAsync().getOrThrow();
} catch (final InterruptedException e) {
throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, e);
}
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
// Loop while iterating through stale connections (see OPENDJ-590).
for (;;) {
final QueueElement holder;
@@ -778,9 +807,7 @@
} else if (hasWaitingConnections()) {
holder = queue.removeFirst();
} else {
- holder =
- new QueueElement(handler, timeSource.currentTimeMillis(),
- getStackTraceIfDebugEnabled());
+ holder = new QueueElement(timeSource.currentTimeMillis(), getStackTraceIfDebugEnabled());
queue.add(holder);
}
}
@@ -790,7 +817,8 @@
final FutureResult<Connection> future = holder.getWaitingFuture();
if (!future.isDone() && availableConnections.tryAcquire()) {
pendingConnectionAttempts.incrementAndGet();
- factory.getConnectionAsync(connectionResultHandler);
+ factory.getConnectionAsync().onSuccess(connectionSuccessHandler)
+ .onFailure(connectionFailureHandler);
}
return future;
}
@@ -798,19 +826,14 @@
// There was a completed connection attempt.
final Connection connection = holder.getWaitingConnection();
if (connection.isValid()) {
- final PooledConnection pooledConnection =
- newPooledConnection(connection, getStackTraceIfDebugEnabled());
- if (handler != null) {
- handler.handleResult(pooledConnection);
- }
- return new CompletedFutureResult<Connection>(pooledConnection);
+ final Connection pooledConnection = newPooledConnection(connection, getStackTraceIfDebugEnabled());
+ return newSuccessfulPromise(pooledConnection);
} else {
// Close the stale connection and try again.
connection.close();
availableConnections.release();
- logger.debug(LocalizableMessage.raw(
- "Connection no longer valid: availableConnections=%d, poolSize=%d",
+ logger.debug(LocalizableMessage.raw("Connection no longer valid: availableConnections=%d, poolSize=%d",
currentPoolSize(), maxPoolSize));
}
}
@@ -892,7 +915,7 @@
final ErrorResultException e =
ErrorResultException.newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED,
ERR_CONNECTION_POOL_CLOSING.get(toString()).toString());
- holder.getWaitingFuture().handleErrorResult(e);
+ holder.getWaitingFuture().handleError(e);
logger.debug(LocalizableMessage.raw(
"Connection attempt failed: availableConnections=%d, maxPoolSize=%d",
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connection.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connection.java
index 471bb50..2bd1b48 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connection.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connection.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
@@ -258,13 +258,6 @@
*
* @param request
* The add request.
- * @param intermediateResponseHandler
- * An intermediate response handler which can be used to process
- * any intermediate responses as they are received, may be
- * {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support add operations.
@@ -274,9 +267,28 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- FutureResult<Result> addAsync(AddRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler);
+ FutureResult<Result> addAsync(AddRequest request);
+
+ /**
+ * Asynchronously adds an entry to the Directory Server using the provided
+ * add request.
+ *
+ * @param request
+ * The add request.
+ * @param intermediateResponseHandler
+ * An intermediate response handler which can be used to process
+ * any intermediate responses as they are received, may be
+ * {@code null}.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support add operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> addAsync(AddRequest request, IntermediateResponseHandler intermediateResponseHandler);
/**
* Registers the provided connection event listener so that it will be
@@ -320,13 +332,28 @@
*
* @param request
* The change request.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support the provided change
+ * request.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> applyChangeAsync(ChangeRecord request);
+
+ /**
+ * Asynchronously applies the provided change request to the Directory
+ * Server.
+ *
+ * @param request
+ * The change request.
* @param intermediateResponseHandler
* An intermediate response handler which can be used to process
* any intermediate responses as they are received, may be
* {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support the provided change
@@ -338,8 +365,7 @@
* If {@code request} was {@code null}.
*/
FutureResult<Result> applyChangeAsync(ChangeRecord request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler);
+ IntermediateResponseHandler intermediateResponseHandler);
/**
* Authenticates to the Directory Server using the provided bind request.
@@ -400,13 +426,6 @@
*
* @param request
* The bind request.
- * @param intermediateResponseHandler
- * An intermediate response handler which can be used to process
- * any intermediate responses as they are received, may be
- * {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support bind operations.
@@ -416,9 +435,28 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- FutureResult<BindResult> bindAsync(BindRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super BindResult> resultHandler);
+ FutureResult<BindResult> bindAsync(BindRequest request);
+
+ /**
+ * Asynchronously authenticates to the Directory Server using the provided
+ * bind request.
+ *
+ * @param request
+ * The bind request.
+ * @param intermediateResponseHandler
+ * An intermediate response handler which can be used to process
+ * any intermediate responses as they are received, may be
+ * {@code null}.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support bind operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<BindResult> bindAsync(BindRequest request, IntermediateResponseHandler intermediateResponseHandler);
/**
* Releases any resources associated with this connection. For physical
@@ -530,13 +568,27 @@
*
* @param request
* The compare request.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support compare operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<CompareResult> compareAsync(CompareRequest request);
+
+ /**
+ * Asynchronously compares an entry in the Directory Server using the
+ * provided compare request.
+ *
+ * @param request
+ * The compare request.
* @param intermediateResponseHandler
* An intermediate response handler which can be used to process
* any intermediate responses as they are received, may be
* {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support compare operations.
@@ -547,8 +599,7 @@
* If {@code request} was {@code null}.
*/
FutureResult<CompareResult> compareAsync(CompareRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super CompareResult> resultHandler);
+ IntermediateResponseHandler intermediateResponseHandler);
/**
* Deletes an entry from the Directory Server using the provided delete
@@ -636,13 +687,6 @@
*
* @param request
* The delete request.
- * @param intermediateResponseHandler
- * An intermediate response handler which can be used to process
- * any intermediate responses as they are received, may be
- * {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support delete operations.
@@ -652,9 +696,28 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- FutureResult<Result> deleteAsync(DeleteRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler);
+ FutureResult<Result> deleteAsync(DeleteRequest request);
+
+ /**
+ * Asynchronously deletes an entry from the Directory Server using the
+ * provided delete request.
+ *
+ * @param request
+ * The delete request.
+ * @param intermediateResponseHandler
+ * An intermediate response handler which can be used to process
+ * any intermediate responses as they are received, may be
+ * {@code null}.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support delete operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> deleteAsync(DeleteRequest request, IntermediateResponseHandler intermediateResponseHandler);
/**
* Requests that the Directory Server performs the provided extended
@@ -703,8 +766,8 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request,
- IntermediateResponseHandler handler) throws ErrorResultException;
+ <R extends ExtendedResult> R extendedRequest(ExtendedRequest<R> request, IntermediateResponseHandler handler)
+ throws ErrorResultException;
/**
* Requests that the Directory Server performs the provided extended
@@ -746,13 +809,29 @@
* The type of result returned by the extended request.
* @param request
* The extended request.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support extended operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(ExtendedRequest<R> request);
+
+ /**
+ * Asynchronously performs the provided extended request in the Directory
+ * Server.
+ *
+ * @param <R>
+ * The type of result returned by the extended request.
+ * @param request
+ * The extended request.
* @param intermediateResponseHandler
* An intermediate response handler which can be used to process
* any intermediate responses as they are received, may be
* {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support extended operations.
@@ -763,8 +842,7 @@
* If {@code request} was {@code null}.
*/
<R extends ExtendedResult> FutureResult<R> extendedRequestAsync(ExtendedRequest<R> request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super R> resultHandler);
+ IntermediateResponseHandler intermediateResponseHandler);
/**
* Indicates whether or not this connection has been explicitly closed by
@@ -845,13 +923,6 @@
*
* @param request
* The modify request.
- * @param intermediateResponseHandler
- * An intermediate response handler which can be used to process
- * any intermediate responses as they are received, may be
- * {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support modify operations.
@@ -861,9 +932,28 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- FutureResult<Result> modifyAsync(ModifyRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler);
+ FutureResult<Result> modifyAsync(ModifyRequest request);
+
+ /**
+ * Asynchronously modifies an entry in the Directory Server using the
+ * provided modify request.
+ *
+ * @param request
+ * The modify request.
+ * @param intermediateResponseHandler
+ * An intermediate response handler which can be used to process
+ * any intermediate responses as they are received, may be
+ * {@code null}.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support modify operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> modifyAsync(ModifyRequest request, IntermediateResponseHandler intermediateResponseHandler);
/**
* Renames an entry in the Directory Server using the provided modify DN
@@ -923,13 +1013,27 @@
*
* @param request
* The modify DN request.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support modify DN operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> modifyDNAsync(ModifyDNRequest request);
+
+ /**
+ * Asynchronously renames an entry in the Directory Server using the
+ * provided modify DN request.
+ *
+ * @param request
+ * The modify DN request.
* @param intermediateResponseHandler
* An intermediate response handler which can be used to process
* any intermediate responses as they are received, may be
* {@code null}.
- * @param resultHandler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support modify DN operations.
@@ -940,8 +1044,7 @@
* If {@code request} was {@code null}.
*/
FutureResult<Result> modifyDNAsync(ModifyDNRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler);
+ IntermediateResponseHandler intermediateResponseHandler);
/**
* Reads the named entry from the Directory Server.
@@ -953,8 +1056,8 @@
* This method is equivalent to the following code:
*
* <pre>
- * SearchRequest request =
- * new SearchRequest(name, SearchScope.BASE_OBJECT, "(objectClass=*)", attributeDescriptions);
+ * SearchRequest request = new SearchRequest(name, SearchScope.BASE_OBJECT,
+ * "(objectClass=*)", attributeDescriptions);
* connection.searchSingleEntry(request);
* </pre>
*
@@ -1037,9 +1140,6 @@
* The names of the attributes to be included with the entry,
* which may be {@code null} or empty indicating that all user
* attributes should be returned.
- * @param handler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support search operations.
@@ -1049,9 +1149,7 @@
* @throws NullPointerException
* If the {@code name} was {@code null}.
*/
- FutureResult<SearchResultEntry> readEntryAsync(DN name,
- Collection<String> attributeDescriptions,
- ResultHandler<? super SearchResultEntry> handler);
+ FutureResult<SearchResultEntry> readEntryAsync(DN name, Collection<String> attributeDescriptions);
/**
* Removes the provided connection event listener from this connection so
@@ -1231,11 +1329,7 @@
*
* @param request
* The search request.
- * @param intermediateResponseHandler
- * An intermediate response handler which can be used to process
- * any intermediate responses as they are received, may be
- * {@code null}.
- * @param resultHandler
+ * @param entryHandler
* A search result handler which can be used to asynchronously
* process the search result entries and references as they are
* received, may be {@code null}.
@@ -1248,9 +1342,33 @@
* @throws NullPointerException
* If {@code request} was {@code null}.
*/
- FutureResult<Result> searchAsync(SearchRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- SearchResultHandler resultHandler);
+ FutureResult<Result> searchAsync(SearchRequest request, SearchResultHandler entryHandler);
+
+ /**
+ * Asynchronously searches the Directory Server using the provided search
+ * request.
+ *
+ * @param request
+ * The search request.
+ * @param intermediateResponseHandler
+ * An intermediate response handler which can be used to process
+ * any intermediate responses as they are received, may be
+ * {@code null}.
+ * @param entryHandler
+ * A search result handler which can be used to asynchronously
+ * process the search result entries and references as they are
+ * received, may be {@code null}.
+ * @return A future representing the result of the operation.
+ * @throws UnsupportedOperationException
+ * If this connection does not support search operations.
+ * @throws IllegalStateException
+ * If this connection has already been closed, i.e. if
+ * {@code isClosed() == true}.
+ * @throws NullPointerException
+ * If {@code request} was {@code null}.
+ */
+ FutureResult<Result> searchAsync(SearchRequest request, IntermediateResponseHandler intermediateResponseHandler,
+ SearchResultHandler entryHandler);
/**
* Searches the Directory Server for a single entry using the provided
@@ -1337,9 +1455,6 @@
*
* @param request
* The search request.
- * @param handler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the result of the operation.
* @throws UnsupportedOperationException
* If this connection does not support search operations.
@@ -1349,6 +1464,5 @@
* @throws NullPointerException
* If the {@code request} was {@code null}.
*/
- FutureResult<SearchResultEntry> searchSingleEntryAsync(SearchRequest request,
- ResultHandler<? super SearchResultEntry> handler);
+ FutureResult<SearchResultEntry> searchSingleEntryAsync(SearchRequest request);
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java
index af6bf07..33431da 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionFactory.java
@@ -22,13 +22,15 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
import java.io.Closeable;
+import org.forgerock.util.promise.Promise;
+
/**
* A connection factory provides an interface for obtaining a connection to a
* Directory Server. Connection factories can be used to wrap other connection
@@ -75,17 +77,12 @@
/**
* Asynchronously obtains a connection to the Directory Server associated
- * with this connection factory. The returned {@code FutureResult} can be
- * used to retrieve the completed connection. Alternatively, if a
- * {@code ResultHandler} is provided, the handler will be notified when the
- * connection is available and ready for use.
+ * with this connection factory. The returned {@code Promise} can be used to
+ * retrieve the completed connection.
*
- * @param handler
- * The completion handler, or {@code null} if no handler is to be
- * used.
- * @return A future which can be used to retrieve the connection.
+ * @return A promise which can be used to retrieve the connection.
*/
- FutureResult<Connection> getConnectionAsync(ResultHandler<? super Connection> handler);
+ Promise<Connection, ErrorResultException> getConnectionAsync();
/**
* Returns a connection to the Directory Server associated with this
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
index d9fc7f1..580c8b6 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ConnectionPool.java
@@ -26,6 +26,8 @@
package org.forgerock.opendj.ldap;
+import org.forgerock.util.promise.Promise;
+
/**
* A connection factory which maintains and re-uses a pool of connections.
* Connections obtained from a connection pool are returned to the connection
@@ -51,28 +53,25 @@
* Calling {@code close} on a connection pool which is already closed has no
* effect.
*/
+ @Override
void close();
/**
* Asynchronously obtains a connection from this connection pool,
* potentially opening a new connection if needed.
* <p>
- * The returned {@code FutureResult} can be used to retrieve the pooled
- * connection. Alternatively, if a {@code ResultHandler} is provided, the
- * handler will be notified when the pooled connection is available and
- * ready for use.
+ * The returned {@code Promise} can be used to retrieve the pooled
+ * connection.
* <p>
* Closing the pooled connection will, depending on the connection pool
* implementation, return the connection to this pool without closing it.
*
- * @param handler
- * The completion handler, or {@code null} if no handler is to be
- * used.
- * @return A future which can be used to retrieve the pooled connection.
+ * @return A promise which can be used to retrieve the pooled connection.
* @throws IllegalStateException
* If this connection pool has already been closed.
*/
- FutureResult<Connection> getConnectionAsync(ResultHandler<? super Connection> handler);
+ @Override
+ Promise<Connection, ErrorResultException> getConnectionAsync();
/**
* Obtains a connection from this connection pool, potentially opening a new
@@ -87,5 +86,6 @@
* @throws IllegalStateException
* If this connection pool has already been closed.
*/
+ @Override
Connection getConnection() throws ErrorResultException;
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connections.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connections.java
index f8a2fab..d17b8a5 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connections.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/Connections.java
@@ -37,6 +37,7 @@
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Promise;
/**
* This class contains methods for creating and manipulating connection
@@ -547,9 +548,8 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
- return factory.getConnectionAsync(handler);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ return factory.getConnectionAsync();
}
@Override
@@ -642,6 +642,7 @@
// Do nothing.
}
+ @Override
public void close(org.forgerock.opendj.ldap.requests.UnbindRequest request,
String reason) {
// Do nothing.
@@ -662,9 +663,8 @@
return new ConnectionFactory() {
@Override
- public FutureResult<Connection> getConnectionAsync(
- ResultHandler<? super Connection> handler) {
- return factory.getConnectionAsync(handler);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ return factory.getConnectionAsync();
}
@Override
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResult.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResult.java
index 1776f14..7aaabef 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResult.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResult.java
@@ -22,80 +22,20 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
+ * Portions copyright 2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+import org.forgerock.util.promise.Promise;
/**
* A handle which can be used to retrieve the Result of an asynchronous Request.
*
* @param <S>
- * The type of result returned by this future.
+ * The type of result returned by this future result.
*/
-public interface FutureResult<S> extends Future<S> {
- /**
- * Attempts to cancel the request. This attempt will fail if the request has
- * already completed or has already been cancelled. If successful, then
- * cancellation results in an abandon or cancel request (if configured)
- * being sent to the server.
- * <p>
- * After this method returns, subsequent calls to {@link #isDone} will
- * always return {@code true}. Subsequent calls to {@link #isCancelled} will
- * always return {@code true} if this method returned {@code true}.
- *
- * @param mayInterruptIfRunning
- * {@code true} if the thread executing executing the response
- * handler should be interrupted; otherwise, in-progress response
- * handlers are allowed to complete.
- * @return {@code false} if the request could not be cancelled, typically
- * because it has already completed normally; {@code true}
- * otherwise.
- */
- boolean cancel(boolean mayInterruptIfRunning);
-
- /**
- * Waits if necessary for the request to complete, and then returns the
- * result if the request succeeded. If the request failed (i.e. a
- * non-successful result code was obtained) then the result is thrown as an
- * {@link ErrorResultException}.
- *
- * @return The result, but only if the result code indicates that the
- * request succeeded.
- * @throws ErrorResultException
- * If the result code indicates that the request failed for some
- * reason.
- * @throws InterruptedException
- * If the current thread was interrupted while waiting.
- */
- S get() throws ErrorResultException, InterruptedException;
-
- /**
- * Waits if necessary for at most the given time for the request to
- * complete, and then returns the result if the request succeeded. If the
- * request failed (i.e. a non-successful result code was obtained) then the
- * result is thrown as an {@link ErrorResultException}.
- *
- * @param timeout
- * The maximum time to wait.
- * @param unit
- * The time unit of the timeout argument.
- * @return The result, but only if the result code indicates that the
- * request succeeded.
- * @throws ErrorResultException
- * If the result code indicates that the request failed for some
- * reason.
- * @throws TimeoutException
- * If the wait timed out.
- * @throws InterruptedException
- * If the current thread was interrupted while waiting.
- */
- S get(long timeout, TimeUnit unit) throws ErrorResultException, TimeoutException,
- InterruptedException;
-
+public interface FutureResult<S> extends Promise<S, ErrorResultException> {
/**
* Returns the request ID of the request if appropriate.
*
@@ -103,23 +43,4 @@
*/
int getRequestID();
- /**
- * Returns {@code true} if the request was cancelled before it completed
- * normally.
- *
- * @return {@code true} if the request was cancelled before it completed
- * normally, otherwise {@code false}.
- */
- boolean isCancelled();
-
- /**
- * Returns {@code true} if the request has completed.
- * <p>
- * Completion may be due to normal termination, an exception, or
- * cancellation. In all of these cases, this method will return {@code true}.
- *
- * @return {@code true} if the request has completed, otherwise
- * {@code false}.
- */
- boolean isDone();
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultImpl.java
new file mode 100644
index 0000000..c6d4c82
--- /dev/null
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultImpl.java
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2014 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap;
+
+import org.forgerock.util.promise.PromiseImpl;
+
+/**
+ * This class provides an implementation of the {@code FutureResult}.
+ *
+ * @param <R>
+ * The type of result returned by this future.
+ * @see Promise
+ * @see Promises
+ */
+public class FutureResultImpl<R> extends PromiseImpl<R, ErrorResultException>
+ implements FutureResult<R>, ResultHandler<R> {
+ private final int requestID;
+
+ /**
+ * Creates a new future result with a request ID of -1.
+ */
+ public FutureResultImpl() {
+ this(-1);
+ }
+
+ /**
+ * Creates a future result with the provided request ID.
+ *
+ * @param requestID
+ * The request ID which will be returned by the default
+ * implementation of {@link #getRequestID}.
+ */
+ public FutureResultImpl(int requestID) {
+ this.requestID = requestID;
+ }
+
+ @Override
+ public int getRequestID() {
+ return requestID;
+ }
+}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultWrapper.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultWrapper.java
new file mode 100644
index 0000000..0fd5252
--- /dev/null
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/FutureResultWrapper.java
@@ -0,0 +1,281 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2014 ForgeRock AS.
+ */
+package org.forgerock.opendj.ldap;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Function;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.Promises;
+import org.forgerock.util.promise.SuccessHandler;
+
+/**
+ * This class is a {@link Promise} wrapper which implements {@link FutureResult} interface.
+ *
+ * It allows client code to return {@link FutureResult} instance when using {@link Promise}
+ * chaining methods (e.g onSuccess(), then(), thenAsync()).
+ *
+ * Wrapping is specially needed with {@link Promise} method which are not returning
+ * the original promise (i.e this) but a new one.
+ *
+ * It also provides some useful methods to create completed
+ * {@link FutureResult} instance.
+ *
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task does
+ * not return anything (i.e. it only has side-effects).
+ */
+public final class FutureResultWrapper<R> {
+ private static class LdapPromiseWrapper<R> implements FutureResult<R> {
+ private final Promise<R, ErrorResultException> wrappedPromise;
+ private final int requestID;
+
+ LdapPromiseWrapper(Promise<R, ErrorResultException> wrappedPromise, int requestID) {
+ this.wrappedPromise = wrappedPromise;
+ this.requestID = requestID;
+ }
+
+ @Override
+ public int getRequestID() {
+ return wrappedPromise instanceof FutureResult ? ((FutureResult<R>) wrappedPromise).getRequestID()
+ : requestID;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return wrappedPromise.cancel(mayInterruptIfRunning);
+ }
+
+ @Override
+ public R get() throws ExecutionException, InterruptedException {
+ return wrappedPromise.get();
+ }
+
+ @Override
+ public R get(long timeout, TimeUnit unit) throws ExecutionException, TimeoutException, InterruptedException {
+ return wrappedPromise.get(timeout, unit);
+ }
+
+ @Override
+ public R getOrThrow() throws InterruptedException, ErrorResultException {
+ return wrappedPromise.getOrThrow();
+ }
+
+ @Override
+ public R getOrThrow(long timeout, TimeUnit unit) throws InterruptedException, ErrorResultException,
+ TimeoutException {
+ return wrappedPromise.getOrThrow(timeout, unit);
+ }
+
+ @Override
+ public R getOrThrowUninterruptibly() throws ErrorResultException {
+ return wrappedPromise.getOrThrowUninterruptibly();
+ }
+
+ @Override
+ public R getOrThrowUninterruptibly(long timeout, TimeUnit unit) throws ErrorResultException, TimeoutException {
+ return wrappedPromise.getOrThrowUninterruptibly(timeout, unit);
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return wrappedPromise.isCancelled();
+ }
+
+ @Override
+ public boolean isDone() {
+ return wrappedPromise.isDone();
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> onFailure(FailureHandler<? super ErrorResultException> onFailure) {
+ wrappedPromise.onFailure(onFailure);
+ return this;
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> onSuccess(SuccessHandler<? super R> onSuccess) {
+ wrappedPromise.onSuccess(onSuccess);
+ return this;
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> onSuccessOrFailure(Runnable onSuccessOrFailure) {
+ wrappedPromise.onSuccessOrFailure(onSuccessOrFailure);
+ return this;
+ }
+
+ @Override
+ // @Checkstyle:ignore
+ public <VOUT> Promise<VOUT, ErrorResultException> then(
+ Function<? super R, VOUT, ErrorResultException> onSuccess) {
+ return new LdapPromiseWrapper<VOUT>(wrappedPromise.then(onSuccess), getRequestID());
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Override
+ // @Checkstyle:ignore
+ public <VOUT, EOUT extends Exception> Promise<VOUT, EOUT> then(Function<? super R, VOUT, EOUT> onSuccess,
+ Function<? super ErrorResultException, VOUT, EOUT> onFailure) {
+ return new LdapPromiseWrapper(wrappedPromise.then(onSuccess, onFailure), getRequestID());
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> then(SuccessHandler<? super R> onSuccess) {
+ wrappedPromise.then(onSuccess);
+ return this;
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> then(SuccessHandler<? super R> onSuccess,
+ FailureHandler<? super ErrorResultException> onFailure) {
+ wrappedPromise.then(onSuccess, onFailure);
+ return this;
+ }
+
+ @Override
+ public Promise<R, ErrorResultException> thenAlways(Runnable onSuccessOrFailure) {
+ wrappedPromise.thenAlways(onSuccessOrFailure);
+ return this;
+ }
+
+ @Override
+ // @Checkstyle:ignore
+ public <VOUT> Promise<VOUT, ErrorResultException> thenAsync(
+ AsyncFunction<? super R, VOUT, ErrorResultException> onSuccess) {
+ return new LdapPromiseWrapper<VOUT>(wrappedPromise.thenAsync(onSuccess), getRequestID());
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ // @Checkstyle:ignore
+ public <VOUT, EOUT extends Exception> Promise<VOUT, EOUT> thenAsync(
+ AsyncFunction<? super R, VOUT, EOUT> onSuccess,
+ AsyncFunction<? super ErrorResultException, VOUT, EOUT> onFailure) {
+ return new LdapPromiseWrapper(wrappedPromise.thenAsync(onSuccess, onFailure), getRequestID());
+ }
+ }
+
+ /**
+ * Returns a {@link FutureResult} representing an asynchronous task which
+ * has already succeeded with the provided result. Attempts to get the
+ * result will immediately return the result.
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task
+ * does not return anything (i.e. it only has side-effects).
+ * @param result
+ * The result of the asynchronous task.
+ * @return A {@link FutureResult} representing an asynchronous task which
+ * has already succeeded with the provided result.
+ */
+ public static <R> FutureResult<R> newSuccessfulFutureResult(final R result) {
+ return new LdapPromiseWrapper<R>(Promises.<R, ErrorResultException> newSuccessfulPromise(result), -1);
+ }
+
+ /**
+ * Returns a {@link FutureResult} representing an asynchronous task,
+ * identified by the provided requestID, which has already succeeded with
+ * the provided result. Attempts to get the result will immediately return
+ * the result.
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task
+ * does not return anything (i.e. it only has side-effects).
+ * @param result
+ * The result of the asynchronous task.
+ * @param requestID
+ * The request ID of the succeeded task.
+ * @return A {@link FutureResult} representing an asynchronous task which
+ * has already succeeded with the provided result.
+ */
+ public static <R> FutureResult<R> newSuccessfulFutureResult(final R result, int requestID) {
+ return new LdapPromiseWrapper<R>(Promises.<R, ErrorResultException> newSuccessfulPromise(result), requestID);
+ }
+
+ /**
+ * Returns a {@link FutureResult} representing an asynchronous task which
+ * has already failed with the provided error.
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task
+ * does not return anything (i.e. it only has side-effects).
+ * @param <E>
+ * The type of the exception thrown by the task if it fails.
+ * @param error
+ * The exception indicating why the asynchronous task has failed.
+ * @return A {@link FutureResult} representing an asynchronous task which
+ * has already failed with the provided error.
+ */
+ public static <R, E extends ErrorResultException> FutureResult<R> newFailedFutureResult(final E error) {
+ return new LdapPromiseWrapper<R>(Promises.<R, ErrorResultException> newFailedPromise(error), -1);
+ }
+
+ /**
+ * Returns a {@link FutureResult} representing an asynchronous task,
+ * identified by the provided requestID, which has already failed with the
+ * provided error.
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task
+ * does not return anything (i.e. it only has side-effects).
+ * @param <E>
+ * The type of the exception thrown by the task if it fails.
+ * @param error
+ * The exception indicating why the asynchronous task has failed.
+ * @param requestID
+ * The request ID of the failed task.
+ * @return A {@link FutureResult} representing an asynchronous task which
+ * has already failed with the provided error.
+ */
+ public static <R, E extends ErrorResultException> FutureResult<R> newFailedFutureResult(final E error,
+ int requestID) {
+ return new LdapPromiseWrapper<R>(Promises.<R, ErrorResultException> newFailedPromise(error), requestID);
+ }
+
+ /**
+ * Converts a {@link Promise} to a {@link FutureResult}.
+ *
+ * @param <R>
+ * The type of the task's result, or {@link Void} if the task
+ * does not return anything (i.e. it only has side-effects).
+ * @param wrappedPromise
+ * The {@link Promise} to wrap.
+ * @return A {@link FutureResult} representing the same asynchronous task as
+ * the {@link Promise} provided.
+ */
+ public static <R> FutureResult<R> asFutureResult(Promise<R, ErrorResultException> wrappedPromise) {
+ return new LdapPromiseWrapper<R>(wrappedPromise, -1);
+ }
+
+ private FutureResultWrapper() {
+ }
+}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java
index 3340904..831b244 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactory.java
@@ -26,15 +26,12 @@
*/
package org.forgerock.opendj.ldap;
-import static com.forgerock.opendj.util.StaticUtils.DEFAULT_SCHEDULER;
-import static com.forgerock.opendj.ldap.CoreMessages.*;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -65,14 +62,20 @@
import org.forgerock.opendj.ldap.responses.SearchResultReference;
import org.forgerock.opendj.ldap.spi.ConnectionState;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Function;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
-import com.forgerock.opendj.util.CompletedFutureResult;
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
import com.forgerock.opendj.util.ReferenceCountedObject;
import com.forgerock.opendj.util.TimeSource;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+
+import static com.forgerock.opendj.ldap.CoreMessages.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
+
/**
* An heart beat connection factory can be used to create connections that sends
* a periodic search request to a Directory Server.
@@ -109,122 +112,58 @@
* to a {@code ConnectionImpl} and registering it in the table of valid
* connections.
*/
- private final class ConnectionFutureResultImpl {
+ private final class ConnectionFutureResultImpl implements Runnable {
+ private Connection connection;
+ private Connection heartBeatConnection;
+ private ErrorResultException heartBeatError;
/**
- * This class handles the initial heart beat result notification or
- * timeout. We need to take care to avoid processing multiple results,
- * which may occur when the heart beat is timed out and a result follows
- * soon after, or vice versa.
+ * Due to a potential race between the heart beat timing out and the
+ * heart beat completing this atomic ensures that notification only
+ * occurs once.
*/
- private final class InitialHeartBeatResultHandler implements SearchResultHandler, Runnable {
- private final ResultHandler<? super Result> handler;
+ private final AtomicBoolean isComplete = new AtomicBoolean();
- /**
- * Due to a potential race between the heart beat timing out and the
- * heart beat completing this atomic ensures that notification only
- * occurs once.
- */
- private final AtomicBoolean isComplete = new AtomicBoolean();
+ private final Function<Result, Connection, ErrorResultException> futureSearchSuccess;
+ private final Function<ErrorResultException, Connection, ErrorResultException> futureSearchError;
- private InitialHeartBeatResultHandler(final ResultHandler<? super Result> handler) {
- this.handler = handler;
- }
-
- @Override
- public boolean handleEntry(final SearchResultEntry entry) {
- /*
- * Depending on the configuration, a heartbeat may return some
- * entries. However, we can just ignore them.
- */
- return true;
- }
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- if (isComplete.compareAndSet(false, true)) {
- handler.handleErrorResult(error);
- }
- }
-
- @Override
- public boolean handleReference(final SearchResultReference reference) {
- /*
- * Depending on the configuration, a heartbeat may return some
- * references. However, we can just ignore them.
- */
- return true;
- }
-
- @Override
- public void handleResult(final Result result) {
- if (isComplete.compareAndSet(false, true)) {
- handler.handleResult(result);
- }
- }
-
- /*
- * Invoked by the scheduler when the heart beat times out.
- */
- @Override
- public void run() {
- handleErrorResult(newHeartBeatTimeoutError());
- }
- }
-
- private Connection connection;
- private final RecursiveFutureResult<Connection, Result> futureConnectionResult;
- private final FutureResultTransformer<Result, Connection> futureSearchResult;
-
- private ConnectionFutureResultImpl(final ResultHandler<? super Connection> handler) {
- // Create a future which will handle the initial heart beat result.
- this.futureSearchResult = new FutureResultTransformer<Result, Connection>(handler) {
+ private ConnectionFutureResultImpl() {
+ this.futureSearchSuccess = new Function<Result, Connection, ErrorResultException>() {
@Override
- protected ErrorResultException transformErrorResult(
- final ErrorResultException errorResult) {
- // Ensure that the connection is closed.
- if (connection != null) {
- connection.close();
- connection = null;
+ public Connection apply(Result result) throws ErrorResultException {
+ if (isComplete.compareAndSet(false, true)) {
+ heartBeatConnection = adaptConnection(connection);
}
- releaseScheduler();
- return adaptHeartBeatError(errorResult);
- }
- @Override
- protected Connection transformResult(final Result result)
- throws ErrorResultException {
- return adaptConnection(connection);
+ return heartBeatConnection;
}
-
};
- // Create a future which will handle connection result.
- this.futureConnectionResult =
- new RecursiveFutureResult<Connection, Result>(futureSearchResult) {
- @Override
- protected FutureResult<? extends Result> chainResult(
- final Connection innerResult,
- final ResultHandler<? super Result> handler)
- throws ErrorResultException {
- // Save the connection for later once the heart beat completes.
- connection = innerResult;
+ this.futureSearchError = new Function<ErrorResultException, Connection, ErrorResultException>() {
+ @Override
+ public Connection apply(ErrorResultException error) throws ErrorResultException {
+ manageError(error);
+ throw heartBeatError;
+ }
+ };
+ }
- /*
- * Send the initial heart beat and schedule a client
- * side timeout notification.
- */
- final InitialHeartBeatResultHandler wrappedHandler =
- new InitialHeartBeatResultHandler(handler);
- scheduler.get().schedule(wrappedHandler, timeoutMS,
- TimeUnit.MILLISECONDS);
- return connection.searchAsync(heartBeatRequest, null, wrappedHandler);
- }
- };
+ @Override
+ public void run() {
+ manageError(newHeartBeatTimeoutError());
+ }
- // Link the two futures.
- futureSearchResult.setFutureResult(futureConnectionResult);
+ private void manageError(ErrorResultException error) {
+ if (isComplete.compareAndSet(false, true)) {
+ // Ensure that the connection is closed.
+ if (connection != null) {
+ connection.close();
+ connection = null;
+ }
+ releaseScheduler();
+ heartBeatError = adaptHeartBeatError(error);
+ }
}
}
@@ -241,105 +180,38 @@
* completed requests are removed from the {@code pendingResults} queue,
* as well as ensuring that requests are only completed once.
*/
- private abstract class AbstractWrappedResultHandler<R, H extends ResultHandler<? super R>>
- implements ResultHandler<R>, FutureResult<R> {
- /** The user provided result handler. */
- protected final H handler;
-
- private final CountDownLatch completed = new CountDownLatch(1);
- private ErrorResultException error;
- private FutureResult<R> innerFuture;
- private R result;
-
- AbstractWrappedResultHandler(final H handler) {
- this.handler = handler;
- }
+ private abstract class AbstractWrappedResultHandler<R> implements ResultHandler<R> {
+ private final AtomicBoolean completed = new AtomicBoolean();
@Override
- public boolean cancel(final boolean mayInterruptIfRunning) {
- return innerFuture.cancel(mayInterruptIfRunning);
- }
-
- @Override
- public R get() throws ErrorResultException, InterruptedException {
- completed.await();
- return get0();
- }
-
- @Override
- public R get(final long timeout, final TimeUnit unit) throws ErrorResultException,
- TimeoutException, InterruptedException {
- if (completed.await(timeout, unit)) {
- return get0();
- } else {
- throw new TimeoutException();
- }
- }
-
- @Override
- public int getRequestID() {
- return innerFuture.getRequestID();
- }
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- if (tryComplete(null, error)) {
- if (handler != null) {
- handler.handleErrorResult(timestamp(error));
- } else {
- timestamp(error);
- }
+ public void handleError(final ErrorResultException error) {
+ if (tryComplete()) {
+ timestamp(error);
}
}
@Override
public void handleResult(final R result) {
- if (tryComplete(result, null)) {
- if (handler != null) {
- handler.handleResult(timestamp(result));
- } else {
- timestamp(result);
- }
+ if (tryComplete()) {
+ timestamp(result);
}
}
- @Override
- public boolean isCancelled() {
- return innerFuture.isCancelled();
- }
-
- @Override
public boolean isDone() {
- return completed.getCount() == 0;
+ return completed.get();
}
abstract void releaseBindOrStartTLSLockIfNeeded();
- FutureResult<R> setInnerFuture(final FutureResult<R> innerFuture) {
- this.innerFuture = innerFuture;
- return this;
- }
-
- private R get0() throws ErrorResultException {
- if (result != null) {
- return result;
- } else {
- throw error;
- }
- }
-
/**
* Attempts to complete this request, returning true if successful.
* This method is synchronized in order to avoid race conditions
* with search result processing.
*/
- private synchronized boolean tryComplete(final R result,
- final ErrorResultException error) {
+ private synchronized boolean tryComplete() {
if (pendingResults.remove(this)) {
- this.result = result;
- this.error = error;
- completed.countDown();
releaseBindOrStartTLSLockIfNeeded();
+ completed.set(true);
return true;
} else {
return false;
@@ -355,14 +227,9 @@
* @param <R>
* The type of result returned by the request.
*/
- private abstract class DelayedFuture<R extends Result> extends
- AsynchronousFutureResult<R, ResultHandler<? super R>> implements Runnable {
+ private abstract class DelayedFuture<R extends Result> extends FutureResultImpl<R> implements Runnable {
private volatile FutureResult<R> innerFuture = null;
- protected DelayedFuture(final ResultHandler<? super R> handler) {
- super(handler);
- }
-
@Override
public final int getRequestID() {
return innerFuture != null ? innerFuture.getRequestID() : -1;
@@ -382,8 +249,7 @@
protected abstract FutureResult<R> dispatch();
@Override
- protected final ErrorResultException handleCancelRequest(
- final boolean mayInterruptIfRunning) {
+ protected final ErrorResultException tryCancel(final boolean mayInterruptIfRunning) {
if (innerFuture != null) {
innerFuture.cancel(mayInterruptIfRunning);
}
@@ -395,12 +261,7 @@
* A result handler wrapper for bind or startTLS requests which releases
* the bind/startTLS lock on completion.
*/
- private final class WrappedBindOrStartTLSResultHandler<R> extends
- AbstractWrappedResultHandler<R, ResultHandler<? super R>> {
- WrappedBindOrStartTLSResultHandler(final ResultHandler<? super R> handler) {
- super(handler);
- }
-
+ private final class WrappedBindOrStartTLSResultHandler<R> extends AbstractWrappedResultHandler<R> {
@Override
void releaseBindOrStartTLSLockIfNeeded() {
releaseBindOrStartTLSLock();
@@ -411,12 +272,7 @@
* A result handler wrapper for normal requests which does not release
* the bind/startTLS lock on completion.
*/
- private final class WrappedResultHandler<R> extends
- AbstractWrappedResultHandler<R, ResultHandler<? super R>> {
- WrappedResultHandler(final ResultHandler<? super R> handler) {
- super(handler);
- }
-
+ private final class WrappedResultHandler<R> extends AbstractWrappedResultHandler<R> {
@Override
void releaseBindOrStartTLSLockIfNeeded() {
// No-op for normal operations.
@@ -428,18 +284,19 @@
* results are not sent once the request has been completed (see
* markComplete()).
*/
- private final class WrappedSearchResultHandler extends
- AbstractWrappedResultHandler<Result, SearchResultHandler> implements
+ private final class WrappedSearchResultHandler extends AbstractWrappedResultHandler<Result> implements
SearchResultHandler {
+ private final SearchResultHandler entryHandler;
+
WrappedSearchResultHandler(final SearchResultHandler handler) {
- super(handler);
+ this.entryHandler = handler;
}
@Override
public synchronized boolean handleEntry(final SearchResultEntry entry) {
if (!isDone()) {
- if (handler != null) {
- handler.handleEntry(timestamp(entry));
+ if (entryHandler != null) {
+ entryHandler.handleEntry(timestamp(entry));
} else {
timestamp(entry);
}
@@ -452,8 +309,8 @@
@Override
public synchronized boolean handleReference(final SearchResultReference reference) {
if (!isDone()) {
- if (handler != null) {
- handler.handleReference(timestamp(reference));
+ if (entryHandler != null) {
+ entryHandler.handleReference(timestamp(reference));
} else {
timestamp(reference);
}
@@ -475,44 +332,17 @@
/**
* Search result handler for processing heart beat responses.
*/
- private final SearchResultHandler heartBeatHandler = new SearchResultHandler() {
+ private final SearchResultHandler heartBeatEntryHandler = new SearchResultHandler() {
@Override
public boolean handleEntry(final SearchResultEntry entry) {
timestamp(entry);
return true;
}
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- /*
- * Connection failure will be handled by connection event
- * listener. Ignore cancellation errors since these indicate
- * that the heart beat was aborted by a client-side close.
- */
- if (!(error instanceof CancelledResultException)) {
- /*
- * Log at debug level to avoid polluting the logs with
- * benign password policy related errors. See OPENDJ-1168
- * and OPENDJ-1167.
- */
- logger.debug(LocalizableMessage.raw("Heartbeat failed for connection factory '%s'", factory,
- error));
- timestamp(error);
- }
- releaseHeartBeatLock();
- }
-
@Override
public boolean handleReference(final SearchResultReference reference) {
timestamp(reference);
return true;
}
-
- @Override
- public void handleResult(final Result result) {
- timestamp(result);
- releaseHeartBeatLock();
- }
};
/**
@@ -527,8 +357,8 @@
* signalled if no heart beat is detected within the permitted timeout
* period.
*/
- private final Queue<AbstractWrappedResultHandler<?, ?>> pendingResults =
- new ConcurrentLinkedQueue<AbstractWrappedResultHandler<?, ?>>();
+ private final Queue<AbstractWrappedResultHandler<?>> pendingResults =
+ new ConcurrentLinkedQueue<AbstractWrappedResultHandler<?>>();
/** Internal connection state. */
private final ConnectionState state = new ConnectionState();
@@ -554,11 +384,9 @@
@Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedResultHandler<Result> h = wrap(resultHandler);
- return checkState(connection.addAsync(request, intermediateResponseHandler, h), h);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
+ return then(connection.addAsync(request, intermediateResponseHandler), createResultHandler());
} else {
return newConnectionErrorFuture();
}
@@ -571,31 +399,24 @@
@Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
- if (checkState(resultHandler)) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
if (sync.tryLockShared()) {
// Fast path
- final WrappedBindOrStartTLSResultHandler<BindResult> h =
- wrapForBindOrStartTLS(resultHandler);
- return checkState(
- connection.bindAsync(request, intermediateResponseHandler, h), h);
+ return then(connection.bindAsync(request, intermediateResponseHandler), wrapForBindOrStartTLS());
} else {
/*
* A heart beat must be in progress so create a runnable
* task which will be executed when the heart beat
* completes.
*/
- final DelayedFuture<BindResult> future =
- new DelayedFuture<BindResult>(resultHandler) {
- @Override
- public FutureResult<BindResult> dispatch() {
- final WrappedBindOrStartTLSResultHandler<BindResult> h =
- wrapForBindOrStartTLS(this);
- return checkState(connection.bindAsync(request,
- intermediateResponseHandler, h), h);
- }
- };
+ final DelayedFuture<BindResult> future = new DelayedFuture<BindResult>() {
+ @Override
+ public FutureResult<BindResult> dispatch() {
+ return HeartBeatConnectionFactory.this.then(
+ connection.bindAsync(request, intermediateResponseHandler), wrapForBindOrStartTLS());
+ }
+ };
/*
* Enqueue and flush if the heart beat has completed in the
* mean time.
@@ -623,12 +444,9 @@
@Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedResultHandler<CompareResult> h = wrap(resultHandler);
- return checkState(connection.compareAsync(request, intermediateResponseHandler, h),
- h);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
+ return then(connection.compareAsync(request, intermediateResponseHandler), createResultHandler());
} else {
return newConnectionErrorFuture();
}
@@ -636,43 +454,35 @@
@Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedResultHandler<Result> h = wrap(resultHandler);
- return checkState(connection.deleteAsync(request, intermediateResponseHandler, h),
- h);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
+ return then(connection.deleteAsync(request, intermediateResponseHandler), createResultHandler());
} else {
return newConnectionErrorFuture();
}
}
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
- if (checkState(resultHandler)) {
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
if (isStartTLSRequest(request)) {
if (sync.tryLockShared()) {
// Fast path
- final WrappedBindOrStartTLSResultHandler<R> h =
- wrapForBindOrStartTLS(resultHandler);
- return checkState(connection.extendedRequestAsync(request,
- intermediateResponseHandler, h), h);
+ return then(connection.extendedRequestAsync(request, intermediateResponseHandler),
+ wrapForBindOrStartTLS());
} else {
/*
* A heart beat must be in progress so create a runnable
* task which will be executed when the heart beat
* completes.
*/
- final DelayedFuture<R> future = new DelayedFuture<R>(resultHandler) {
+ final DelayedFuture<R> future = new DelayedFuture<R>() {
@Override
public FutureResult<R> dispatch() {
- final WrappedBindOrStartTLSResultHandler<R> h =
- wrapForBindOrStartTLS(this);
- return checkState(connection.extendedRequestAsync(request,
- intermediateResponseHandler, h), h);
+ return HeartBeatConnectionFactory.this.then(
+ connection.extendedRequestAsync(request, intermediateResponseHandler),
+ wrapForBindOrStartTLS());
}
};
@@ -685,9 +495,8 @@
return future;
}
} else {
- final WrappedResultHandler<R> h = wrap(resultHandler);
- return checkState(connection.extendedRequestAsync(request,
- intermediateResponseHandler, h), h);
+ return then(connection.extendedRequestAsync(request, intermediateResponseHandler),
+ createResultHandler());
}
} else {
return newConnectionErrorFuture();
@@ -740,12 +549,9 @@
@Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedResultHandler<Result> h = wrap(resultHandler);
- return checkState(connection.modifyAsync(request, intermediateResponseHandler, h),
- h);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
+ return then(connection.modifyAsync(request, intermediateResponseHandler), createResultHandler());
} else {
return newConnectionErrorFuture();
}
@@ -753,12 +559,9 @@
@Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedResultHandler<Result> h = wrap(resultHandler);
- return checkState(
- connection.modifyDNAsync(request, intermediateResponseHandler, h), h);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ if (checkState()) {
+ return then(connection.modifyDNAsync(request, intermediateResponseHandler), createResultHandler());
} else {
return newConnectionErrorFuture();
}
@@ -772,11 +575,11 @@
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
- if (checkState(resultHandler)) {
- final WrappedSearchResultHandler h = wrap(resultHandler);
- return checkState(connection.searchAsync(request, intermediateResponseHandler, h),
- h);
+ final SearchResultHandler searchHandler) {
+ if (checkState()) {
+ final WrappedSearchResultHandler entryHandler = wrap(searchHandler);
+ return then(connection.searchAsync(request, intermediateResponseHandler, entryHandler),
+ createResultHandler());
} else {
return newConnectionErrorFuture();
}
@@ -809,23 +612,8 @@
}
}
- private <R> FutureResult<R> checkState(final FutureResult<R> future,
- final AbstractWrappedResultHandler<R, ? extends ResultHandler<? super R>> h) {
- h.setInnerFuture(future);
- checkState(h);
- return h;
- }
-
- private boolean checkState(final ResultHandler<?> h) {
- final ErrorResultException error = state.getConnectionError();
- if (error != null) {
- if (h != null) {
- h.handleErrorResult(error);
- }
- return false;
- } else {
- return true;
- }
+ private boolean checkState() {
+ return state.getConnectionError() == null;
}
private void failPendingResults(final ErrorResultException error) {
@@ -833,9 +621,9 @@
* Peek instead of pool because notification is responsible for
* removing the element from the queue.
*/
- AbstractWrappedResultHandler<?, ?> pendingResult;
+ AbstractWrappedResultHandler<?> pendingResult;
while ((pendingResult = pendingResults.peek()) != null) {
- pendingResult.handleErrorResult(error);
+ pendingResult.handleError(error);
}
}
@@ -864,8 +652,8 @@
return request.getOID().equals(StartTLSExtendedRequest.OID);
}
- private <R> CompletedFutureResult<R> newConnectionErrorFuture() {
- return new CompletedFutureResult<R>(state.getConnectionError());
+ private <R> FutureResult<R> newConnectionErrorFuture() {
+ return FutureResultWrapper.newFailedFutureResult(state.getConnectionError());
}
private void releaseBindOrStartTLSLock() {
@@ -908,7 +696,39 @@
*/
if (sync.tryLockExclusively()) {
try {
- connection.searchAsync(heartBeatRequest, null, heartBeatHandler);
+ FutureResult<Result> future = connection.searchAsync(heartBeatRequest, heartBeatEntryHandler);
+ if (future != null) {
+ future.onSuccess(new SuccessHandler<Result>() {
+ @Override
+ public void handleResult(Result result) {
+ timestamp(result);
+ releaseHeartBeatLock();
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ /*
+ * Connection failure will be handled by
+ * connection event listener. Ignore
+ * cancellation errors since these indicate that
+ * the heart beat was aborted by a client-side
+ * close.
+ */
+ if (!(error instanceof CancelledResultException)) {
+ /*
+ * Log at debug level to avoid polluting the
+ * logs with benign password policy related
+ * errors. See OPENDJ-1168 and OPENDJ-1167.
+ */
+ logger.debug(LocalizableMessage.raw("Heartbeat failed for connection factory '%s'",
+ factory, error));
+ timestamp(error);
+ }
+ releaseHeartBeatLock();
+
+ }
+ });
+ }
} catch (final IllegalStateException e) {
/*
* This may happen when we attempt to send the heart beat
@@ -938,8 +758,8 @@
return response;
}
- private <R> WrappedResultHandler<R> wrap(final ResultHandler<? super R> handler) {
- final WrappedResultHandler<R> h = new WrappedResultHandler<R>(handler);
+ private <R> WrappedResultHandler<R> createResultHandler() {
+ final WrappedResultHandler<R> h = new WrappedResultHandler<R>();
pendingResults.add(h);
return h;
}
@@ -950,10 +770,8 @@
return h;
}
- private <R> WrappedBindOrStartTLSResultHandler<R> wrapForBindOrStartTLS(
- final ResultHandler<? super R> handler) {
- final WrappedBindOrStartTLSResultHandler<R> h =
- new WrappedBindOrStartTLSResultHandler<R>(handler);
+ private <R> WrappedBindOrStartTLSResultHandler<R> wrapForBindOrStartTLS() {
+ final WrappedBindOrStartTLSResultHandler<R> h = new WrappedBindOrStartTLSResultHandler<R>();
pendingResults.add(h);
return h;
}
@@ -1241,7 +1059,7 @@
try {
final Connection connection = factory.getConnection();
try {
- connection.searchAsync(heartBeatRequest, null, null).get(timeoutMS,
+ connection.searchAsync(heartBeatRequest, null).getOrThrow(timeoutMS,
TimeUnit.MILLISECONDS);
succeeded = true;
return adaptConnection(connection);
@@ -1260,22 +1078,24 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
acquireScheduler(); // Protect scheduler.
- // Create a future responsible for chaining the initial heartbeat search.
- final ConnectionFutureResultImpl compositeFuture = new ConnectionFutureResultImpl(handler);
+ // Create a future responsible for chaining the initial heartbeat
+ // search.
+ final ConnectionFutureResultImpl compositeFuture = new ConnectionFutureResultImpl();
- // Request a connection.
- final FutureResult<Connection> connectionFuture =
- factory.getConnectionAsync(compositeFuture.futureConnectionResult);
-
- // Set the connection future in the composite so that the returned search future can delegate.
- compositeFuture.futureConnectionResult.setFutureResult(connectionFuture);
-
- // Return the future representing the heartbeat.
- return compositeFuture.futureSearchResult;
+ // Request a connection and return the future representing the
+ // heartbeat.
+ return factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(final Connection connectionResult) {
+ // Save the connection for later once the heart beat completes.
+ compositeFuture.connection = connectionResult;
+ scheduler.get().schedule(compositeFuture, timeoutMS, TimeUnit.MILLISECONDS);
+ return connectionResult.searchAsync(heartBeatRequest, null);
+ }
+ }).then(compositeFuture.futureSearchSuccess, compositeFuture.futureSearchError);
}
@Override
@@ -1301,6 +1121,11 @@
}
}
+ private <R extends Result> FutureResult<R> then(FutureResult<R> future,
+ ResultHandler<? super Object> resultHandler) {
+ return (FutureResult<R>) future.onSuccess(resultHandler).onFailure(resultHandler);
+ }
+
private ErrorResultException adaptHeartBeatError(final Exception error) {
if (error instanceof ConnectionException) {
return (ErrorResultException) error;
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnection.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnection.java
index 319b279..4d753d4 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnection.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnection.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
@@ -51,8 +51,6 @@
import org.forgerock.opendj.ldap.spi.LDAPExtendedFutureResultImpl;
import org.forgerock.opendj.ldap.spi.LDAPFutureResultImpl;
import org.forgerock.opendj.ldap.spi.LDAPSearchFutureResultImpl;
-
-import com.forgerock.opendj.util.CompletedFutureResult;
import org.forgerock.util.Reject;
/**
@@ -66,10 +64,9 @@
private final BindRequest bindRequest;
InternalBindFutureResultImpl(final int messageID, final BindRequest bindRequest,
- final ResultHandler<? super BindResult> resultHandler,
final IntermediateResponseHandler intermediateResponseHandler,
final Connection connection) {
- super(messageID, resultHandler, intermediateResponseHandler, connection);
+ super(messageID, intermediateResponseHandler, connection);
this.bindRequest = bindRequest;
}
@@ -117,7 +114,7 @@
public FutureResult<Void> abandonAsync(final AbandonRequest request) {
final int i = messageID.getAndIncrement();
serverConnection.handleAbandon(i, request);
- return new CompletedFutureResult<Void>((Void) null, i);
+ return FutureResultWrapper.newSuccessfulFutureResult((Void) null, i);
}
/**
@@ -125,12 +122,9 @@
*/
@Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler,
- this);
+ final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, intermediateResponseHandler, this);
serverConnection.handleAdd(i, request, future, future);
return future;
}
@@ -149,12 +143,10 @@
*/
@Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final InternalBindFutureResultImpl future =
- new InternalBindFutureResultImpl(i, request, resultHandler,
- intermediateResponseHandler, this);
+ final InternalBindFutureResultImpl future = new InternalBindFutureResultImpl(i, request,
+ intermediateResponseHandler, this);
serverConnection.handleBind(i, 3, request, future, future);
return future;
}
@@ -173,12 +165,10 @@
*/
@Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPCompareFutureResultImpl future =
- new LDAPCompareFutureResultImpl(i, request, resultHandler,
- intermediateResponseHandler, this);
+ final LDAPCompareFutureResultImpl future = new LDAPCompareFutureResultImpl(i, request,
+ intermediateResponseHandler, this);
serverConnection.handleCompare(i, request, future, future);
return future;
}
@@ -188,12 +178,9 @@
*/
@Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler,
- this);
+ final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, intermediateResponseHandler, this);
serverConnection.handleDelete(i, request, future, future);
return future;
}
@@ -202,14 +189,11 @@
* {@inheritDoc}
*/
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPExtendedFutureResultImpl<R> future =
- new LDAPExtendedFutureResultImpl<R>(i, request, resultHandler,
- intermediateResponseHandler, this);
+ final LDAPExtendedFutureResultImpl<R> future = new LDAPExtendedFutureResultImpl<R>(i, request,
+ intermediateResponseHandler, this);
serverConnection.handleExtendedRequest(i, request, future, future);
return future;
}
@@ -237,12 +221,9 @@
*/
@Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler,
- this);
+ final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, intermediateResponseHandler, this);
serverConnection.handleModify(i, request, future, future);
return future;
}
@@ -252,12 +233,9 @@
*/
@Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int i = messageID.getAndIncrement();
- final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(i, request, resultHandler, intermediateResponseHandler,
- this);
+ final LDAPFutureResultImpl future = new LDAPFutureResultImpl(i, request, intermediateResponseHandler, this);
serverConnection.handleModifyDN(i, request, future, future);
return future;
}
@@ -276,19 +254,18 @@
*/
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler) {
final int i = messageID.getAndIncrement();
- final LDAPSearchFutureResultImpl future =
- new LDAPSearchFutureResultImpl(i, request, resultHandler,
- intermediateResponseHandler, this);
- serverConnection.handleSearch(i, request, future, future);
+ final LDAPSearchFutureResultImpl future = new LDAPSearchFutureResultImpl(i, request, entryHandler,
+ intermediateResponseHandler, this);
+ serverConnection.handleSearch(i, request, future, future, future);
return future;
}
/**
* {@inheritDoc}
*/
+ @Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("InternalConnection(");
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java
index af979b5..ca78947 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/InternalConnectionFactory.java
@@ -22,12 +22,16 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import org.forgerock.util.promise.Promise;
+
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+import static org.forgerock.util.promise.Promises.*;
+
/**
* A special {@code ConnectionFactory} which waits for internal connection
@@ -63,30 +67,25 @@
// Nothing to do.
}
+ @Override
public Connection getConnection() throws ErrorResultException {
final ServerConnection<Integer> serverConnection = factory.handleAccept(clientContext);
return new InternalConnection(serverConnection);
}
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
+ @Override
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
final ServerConnection<Integer> serverConnection;
try {
serverConnection = factory.handleAccept(clientContext);
} catch (final ErrorResultException e) {
- if (handler != null) {
- handler.handleErrorResult(e);
- }
- return new CompletedFutureResult<Connection>(e);
+ return newFailedFutureResult(e);
}
- final InternalConnection connection = new InternalConnection(serverConnection);
- if (handler != null) {
- handler.handleResult(connection);
- }
- return new CompletedFutureResult<Connection>(connection);
+ return newSuccessfulPromise((Connection) new InternalConnection(serverConnection));
}
+ @Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("InternalConnectionFactory(");
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
index 1881392..9e7cf6a 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPConnectionFactory.java
@@ -32,6 +32,7 @@
import org.forgerock.opendj.ldap.spi.LDAPConnectionFactoryImpl;
import org.forgerock.opendj.ldap.spi.TransportProvider;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Promise;
/**
* A factory class which can be used to obtain connections to an LDAP Directory
@@ -47,7 +48,7 @@
/*
* Transport provider that provides the implementation of this factory.
*/
- private TransportProvider provider;
+ private final TransportProvider provider;
/**
* Creates a new LDAP connection factory which can be used to create LDAP
@@ -96,9 +97,8 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
- return impl.getConnectionAsync(handler);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ return impl.getConnectionAsync();
}
@Override
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java
index c3edcdf..dfd8078 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LoadBalancer.java
@@ -22,13 +22,15 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
-import com.forgerock.opendj.util.CompletedFutureResult;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Promise;
+
+import static org.forgerock.util.promise.Promises.*;
/**
* A load balancing connection factory allocates connections using the provided
@@ -54,20 +56,16 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> resultHandler) {
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
final ConnectionFactory factory;
try {
factory = algorithm.getConnectionFactory();
} catch (final ErrorResultException e) {
- if (resultHandler != null) {
- resultHandler.handleErrorResult(e);
- }
- return new CompletedFutureResult<Connection>(e);
+ return newFailedPromise(e);
}
- return factory.getConnectionAsync(resultHandler);
+ return factory.getConnectionAsync();
}
@Override
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
index b8065b0..f767725 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/MemoryBackend.java
@@ -20,7 +20,7 @@
*
* CDDL HEADER END
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
@@ -248,7 +248,7 @@
}
resultHandler.handleResult(getResult(request, null, request));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -279,17 +279,17 @@
}
resultHandler.handleResult(getBindResult(request, entry, entry));
} catch (final LocalizedIllegalArgumentException e) {
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, e));
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR, e));
} catch (final EntryNotFoundException e) {
/*
* Usually you would not include a diagnostic message, but we'll add
* one here because the memory back-end is not intended for
* production use.
*/
- resultHandler.handleErrorResult(newErrorResult(ResultCode.INVALID_CREDENTIALS,
+ resultHandler.handleError(newErrorResult(ResultCode.INVALID_CREDENTIALS,
"Unknown user"));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -310,7 +310,7 @@
resultHandler.handleResult(getCompareResult(request, entry, entry.containsAttribute(
assertion, null)));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -338,9 +338,9 @@
}
resultHandler.handleResult(getResult(request, entry, null));
} catch (final DecodeException e) {
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, e));
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR, e));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -349,7 +349,7 @@
final RequestContext requestContext, final ExtendedRequest<R> request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<R> resultHandler) {
- resultHandler.handleErrorResult(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
+ resultHandler.handleError(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
"Extended request operation not supported"));
}
@@ -368,7 +368,7 @@
}
resultHandler.handleResult(getResult(request, entry, newEntry));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -376,42 +376,40 @@
public void handleModifyDN(final RequestContext requestContext, final ModifyDNRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) {
- resultHandler.handleErrorResult(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
+ resultHandler.handleError(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
"ModifyDN request operation not supported"));
}
@Override
public void handleSearch(final RequestContext requestContext, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ ResultHandler<Result> resultHandler) {
try {
final DN dn = request.getName();
final SearchScope scope = request.getScope();
final Filter filter = request.getFilter();
final Matcher matcher = filter.matcher(schema);
final AttributeFilter attributeFilter =
- new AttributeFilter(request.getAttributes(), schema).typesOnly(request
- .isTypesOnly());
+ new AttributeFilter(request.getAttributes(), schema).typesOnly(request.isTypesOnly());
if (scope.equals(SearchScope.BASE_OBJECT)) {
final Entry baseEntry = getRequiredEntry(request, dn);
if (matcher.matches(baseEntry).toBoolean()) {
- sendEntry(attributeFilter, resultHandler, baseEntry);
+ sendEntry(attributeFilter, entryHandler, baseEntry);
}
resultHandler.handleResult(newResult(ResultCode.SUCCESS));
} else if (scope.equals(SearchScope.SINGLE_LEVEL) || scope.equals(SearchScope.SUBORDINATES)
|| scope.equals(SearchScope.WHOLE_SUBTREE)) {
- searchWithSubordinates(requestContext, resultHandler, dn, matcher, attributeFilter,
- request.getSizeLimit(), scope, request.getControl(
- SimplePagedResultsControl.DECODER, new DecodeOptions()));
+ searchWithSubordinates(requestContext, entryHandler, resultHandler, dn, matcher, attributeFilter,
+ request.getSizeLimit(), scope,
+ request.getControl(SimplePagedResultsControl.DECODER, new DecodeOptions()));
} else {
- throw newErrorResult(ResultCode.PROTOCOL_ERROR,
- "Search request contains an unsupported search scope");
+ throw newErrorResult(ResultCode.PROTOCOL_ERROR, "Search request contains an unsupported search scope");
}
} catch (DecodeException e) {
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
- ResultCode.PROTOCOL_ERROR, e.getMessage(), e));
+ resultHandler.handleError(ErrorResultException.newErrorResult(ResultCode.PROTOCOL_ERROR, e.getMessage(),
+ e));
} catch (final ErrorResultException e) {
- resultHandler.handleErrorResult(e);
+ resultHandler.handleError(e);
}
}
@@ -490,11 +488,10 @@
* @throws ErrorResultException
* If the request is unsuccessful.
*/
- private void searchWithSubordinates(final RequestContext requestContext,
- final SearchResultHandler resultHandler, final DN dn, final Matcher matcher,
+ private void searchWithSubordinates(final RequestContext requestContext, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler, final DN dn, final Matcher matcher,
final AttributeFilter attributeFilter, final int sizeLimit, SearchScope scope,
- SimplePagedResultsControl pagedResults) throws CancelledResultException,
- ErrorResultException {
+ SimplePagedResultsControl pagedResults) throws CancelledResultException, ErrorResultException {
final int pageSize = pagedResults != null ? pagedResults.getSize() : 0;
final int offset = (pagedResults != null && !pagedResults.getCookie().isEmpty())
? Integer.valueOf(pagedResults.getCookie().toString()) : 0;
@@ -504,7 +501,7 @@
for (final Entry entry : subtree.values()) {
requestContext.checkIfCancelled(false);
if (scope.equals(SearchScope.WHOLE_SUBTREE) || entry.getName().isChildOf(dn)
- || (scope.equals(SearchScope.SUBORDINATES) && !entry.getName().equals(dn))) {
+ || (scope.equals(SearchScope.SUBORDINATES) && !entry.getName().equals(dn))) {
if (matcher.matches(entry).toBoolean()) {
/*
* This entry is going to be returned to the client so it
@@ -522,7 +519,7 @@
}
// Send the entry back to the client.
- if (!sendEntry(attributeFilter, resultHandler, entry)) {
+ if (!sendEntry(attributeFilter, entryHandler, entry)) {
// Client has disconnected or cancelled.
break;
}
@@ -538,9 +535,8 @@
}
final Result result = newResult(ResultCode.SUCCESS);
if (pageSize > 0) {
- final ByteString cookie =
- numberOfResults == pageSize ? ByteString.valueOf(String.valueOf(position))
- : ByteString.empty();
+ final ByteString cookie = numberOfResults == pageSize ? ByteString.valueOf(String.valueOf(position))
+ : ByteString.empty();
result.addControl(SimplePagedResultsControl.newControl(true, 0, cookie));
}
resultHandler.handleResult(result);
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java
index c94f0ca..94d5a4c 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandler.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
@@ -213,13 +213,16 @@
* @param intermediateResponseHandler
* The handler which should be used to send back any intermediate
* responses to the client.
+ * @param entryHandler
+ * The entry handler which should be used to send back the search
+ * entries results to the client.
* @param resultHandler
- * The handler which should be used to send back the search
- * results to the client.
+ * The handler which should be used to send back the result to
+ * the client.
* @throws UnsupportedOperationException
* If this request handler does not handle search requests.
*/
void handleSearch(C requestContext, SearchRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- SearchResultHandler resultHandler);
+ IntermediateResponseHandler intermediateResponseHandler, SearchResultHandler entryHandler,
+ ResultHandler<Result> resultHandler);
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java
index 05422c7..631afdd 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RequestHandlerFactoryAdapter.java
@@ -21,7 +21,7 @@
* CDDL HEADER END
*
*
- * Copyright 2011-2013 ForgeRock AS
+ * Copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
@@ -103,7 +103,7 @@
final R cancelResult =
request.getResultDecoder().newExtendedErrorResult(ResultCode.TOO_LATE, "",
"");
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(cancelResult));
+ resultHandler.handleError(ErrorResultException.newErrorResult(cancelResult));
}
}
@@ -238,7 +238,7 @@
* {@inheritDoc}
*/
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
if (clientConnection.removePendingRequest(this)) {
if (setResult(error.getResult())) {
/*
@@ -248,7 +248,7 @@
* not be sent to the client.
*/
}
- resultHandler.handleErrorResult(error);
+ resultHandler.handleError(error);
}
}
@@ -293,7 +293,7 @@
if (cancelResultHandler != null) {
final Result result =
Responses.newGenericExtendedResult(ResultCode.CANNOT_CANCEL);
- cancelResultHandler.handleErrorResult(newErrorResult(result));
+ cancelResultHandler.handleError(newErrorResult(result));
}
return;
}
@@ -370,7 +370,7 @@
cancelResultHandler.handleResult(result);
} else {
final Result result = Responses.newGenericExtendedResult(ResultCode.TOO_LATE);
- cancelResultHandler.handleErrorResult(ErrorResultException
+ cancelResultHandler.handleError(ErrorResultException
.newErrorResult(result));
}
}
@@ -445,13 +445,16 @@
/**
* Search request context implementation.
*/
- private final static class SearchRequestContextImpl extends
- RequestContextImpl<Result, SearchResultHandler> implements SearchResultHandler {
+ private final static class SearchRequestContextImpl extends RequestContextImpl<Result, ResultHandler<Result>>
+ implements SearchResultHandler {
+
+ private final SearchResultHandler entryHandler;
private SearchRequestContextImpl(final ServerConnectionImpl clientConnection,
- final SearchResultHandler resultHandler, final int messageID,
- final boolean isCancelSupported) {
+ final SearchResultHandler entryHandler, final ResultHandler<Result> resultHandler, final int messageID,
+ final boolean isCancelSupported) {
super(clientConnection, resultHandler, messageID, isCancelSupported);
+ this.entryHandler = entryHandler;
}
/**
@@ -459,7 +462,7 @@
*/
@Override
public boolean handleEntry(final SearchResultEntry entry) {
- return resultHandler.handleEntry(entry);
+ return entryHandler.handleEntry(entry);
}
/**
@@ -467,7 +470,7 @@
*/
@Override
public boolean handleReference(final SearchResultReference reference) {
- return resultHandler.handleReference(reference);
+ return entryHandler.handleReference(reference);
}
}
@@ -604,7 +607,7 @@
new DecodeOptions());
} catch (final DecodeException e) {
// Couldn't decode a cancel request.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, e
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR, e
.getLocalizedMessage()));
return;
}
@@ -630,8 +633,7 @@
* Couldn't find the request. Invoke on context in order
* to remove pending request.
*/
- requestContext
- .handleErrorResult(newErrorResult(ResultCode.NO_SUCH_OPERATION));
+ requestContext.handleError(newErrorResult(ResultCode.NO_SUCH_OPERATION));
}
}
} else {
@@ -691,13 +693,13 @@
*/
@Override
public void handleSearch(final Integer messageID, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler) {
final SearchRequestContextImpl requestContext =
- new SearchRequestContextImpl(this, resultHandler, messageID, true);
+ new SearchRequestContextImpl(this, entryHandler, resultHandler, messageID, true);
if (addPendingRequest(requestContext)) {
- requestHandler.handleSearch(requestContext, request, intermediateResponseHandler,
- requestContext);
+ requestHandler.handleSearch(requestContext, request, intermediateResponseHandler, entryHandler,
+ requestContext);
}
}
@@ -706,14 +708,13 @@
if (isClosed.get()) {
final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING.get();
- requestContext.handleErrorResult(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
+ requestContext.handleError(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
message.toString()));
return false;
} else if (pendingRequests.putIfAbsent(messageID, requestContext) != null) {
final LocalizableMessage message =
WARN_CLIENT_DUPLICATE_MESSAGE_ID.get(requestContext.getMessageID());
- requestContext.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR, message
- .toString()));
+ requestContext.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR, message.toString()));
return false;
} else if (isClosed.get()) {
/*
@@ -723,8 +724,7 @@
pendingRequests.remove(messageID);
final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING.get();
- requestContext.handleErrorResult(newErrorResult(ResultCode.UNWILLING_TO_PERFORM,
- message.toString()));
+ requestContext.handleError(newErrorResult(ResultCode.UNWILLING_TO_PERFORM, message.toString()));
return false;
} else {
/*
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java
index 316c7c9..a7cf7fe 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ResultHandler.java
@@ -22,11 +22,14 @@
*
*
* Copyright 2009 Sun Microsystems, Inc.
- * Portions copyright 2011 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.SuccessHandler;
+
/**
* A completion handler for consuming the result of an asynchronous operation or
* connection attempts.
@@ -46,7 +49,7 @@
* @param <S>
* The type of result handled by this result handler.
*/
-public interface ResultHandler<S> {
+public interface ResultHandler<S> extends SuccessHandler<S>, FailureHandler<ErrorResultException> {
/**
* Invoked when the asynchronous operation has failed.
*
@@ -54,7 +57,7 @@
* The error result exception indicating why the asynchronous
* operation has failed.
*/
- void handleErrorResult(ErrorResultException error);
+ void handleError(ErrorResultException error);
/**
* Invoked when the asynchronous operation has completed successfully.
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RootDSE.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
index 574b7e6..1b0b6bf 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/RootDSE.java
@@ -36,8 +36,9 @@
import org.forgerock.opendj.ldap.schema.CoreSchema;
import com.forgerock.opendj.util.Collections2;
-import com.forgerock.opendj.util.FutureResultTransformer;
+
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Function;
/**
* The root DSE is a DSA-specific Entry (DSE) and not part of any naming context
@@ -151,21 +152,13 @@
*/
public static FutureResult<RootDSE> readRootDSEAsync(final Connection connection,
final ResultHandler<? super RootDSE> handler) {
- final FutureResultTransformer<SearchResultEntry, RootDSE> future =
- new FutureResultTransformer<SearchResultEntry, RootDSE>(handler) {
-
- @Override
- protected RootDSE transformResult(final SearchResultEntry result)
- throws ErrorResultException {
- return valueOf(result);
- }
-
- };
-
- final FutureResult<SearchResultEntry> innerFuture =
- connection.searchSingleEntryAsync(SEARCH_REQUEST, future);
- future.setFutureResult(innerFuture);
- return future;
+ return FutureResultWrapper.asFutureResult(connection.searchSingleEntryAsync(SEARCH_REQUEST).then(
+ new Function<SearchResultEntry, RootDSE, ErrorResultException>() {
+ @Override
+ public RootDSE apply(SearchResultEntry result) {
+ return valueOf(result);
+ }
+ }));
}
/**
@@ -422,7 +415,7 @@
private <N> Collection<N> getMultiValuedAttribute(
final AttributeDescription attributeDescription,
- final Function<ByteString, N, Void> function) {
+ final org.forgerock.opendj.ldap.Function<ByteString, N, Void> function) {
// The returned collection is unmodifiable because we may need to
// return an empty collection if the attribute does not exist in the
// underlying entry. If a value is then added to the returned empty
@@ -438,7 +431,7 @@
}
private <N> N getSingleValuedAttribute(final AttributeDescription attributeDescription,
- final Function<ByteString, N, Void> function) {
+ final org.forgerock.opendj.ldap.Function<ByteString, N, Void> function) {
final Attribute attr = entry.getAttribute(attributeDescription);
if (attr == null || attr.isEmpty()) {
return null;
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java
index 773681e..3ac2143 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/SearchResultHandler.java
@@ -22,12 +22,11 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
-import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.responses.SearchResultReference;
@@ -45,7 +44,7 @@
* avoid keeping the invoking thread from dispatching to other completion
* handlers.
*/
-public interface SearchResultHandler extends ResultHandler<Result> {
+public interface SearchResultHandler {
/**
* Invoked each time a search result entry is returned from an asynchronous
* search operation.
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java
index 49d277d..285d937 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/responses/AbstractExtendedResultDecoder.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2012 ForgeRock AS.
+ * Portions copyright 2012-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.responses;
@@ -68,13 +68,13 @@
return new ResultHandler<S>() {
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
final Result result = error.getResult();
final R adaptedResult =
request.getResultDecoder().newExtendedErrorResult(result.getResultCode(),
result.getMatchedDN(), result.getDiagnosticMessage());
adaptedResult.setCause(result.getCause());
- resultHandler.handleErrorResult(newErrorResult(adaptedResult));
+ resultHandler.handleError(newErrorResult(adaptedResult));
}
@Override
@@ -85,7 +85,7 @@
resultHandler.handleResult(adaptedResult);
} catch (final DecodeException e) {
final R adaptedResult = request.getResultDecoder().adaptDecodeException(e);
- resultHandler.handleErrorResult(newErrorResult(adaptedResult));
+ resultHandler.handleError(newErrorResult(adaptedResult));
}
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
index 4d8b361..eff6d99 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/Schema.java
@@ -27,9 +27,6 @@
*/
package org.forgerock.opendj.ldap.schema;
-import static org.forgerock.opendj.ldap.AttributeDescription.objectClass;
-import static com.forgerock.opendj.ldap.CoreMessages.*;
-
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
@@ -51,11 +48,15 @@
import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.LinkedAttribute;
import org.forgerock.opendj.ldap.RDN;
-import org.forgerock.opendj.ldap.ResultHandler;
-
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.StaticUtils;
import org.forgerock.util.Reject;
+import org.forgerock.util.promise.Function;
+
+import com.forgerock.opendj.util.StaticUtils;
+
+import static org.forgerock.opendj.ldap.AttributeDescription.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+
+import static com.forgerock.opendj.ldap.CoreMessages.*;
/**
* This class defines a data structure that holds information about the
@@ -996,8 +997,6 @@
* read.
* @param name
* The distinguished name of the subschema sub-entry.
- * @param handler
- * A result handler which can be used to asynchronously process
* the operation result when it is received, may be {@code null}.
* @return A future representing the retrieved schema.
* @throws UnsupportedOperationException
@@ -1008,24 +1007,15 @@
* @throws NullPointerException
* If the {@code connection} or {@code name} was {@code null}.
*/
- public static FutureResult<Schema> readSchemaAsync(final Connection connection, final DN name,
- final ResultHandler<? super Schema> handler) {
- final FutureResultTransformer<SchemaBuilder, Schema> future =
- new FutureResultTransformer<SchemaBuilder, Schema>(handler) {
-
+ public static FutureResult<Schema> readSchemaAsync(final Connection connection, final DN name) {
+ final SchemaBuilder builder = new SchemaBuilder();
+ return asFutureResult(builder.addSchemaAsync(connection, name, true).then(
+ new Function<SchemaBuilder, Schema, ErrorResultException>() {
@Override
- protected Schema transformResult(final SchemaBuilder builder)
- throws ErrorResultException {
+ public Schema apply(SchemaBuilder builder) throws ErrorResultException {
return builder.toSchema();
}
-
- };
-
- final SchemaBuilder builder = new SchemaBuilder();
- final FutureResult<SchemaBuilder> innerFuture =
- builder.addSchemaAsync(connection, name, future, true);
- future.setFutureResult(innerFuture);
- return future;
+ }));
}
/**
@@ -1085,9 +1075,6 @@
* @param name
* The distinguished name of the entry whose schema is to be
* located.
- * @param handler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @return A future representing the retrieved schema.
* @throws UnsupportedOperationException
* If the connection does not support search operations.
@@ -1097,25 +1084,16 @@
* @throws NullPointerException
* If the {@code connection} or {@code name} was {@code null}.
*/
- public static FutureResult<Schema> readSchemaForEntryAsync(final Connection connection,
- final DN name, final ResultHandler<? super Schema> handler) {
- final FutureResultTransformer<SchemaBuilder, Schema> future =
- new FutureResultTransformer<SchemaBuilder, Schema>(handler) {
-
- @Override
- protected Schema transformResult(final SchemaBuilder builder)
- throws ErrorResultException {
- return builder.toSchema();
- }
-
- };
-
+ public static FutureResult<Schema> readSchemaForEntryAsync(final Connection connection, final DN name) {
final SchemaBuilder builder = new SchemaBuilder();
- final FutureResult<SchemaBuilder> innerFuture =
- builder.addSchemaForEntryAsync(connection, name, future, true);
- future.setFutureResult(innerFuture);
- return future;
+ return asFutureResult(builder.addSchemaForEntryAsync(connection, name, true).then(
+ new Function<SchemaBuilder, Schema, ErrorResultException>() {
+ @Override
+ public Schema apply(SchemaBuilder builder) throws ErrorResultException {
+ return builder.toSchema();
+ }
+ }));
}
/**
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
index 7697890..f49cfda 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/schema/SchemaBuilder.java
@@ -28,18 +28,6 @@
package org.forgerock.opendj.ldap.schema;
-import static com.forgerock.opendj.util.StaticUtils.toLowerCase;
-import static com.forgerock.opendj.ldap.CoreMessages.*;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.schema.Schema.*;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.EXTENSIBLE_OBJECT_OBJECTCLASS_OID;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.OMR_GENERIC_ENUM_NAME;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.SCHEMA_PROPERTY_APPROX_RULE;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfExtraProperties;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfList;
-import static org.forgerock.opendj.ldap.schema.SchemaUtils.unmodifiableCopyOfSet;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -66,17 +54,26 @@
import org.forgerock.opendj.ldap.Filter;
import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.Reject;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.Function;
+import org.forgerock.util.promise.Promise;
-import com.forgerock.opendj.util.FutureResultTransformer;
-import com.forgerock.opendj.util.RecursiveFutureResult;
import com.forgerock.opendj.util.StaticUtils;
import com.forgerock.opendj.util.SubstringReader;
-import org.forgerock.util.Reject;
+
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+import static org.forgerock.opendj.ldap.schema.Schema.*;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
+import static org.forgerock.opendj.ldap.schema.SchemaUtils.*;
+
+import static com.forgerock.opendj.ldap.CoreMessages.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
/**
* Schema builders should be used for incremental construction of new schemas.
@@ -94,15 +91,19 @@
private static final String[] SUBSCHEMA_SUBENTRY_ATTRS =
new String[] { ATTR_SUBSCHEMA_SUBENTRY };
- // Constructs a search request for retrieving the subschemaSubentry
- // attribute from the named entry.
+ /**
+ * Constructs a search request for retrieving the subschemaSubentry
+ * attribute from the named entry.
+ */
private static SearchRequest getReadSchemaForEntrySearchRequest(final DN dn) {
return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, Filter.objectClassPresent(),
SUBSCHEMA_SUBENTRY_ATTRS);
}
- // Constructs a search request for retrieving the named subschema
- // sub-entry.
+ /**
+ * Constructs a search request for retrieving the named subschema
+ * sub-entry.
+ */
private static SearchRequest getReadSchemaSearchRequest(final DN dn) {
return Requests.newSearchRequest(dn, SearchScope.BASE_OBJECT, SUBSCHEMA_FILTER,
SUBSCHEMA_ATTRS);
@@ -158,11 +159,13 @@
private String defaultSyntaxOID;
private String defaultMatchingRuleOID;
- // A schema which should be copied into this builder on any mutation.
- private Schema copyOnWriteSchema = null;
+ /** A schema which should be copied into this builder on any mutation. */
+ private Schema copyOnWriteSchema;
- // A unique ID which can be used to uniquely identify schemas
- // constructed without a name.
+ /**
+ * A unique ID which can be used to uniquely identify schemas
+ * constructed without a name.
+ */
private static final AtomicInteger NEXT_SCHEMA_ID = new AtomicInteger();
/**
@@ -256,9 +259,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS.get(definition, (reader
- .pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRTYPE_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -298,39 +300,39 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
description = SchemaUtils.readQuotedString(reader);
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
isObsolete = true;
- } else if (tokenName.equalsIgnoreCase("sup")) {
+ } else if ("sup".equalsIgnoreCase(tokenName)) {
// This specifies the name or OID of the superior attribute
// type from which this attribute type should inherit its
// properties.
superiorType = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("equality")) {
+ } else if ("equality".equalsIgnoreCase(tokenName)) {
// This specifies the name or OID of the equality matching
// rule to use for this attribute type.
equalityMatchingRule =
SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("ordering")) {
+ } else if ("ordering".equalsIgnoreCase(tokenName)) {
// This specifies the name or OID of the ordering matching
// rule to use for this attribute type.
orderingMatchingRule =
SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("substr")) {
+ } else if ("substr".equalsIgnoreCase(tokenName)) {
// This specifies the name or OID of the substring matching
// rule to use for this attribute type.
substringMatchingRule =
SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("syntax")) {
+ } else if ("syntax".equalsIgnoreCase(tokenName)) {
// This specifies the numeric OID of the syntax for this
// matching rule. It may optionally be immediately followed
// by an open curly brace, an integer definition, and a close
@@ -340,28 +342,28 @@
// does not impose any practical limit on the length of attribute
// values.
syntax = SchemaUtils.readOIDLen(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("single-definition")) {
+ } else if ("single-definition".equalsIgnoreCase(tokenName)) {
// This indicates that attributes of this type are allowed
// to have at most one definition. We do not need any more
// parsing for this token.
isSingleValue = true;
- } else if (tokenName.equalsIgnoreCase("single-value")) {
+ } else if ("single-value".equalsIgnoreCase(tokenName)) {
// This indicates that attributes of this type are allowed
// to have at most one value. We do not need any more parsing
// for this token.
isSingleValue = true;
- } else if (tokenName.equalsIgnoreCase("collective")) {
+ } else if ("collective".equalsIgnoreCase(tokenName)) {
// This indicates that attributes of this type are
// collective
// (i.e., have their values generated dynamically in some
// way). We do not need any more parsing for this token.
isCollective = true;
- } else if (tokenName.equalsIgnoreCase("no-user-modification")) {
+ } else if ("no-user-modification".equalsIgnoreCase(tokenName)) {
// This indicates that the values of attributes of this type
// are not to be modified by end users. We do not need any
// more parsing for this token.
isNoUserModification = true;
- } else if (tokenName.equalsIgnoreCase("usage")) {
+ } else if ("usage".equalsIgnoreCase(tokenName)) {
// This specifies the usage string for this attribute type.
// It should be followed by one of the strings
// "userApplications", "directoryOperation",
@@ -377,18 +379,17 @@
reader.reset();
final String usageStr = reader.read(length);
- if (usageStr.equalsIgnoreCase("userapplications")) {
+ if ("userapplications".equalsIgnoreCase(usageStr)) {
attributeUsage = AttributeUsage.USER_APPLICATIONS;
- } else if (usageStr.equalsIgnoreCase("directoryoperation")) {
+ } else if ("directoryoperation".equalsIgnoreCase(usageStr)) {
attributeUsage = AttributeUsage.DIRECTORY_OPERATION;
- } else if (usageStr.equalsIgnoreCase("distributedoperation")) {
+ } else if ("distributedoperation".equalsIgnoreCase(usageStr)) {
attributeUsage = AttributeUsage.DISTRIBUTED_OPERATION;
- } else if (usageStr.equalsIgnoreCase("dsaoperation")) {
+ } else if ("dsaoperation".equalsIgnoreCase(usageStr)) {
attributeUsage = AttributeUsage.DSA_OPERATION;
} else {
final LocalizableMessage message =
- WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE1.get(definition,
- usageStr);
+ WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_ATTRIBUTE_USAGE1.get(definition, usageStr);
throw new LocalizedIllegalArgumentException(message);
}
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -556,9 +557,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS.get(definition,
- (reader.pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_DCR_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -593,27 +593,27 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
description = SchemaUtils.readQuotedString(reader);
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
isObsolete = true;
- } else if (tokenName.equalsIgnoreCase("aux")) {
+ } else if ("aux".equalsIgnoreCase(tokenName)) {
auxiliaryClasses = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("must")) {
+ } else if ("must".equalsIgnoreCase(tokenName)) {
requiredAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("may")) {
+ } else if ("may".equalsIgnoreCase(tokenName)) {
optionalAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("not")) {
+ } else if ("not".equalsIgnoreCase(tokenName)) {
prohibitedAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -786,9 +786,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS.get(definition,
- (reader.pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_DSR_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -820,21 +819,21 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
description = SchemaUtils.readQuotedString(reader);
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
isObsolete = true;
- } else if (tokenName.equalsIgnoreCase("form")) {
+ } else if ("form".equalsIgnoreCase(tokenName)) {
nameForm = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("sup")) {
+ } else if ("sup".equalsIgnoreCase(tokenName)) {
superiorRules = SchemaUtils.readRuleIDs(reader);
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
// This must be a non-standard property and it must be
@@ -959,9 +958,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS.get(definition,
- (reader.pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_MR_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -990,19 +988,19 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
matchingRuleBuilder.names(SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions));
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the matching rule. It
// is an arbitrary string of characters enclosed in single
// quotes.
matchingRuleBuilder.description(SchemaUtils.readQuotedString(reader));
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the matching rule should be
// considered obsolete. We do not need to do any more
// parsing for this token.
matchingRuleBuilder.obsolete(true);
- } else if (tokenName.equalsIgnoreCase("syntax")) {
+ } else if ("syntax".equalsIgnoreCase(tokenName)) {
syntax = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
matchingRuleBuilder.syntaxOID(syntax);
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -1081,9 +1079,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS.get(definition, (reader
- .pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_MRUSE_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -1114,19 +1111,19 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
description = SchemaUtils.readQuotedString(reader);
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
isObsolete = true;
- } else if (tokenName.equalsIgnoreCase("applies")) {
+ } else if ("applies".equalsIgnoreCase(tokenName)) {
attributes = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
// This must be a non-standard property and it must be
@@ -1264,9 +1261,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS.get(definition, (reader
- .pos() - 1), c);
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_NAME_FORM_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, c);
throw new LocalizedIllegalArgumentException(message);
}
@@ -1298,27 +1294,27 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
nameFormBuilder.names(SchemaUtils.readNameDescriptors(reader,
allowMalformedNamesAndOptions));
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
nameFormBuilder.description(SchemaUtils.readQuotedString(reader));
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
nameFormBuilder.obsolete(true);
- } else if (tokenName.equalsIgnoreCase("oc")) {
+ } else if ("oc".equalsIgnoreCase(tokenName)) {
structuralOID = SchemaUtils.readOID(reader, allowMalformedNamesAndOptions);
nameFormBuilder.structuralObjectClassOID(structuralOID);
- } else if (tokenName.equalsIgnoreCase("must")) {
+ } else if ("must".equalsIgnoreCase(tokenName)) {
requiredAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
nameFormBuilder.requiredAttributes(requiredAttributes);
- } else if (tokenName.equalsIgnoreCase("may")) {
+ } else if ("may".equalsIgnoreCase(tokenName)) {
nameFormBuilder.optionalAttributes(SchemaUtils.readOIDs(reader,
allowMalformedNamesAndOptions));
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -1578,9 +1574,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS1.get(definition,
- (reader.pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_OBJECTCLASS_EXPECTED_OPEN_PARENTHESIS1.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -1614,38 +1609,38 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("name")) {
+ } else if ("name".equalsIgnoreCase(tokenName)) {
names = SchemaUtils.readNameDescriptors(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the attribute type. It
// is an arbitrary string of characters enclosed in single
// quotes.
description = SchemaUtils.readQuotedString(reader);
- } else if (tokenName.equalsIgnoreCase("obsolete")) {
+ } else if ("obsolete".equalsIgnoreCase(tokenName)) {
// This indicates whether the attribute type should be
// considered obsolete. We do not need to do any more
// parsing for this token.
isObsolete = true;
- } else if (tokenName.equalsIgnoreCase("sup")) {
+ } else if ("sup".equalsIgnoreCase(tokenName)) {
superiorClasses = SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("abstract")) {
+ } else if ("abstract".equalsIgnoreCase(tokenName)) {
// This indicates that entries must not include this
// objectclass unless they also include a non-abstract
// objectclass that inherits from this class. We do not need
// any more parsing for this token.
objectClassType = ObjectClassType.ABSTRACT;
- } else if (tokenName.equalsIgnoreCase("structural")) {
+ } else if ("structural".equalsIgnoreCase(tokenName)) {
// This indicates that this is a structural objectclass. We
// do not need any more parsing for this token.
objectClassType = ObjectClassType.STRUCTURAL;
- } else if (tokenName.equalsIgnoreCase("auxiliary")) {
+ } else if ("auxiliary".equalsIgnoreCase(tokenName)) {
// This indicates that this is an auxiliary objectclass. We
// do not need any more parsing for this token.
objectClassType = ObjectClassType.AUXILIARY;
- } else if (tokenName.equalsIgnoreCase("must")) {
+ } else if ("must".equalsIgnoreCase(tokenName)) {
requiredAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
- } else if (tokenName.equalsIgnoreCase("may")) {
+ } else if ("may".equalsIgnoreCase(tokenName)) {
optionalAttributes =
SchemaUtils.readOIDs(reader, allowMalformedNamesAndOptions);
} else if (tokenName.matches("^X-[A-Za-z_-]+$")) {
@@ -1665,7 +1660,7 @@
}
}
- if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID)) {
+ if (EXTENSIBLE_OBJECT_OBJECTCLASS_OID.equals(oid)) {
addObjectClass(new ObjectClass(description, extraProperties), overwrite);
} else {
if (objectClassType == ObjectClassType.STRUCTURAL && superiorClasses.isEmpty()) {
@@ -1726,7 +1721,7 @@
final boolean overwrite) {
lazyInitBuilder();
- if (oid.equals(EXTENSIBLE_OBJECT_OBJECTCLASS_OID)) {
+ if (EXTENSIBLE_OBJECT_OBJECTCLASS_OID.equals(oid)) {
addObjectClass(new ObjectClass(description,
unmodifiableCopyOfExtraProperties(extraProperties)), overwrite);
} else {
@@ -1958,8 +1953,6 @@
* read.
* @param name
* The distinguished name of the subschema sub-entry.
- * @param handler
- * A result handler which can be used to asynchronously process
* the operation result when it is received, may be {@code null}.
* @param overwrite
* {@code true} if existing schema elements with the same
@@ -1974,26 +1967,18 @@
* If the {@code connection} or {@code name} was {@code null}.
*/
public FutureResult<SchemaBuilder> addSchemaAsync(final Connection connection, final DN name,
- final ResultHandler<? super SchemaBuilder> handler, final boolean overwrite) {
+ final boolean overwrite) {
// The call to addSchema will perform copyOnWrite.
final SearchRequest request = getReadSchemaSearchRequest(name);
- final FutureResultTransformer<SearchResultEntry, SchemaBuilder> future =
- new FutureResultTransformer<SearchResultEntry, SchemaBuilder>(handler) {
-
+ return asFutureResult(connection.searchSingleEntryAsync(request).then(
+ new Function<SearchResultEntry, SchemaBuilder, ErrorResultException>() {
@Override
- protected SchemaBuilder transformResult(final SearchResultEntry result)
- throws ErrorResultException {
+ public SchemaBuilder apply(SearchResultEntry result) throws ErrorResultException {
addSchema(result, overwrite);
return SchemaBuilder.this;
}
-
- };
-
- final FutureResult<SearchResultEntry> innerFuture =
- connection.searchSingleEntryAsync(request, future);
- future.setFutureResult(innerFuture);
- return future;
+ }));
}
/**
@@ -2058,9 +2043,6 @@
* @param name
* The distinguished name of the entry whose schema is to be
* located.
- * @param handler
- * A result handler which can be used to asynchronously process
- * the operation result when it is received, may be {@code null}.
* @param overwrite
* {@code true} if existing schema elements with the same
* conflicting OIDs should be overwritten.
@@ -2073,29 +2055,19 @@
* @throws NullPointerException
* If the {@code connection} or {@code name} was {@code null}.
*/
- public FutureResult<SchemaBuilder> addSchemaForEntryAsync(final Connection connection,
- final DN name, final ResultHandler<? super SchemaBuilder> handler,
- final boolean overwrite) {
- // The call to addSchema will perform copyOnWrite.
- final RecursiveFutureResult<SearchResultEntry, SchemaBuilder> future =
- new RecursiveFutureResult<SearchResultEntry, SchemaBuilder>(handler) {
-
- @Override
- protected FutureResult<SchemaBuilder> chainResult(
- final SearchResultEntry innerResult,
- final ResultHandler<? super SchemaBuilder> handler)
- throws ErrorResultException {
- final DN subschemaDN = getSubschemaSubentryDN(name, innerResult);
- return addSchemaAsync(connection, subschemaDN, handler, overwrite);
- }
-
- };
-
+ public FutureResult<SchemaBuilder> addSchemaForEntryAsync(final Connection connection, final DN name,
+ final boolean overwrite) {
final SearchRequest request = getReadSchemaForEntrySearchRequest(name);
- final FutureResult<SearchResultEntry> innerFuture =
- connection.searchSingleEntryAsync(request, future);
- future.setFutureResult(innerFuture);
- return future;
+
+ return asFutureResult(connection.searchSingleEntryAsync(request).thenAsync(
+ new AsyncFunction<SearchResultEntry, SchemaBuilder, ErrorResultException>() {
+ @Override
+ public Promise<SchemaBuilder, ErrorResultException> apply(SearchResultEntry result)
+ throws ErrorResultException {
+ final DN subschemaDN = getSubschemaSubentryDN(name, result);
+ return addSchemaAsync(connection, subschemaDN, overwrite);
+ }
+ }));
}
/**
@@ -2171,9 +2143,8 @@
// then that is an error.
final char c = reader.read();
if (c != '(') {
- final LocalizableMessage message =
- ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get(definition,
- (reader.pos() - 1), String.valueOf(c));
+ final LocalizableMessage message = ERR_ATTR_SYNTAX_ATTRSYNTAX_EXPECTED_OPEN_PARENTHESIS.get(
+ definition, reader.pos() - 1, String.valueOf(c));
throw new LocalizedIllegalArgumentException(message);
}
@@ -2199,7 +2170,7 @@
if (tokenName == null) {
// No more tokens.
break;
- } else if (tokenName.equalsIgnoreCase("desc")) {
+ } else if ("desc".equalsIgnoreCase(tokenName)) {
// This specifies the description for the syntax. It is an
// arbitrary string of characters enclosed in single quotes.
syntaxBuilder.description(SchemaUtils.readQuotedString(reader));
@@ -2220,7 +2191,7 @@
// See if it is a enum syntax
for (final Map.Entry<String, List<String>> property : syntaxBuilder.getExtraProperties().entrySet()) {
- if (property.getKey().equalsIgnoreCase("x-enum")) {
+ if ("x-enum".equalsIgnoreCase(property.getKey())) {
final EnumSyntaxImpl enumImpl = new EnumSyntaxImpl(oid, property.getValue());
syntaxBuilder.implementation(enumImpl);
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/AbstractLDAPFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/AbstractLDAPFutureResultImpl.java
index 0e7c691..514761e 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/AbstractLDAPFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/AbstractLDAPFutureResultImpl.java
@@ -22,21 +22,20 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.FutureResultImpl;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.responses.IntermediateResponse;
import org.forgerock.opendj.ldap.responses.Result;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
/**
* Abstract future result implementation.
@@ -44,9 +43,8 @@
* @param <S>
* The type of result returned by this future.
*/
-public abstract class AbstractLDAPFutureResultImpl<S extends Result> extends
- AsynchronousFutureResult<S, ResultHandler<? super S>> implements
- IntermediateResponseHandler {
+public abstract class AbstractLDAPFutureResultImpl<S extends Result> extends FutureResultImpl<S> implements
+ IntermediateResponseHandler {
private final Connection connection;
private IntermediateResponseHandler intermediateResponseHandler;
private volatile long timestamp;
@@ -56,8 +54,6 @@
*
* @param requestID
* identifier of the request
- * @param resultHandler
- * handler that consumes the result
* @param intermediateResponseHandler
* handler that consumes intermediate responses from extended
* operations
@@ -65,10 +61,8 @@
* the connection to directory server
*/
protected AbstractLDAPFutureResultImpl(final int requestID,
- final ResultHandler<? super S> resultHandler,
- final IntermediateResponseHandler intermediateResponseHandler,
- final Connection connection) {
- super(resultHandler, requestID);
+ final IntermediateResponseHandler intermediateResponseHandler, final Connection connection) {
+ super(requestID);
this.connection = connection;
this.intermediateResponseHandler = intermediateResponseHandler;
this.timestamp = System.currentTimeMillis();
@@ -83,40 +77,37 @@
// the synchronizer.
if (!isDone()) {
updateTimestamp();
- if (intermediateResponseHandler != null) {
- if (!intermediateResponseHandler.handleIntermediateResponse(response)) {
- intermediateResponseHandler = null;
- }
+ if (intermediateResponseHandler != null
+ && !intermediateResponseHandler.handleIntermediateResponse(response)) {
+ intermediateResponseHandler = null;
}
}
return true;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
- protected final ErrorResultException handleCancelRequest(final boolean mayInterruptIfRunning) {
- /*
- * This will abandon the request, but will also recursively cancel this
- * future. There is no risk of an infinite loop because the state of
- * this future has already been changed.
- */
- connection.abandonAsync(Requests.newAbandonRequest(getRequestID()));
- return null;
- }
-
- @Override
- protected final boolean isCancelable() {
+ protected final ErrorResultException tryCancel(final boolean mayInterruptIfRunning) {
/*
* No other operations can be performed while a bind or startTLS
* operations is active. Therefore it is not possible to cancel bind or
* startTLS requests, since doing so will leave the connection in a
* state which prevents other operations from being performed.
*/
- return !isBindOrStartTLS();
+ if (isBindOrStartTLS()) {
+ return null;
+ }
+
+ /*
+ * This will abandon the request, but will also recursively cancel this
+ * future. There is no risk of an infinite loop because the state of
+ * this future has already been changed.
+ */
+ connection.abandonAsync(Requests.newAbandonRequest(getRequestID()));
+ return ErrorResultException.newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED);
}
+
/**
* Returns {@code true} if this future represents the result of a bind or
* StartTLS request. The default implementation is to return {@code false}.
@@ -128,13 +119,18 @@
return false;
}
- @Override
+ /**
+ * Appends a string representation of this future's state to the provided
+ * builder.
+ *
+ * @param sb
+ * The string builder.
+ */
protected void toString(final StringBuilder sb) {
sb.append(" requestID = ");
sb.append(getRequestID());
sb.append(" timestamp = ");
sb.append(timestamp);
- super.toString(sb);
}
/**
@@ -145,8 +141,7 @@
*/
public final void adaptErrorResult(final Result result) {
final S errorResult =
- newErrorResult(result.getResultCode(), result.getDiagnosticMessage(), result
- .getCause());
+ newErrorResult(result.getResultCode(), result.getDiagnosticMessage(), result.getCause());
setResultOrError(errorResult);
}
@@ -170,8 +165,7 @@
* cause of the error
* @return the error result
*/
- protected abstract S newErrorResult(ResultCode resultCode, String diagnosticMessage,
- Throwable cause);
+ protected abstract S newErrorResult(ResultCode resultCode, String diagnosticMessage, Throwable cause);
/**
* Sets the result associated to this future.
@@ -181,7 +175,7 @@
*/
public final void setResultOrError(final S result) {
if (result.getResultCode().isExceptional()) {
- handleErrorResult(ErrorResultException.newErrorResult(result));
+ handleError(ErrorResultException.newErrorResult(result));
} else {
handleResult(result);
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPBindFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPBindFutureResultImpl.java
index d068520..c314ad9 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPBindFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPBindFutureResultImpl.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
@@ -30,7 +30,6 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.BindClient;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.Responses;
@@ -48,8 +47,6 @@
* identifier of the request
* @param bindClient
* client that binds to the server
- * @param resultHandler
- * handler that consumes result of bind
* @param intermediateResponseHandler
* handler that consumes intermediate responses from extended
* operations
@@ -57,10 +54,9 @@
* the connection to directory server
*/
public LDAPBindFutureResultImpl(final int requestID, final BindClient bindClient,
- final ResultHandler<? super BindResult> resultHandler,
final IntermediateResponseHandler intermediateResponseHandler,
final Connection connection) {
- super(requestID, resultHandler, intermediateResponseHandler, connection);
+ super(requestID, intermediateResponseHandler, connection);
this.bindClient = bindClient;
}
@@ -89,9 +85,6 @@
return bindClient;
}
- /**
- * {@inheritDoc}
- */
@Override
protected BindResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage,
final Throwable cause) {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPCompareFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPCompareFutureResultImpl.java
index 209215b..64c8617 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPCompareFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPCompareFutureResultImpl.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
@@ -30,7 +30,6 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.CompareRequest;
import org.forgerock.opendj.ldap.responses.CompareResult;
import org.forgerock.opendj.ldap.responses.Responses;
@@ -48,8 +47,6 @@
* identifier of the request
* @param request
* compare request
- * @param resultHandler
- * handler that consumes compare result
* @param intermediateResponseHandler
* handler that consumes intermediate responses from extended
* operations
@@ -57,10 +54,9 @@
* the connection to directory server
*/
public LDAPCompareFutureResultImpl(final int requestID, final CompareRequest request,
- final ResultHandler<? super CompareResult> resultHandler,
final IntermediateResponseHandler intermediateResponseHandler,
final Connection connection) {
- super(requestID, resultHandler, intermediateResponseHandler, connection);
+ super(requestID, intermediateResponseHandler, connection);
this.request = request;
}
@@ -79,9 +75,7 @@
return request;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
protected CompareResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage,
final Throwable cause) {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPExtendedFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPExtendedFutureResultImpl.java
index 88b81dd..1429491 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPExtendedFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPExtendedFutureResultImpl.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
@@ -32,7 +32,6 @@
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.ExtendedRequest;
import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
@@ -54,8 +53,6 @@
* identifier of the request
* @param request
* extended request
- * @param resultHandler
- * handler that consumes result
* @param intermediateResponseHandler
* handler that consumes intermediate responses from extended
* operations
@@ -63,10 +60,9 @@
* the connection to directory server
*/
public LDAPExtendedFutureResultImpl(final int requestID, final ExtendedRequest<R> request,
- final ResultHandler<? super R> resultHandler,
final IntermediateResponseHandler intermediateResponseHandler,
final Connection connection) {
- super(requestID, resultHandler, intermediateResponseHandler, connection);
+ super(requestID, intermediateResponseHandler, connection);
this.request = request;
}
@@ -83,7 +79,7 @@
@Override
public boolean isBindOrStartTLS() {
- return request.getOID().equals(StartTLSExtendedRequest.OID);
+ return StartTLSExtendedRequest.OID.equals(request.getOID());
}
/**
@@ -110,9 +106,7 @@
return request;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
protected R newErrorResult(final ResultCode resultCode, final String diagnosticMessage,
final Throwable cause) {
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPFutureResultImpl.java
index 75a40de..d871acd 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPFutureResultImpl.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
@@ -30,7 +30,6 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.Request;
import org.forgerock.opendj.ldap.responses.Responses;
import org.forgerock.opendj.ldap.responses.Result;
@@ -48,8 +47,6 @@
* identifier of the request
* @param request
* the request sent to server
- * @param resultHandler
- * handler that consumes the result
* @param intermediateResponseHandler
* handler that consumes intermediate responses from extended
* operations
@@ -57,10 +54,9 @@
* the connection to directory server
*/
public LDAPFutureResultImpl(final int requestID, final Request request,
- final ResultHandler<? super Result> resultHandler,
final IntermediateResponseHandler intermediateResponseHandler,
final Connection connection) {
- super(requestID, resultHandler, intermediateResponseHandler, connection);
+ super(requestID, intermediateResponseHandler, connection);
this.request = request;
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPSearchFutureResultImpl.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPSearchFutureResultImpl.java
index d1a700b..c9edee0 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPSearchFutureResultImpl.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/spi/LDAPSearchFutureResultImpl.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap.spi;
@@ -64,13 +64,13 @@
* the connection to directory server
*/
public LDAPSearchFutureResultImpl(final int requestID, final SearchRequest request,
- final SearchResultHandler resultHandler,
- final IntermediateResponseHandler intermediateResponseHandler,
- final Connection connection) {
- super(requestID, resultHandler, intermediateResponseHandler, connection);
+ final SearchResultHandler resultHandler, final IntermediateResponseHandler intermediateResponseHandler,
+ final Connection connection) {
+ super(requestID, intermediateResponseHandler, connection);
this.request = request;
this.searchResultHandler = resultHandler;
- this.isPersistentSearch = request.containsControl(PersistentSearchRequestControl.OID)
+ this.isPersistentSearch =
+ request.containsControl(PersistentSearchRequestControl.OID)
|| request.containsControl(ADNotificationRequestControl.OID);
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java b/opendj-core/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java
index 8b5b56c..8d8de0b 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldif/ConnectionEntryReader.java
@@ -22,13 +22,11 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldif;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@@ -39,6 +37,7 @@
import org.forgerock.opendj.ldap.ErrorResultIOException;
import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.SearchResultReferenceIOException;
import org.forgerock.opendj.ldap.requests.SearchRequest;
@@ -47,9 +46,10 @@
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.Reject;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+
/**
* A {@code ConnectionEntryReader} is a bridge from {@code Connection}s to
* {@code EntryReader}s. A connection entry reader allows applications to
@@ -114,7 +114,7 @@
/**
* Result handler that places all responses in a queue.
*/
- private final static class BufferHandler implements SearchResultHandler {
+ private final static class BufferHandler implements SearchResultHandler, ResultHandler<Result> {
private final BlockingQueue<Response> responses;
private volatile boolean isInterrupted = false;
@@ -137,7 +137,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
try {
responses.put(error.getResult());
} catch (final InterruptedException e) {
@@ -209,10 +209,11 @@
* If {@code connection} was {@code null}.
*/
public ConnectionEntryReader(final Connection connection, final SearchRequest searchRequest,
- final BlockingQueue<Response> entries) {
+ final BlockingQueue<Response> entries) {
Reject.ifNull(connection);
buffer = new BufferHandler(entries);
- future = connection.searchAsync(searchRequest, null, buffer);
+ future = (FutureResult<Result>) connection.searchAsync(searchRequest, buffer)
+ .onSuccess(buffer).onFailure(buffer);
}
/**
diff --git a/opendj-core/src/test/java/com/forgerock/opendj/util/FutureResultTransformerTestCase.java b/opendj-core/src/test/java/com/forgerock/opendj/util/FutureResultTransformerTestCase.java
deleted file mode 100644
index 5372fd7..0000000
--- a/opendj-core/src/test/java/com/forgerock/opendj/util/FutureResultTransformerTestCase.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- * Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- * Copyright 2013 ForgeRock AS.
- */
-
-package com.forgerock.opendj.util;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import java.util.concurrent.TimeUnit;
-
-import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
-import org.testng.annotations.Test;
-
-/**
- * Tests {@link FutureResultTransformer}.
- */
-@SuppressWarnings("javadoc")
-public class FutureResultTransformerTestCase extends UtilTestCase {
- private static final class TestFuture extends FutureResultTransformer<Integer, String> {
- public TestFuture(final ResultHandler<? super String> handler) {
- super(handler);
- }
-
- @Override
- protected ErrorResultException transformErrorResult(final ErrorResultException error) {
- assertThat(error).isSameAs(UNTRANSFORMED_ERROR);
- return TRANSFORMED_ERROR;
- }
-
- @Override
- protected String transformResult(final Integer result) throws ErrorResultException {
- assertThat(result).isSameAs(UNTRANSFORMED_RESULT);
- return TRANSFORMED_RESULT;
- }
- }
-
- private static final ErrorResultException TRANSFORMED_ERROR = newErrorResult(ResultCode.OTHER,
- "transformed");
- private static final String TRANSFORMED_RESULT = "transformed";
- private static final ErrorResultException UNTRANSFORMED_ERROR = newErrorResult(
- ResultCode.OTHER, "untransformed");
- private static final Integer UNTRANSFORMED_RESULT = Integer.valueOf(0);
-
- @Test
- public void testGetTransformsError() throws Exception {
- final TestFuture future = new TestFuture(null);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_ERROR));
- future.handleErrorResult(UNTRANSFORMED_ERROR);
- try {
- future.get();
- fail();
- } catch (final ErrorResultException e) {
- assertThat(e).isSameAs(TRANSFORMED_ERROR);
- }
- }
-
- @Test
- public void testGetTransformsResult() throws Exception {
- final TestFuture future = new TestFuture(null);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_RESULT));
- future.handleResult(UNTRANSFORMED_RESULT);
- assertThat(future.get()).isSameAs(TRANSFORMED_RESULT);
- }
-
- @Test
- public void testGetWithTimeoutTransformsError() throws Exception {
- final TestFuture future = new TestFuture(null);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_ERROR));
- future.handleErrorResult(UNTRANSFORMED_ERROR);
- try {
- future.get(100, TimeUnit.SECONDS);
- fail();
- } catch (final ErrorResultException e) {
- assertThat(e).isSameAs(TRANSFORMED_ERROR);
- }
- }
-
- @Test
- public void testGetWithTimeoutTransformsResult() throws Exception {
- final TestFuture future = new TestFuture(null);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_RESULT));
- future.handleResult(UNTRANSFORMED_RESULT);
- assertThat(future.get(100, TimeUnit.SECONDS)).isSameAs(TRANSFORMED_RESULT);
- }
-
- @Test
- public void testResultHandlerTransformsError() throws Exception {
- @SuppressWarnings("unchecked")
- final ResultHandler<String> handler = mock(ResultHandler.class);
- final TestFuture future = new TestFuture(handler);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_ERROR));
- future.handleErrorResult(UNTRANSFORMED_ERROR);
- verify(handler).handleErrorResult(TRANSFORMED_ERROR);
- }
-
- @Test
- public void testResultHandlerTransformsResult() throws Exception {
- @SuppressWarnings("unchecked")
- final ResultHandler<String> handler = mock(ResultHandler.class);
- final TestFuture future = new TestFuture(handler);
- future.setFutureResult(new CompletedFutureResult<Integer>(UNTRANSFORMED_RESULT));
- future.handleResult(UNTRANSFORMED_RESULT);
- verify(handler).handleResult(TRANSFORMED_RESULT);
- }
-}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java
index 5adf70a..3f75145 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractAsynchronousConnectionTestCase.java
@@ -22,16 +22,11 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.mockito.Mockito.*;
-
import java.util.LinkedList;
import java.util.List;
@@ -44,18 +39,26 @@
import org.forgerock.opendj.ldap.requests.GenericExtendedRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
-import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.requests.UnbindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.CompareResult;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
-import org.forgerock.opendj.ldap.responses.Responses;
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.SuccessHandler;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import static org.fest.assertions.Assertions.*;
+import static org.fest.assertions.Fail.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+import static org.forgerock.opendj.ldap.responses.Responses.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
/**
* Unit test for AbstractAsynchronousConnection. The tests verify that all
@@ -73,169 +76,116 @@
this.entries = entries;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Void> abandonAsync(AbandonRequest request) {
if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<Void>((Void) null);
+ return newSuccessfulFutureResult((Void) null);
} else {
- return new CompletedFutureResult<Void>(newErrorResult(resultCode));
+ return newFailedFutureResult(newErrorResult(resultCode));
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Result> addAsync(AddRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<Result>(Responses.newResult(resultCode));
- } else {
- return new CompletedFutureResult<Result>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public void addConnectionEventListener(ConnectionEventListener listener) {
// Do nothing.
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<BindResult> bindAsync(BindRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super BindResult> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<BindResult>(Responses.newBindResult(resultCode));
- } else {
- return new CompletedFutureResult<BindResult>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newBindResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public void close(UnbindRequest request, String reason) {
// Do nothing.
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<CompareResult> compareAsync(CompareRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super CompareResult> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<CompareResult>(Responses
- .newCompareResult(resultCode));
- } else {
- return new CompletedFutureResult<CompareResult>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newCompareResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Result> deleteAsync(DeleteRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<Result>(Responses.newResult(resultCode));
- } else {
- return new CompletedFutureResult<Result>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- ExtendedRequest<R> request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super R> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<R>(request.getResultDecoder()
- .newExtendedErrorResult(resultCode, "", ""));
- } else {
- return new CompletedFutureResult<R>(newErrorResult(resultCode));
- }
+ /** {@inheritDoc} */
+ @Override
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(ExtendedRequest<R> request,
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(request.getResultDecoder().newExtendedErrorResult(resultCode, "", ""));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public boolean isClosed() {
return false;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public boolean isValid() {
return true;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Result> modifyAsync(ModifyRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<Result>(Responses.newResult(resultCode));
- } else {
- return new CompletedFutureResult<Result>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Result> modifyDNAsync(ModifyDNRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- ResultHandler<? super Result> resultHandler) {
- if (!resultCode.isExceptional()) {
- return new CompletedFutureResult<Result>(Responses.newResult(resultCode));
- } else {
- return new CompletedFutureResult<Result>(newErrorResult(resultCode));
- }
+ IntermediateResponseHandler intermediateResponseHandler) {
+ return getFutureFromResultCode(newResult(resultCode));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public void removeConnectionEventListener(ConnectionEventListener listener) {
// Do nothing.
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public FutureResult<Result> searchAsync(SearchRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- SearchResultHandler resultHandler) {
+ IntermediateResponseHandler intermediateResponseHandler, SearchResultHandler entryHandler) {
for (SearchResultEntry entry : entries) {
- resultHandler.handleEntry(entry);
+ entryHandler.handleEntry(entry);
}
+
+ return getFutureFromResultCode(newResult(resultCode));
+ }
+
+ private <T extends Result> FutureResult<T> getFutureFromResultCode(T correctResult) {
if (resultCode.isExceptional()) {
- ErrorResultException errorResult = newErrorResult(resultCode);
- resultHandler.handleErrorResult(errorResult);
- return new CompletedFutureResult<Result>(errorResult);
+ return newFailedFutureResult(newErrorResult(resultCode));
} else {
- Result result = Responses.newResult(resultCode);
- resultHandler.handleResult(result);
- return new CompletedFutureResult<Result>(result);
+ return newSuccessfulFutureResult(correctResult);
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public String toString() {
return "MockConnection";
}
@@ -245,14 +195,14 @@
@Test()
public void testAddRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final AddRequest addRequest = Requests.newAddRequest("cn=test");
+ final AddRequest addRequest = newAddRequest("cn=test");
assertThat(mockConnection.add(addRequest).getResultCode()).isEqualTo(ResultCode.SUCCESS);
}
@Test()
public void testAddRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final AddRequest addRequest = Requests.newAddRequest("cn=test");
+ final AddRequest addRequest = newAddRequest("cn=test");
try {
mockConnection.add(addRequest);
fail();
@@ -264,14 +214,14 @@
@Test()
public void testBindRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final BindRequest bindRequest = Requests.newSimpleBindRequest();
+ final BindRequest bindRequest = newSimpleBindRequest();
assertThat(mockConnection.bind(bindRequest).getResultCode()).isEqualTo(ResultCode.SUCCESS);
}
@Test()
public void testBindRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final BindRequest bindRequest = Requests.newSimpleBindRequest();
+ final BindRequest bindRequest = newSimpleBindRequest();
try {
mockConnection.bind(bindRequest);
fail();
@@ -283,7 +233,7 @@
@Test()
public void testCompareRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final CompareRequest compareRequest = Requests.newCompareRequest("cn=test", "cn", "test");
+ final CompareRequest compareRequest = newCompareRequest("cn=test", "cn", "test");
assertThat(mockConnection.compare(compareRequest).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
}
@@ -291,7 +241,7 @@
@Test()
public void testCompareRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final CompareRequest compareRequest = Requests.newCompareRequest("cn=test", "cn", "test");
+ final CompareRequest compareRequest = newCompareRequest("cn=test", "cn", "test");
try {
mockConnection.compare(compareRequest);
fail();
@@ -303,7 +253,7 @@
@Test()
public void testDeleteRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final DeleteRequest deleteRequest = Requests.newDeleteRequest("cn=test");
+ final DeleteRequest deleteRequest = newDeleteRequest("cn=test");
assertThat(mockConnection.delete(deleteRequest).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
}
@@ -311,7 +261,7 @@
@Test()
public void testDeleteRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final DeleteRequest deleteRequest = Requests.newDeleteRequest("cn=test");
+ final DeleteRequest deleteRequest = newDeleteRequest("cn=test");
try {
mockConnection.delete(deleteRequest);
fail();
@@ -323,7 +273,7 @@
@Test()
public void testExtendedRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final GenericExtendedRequest extendedRequest = Requests.newGenericExtendedRequest("test");
+ final GenericExtendedRequest extendedRequest = newGenericExtendedRequest("test");
assertThat(mockConnection.extendedRequest(extendedRequest).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
}
@@ -331,7 +281,7 @@
@Test()
public void testExtendedRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final GenericExtendedRequest extendedRequest = Requests.newGenericExtendedRequest("test");
+ final GenericExtendedRequest extendedRequest = newGenericExtendedRequest("test");
try {
mockConnection.extendedRequest(extendedRequest);
fail();
@@ -343,7 +293,7 @@
@Test()
public void testModifyRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final ModifyRequest modifyRequest = Requests.newModifyRequest("cn=test");
+ final ModifyRequest modifyRequest = newModifyRequest("cn=test");
assertThat(mockConnection.modify(modifyRequest).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
}
@@ -351,7 +301,7 @@
@Test()
public void testModifyRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final ModifyRequest modifyRequest = Requests.newModifyRequest("cn=test");
+ final ModifyRequest modifyRequest = newModifyRequest("cn=test");
try {
mockConnection.modify(modifyRequest);
fail();
@@ -363,7 +313,7 @@
@Test()
public void testModifyDNRequestSuccess() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
- final ModifyDNRequest modifyDNRequest = Requests.newModifyDNRequest("cn=test", "cn=newrdn");
+ final ModifyDNRequest modifyDNRequest = newModifyDNRequest("cn=test", "cn=newrdn");
assertThat(mockConnection.modifyDN(modifyDNRequest).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
}
@@ -371,7 +321,7 @@
@Test()
public void testModifyDNRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
- final ModifyDNRequest modifyDNRequest = Requests.newModifyDNRequest("cn=test", "cn=newrdn");
+ final ModifyDNRequest modifyDNRequest = newModifyDNRequest("cn=test", "cn=newrdn");
try {
mockConnection.modifyDN(modifyDNRequest);
fail();
@@ -382,10 +332,10 @@
@Test()
public void testSearchRequestSuccess() throws Exception {
- final SearchResultEntry entry = Responses.newSearchResultEntry("cn=test");
+ final SearchResultEntry entry = newSearchResultEntry("cn=test");
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, entry);
final SearchRequest searchRequest =
- Requests.newSearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>();
assertThat(mockConnection.search(searchRequest, entries).getResultCode()).isEqualTo(
ResultCode.SUCCESS);
@@ -397,11 +347,11 @@
public void testSearchRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
final SearchRequest searchRequest =
- Requests.newSearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
List<SearchResultEntry> entries = new LinkedList<SearchResultEntry>();
try {
mockConnection.search(searchRequest, entries);
- TestCaseUtils.failWasExpected(ErrorResultException.class);
+ failWasExpected(ErrorResultException.class);
} catch (ErrorResultException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM);
assertThat(entries.isEmpty());
@@ -410,36 +360,37 @@
@Test()
public void testSingleEntrySearchRequestSuccess() throws Exception {
- final SearchResultEntry entry = Responses.newSearchResultEntry("cn=test");
+ final SearchResultEntry entry = newSearchResultEntry("cn=test");
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, entry);
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
assertThat(mockConnection.searchSingleEntry(request)).isEqualTo(entry);
}
@SuppressWarnings("unchecked")
@Test()
public void testSingleEntrySearchAsyncRequestSuccess() throws Exception {
- final SearchResultEntry entry = Responses.newSearchResultEntry("cn=test");
+ final SearchResultEntry entry = newSearchResultEntry("cn=test");
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, entry);
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
- ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class);
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ SuccessHandler<SearchResultEntry> successHandler = mock(SuccessHandler.class);
- FutureResult<SearchResultEntry> futureResult = mockConnection.searchSingleEntryAsync(request, handler);
+ FutureResult<SearchResultEntry> futureResult = (FutureResult<SearchResultEntry>) mockConnection
+ .searchSingleEntryAsync(request).onSuccess(successHandler);
assertThat(futureResult.get()).isEqualTo(entry);
- verify(handler).handleResult(any(SearchResultEntry.class));
+ verify(successHandler).handleResult(any(SearchResultEntry.class));
}
@Test()
public void testSingleEntrySearchRequestNoEntryReturned() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SUCCESS);
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
try {
mockConnection.searchSingleEntry(request);
- TestCaseUtils.failWasExpected(EntryNotFoundException.class);
+ failWasExpected(EntryNotFoundException.class);
} catch (EntryNotFoundException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED);
}
@@ -448,12 +399,12 @@
@Test()
public void testSingleEntrySearchRequestMultipleEntriesToReturn() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SIZE_LIMIT_EXCEEDED,
- Responses.newSearchResultEntry("cn=test"));
+ newSearchResultEntry("cn=test"));
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
try {
mockConnection.searchSingleEntry(request);
- TestCaseUtils.failWasExpected(MultipleEntriesFoundException.class);
+ failWasExpected(MultipleEntriesFoundException.class);
} catch (MultipleEntriesFoundException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED);
}
@@ -462,14 +413,13 @@
@Test()
public void testSingleEntrySearchRequestMultipleEntriesReturnedByServer() throws Exception {
// could happen if server does not enforce size limit
- final Connection mockConnection = new MockConnection(ResultCode.SUCCESS,
- Responses.newSearchResultEntry("cn=test"),
- Responses.newSearchResultEntry("cn=test,ou=org"));
- final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.WHOLE_SUBTREE, "(objectClass=*)");
+ final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, newSearchResultEntry("cn=test"),
+ newSearchResultEntry("cn=test,ou=org"));
+ final SearchRequest request = newSingleEntrySearchRequest("cn=test", SearchScope.WHOLE_SUBTREE,
+ "(objectClass=*)");
try {
mockConnection.searchSingleEntry(request);
- TestCaseUtils.failWasExpected(MultipleEntriesFoundException.class);
+ failWasExpected(MultipleEntriesFoundException.class);
} catch (MultipleEntriesFoundException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED);
}
@@ -479,36 +429,35 @@
@Test()
public void testSingleEntrySearchAsyncRequestMultipleEntriesToReturn() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.SIZE_LIMIT_EXCEEDED,
- Responses.newSearchResultEntry("cn=test"));
+ newSearchResultEntry("cn=test"));
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
- ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class);
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ FailureHandler<ErrorResultException> failureHandler = mock(FailureHandler.class);
try {
- mockConnection.searchSingleEntryAsync(request, handler).get();
- TestCaseUtils.failWasExpected(MultipleEntriesFoundException.class);
+ mockConnection.searchSingleEntryAsync(request).onFailure(failureHandler).getOrThrow();
+ failWasExpected(MultipleEntriesFoundException.class);
} catch (MultipleEntriesFoundException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED);
- verify(handler).handleErrorResult(any(ErrorResultException.class));
+ verify(failureHandler).handleError(any(ErrorResultException.class));
}
}
@Test()
public void testSingleEntrySearchAsyncRequestMultipleEntriesReturnedByServer() throws Exception {
// could happen if server does not enfore size limit
- final Connection mockConnection = new MockConnection(ResultCode.SUCCESS,
- Responses.newSearchResultEntry("cn=test"),
- Responses.newSearchResultEntry("cn=test,ou=org"));
- final SearchRequest request = Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT,
+ final Connection mockConnection = new MockConnection(ResultCode.SUCCESS, newSearchResultEntry("cn=test"),
+ newSearchResultEntry("cn=test,ou=org"));
+ final SearchRequest request = newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT,
"(objectClass=*)");
@SuppressWarnings("unchecked")
- ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class);
+ FailureHandler<ErrorResultException> failureHandler = mock(FailureHandler.class);
try {
- mockConnection.searchSingleEntryAsync(request, handler).get();
- TestCaseUtils.failWasExpected(MultipleEntriesFoundException.class);
+ mockConnection.searchSingleEntryAsync(request).onFailure(failureHandler).getOrThrow();
+ failWasExpected(MultipleEntriesFoundException.class);
} catch (MultipleEntriesFoundException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED);
- verify(handler).handleErrorResult(any(ErrorResultException.class));
+ verify(failureHandler).handleError(any(ErrorResultException.class));
}
}
@@ -516,10 +465,10 @@
public void testSingleEntrySearchRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
try {
mockConnection.searchSingleEntry(request);
- TestCaseUtils.failWasExpected(ErrorResultException.class);
+ failWasExpected(ErrorResultException.class);
} catch (ErrorResultException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM);
}
@@ -529,15 +478,15 @@
public void testSingleEntrySearchAsyncRequestFail() throws Exception {
final Connection mockConnection = new MockConnection(ResultCode.UNWILLING_TO_PERFORM);
final SearchRequest request =
- Requests.newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
+ newSingleEntrySearchRequest("cn=test", SearchScope.BASE_OBJECT, "(objectClass=*)");
@SuppressWarnings("unchecked")
- ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class);
+ FailureHandler<ErrorResultException> failureHandler = mock(FailureHandler.class);
try {
- mockConnection.searchSingleEntryAsync(request, handler).get();
- TestCaseUtils.failWasExpected(ErrorResultException.class);
+ mockConnection.searchSingleEntryAsync(request).onFailure(failureHandler).getOrThrow();
+ failWasExpected(ErrorResultException.class);
} catch (ErrorResultException e) {
assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.UNWILLING_TO_PERFORM);
- verify(handler).handleErrorResult(any(ErrorResultException.class));
+ verify(failureHandler).handleError(any(ErrorResultException.class));
}
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java
index f0982e2..391ae70 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/AbstractLoadBalancingAlgorithmTestCase.java
@@ -21,28 +21,26 @@
* CDDL HEADER END
*
*
- * Copyright 2013 ForgeRock AS
+ * Copyright 2014 ForgeRock AS
*/
package org.forgerock.opendj.ldap;
-import static java.util.Arrays.asList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.Connections.newLoadBalancer;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
+import org.forgerock.util.promise.Promise;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import static java.util.Arrays.*;
+
+import static org.fest.assertions.Assertions.*;
+import static org.fest.assertions.Fail.*;
+import static org.forgerock.opendj.ldap.Connections.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.util.promise.Promises.*;
+import static org.mockito.Mockito.*;
@SuppressWarnings("javadoc")
public class AbstractLoadBalancingAlgorithmTestCase extends SdkTestCase {
@@ -59,19 +57,11 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
try {
- final Connection connection = mock.getConnection();
- if (handler != null) {
- handler.handleResult(connection);
- }
- return new CompletedFutureResult<Connection>(connection);
+ return newSuccessfulPromise(mock.getConnection());
} catch (final ErrorResultException e) {
- if (handler != null) {
- handler.handleErrorResult(e);
- }
- return new CompletedFutureResult<Connection>(e);
+ return newFailedPromise(e);
}
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/ConnectionPoolTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/ConnectionPoolTestCase.java
index 6efb8ab..9b302e7 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/ConnectionPoolTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/ConnectionPoolTestCase.java
@@ -27,18 +27,6 @@
package org.forgerock.opendj.ldap;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.forgerock.opendj.ldap.Connections.newFixedConnectionPool;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.TestCaseUtils.mockConnection;
-import static org.forgerock.opendj.ldap.TestCaseUtils.mockConnectionFactory;
-import static org.forgerock.opendj.ldap.TestCaseUtils.mockTimeSource;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.*;
-
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -48,9 +36,20 @@
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.responses.Responses;
-import org.mockito.ArgumentCaptor;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.testng.Assert;
import org.testng.annotations.Test;
+import static org.fest.assertions.Assertions.*;
+import static org.forgerock.opendj.ldap.Connections.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
/**
* Tests the connection pool implementation..
*/
@@ -248,7 +247,7 @@
* is a connection available immediately then the future will be
* completed immediately).
*/
- final FutureResult<Connection> future = pool.getConnectionAsync(null);
+ final Promise<? extends Connection, ErrorResultException> future = pool.getConnectionAsync();
assertThat(future.isDone()).isFalse();
// Release a connection and verify that it is immediately redeemed by
@@ -521,24 +520,31 @@
final ConnectionFactory factory = mock(ConnectionFactory.class);
final int poolSize = 2;
final ConnectionPool pool = Connections.newFixedConnectionPool(factory, poolSize);
+ doAnswer(new Answer<Promise<Connection, ErrorResultException>>() {
+ @Override
+ public Promise<Connection, ErrorResultException> answer(final InvocationOnMock invocation)
+ throws Throwable {
+ return PromiseImpl.create();
+ }
+ }).when(factory).getConnectionAsync();
- List<FutureResult<Connection>> futures = new ArrayList<FutureResult<Connection>>();
+ List<Promise<? extends Connection, ErrorResultException>> futures =
+ new ArrayList<Promise<? extends Connection, ErrorResultException>>();
for (int i = 0; i < poolSize + 1; i++) {
- futures.add(pool.getConnectionAsync(null));
+ futures.add(pool.getConnectionAsync());
}
+ // factory.getConnectionAsync() has been called by the pool poolSize times
+ verify(factory, times(poolSize)).getConnectionAsync();
+ final ErrorResultException connectError = ErrorResultException
+ .newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
+ for (Promise<? extends Connection, ErrorResultException> future : futures) {
+ // Simulate that an error happened with the created connections
+ ((FutureResultImpl) future).handleError(connectError);
- final ArgumentCaptor<ResultHandler> arg = ArgumentCaptor.forClass(ResultHandler.class);
- verify(factory, times(poolSize)).getConnectionAsync(arg.capture());
- final ErrorResultException connectError =
- ErrorResultException.newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
- for (ResultHandler<Connection> handler : arg.getAllValues()) {
- handler.handleErrorResult(connectError);
- }
-
- for (FutureResult<Connection> future : futures) {
try {
// Before the fix for OPENDJ-1348 the third future.get() would hang.
- future.get();
+ future.getOrThrow();
+ Assert.fail("ErrorResultException should have been called");
} catch (ErrorResultException e) {
assertThat(e).isSameAs(connectError);
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactoryTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactoryTestCase.java
index 1f64f20..071ccf4 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactoryTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/HeartBeatConnectionFactoryTestCase.java
@@ -21,7 +21,7 @@
* CDDL HEADER END
*
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
@@ -33,7 +33,14 @@
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.BindResult;
+import org.forgerock.opendj.ldap.responses.Responses;
import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.NeverThrowsException;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.forgerock.util.promise.SuccessHandler;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
@@ -42,11 +49,10 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.CompletedFutureResult;
-
import static org.fest.assertions.Assertions.*;
import static org.fest.assertions.Fail.*;
import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
import static org.forgerock.opendj.ldap.SearchScope.*;
import static org.forgerock.opendj.ldap.TestCaseUtils.*;
import static org.forgerock.opendj.ldap.requests.Requests.*;
@@ -125,43 +131,34 @@
}
}
- @SuppressWarnings("unchecked")
@Test
public void testBindWhileHeartBeatInProgress() throws Exception {
mockConnectionWithInitialHeartbeatResult(ResultCode.SUCCESS);
-
+ mockBindAsyncResponse();
hbc = hbcf.getConnection();
/*
* Send a heartbeat, trapping the search call-back so that we can send
* the response once we have attempted a bind.
*/
- when(
- connection.searchAsync(any(SearchRequest.class),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class)))
- .thenReturn(null);
+ when(connection.searchAsync(any(SearchRequest.class), any(SearchResultHandler.class))).thenReturn(
+ FutureResultWrapper.newSuccessfulFutureResult(Responses.newResult(ResultCode.SUCCESS)));
when(hbcf.timeSource.currentTimeMillis()).thenReturn(11000L);
scheduler.runAllTasks(); // Send the heartbeat.
// Capture the heartbeat search result handler.
- final ArgumentCaptor<SearchResultHandler> arg =
- ArgumentCaptor.forClass(SearchResultHandler.class);
- verify(connection, times(2)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), arg.capture());
+ verify(connection, times(2)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
assertThat(hbc.isValid()).isTrue(); // Not checked yet.
/*
* Now attempt a bind request, which should be held in a queue until the
* heart beat completes.
*/
- hbc.bindAsync(newSimpleBindRequest(), null, null);
- verify(connection, times(0)).bindAsync(any(BindRequest.class),
- any(IntermediateResponseHandler.class), any(ResultHandler.class));
+ hbc.bindAsync(newSimpleBindRequest());
+ verify(connection, times(0)).bindAsync(any(BindRequest.class));
// Send fake heartbeat response, releasing the bind request.
- arg.getValue().handleResult(newResult(ResultCode.SUCCESS));
- verify(connection, times(1)).bindAsync(any(BindRequest.class),
- any(IntermediateResponseHandler.class), any(ResultHandler.class));
+ verify(connection, times(1)).bindAsync(any(BindRequest.class), any(IntermediateResponseHandler.class));
}
@Test
@@ -175,34 +172,42 @@
@Test
public void testGetConnectionAsync() throws Exception {
@SuppressWarnings("unchecked")
- final ResultHandler<Connection> mockResultHandler = mock(ResultHandler.class);
+ final SuccessHandler<Connection> mockSuccessHandler = mock(SuccessHandler.class);
mockConnectionWithInitialHeartbeatResult(ResultCode.SUCCESS);
- hbc = hbcf.getConnectionAsync(mockResultHandler).get();
+ hbc = hbcf.getConnectionAsync().onSuccess(mockSuccessHandler).getOrThrow();
assertThat(hbc).isNotNull();
assertThat(hbc.isValid()).isTrue();
- verify(mockResultHandler).handleResult(any(Connection.class));
- verifyNoMoreInteractions(mockResultHandler);
+ verify(mockSuccessHandler).handleResult(any(Connection.class));
+ verifyNoMoreInteractions(mockSuccessHandler);
}
@Test
public void testGetConnectionAsyncWithInitialHeartBeatError() throws Exception {
@SuppressWarnings("unchecked")
- final ResultHandler<Connection> mockResultHandler = mock(ResultHandler.class);
- ErrorResultException expectedException = null;
+ final SuccessHandler<Connection> mockSuccessHandler = mock(SuccessHandler.class);
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promisedError = PromiseImpl.create();
mockConnectionWithInitialHeartbeatResult(ResultCode.BUSY);
+ Promise<? extends Connection, ErrorResultException> promise = hbcf.getConnectionAsync();
+ promise.onSuccess(mockSuccessHandler).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ promisedError.handleResult(error);
+ }
+ });
+
+ checkInitialHeartBeatFailure(promisedError.getOrThrow());
+
try {
- hbcf.getConnectionAsync(mockResultHandler).get();
+ promise.getOrThrow();
fail("Unexpectedly obtained a connection");
} catch (final ErrorResultException e) {
checkInitialHeartBeatFailure(e);
- expectedException = e;
}
- verify(mockResultHandler).handleErrorResult(expectedException);
- verifyNoMoreInteractions(mockResultHandler);
+ verifyNoMoreInteractions(mockSuccessHandler);
}
@Test
@@ -251,11 +256,11 @@
// Attempt to send a new request: it should fail immediately.
@SuppressWarnings("unchecked")
- final ResultHandler<Result> mockHandler = mock(ResultHandler.class);
- hbc.modifyAsync(newModifyRequest(DN.rootDN()), null, mockHandler);
+ final FailureHandler<ErrorResultException> mockHandler = mock(FailureHandler.class);
+ hbc.modifyAsync(newModifyRequest(DN.rootDN())).onFailure(mockHandler);
final ArgumentCaptor<ErrorResultException> arg =
ArgumentCaptor.forClass(ErrorResultException.class);
- verify(mockHandler).handleErrorResult(arg.capture());
+ verify(mockHandler).handleError(arg.capture());
assertThat(arg.getValue().getResult().getResultCode()).isEqualTo(
ResultCode.CLIENT_SIDE_SERVER_DOWN);
@@ -282,10 +287,11 @@
assertThat(hbc.isClosed()).isFalse();
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "rawtypes", "unchecked" })
@Test(description = "OPENDJ-1348")
public void testBindPreventsHeartBeatTimeout() throws Exception {
mockConnectionWithInitialHeartbeatResult(ResultCode.SUCCESS);
+ mockBindAsyncResponse();
hbc = hbcf.getConnection();
/*
@@ -293,21 +299,18 @@
* the response once we have attempted a heartbeat.
*/
when(hbcf.timeSource.currentTimeMillis()).thenReturn(11000L);
- hbc.bindAsync(newSimpleBindRequest(), null, null);
- @SuppressWarnings("rawtypes")
- final ArgumentCaptor<ResultHandler> arg = ArgumentCaptor.forClass(ResultHandler.class);
- verify(connection, times(1)).bindAsync(any(BindRequest.class),
- any(IntermediateResponseHandler.class), arg.capture());
+ FutureResult<BindResult> future = hbc.bindAsync(newSimpleBindRequest());
+
+ verify(connection, times(1)).bindAsync(any(BindRequest.class), any(IntermediateResponseHandler.class));
// Verify no heartbeat is sent because there is a bind in progress.
when(hbcf.timeSource.currentTimeMillis()).thenReturn(11001L);
scheduler.runAllTasks(); // Invokes HBCF.ConnectionImpl.sendHeartBeat()
- verify(connection, times(1)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ verify(connection, times(1)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
// Send fake bind response, releasing the heartbeat.
when(hbcf.timeSource.currentTimeMillis()).thenReturn(11099L);
- arg.getValue().handleResult(newResult(ResultCode.SUCCESS));
+ ((ResultHandler) future).handleResult(newResult(ResultCode.SUCCESS));
// Check that bind response acts as heartbeat.
assertThat(hbc.isValid()).isTrue();
@@ -316,25 +319,21 @@
assertThat(hbc.isValid()).isTrue();
}
- @SuppressWarnings("unchecked")
@Test(description = "OPENDJ-1348")
public void testBindTriggersHeartBeatTimeoutWhenTooSlow() throws Exception {
mockConnectionWithInitialHeartbeatResult(ResultCode.SUCCESS);
+ mockBindAsyncResponse();
hbc = hbcf.getConnection();
// Send another bind request which will timeout.
when(hbcf.timeSource.currentTimeMillis()).thenReturn(20000L);
- hbc.bindAsync(newSimpleBindRequest(), null, null);
- @SuppressWarnings("rawtypes")
- final ArgumentCaptor<ResultHandler> arg = ArgumentCaptor.forClass(ResultHandler.class);
- verify(connection, times(1)).bindAsync(any(BindRequest.class),
- any(IntermediateResponseHandler.class), arg.capture());
+ hbc.bindAsync(newSimpleBindRequest());
+ verify(connection, times(1)).bindAsync(any(BindRequest.class), any(IntermediateResponseHandler.class));
// Verify no heartbeat is sent because there is a bind in progress.
when(hbcf.timeSource.currentTimeMillis()).thenReturn(20001L);
scheduler.runAllTasks(); // Invokes HBCF.ConnectionImpl.sendHeartBeat()
- verify(connection, times(1)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ verify(connection, times(1)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
// Check that lack of bind response acts as heartbeat timeout.
assertThat(hbc.isValid()).isTrue();
@@ -343,41 +342,39 @@
assertThat(hbc.isValid()).isFalse();
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testHeartBeatWhileBindInProgress() throws Exception {
mockConnectionWithInitialHeartbeatResult(ResultCode.SUCCESS);
+ mockBindAsyncResponse();
hbc = hbcf.getConnection();
/*
* Send a bind request, trapping the bind call-back so that we can send
* the response once we have attempted a heartbeat.
*/
- hbc.bindAsync(newSimpleBindRequest(), null, null);
+ FutureResult result = hbc.bindAsync(newSimpleBindRequest());
// Capture the bind result handler.
- @SuppressWarnings("rawtypes")
- final ArgumentCaptor<ResultHandler> arg = ArgumentCaptor.forClass(ResultHandler.class);
- verify(connection, times(1)).bindAsync(any(BindRequest.class),
- any(IntermediateResponseHandler.class), arg.capture());
+ verify(connection, times(1)).bindAsync(any(BindRequest.class), any(IntermediateResponseHandler.class));
/*
* Now attempt the heartbeat which should not happen because there is a
* bind in progress.
*/
when(hbcf.timeSource.currentTimeMillis()).thenReturn(11000L);
- scheduler.runAllTasks(); // Attempt to send the heartbeat.
- verify(connection, times(1)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ // Attempt to send the heartbeat.
+ scheduler.runAllTasks();
+ verify(connection, times(1)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
// Send fake bind response, releasing the heartbeat.
- arg.getValue().handleResult(newResult(ResultCode.SUCCESS));
+ ((ResultHandler) result).handleResult(newResult(ResultCode.SUCCESS));
// Attempt to send a heartbeat again.
when(hbcf.timeSource.currentTimeMillis()).thenReturn(16000L);
- scheduler.runAllTasks(); // Attempt to send the heartbeat.
- verify(connection, times(2)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ // Attempt to send the heartbeat.
+ scheduler.runAllTasks();
+ verify(connection, times(2)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
}
@Test
@@ -417,43 +414,46 @@
hbcf.timeSource = mockTimeSource(0);
}
- private Connection mockHeartBeatResponse(final Connection mockConnection,
- final List<ConnectionEventListener> listeners, final ResultCode resultCode) {
+ private void mockBindAsyncResponse() {
doAnswer(new Answer<FutureResult<Result>>() {
@Override
public FutureResult<Result> answer(final InvocationOnMock invocation) throws Throwable {
+ return new FutureResultImpl<Result>();
+ }
+ }).when(connection).bindAsync(any(BindRequest.class), any(IntermediateResponseHandler.class));
+ }
+
+ private Connection mockHeartBeatResponse(final Connection mockConnection,
+ final List<ConnectionEventListener> listeners, final ResultCode resultCode) {
+ Answer<FutureResult<Result>> answer = new Answer<FutureResult<Result>>() {
+ @Override
+ public FutureResult<Result> answer(final InvocationOnMock invocation) throws Throwable {
if (resultCode == null) {
return null;
}
- final SearchResultHandler handler =
- (SearchResultHandler) invocation.getArguments()[2];
if (resultCode.isExceptional()) {
final ErrorResultException error = newErrorResult(resultCode);
- if (handler != null) {
- handler.handleErrorResult(error);
- }
if (error instanceof ConnectionException) {
for (final ConnectionEventListener listener : listeners) {
listener.handleConnectionError(false, error);
}
}
- return new CompletedFutureResult<Result>(error);
+ return newFailedFutureResult(error);
} else {
- final Result result = newResult(resultCode);
- if (handler != null) {
- handler.handleResult(result);
- }
- return new CompletedFutureResult<Result>(result);
+ return newSuccessfulFutureResult(newResult(resultCode));
}
}
- }).when(mockConnection).searchAsync(any(SearchRequest.class),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ };
+
+ doAnswer(answer).when(mockConnection).searchAsync(any(SearchRequest.class), any(SearchResultHandler.class));
+ doAnswer(answer).when(mockConnection).searchAsync(any(SearchRequest.class),
+ any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+
return mockConnection;
}
private void verifyHeartBeatSent(final Connection connection, final int times) {
- verify(connection, times(times)).searchAsync(same(HEARTBEAT),
- any(IntermediateResponseHandler.class), any(SearchResultHandler.class));
+ verify(connection, times(times)).searchAsync(same(HEARTBEAT), any(SearchResultHandler.class));
}
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
index c212fca..960042e 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -27,8 +27,6 @@
package org.forgerock.opendj.ldap;
-import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
-
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
@@ -78,6 +76,8 @@
import com.forgerock.opendj.ldap.controls.AccountUsabilityRequestControl;
import com.forgerock.opendj.ldap.controls.AccountUsabilityResponseControl;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+
/**
* A simple ldap server that manages 1000 entries and used for running
* testcases.
@@ -100,19 +100,23 @@
this.isCanceled = new AtomicBoolean(false);
}
+ @Override
public Request addControl(final Control cntrl) {
return request.addControl(cntrl);
}
+ @Override
public boolean containsControl(final String oid) {
return request.containsControl(oid);
}
+ @Override
public <C extends Control> C getControl(final ControlDecoder<C> decoder,
final DecodeOptions options) throws DecodeException {
return request.getControl(decoder, options);
}
+ @Override
public List<Control> getControls() {
return request.getControls();
}
@@ -147,6 +151,7 @@
this.clientContext = clientContext;
}
+ @Override
public void handleAbandon(final Integer context, final AbandonRequest request)
throws UnsupportedOperationException {
// Check if we have any concurrent operation with this message id.
@@ -160,6 +165,7 @@
// No response is needed.
}
+ @Override
public void handleAdd(final Integer context, final AddRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> handler) throws UnsupportedOperationException {
@@ -172,7 +178,7 @@
// duplicate entry.
result = Responses.newResult(ResultCode.ENTRY_ALREADY_EXISTS);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- handler.handleErrorResult(ere);
+ handler.handleError(ere);
// doesn't matter if it was canceled.
requestsInProgress.remove(context);
return;
@@ -191,7 +197,7 @@
if (abReq.isCanceled()) {
result = Responses.newResult(ResultCode.CANCELLED);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- handler.handleErrorResult(ere);
+ handler.handleError(ere);
requestsInProgress.remove(context);
return;
}
@@ -202,6 +208,7 @@
handler.handleResult(result);
}
+ @Override
public void handleBind(final Integer context, final int version, final BindRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<BindResult> resultHandler) throws UnsupportedOperationException {
@@ -229,6 +236,7 @@
Sasl.createSaslServer(saslMech, "ldap",
listener.getHostName(), props,
new CallbackHandler() {
+ @Override
public void handle(Callback[] callbacks)
throws IOException,
UnsupportedCallbackException {
@@ -264,6 +272,7 @@
&& (qop.equalsIgnoreCase("auth-int") || qop
.equalsIgnoreCase("auth-conf"))) {
ConnectionSecurityLayer csl = new ConnectionSecurityLayer() {
+ @Override
public void dispose() {
try {
saslServer.dispose();
@@ -272,6 +281,7 @@
}
}
+ @Override
public byte[] unwrap(byte[] incoming, int offset, int len)
throws ErrorResultException {
try {
@@ -283,6 +293,7 @@
}
}
+ @Override
public byte[] wrap(byte[] outgoing, int offset, int len)
throws ErrorResultException {
try {
@@ -304,7 +315,7 @@
ByteString.wrap(challenge)));
}
} catch (Exception e) {
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(Responses
+ resultHandler.handleError(ErrorResultException.newErrorResult(Responses
.newBindResult(ResultCode.OPERATIONS_ERROR).setCause(e)
.setDiagnosticMessage(e.toString())));
}
@@ -314,6 +325,7 @@
requestsInProgress.remove(context);
}
+ @Override
public void handleConnectionClosed(final Integer context, final UnbindRequest request) {
close();
}
@@ -328,14 +340,17 @@
}
}
+ @Override
public void handleConnectionDisconnected(ResultCode resultCode, String message) {
close();
}
+ @Override
public void handleConnectionError(final Throwable error) {
close();
}
+ @Override
public void handleCompare(final Integer context, final CompareRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<CompareResult> resultHandler)
@@ -349,7 +364,7 @@
// entry not found.
result = Responses.newCompareResult(ResultCode.NO_SUCH_ATTRIBUTE);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- resultHandler.handleErrorResult(ere);
+ resultHandler.handleError(ere);
// doesn't matter if it was canceled.
requestsInProgress.remove(context);
return;
@@ -365,7 +380,7 @@
if (abReq.isCanceled()) {
final Result r = Responses.newResult(ResultCode.CANCELLED);
final ErrorResultException ere = ErrorResultException.newErrorResult(r);
- resultHandler.handleErrorResult(ere);
+ resultHandler.handleError(ere);
requestsInProgress.remove(context);
return;
}
@@ -382,6 +397,7 @@
requestsInProgress.remove(context);
}
+ @Override
public void handleDelete(final Integer context, final DeleteRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> handler) throws UnsupportedOperationException {
@@ -394,7 +410,7 @@
// entry is not found.
result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- handler.handleErrorResult(ere);
+ handler.handleError(ere);
// doesn't matter if it was canceled.
requestsInProgress.remove(context);
return;
@@ -403,7 +419,7 @@
if (abReq.isCanceled()) {
result = Responses.newResult(ResultCode.CANCELLED);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- handler.handleErrorResult(ere);
+ handler.handleError(ere);
requestsInProgress.remove(context);
return;
}
@@ -414,6 +430,7 @@
handler.handleResult(result);
}
+ @Override
public <R extends ExtendedResult> void handleExtendedRequest(final Integer context,
final ExtendedRequest<R> request,
final IntermediateResponseHandler intermediateResponseHandler,
@@ -428,21 +445,24 @@
}
}
+ @Override
public void handleModify(final Integer context, final ModifyRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) throws UnsupportedOperationException {
// TODO:
}
+ @Override
public void handleModifyDN(final Integer context, final ModifyDNRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) throws UnsupportedOperationException {
// TODO
}
+ @Override
public void handleSearch(final Integer context, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) throws UnsupportedOperationException {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler) throws UnsupportedOperationException {
Result result = null;
final AbandonableRequest abReq = new AbandonableRequest(request);
requestsInProgress.put(context, abReq);
@@ -452,7 +472,7 @@
// Entry not found.
result = Responses.newResult(ResultCode.NO_SUCH_OBJECT);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- resultHandler.handleErrorResult(ere);
+ resultHandler.handleError(ere);
// Should searchResultHandler handle anything?
// doesn't matter if it was canceled.
@@ -463,21 +483,19 @@
if (abReq.isCanceled()) {
result = Responses.newResult(ResultCode.CANCELLED);
final ErrorResultException ere = ErrorResultException.newErrorResult(result);
- resultHandler.handleErrorResult(ere);
+ resultHandler.handleError(ere);
requestsInProgress.remove(context);
return;
}
- final SearchResultEntry e =
- Responses.newSearchResultEntry(new LinkedHashMapEntry(entryMap.get(dn)));
+ final SearchResultEntry e = Responses.newSearchResultEntry(new LinkedHashMapEntry(entryMap.get(dn)));
// Check we have had any controls in the request.
for (final Control control : request.getControls()) {
if (control.getOID().equals(AccountUsabilityRequestControl.OID)) {
- e.addControl(AccountUsabilityResponseControl.newControl(false, false, false,
- 10, false, 0));
+ e.addControl(AccountUsabilityResponseControl.newControl(false, false, false, 10, false, 0));
}
}
- resultHandler.handleEntry(e);
+ entryHandler.handleEntry(e);
result = Responses.newResult(ResultCode.SUCCESS);
resultHandler.handleResult(result);
requestsInProgress.remove(context);
@@ -521,6 +539,7 @@
}
}
+ @Override
public ServerConnection<Integer> handleAccept(final LDAPClientContext context) {
return new LDAPServerConnection(context);
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
index e81a94c..449830e 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/TestCaseUtils.java
@@ -26,12 +26,6 @@
*/
package org.forgerock.opendj.ldap;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@@ -42,13 +36,18 @@
import java.util.logging.Level;
import java.util.logging.Logger;
+import org.forgerock.util.promise.Promise;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.OngoingStubbing;
-import com.forgerock.opendj.util.CompletedFutureResult;
import com.forgerock.opendj.util.TimeSource;
+import static org.fest.assertions.Fail.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
/**
* This class defines some utility functions which can be used by test cases.
*/
@@ -164,30 +163,20 @@
* The remaining connections to return.
* @return The connection factory.
*/
- @SuppressWarnings("unchecked")
- public static ConnectionFactory mockConnectionFactory(final Connection first,
- final Connection... remaining) {
+ public static ConnectionFactory mockConnectionFactory(final Connection first, final Connection... remaining) {
final ConnectionFactory factory = mock(ConnectionFactory.class);
try {
when(factory.getConnection()).thenReturn(first, remaining);
} catch (ErrorResultException ignored) {
// Cannot happen.
}
- when(factory.getConnectionAsync(any(ResultHandler.class))).thenAnswer(
- new Answer<FutureResult<Connection>>() {
- @Override
- public FutureResult<Connection> answer(final InvocationOnMock invocation)
- throws Throwable {
- final Connection connection = factory.getConnection();
- // Execute handler and return future.
- final ResultHandler<? super Connection> handler =
- (ResultHandler<? super Connection>) invocation.getArguments()[0];
- if (handler != null) {
- handler.handleResult(connection);
- }
- return new CompletedFutureResult<Connection>(connection);
- }
- });
+ when(factory.getConnectionAsync()).thenAnswer(new Answer<Promise<Connection, ErrorResultException>>() {
+ @Override
+ public Promise<Connection, ErrorResultException> answer(final InvocationOnMock invocation)
+ throws Throwable {
+ return newSuccessfulFutureResult(factory.getConnection());
+ }
+ });
return factory;
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
index 7cbfaa0..e88de44 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaBuilderTestCase.java
@@ -25,31 +25,33 @@
*/
package org.forgerock.opendj.ldap.schema;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.SCHEMA_PROPERTY_ORIGIN;
-import static org.forgerock.opendj.ldap.schema.SchemaConstants.TOP_OBJECTCLASS_NAME;
-
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.EntryNotFoundException;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.FutureResultWrapper;
import org.forgerock.opendj.ldap.LinkedHashMapEntry;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import org.testng.annotations.Test;
-import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.responses.Responses;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.promise.Promise;
+import org.testng.annotations.Test;
+
+import static org.fest.assertions.Assertions.*;
+import static org.fest.assertions.Fail.*;
+import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
+import static org.forgerock.util.promise.Promises.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
/**
* Test SchemaBuilder.
@@ -1969,6 +1971,55 @@
connection.close();
}
+ /**
+ * Asynchronously retrieving an LDAP Server's schema.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testSchemaBuilderAddSchemaForEntryAsyncMockConnection() throws Exception {
+ Connection connection = mock(Connection.class);
+ final SchemaBuilder scBuild = new SchemaBuilder(Schema.getCoreSchema());
+
+ // @formatter:off
+ final String[] entry = {
+ "# Search result entry: uid=bjensen,ou=People,dc=example,dc=com",
+ "dn: uid=bjensen,ou=People,dc=example,dc=com",
+ "subschemaSubentry: cn=schema",
+ "entryDN: uid=bjensen,ou=people,dc=example,dc=com",
+ "entryUUID: fc252fd9-b982-3ed6-b42a-c76d2546312c"
+ // N.B : also works with previous example but needs the subschemaSubentry line.
+ };
+
+ // Send a search entry result promise :
+ Promise<SearchResultEntry, ErrorResultException> promise =
+ newSuccessfulPromise(Responses.newSearchResultEntry(entry));
+ FutureResult<SearchResultEntry> result = FutureResultWrapper.asFutureResult(promise);
+ when(connection.searchSingleEntryAsync((SearchRequest) any())).thenReturn(result);
+ DN testDN = DN.valueOf("uid=bjensen,ou=People,dc=example,dc=com");
+ // @formatter:on
+ Schema sc = scBuild.addSchemaForEntryAsync(connection, testDN, false).getOrThrow().toSchema();
+
+ // We retrieve the schema
+ assertThat(sc.getSyntaxes()).isNotNull();
+ assertThat(sc.getAttributeTypes()).isNotNull();
+ assertThat(sc.getAttributeTypes()).isNotEmpty();
+ assertThat(sc.getObjectClasses()).isNotNull();
+ assertThat(sc.getObjectClasses()).isNotEmpty();
+ assertThat(sc.getMatchingRuleUses()).isNotNull();
+ assertThat(sc.getMatchingRuleUses()).isEmpty();
+ assertThat(sc.getMatchingRules()).isNotNull();
+ assertThat(sc.getMatchingRules()).isNotEmpty();
+ assertThat(sc.getDITContentRules()).isNotNull();
+ assertThat(sc.getDITContentRules()).isEmpty();
+ assertThat(sc.getDITStuctureRules()).isNotNull();
+ assertThat(sc.getDITStuctureRules()).isEmpty();
+ assertThat(sc.getNameForms()).isNotNull();
+ assertThat(sc.getNameForms()).isEmpty();
+
+ connection.close();
+ }
+
@Test
public void testDefaultSyntax() {
final Schema schema =
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java
index 7cf4601..0bdc26a 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/schema/SchemaTestCase.java
@@ -26,7 +26,19 @@
package org.forgerock.opendj.ldap.schema;
import static org.fest.assertions.Assertions.assertThat;
+import static org.forgerock.util.promise.Promises.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.FutureResultWrapper;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.Responses;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.promise.Promise;
import org.testng.annotations.Test;
/**
@@ -50,4 +62,54 @@
final Schema strictSchema2 = schema.asStrictSchema().asNonStrictSchema().asStrictSchema();
assertThat(strictSchema1).isSameAs(strictSchema2);
}
+
+ /**
+ * Asynchronously retrieving a simple schema.
+ *
+ * @throws Exception
+ */
+ @Test()
+ public final void testReadSchemaAsyncMethodsMockConnection() throws Exception {
+ Connection connection = mock(Connection.class);
+
+ // @formatter:off
+ final String[] entry = {
+ "# Search result entry: uid=bjensen,ou=People,dc=example,dc=com",
+ "dn: uid=bjensen,ou=People,dc=example,dc=com",
+ "subschemaSubentry: cn=schema",
+ "entryDN: uid=bjensen,ou=people,dc=example,dc=com",
+ "entryUUID: fc252fd9-b982-3ed6-b42a-c76d2546312c"
+ // N.B : also works with previous example but needs the subschemaSubentry line.
+ };
+
+ // Send a search entry result promise :
+ Promise<SearchResultEntry, ErrorResultException> promise =
+ newSuccessfulPromise(Responses.newSearchResultEntry(entry));
+ FutureResult<SearchResultEntry> result = FutureResultWrapper.asFutureResult(promise);
+ when(connection.searchSingleEntryAsync((SearchRequest) any())).thenReturn(result);
+ DN testDN = DN.valueOf("uid=bjensen,ou=People,dc=example,dc=com");
+ // @formatter:on
+ Schema[] schemas = new Schema[] {
+ Schema.readSchemaAsync(connection, testDN).getOrThrow(),
+ Schema.readSchemaForEntryAsync(connection, testDN).getOrThrow()
+ };
+
+ // We retrieve the schemas :
+ for (Schema sc : schemas) {
+ assertThat(sc.getSyntaxes()).isNotNull();
+ assertThat(sc.getAttributeTypes()).isNotNull();
+ assertThat(sc.getObjectClasses()).isNotNull();
+ assertThat(sc.getMatchingRuleUses()).isNotNull();
+ assertThat(sc.getMatchingRuleUses()).isEmpty();
+ assertThat(sc.getMatchingRules()).isNotNull();
+ assertThat(sc.getDITContentRules()).isNotNull();
+ assertThat(sc.getDITContentRules()).isEmpty();
+ assertThat(sc.getDITStuctureRules()).isNotNull();
+ assertThat(sc.getDITStuctureRules()).isEmpty();
+ assertThat(sc.getNameForms()).isNotNull();
+ assertThat(sc.getNameForms()).isEmpty();
+ }
+ connection.close();
+ }
+
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/spi/BasicLDAPConnectionFactory.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/spi/BasicLDAPConnectionFactory.java
index 125d926..72e391f 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/spi/BasicLDAPConnectionFactory.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/spi/BasicLDAPConnectionFactory.java
@@ -26,19 +26,17 @@
package org.forgerock.opendj.ldap.spi;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.mockito.Mockito.mock;
-
import java.net.InetSocketAddress;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.LDAPOptions;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
+import org.forgerock.util.promise.Promise;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.util.promise.Promises.*;
+import static org.mockito.Mockito.*;
/**
* Basic LDAP connection factory implementation to use for tests only.
@@ -73,19 +71,15 @@
@Override
public Connection getConnection() throws ErrorResultException {
try {
- return getConnectionAsync(null).get();
+ return getConnectionAsync().getOrThrow();
} catch (final InterruptedException e) {
throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, e);
}
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
- final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future =
- new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(handler);
- future.handleResult(mock(Connection.class));
- return future;
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ return newSuccessfulPromise(mock(Connection.class));
}
/**
@@ -93,6 +87,7 @@
*
* @return The address of the Directory Server.
*/
+ @Override
public InetSocketAddress getSocketAddress() {
return new InetSocketAddress(host, port);
}
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldif/ConnectionEntryReaderTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldif/ConnectionEntryReaderTestCase.java
index 34882fd..553274a 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldif/ConnectionEntryReaderTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldif/ConnectionEntryReaderTestCase.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2011 ForgeRock AS
- * Portions copyright 2012 ForgeRock AS.
+ * Portions copyright 2012-2014 ForgeRock AS.
*/
package org.forgerock.opendj.ldif;
@@ -34,7 +34,6 @@
import static org.forgerock.opendj.ldap.responses.Responses.newSearchResultEntry;
import static org.forgerock.opendj.ldap.responses.Responses.newSearchResultReference;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.isNull;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -44,7 +43,7 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultIOException;
import org.forgerock.opendj.ldap.FutureResult;
-import org.forgerock.opendj.ldap.IntermediateResponseHandler;
+import org.forgerock.opendj.ldap.FutureResultWrapper;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.SearchResultReferenceIOException;
@@ -58,8 +57,6 @@
import org.mockito.stubbing.Answer;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.CompletedFutureResult;
-
/**
* This class tests the ConnectionEntryReader functionality.
*/
@@ -254,37 +251,30 @@
private ConnectionEntryReader newReader(final Object... responses) {
final Connection connection = mock(Connection.class);
// @formatter:off
- when(connection.searchAsync(same(SEARCH), (IntermediateResponseHandler) isNull(),
- any(SearchResultHandler.class))).thenAnswer(
- new Answer<FutureResult<Result>>() {
- @Override
- public FutureResult<Result> answer(final InvocationOnMock invocation)
- throws Throwable {
- // Execute handler and return future.
- final SearchResultHandler handler =
- (SearchResultHandler) invocation.getArguments()[2];
- if (handler != null) {
- for (int i = 0; i < responses.length; i++) {
- final Object response = responses[i];
- if (response instanceof SearchResultEntry) {
- handler.handleEntry((SearchResultEntry) response);
- } else if (response instanceof SearchResultReference) {
- handler.handleReference((SearchResultReference) response);
- } else if (((Result) response).isSuccess()) {
- handler.handleResult((Result) response);
- } else {
- handler.handleErrorResult(newErrorResult((Result) response));
- }
- }
- }
- final Result result = (Result) responses[responses.length - 1];
- if (result.isSuccess()) {
- return new CompletedFutureResult<Result>(result);
- } else {
- return new CompletedFutureResult<Result>(newErrorResult(result));
- }
+ when(connection.searchAsync(same(SEARCH), any(SearchResultHandler.class))).thenAnswer(
+ new Answer<FutureResult<Result>>() {
+ @Override
+ public FutureResult<Result> answer(final InvocationOnMock invocation) throws Throwable {
+ // Execute handler and return future.
+ final SearchResultHandler handler = (SearchResultHandler) invocation.getArguments()[1];
+ if (handler != null) {
+ for (int i = 0; i < responses.length; i++) {
+ final Object response = responses[i];
+ if (response instanceof SearchResultEntry) {
+ handler.handleEntry((SearchResultEntry) response);
+ } else if (response instanceof SearchResultReference) {
+ handler.handleReference((SearchResultReference) response);
}
- });
+ }
+ }
+ final Result result = (Result) responses[responses.length - 1];
+ if (result.isSuccess()) {
+ return FutureResultWrapper.newSuccessfulFutureResult(result);
+ } else {
+ return FutureResultWrapper.newFailedFutureResult(newErrorResult(result));
+ }
+ }
+ });
// @formatter:on
return new ConnectionEntryReader(connection, SEARCH);
}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
index 591a660..f1470e4 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -26,9 +26,6 @@
*/
package org.forgerock.opendj.grizzly;
-import static com.forgerock.opendj.grizzly.GrizzlyMessages.*;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.List;
@@ -52,7 +49,6 @@
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.LDAPOptions;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SSLContextBuilder;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.TimeoutEventListener;
@@ -81,15 +77,17 @@
import org.forgerock.opendj.ldap.spi.LDAPExtendedFutureResultImpl;
import org.forgerock.opendj.ldap.spi.LDAPFutureResultImpl;
import org.forgerock.opendj.ldap.spi.LDAPSearchFutureResultImpl;
+import org.forgerock.util.Reject;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.filterchain.FilterChain;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
-import org.forgerock.util.Reject;
+import static com.forgerock.opendj.grizzly.GrizzlyMessages.*;
/**
* LDAP connection implementation.
@@ -120,12 +118,12 @@
private final ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>> pendingRequests =
new ConcurrentHashMap<Integer, AbstractLDAPFutureResultImpl<?>>();
private final Object stateLock = new Object();
- // Guarded by stateLock
+ /** Guarded by stateLock. */
private Result connectionInvalidReason;
- private boolean failedDueToDisconnect = false;
- private boolean isClosed = false;
- private boolean isFailed = false;
- private List<ConnectionEventListener> listeners = null;
+ private boolean failedDueToDisconnect;
+ private boolean isClosed;
+ private boolean isFailed;
+ private List<ConnectionEventListener> listeners;
/**
* Create a LDAP Connection with provided Grizzly connection and LDAP
@@ -162,19 +160,18 @@
checkBindOrStartTLSInProgress();
}
} catch (final ErrorResultException e) {
- return new CompletedFutureResult<Void>(e);
+ return newFailedFutureResult(e);
}
// Remove the future associated with the request to be abandoned.
- final AbstractLDAPFutureResultImpl<?> pendingRequest =
- pendingRequests.remove(request.getRequestID());
+ final AbstractLDAPFutureResultImpl<?> pendingRequest = pendingRequests.remove(request.getRequestID());
if (pendingRequest == null) {
/*
* There has never been a request with the specified message ID or
* the response has already been received and handled. We can ignore
* this abandon request.
*/
- return new CompletedFutureResult<Void>((Void) null);
+ return newSuccessfulFutureResult((Void) null);
}
/*
@@ -197,9 +194,9 @@
final int messageID = nextMsgID.getAndIncrement();
writer.writeAbandonRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
- return new CompletedFutureResult<Void>((Void) null, messageID);
+ return newSuccessfulFutureResult((Void) null, messageID);
} catch (final IOException e) {
- return new CompletedFutureResult<Void>(adaptRequestIOException(e));
+ return newFailedFutureResult(adaptRequestIOException(e));
} finally {
GrizzlyUtils.recycleWriter(writer);
}
@@ -207,12 +204,10 @@
@Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPFutureResultImpl(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -264,42 +259,35 @@
@Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final BindClient context;
try {
- context =
- request.createBindClient(Connections.getHostString(factory.getSocketAddress()));
+ context = request.createBindClient(Connections.getHostString(factory.getSocketAddress()));
} catch (final Exception e) {
// FIXME: I18N need to have a better error message.
// FIXME: Is this the best result code?
- final Result errorResult =
- Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage(
- "An error occurred while creating a bind context").setCause(e);
+ final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR)
+ .setDiagnosticMessage("An error occurred while creating a bind context").setCause(e);
final ErrorResultException error = ErrorResultException.newErrorResult(errorResult);
- if (resultHandler != null) {
- resultHandler.handleErrorResult(error);
- }
- return new CompletedFutureResult<BindResult>(error, messageID);
+
+ return newFailedFutureResult(error, messageID);
}
final LDAPBindFutureResultImpl future =
- new LDAPBindFutureResultImpl(messageID, context, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPBindFutureResultImpl(messageID, context, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
if (!pendingRequests.isEmpty()) {
- future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR)
- .setDiagnosticMessage(
- "There are other operations pending on this connection"));
+ future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+ "There are other operations pending on this connection"));
return future;
}
if (!bindOrStartTLSInProgress.compareAndSet(false, true)) {
- future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR)
- .setDiagnosticMessage("Bind or Start TLS operation in progress"));
+ future.setResultOrError(Responses.newBindResult(ResultCode.OPERATIONS_ERROR).setDiagnosticMessage(
+ "Bind or Start TLS operation in progress"));
return future;
}
pendingRequests.put(messageID, future);
@@ -338,12 +326,10 @@
@Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPCompareFutureResultImpl future =
- new LDAPCompareFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPCompareFutureResultImpl(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -370,12 +356,10 @@
@Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPFutureResultImpl(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -401,32 +385,26 @@
}
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPExtendedFutureResultImpl<R> future =
- new LDAPExtendedFutureResultImpl<R>(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPExtendedFutureResultImpl<R>(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
- if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
+ if (StartTLSExtendedRequest.OID.equals(request.getOID())) {
if (!pendingRequests.isEmpty()) {
future.setResultOrError(request.getResultDecoder().newExtendedErrorResult(
- ResultCode.OPERATIONS_ERROR, "",
- "There are pending operations on this connection"));
+ ResultCode.OPERATIONS_ERROR, "", "There are pending operations on this connection"));
return future;
} else if (isTLSEnabled()) {
future.setResultOrError(request.getResultDecoder().newExtendedErrorResult(
- ResultCode.OPERATIONS_ERROR, "",
- "This connection is already TLS enabled"));
+ ResultCode.OPERATIONS_ERROR, "", "This connection is already TLS enabled"));
return future;
} else if (!bindOrStartTLSInProgress.compareAndSet(false, true)) {
future.setResultOrError(request.getResultDecoder().newExtendedErrorResult(
- ResultCode.OPERATIONS_ERROR, "",
- "Bind or Start TLS operation in progress"));
+ ResultCode.OPERATIONS_ERROR, "", "Bind or Start TLS operation in progress"));
return future;
}
} else {
@@ -469,12 +447,10 @@
@Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPFutureResultImpl(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -501,12 +477,10 @@
@Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPFutureResultImpl future =
- new LDAPFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPFutureResultImpl(messageID, request, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -541,14 +515,13 @@
}
}
+ /** {@inheritDoc} */
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler) {
final int messageID = nextMsgID.getAndIncrement();
final LDAPSearchFutureResultImpl future =
- new LDAPSearchFutureResultImpl(messageID, request, resultHandler,
- intermediateResponseHandler, this);
+ new LDAPSearchFutureResultImpl(messageID, request, entryHandler, intermediateResponseHandler, this);
try {
synchronized (stateLock) {
checkConnectionIsValid();
@@ -614,23 +587,18 @@
*/
logger.debug(LocalizableMessage.raw("Failing bind or StartTLS request due to timeout %s"
+ "(connection will be invalidated): ", future));
- final Result result =
- Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
- LDAP_CONNECTION_BIND_OR_START_TLS_REQUEST_TIMEOUT.get(timeout)
- .toString());
+ final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
+ LDAP_CONNECTION_BIND_OR_START_TLS_REQUEST_TIMEOUT.get(timeout).toString());
future.adaptErrorResult(result);
// Fail the connection.
- final Result errorResult =
- Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
- LDAP_CONNECTION_BIND_OR_START_TLS_CONNECTION_TIMEOUT.get(timeout)
- .toString());
+ final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
+ LDAP_CONNECTION_BIND_OR_START_TLS_CONNECTION_TIMEOUT.get(timeout).toString());
connectionErrorOccurred(errorResult);
} else {
logger.debug(LocalizableMessage.raw("Failing request due to timeout: %s", future));
- final Result result =
- Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
- LDAP_CONNECTION_REQUEST_TIMEOUT.get(timeout).toString());
+ final Result result = Responses.newResult(ResultCode.CLIENT_SIDE_TIMEOUT).setDiagnosticMessage(
+ LDAP_CONNECTION_REQUEST_TIMEOUT.get(timeout).toString());
future.adaptErrorResult(result);
/*
@@ -640,9 +608,9 @@
* request while holding the state lock, since a blocking write
* could hang the application.
*/
-// if (!bindOrStartTLSInProgress.get()) {
-// sendAbandonRequest(newAbandonRequest(future.getRequestID()));
-// }
+ // if (!bindOrStartTLSInProgress.get()) {
+ // sendAbandonRequest(newAbandonRequest(future.getRequestID()));
+ // }
}
}
return delay;
@@ -813,22 +781,20 @@
bindOrStartTLSInProgress.set(state);
}
- void startTLS(final SSLContext sslContext, final List<String> protocols,
- final List<String> cipherSuites, final CompletionHandler<SSLEngine> completionHandler)
- throws IOException {
+ void startTLS(final SSLContext sslContext, final List<String> protocols, final List<String> cipherSuites,
+ final CompletionHandler<SSLEngine> completionHandler) throws IOException {
synchronized (stateLock) {
if (isTLSEnabled()) {
throw new IllegalStateException("TLS already enabled");
}
- final SSLEngineConfigurator sslEngineConfigurator =
- new SSLEngineConfigurator(sslContext, true, false, false);
+ final SSLEngineConfigurator sslEngineConfigurator = new SSLEngineConfigurator(sslContext, true, false,
+ false);
sslEngineConfigurator.setEnabledProtocols(protocols.isEmpty() ? null : protocols
.toArray(new String[protocols.size()]));
- sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ? null
- : cipherSuites.toArray(new String[cipherSuites.size()]));
- final SSLFilter sslFilter =
- new SSLFilter(DUMMY_SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
+ sslEngineConfigurator.setEnabledCipherSuites(cipherSuites.isEmpty() ? null : cipherSuites
+ .toArray(new String[cipherSuites.size()]));
+ final SSLFilter sslFilter = new SSLFilter(DUMMY_SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
installFilter(sslFilter);
sslFilter.handshake(connection, completionHandler);
}
@@ -837,16 +803,14 @@
private ErrorResultException adaptRequestIOException(final IOException e) {
// FIXME: what other sort of IOExceptions can be thrown?
// FIXME: Is this the best result code?
- final Result errorResult =
- Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
+ final Result errorResult = Responses.newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e);
connectionErrorOccurred(errorResult);
return newErrorResult(errorResult);
}
private void checkBindOrStartTLSInProgress() throws ErrorResultException {
if (bindOrStartTLSInProgress.get()) {
- throw newErrorResult(ResultCode.OPERATIONS_ERROR,
- "Bind or Start TLS operation in progress");
+ throw newErrorResult(ResultCode.OPERATIONS_ERROR, "Bind or Start TLS operation in progress");
}
}
@@ -861,8 +825,7 @@
* this could be misinterpreted as a genuine authentication
* failure for subsequent bind requests.
*/
- throw newErrorResult(ResultCode.CLIENT_SIDE_SERVER_DOWN,
- "Connection closed by server");
+ throw newErrorResult(ResultCode.CLIENT_SIDE_SERVER_DOWN, "Connection closed by server");
} else {
throw newErrorResult(connectionInvalidReason);
}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
index 4d3b78f..59a1959 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
@@ -27,13 +27,6 @@
package org.forgerock.opendj.grizzly;
-import static com.forgerock.opendj.grizzly.GrizzlyMessages.LDAP_CONNECTION_CONNECT_TIMEOUT;
-import static org.forgerock.opendj.grizzly.DefaultTCPNIOTransport.DEFAULT_TRANSPORT;
-import static org.forgerock.opendj.grizzly.GrizzlyUtils.buildFilterChain;
-import static org.forgerock.opendj.grizzly.GrizzlyUtils.configureConnection;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.TimeoutChecker.TIMEOUT_CHECKER;
-
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutionException;
@@ -46,16 +39,18 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.FutureResultImpl;
import org.forgerock.opendj.ldap.LDAPOptions;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.TimeoutChecker;
import org.forgerock.opendj.ldap.TimeoutEventListener;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.spi.LDAPConnectionFactoryImpl;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
import org.glassfish.grizzly.CompletionHandler;
import org.glassfish.grizzly.EmptyCompletionHandler;
import org.glassfish.grizzly.SocketConnectorHandler;
@@ -63,9 +58,15 @@
import org.glassfish.grizzly.nio.transport.TCPNIOConnectorHandler;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
import com.forgerock.opendj.util.ReferenceCountedObject;
+import static org.forgerock.opendj.grizzly.DefaultTCPNIOTransport.*;
+import static org.forgerock.opendj.grizzly.GrizzlyUtils.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.TimeoutChecker.*;
+
+import static com.forgerock.opendj.grizzly.GrizzlyMessages.*;
+
/**
* LDAP connection factory implementation using Grizzly for transport.
*/
@@ -79,11 +80,10 @@
@SuppressWarnings("rawtypes")
private final class CompletionHandlerAdapter implements
CompletionHandler<org.glassfish.grizzly.Connection>, TimeoutEventListener {
- private final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future;
+ private final FutureResultImpl<Connection> future;
private final long timeoutEndTime;
- private CompletionHandlerAdapter(
- final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future) {
+ private CompletionHandlerAdapter(final FutureResultImpl<Connection> future) {
this.future = future;
final long timeoutMS = getTimeout();
this.timeoutEndTime = timeoutMS > 0 ? System.currentTimeMillis() + timeoutMS : 0;
@@ -120,37 +120,36 @@
final StartTLSExtendedRequest startTLS =
Requests.newStartTLSExtendedRequest(options.getSSLContext());
startTLS.addEnabledCipherSuite(options.getEnabledCipherSuites().toArray(
- new String[options.getEnabledCipherSuites().size()]));
+ new String[options.getEnabledCipherSuites().size()]));
startTLS.addEnabledProtocol(options.getEnabledProtocols().toArray(
- new String[options.getEnabledProtocols().size()]));
- final ResultHandler<ExtendedResult> handler = new ResultHandler<ExtendedResult>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- onFailure(connection, error);
- }
+ new String[options.getEnabledProtocols().size()]));
+ connection.extendedRequestAsync(startTLS).onSuccess(new SuccessHandler<ExtendedResult>() {
@Override
public void handleResult(final ExtendedResult result) {
onSuccess(connection);
}
- };
- connection.extendedRequestAsync(startTLS, null, handler);
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ onFailure(connection, error);
+ }
+ });
} else {
// Install SSL/TLS layer.
try {
connection.startTLS(options.getSSLContext(), options.getEnabledProtocols(),
- options.getEnabledCipherSuites(),
- new EmptyCompletionHandler<SSLEngine>() {
- @Override
- public void completed(final SSLEngine result) {
- onSuccess(connection);
- }
+ options.getEnabledCipherSuites(), new EmptyCompletionHandler<SSLEngine>() {
+ @Override
+ public void completed(final SSLEngine result) {
+ onSuccess(connection);
+ }
- @Override
- public void failed(final Throwable throwable) {
- onFailure(connection, throwable);
- }
- });
+ @Override
+ public void failed(final Throwable throwable) {
+ onFailure(connection, throwable);
+ }
+ });
} catch (final IOException e) {
onFailure(connection, e);
}
@@ -161,7 +160,7 @@
public void failed(final Throwable throwable) {
// Adapt and forward.
timeoutChecker.get().removeListener(this);
- future.handleErrorResult(adaptConnectionException(throwable));
+ future.handleError(adaptConnectionException(throwable));
releaseTransportAndTimeoutChecker();
}
@@ -197,7 +196,7 @@
private void onFailure(final GrizzlyLDAPConnection connection, final Throwable t) {
// Abort connection attempt due to error.
timeoutChecker.get().removeListener(this);
- future.handleErrorResult(adaptConnectionException(t));
+ future.handleError(adaptConnectionException(t));
connection.close();
}
@@ -216,7 +215,7 @@
} else if (timeoutEndTime > currentTime) {
return timeoutEndTime - currentTime;
} else {
- future.handleErrorResult(newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR,
+ future.handleError(newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR,
LDAP_CONNECTION_CONNECT_TIMEOUT.get(getSocketAddress(), getTimeout()).toString()));
return 0;
}
@@ -303,21 +302,19 @@
@Override
public Connection getConnection() throws ErrorResultException {
try {
- return getConnectionAsync(null).get();
+ return getConnectionAsync().getOrThrow();
} catch (final InterruptedException e) {
throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, e);
}
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- final ResultHandler<? super Connection> handler) {
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
acquireTransportAndTimeoutChecker(); // Protect resources.
final SocketConnectorHandler connectorHandler =
TCPNIOConnectorHandler.builder(transport.get()).processor(defaultFilterChain)
.build();
- final AsynchronousFutureResult<Connection, ResultHandler<? super Connection>> future =
- new AsynchronousFutureResult<Connection, ResultHandler<? super Connection>>(handler);
+ final FutureResultImpl<Connection> future = new FutureResultImpl<Connection>();
connectorHandler.connect(getSocketAddress(), new CompletionHandlerAdapter(future));
return future;
}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
index d9893dd..f005273 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2012-2013 ForgeRock AS.
+ * Portions copyright 2012-2014 ForgeRock AS.
*/
package org.forgerock.opendj.grizzly;
@@ -207,7 +207,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -224,7 +224,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
final Result result = error.getResult();
if (result instanceof BindResult) {
handleResult((BindResult) result);
@@ -458,7 +458,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
final Result result = error.getResult();
if (result instanceof CompareResult) {
handleResult((CompareResult) result);
@@ -483,7 +483,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -500,7 +500,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
final Result result = error.getResult();
if (result instanceof ExtendedResult) {
handleResult((ExtendedResult) result);
@@ -540,7 +540,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -557,7 +557,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -586,7 +586,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -779,7 +779,7 @@
if (clientContext != null) {
final ServerConnection<Integer> conn = clientContext.getServerConnection();
final SearchHandler handler = new SearchHandler(clientContext, messageID);
- conn.handleSearch(messageID, request, handler, handler);
+ conn.handleSearch(messageID, request, handler, handler, handler);
}
}
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java
index 5763cca..9e878f6 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ConnectionFactoryTestCase.java
@@ -22,20 +22,11 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.grizzly;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.forgerock.opendj.ldap.Connections.*;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.TestCaseUtils.*;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
-
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.concurrent.Callable;
@@ -83,6 +74,10 @@
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.schema.SchemaBuilder;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.forgerock.util.promise.SuccessHandler;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.AfterClass;
@@ -90,41 +85,24 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.CompletedFutureResult;
+import static org.fest.assertions.Assertions.*;
+import static org.forgerock.opendj.ldap.Connections.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.FutureResultWrapper.*;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+import static org.testng.Assert.*;
/**
* Tests the {@code ConnectionFactory} classes.
*/
@SuppressWarnings("javadoc")
public class ConnectionFactoryTestCase extends SdkTestCase {
- // Test timeout in ms for tests which need to wait for network events.
+ /** Test timeout in ms for tests which need to wait for network events. */
private static final long TEST_TIMEOUT = 30L;
private static final long TEST_TIMEOUT_MS = TEST_TIMEOUT * 1000L;
- class MyResultHandler implements ResultHandler<Connection> {
- // latch.
- private final CountDownLatch latch;
- // invalid flag.
- private volatile ErrorResultException error;
-
- MyResultHandler(final CountDownLatch latch) {
- this.latch = latch;
- }
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- // came here.
- this.error = error;
- latch.countDown();
- }
-
- @Override
- public void handleResult(final Connection con) {
- con.close();
- latch.countDown();
- }
- }
-
/**
* Ensures that the LDAP Server is running.
*
@@ -164,7 +142,7 @@
// HeartBeatConnectionFactory
// Use custom search request.
SearchRequest request =
- Requests.newSearchRequest("uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
+ Requests.newSearchRequest("uid=user.0,ou=people,o=test", SearchScope.BASE_OBJECT,
"objectclass=*", "cn");
InetSocketAddress serverAddress = getServerSocketAddress();
@@ -284,11 +262,11 @@
*/
@Test(dataProvider = "connectionFactories", timeOut = TEST_TIMEOUT_MS)
public void testBlockingFutureNoHandler(ConnectionFactory factory) throws Exception {
- final FutureResult<Connection> future = factory.getConnectionAsync(null);
- final Connection con = future.get();
+ final Promise<? extends Connection, ErrorResultException> promise = factory.getConnectionAsync();
+ final Connection con = promise.get();
// quickly check if it is a valid connection.
// Don't use a result handler.
- assertNotNull(con.readEntryAsync(DN.rootDN(), null, null).get());
+ assertNotNull(con.readEntryAsync(DN.rootDN(), null).getOrThrow());
con.close();
}
@@ -300,16 +278,26 @@
@Test(dataProvider = "connectionFactories", timeOut = TEST_TIMEOUT_MS)
public void testNonBlockingFutureWithHandler(ConnectionFactory factory) throws Exception {
// Use the handler to get the result asynchronously.
- final CountDownLatch latch = new CountDownLatch(1);
- final MyResultHandler handler = new MyResultHandler(latch);
- factory.getConnectionAsync(handler);
+ final PromiseImpl<Connection, ErrorResultException> promise = PromiseImpl.create();
+
+ factory.getConnectionAsync().onSuccess(new SuccessHandler<Connection>() {
+ @Override
+ public void handleResult(Connection con) {
+ con.close();
+ promise.handleResult(con);
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+
+ @Override
+ public void handleError(ErrorResultException error) {
+ promise.handleError(error);
+ }
+
+ });
// Since we don't have anything to do, we would rather
- // be notified by the latch when the other thread calls our handler.
- latch.await(); // should do a timed wait rather?
- if (handler.error != null) {
- throw handler.error;
- }
+ // be notified by the promise when the other thread calls our handler.
+ promise.getOrThrow(); // should do a timed wait rather?
}
/**
@@ -379,7 +367,6 @@
* @throws Exception
* If an unexpected exception occurred.
*/
- @SuppressWarnings("unchecked")
@Test
public void testConnectionPoolClose() throws Exception {
// We'll use a pool of 4 connections.
@@ -392,39 +379,30 @@
// Mock underlying connection factory which always succeeds.
final ConnectionFactory mockFactory = mock(ConnectionFactory.class);
- when(mockFactory.getConnectionAsync(any(ResultHandler.class))).thenAnswer(
- new Answer<FutureResult<Connection>>() {
+ when(mockFactory.getConnectionAsync()).thenAnswer(new Answer<FutureResult<Connection>>() {
+ @Override
+ public FutureResult<Connection> answer(InvocationOnMock invocation) throws Throwable {
+ // Update state.
+ final int connectionID = realConnectionCount.getAndIncrement();
+ realConnectionIsClosed[connectionID] = false;
+
+ // Mock connection decrements counter on close.
+ Connection mockConnection = mock(Connection.class);
+ doAnswer(new Answer<Void>() {
@Override
- public FutureResult<Connection> answer(InvocationOnMock invocation)
- throws Throwable {
- // Update state.
- final int connectionID = realConnectionCount.getAndIncrement();
- realConnectionIsClosed[connectionID] = false;
-
- // Mock connection decrements counter on close.
- Connection mockConnection = mock(Connection.class);
- doAnswer(new Answer<Void>() {
- @Override
- public Void answer(InvocationOnMock invocation) throws Throwable {
- realConnectionCount.decrementAndGet();
- realConnectionIsClosed[connectionID] = true;
- return null;
- }
- }).when(mockConnection).close();
- when(mockConnection.isValid()).thenReturn(true);
- when(mockConnection.toString()).thenReturn(
- "Mock connection " + connectionID);
-
- // Execute handler and return future.
- ResultHandler<? super Connection> handler =
- (ResultHandler<? super Connection>) invocation.getArguments()[0];
- if (handler != null) {
- handler.handleResult(mockConnection);
- }
- return new CompletedFutureResult<Connection>(mockConnection);
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ realConnectionCount.decrementAndGet();
+ realConnectionIsClosed[connectionID] = true;
+ return null;
}
- });
+ }).when(mockConnection).close();
+ when(mockConnection.isValid()).thenReturn(true);
+ when(mockConnection.toString()).thenReturn("Mock connection " + connectionID);
+
+ return newSuccessfulFutureResult(mockConnection);
+ }
+ });
ConnectionPool pool = Connections.newFixedConnectionPool(mockFactory, size);
Connection[] pooledConnections = new Connection[size];
@@ -483,10 +461,10 @@
}
private static final class CloseNotify {
- private boolean closeOnAccept;
- private boolean doBindFirst;
- private boolean useEventListener;
- private boolean sendDisconnectNotification;
+ private final boolean closeOnAccept;
+ private final boolean doBindFirst;
+ private final boolean useEventListener;
+ private final boolean sendDisconnectNotification;
private CloseNotify(boolean closeOnAccept, boolean doBindFirst, boolean useEventListener,
boolean sendDisconnectNotification) {
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactoryTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactoryTestCase.java
index 980e64b..d90ed9d 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactoryTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactoryTestCase.java
@@ -25,20 +25,10 @@
*/
package org.forgerock.opendj.grizzly;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
-import static org.forgerock.opendj.ldap.requests.Requests.newSimpleBindRequest;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.*;
-
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import org.forgerock.opendj.ldap.Connection;
@@ -69,12 +59,23 @@
import org.forgerock.opendj.ldap.requests.UnbindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.NeverThrowsException;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Stubber;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
+import static org.fest.assertions.Assertions.*;
+import static org.fest.assertions.Fail.*;
+import static org.forgerock.opendj.ldap.TestCaseUtils.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
/**
* Tests the {@link LDAPConnectionFactory} class.
*/
@@ -121,21 +122,22 @@
@Test(description = "OPENDJ-1197")
public void testClientSideConnectTimeout() throws Exception {
// Use an non-local unreachable network address.
- final ConnectionFactory factory =
- new LDAPConnectionFactory("10.20.30.40", 1389, new LDAPOptions().setConnectTimeout(
- 1, TimeUnit.MILLISECONDS));
+ final ConnectionFactory factory = new LDAPConnectionFactory("10.20.30.40", 1389,
+ new LDAPOptions().setConnectTimeout(1, TimeUnit.MILLISECONDS));
try {
for (int i = 0; i < ITERATIONS; i++) {
- final ResultHandler<Connection> handler = mock(ResultHandler.class);
- final FutureResult<Connection> future = factory.getConnectionAsync(handler);
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promise = PromiseImpl.create();
+ final Promise<? extends Connection, ErrorResultException> future = factory.getConnectionAsync();
+ future.onFailure(getFailureHandler(promise));
+
+ ConnectionException e = (ConnectionException) promise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
+ assertThat(e.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
// Wait for the connect to timeout.
try {
- future.get(TEST_TIMEOUT, TimeUnit.SECONDS);
+ future.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
fail("The connect request succeeded unexpectedly");
- } catch (ConnectionException e) {
- assertThat(e.getResult().getResultCode()).isEqualTo(
- ResultCode.CLIENT_SIDE_CONNECT_ERROR);
- verify(handler).handleErrorResult(same(e));
+ } catch (ConnectionException ce) {
+ assertThat(ce.getResult().getResultCode()).isEqualTo(ResultCode.CLIENT_SIDE_CONNECT_ERROR);
}
}
} finally {
@@ -161,32 +163,32 @@
waitForConnect();
final MockConnectionEventListener listener = new MockConnectionEventListener();
connection.addConnectionEventListener(listener);
-
- final ResultHandler<BindResult> handler = mock(ResultHandler.class);
- final FutureResult<BindResult> future =
- connection.bindAsync(newSimpleBindRequest(), null, handler);
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promise = PromiseImpl.create();
+ final FutureResult<BindResult> future = connection.bindAsync(newSimpleBindRequest());
+ future.onFailure(getFailureHandler(promise));
waitForBind();
+ TimeoutResultException e = (TimeoutResultException) promise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
+ verifyResultCodeIsClientSideTimeout(e);
+
// Wait for the request to timeout.
try {
- future.get(TEST_TIMEOUT, TimeUnit.SECONDS);
+ future.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
fail("The bind request succeeded unexpectedly");
- } catch (TimeoutResultException e) {
- verifyResultCodeIsClientSideTimeout(e);
- verify(handler).handleErrorResult(same(e));
-
- /*
- * The connection should no longer be valid, the event listener
- * should have been notified, but no abandon should have been
- * sent.
- */
- listener.awaitError(TEST_TIMEOUT, TimeUnit.SECONDS);
- assertThat(connection.isValid()).isFalse();
- verifyResultCodeIsClientSideTimeout(listener.getError());
- connection.close();
- waitForClose();
- verifyNoAbandonSent();
+ } catch (TimeoutResultException te) {
+ verifyResultCodeIsClientSideTimeout(te);
}
+
+ /*
+ * The connection should no longer be valid, the event listener
+ * should have been notified, but no abandon should have been sent.
+ */
+ listener.awaitError(TEST_TIMEOUT, TimeUnit.SECONDS);
+ assertThat(connection.isValid()).isFalse();
+ verifyResultCodeIsClientSideTimeout(listener.getError());
+ connection.close();
+ waitForClose();
+ verifyNoAbandonSent();
} finally {
connection.close();
}
@@ -211,39 +213,41 @@
connection.addConnectionEventListener(listener);
// Now bind with timeout.
- final ResultHandler<BindResult> handler = mock(ResultHandler.class);
- final FutureResult<BindResult> future =
- connection.bindAsync(newSimpleBindRequest(), null, handler);
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promise = PromiseImpl.create();
+ final FutureResult<BindResult> future = connection.bindAsync(newSimpleBindRequest());
+ future.onFailure(getFailureHandler(promise));
waitForBind();
- // Wait for the request to timeout.
- try {
- future.get(5, TimeUnit.SECONDS);
- fail("The bind request succeeded unexpectedly");
- } catch (TimeoutException e) {
- fail("The bind request future get timed out");
- } catch (TimeoutResultException e) {
- verifyResultCodeIsClientSideTimeout(e);
- verify(handler).handleErrorResult(same(e));
+ // Wait for the request to timeout and check the handler was invoked.
+ TimeoutResultException e = (TimeoutResultException) promise.getOrThrow(5, TimeUnit.SECONDS);
+ verifyResultCodeIsClientSideTimeout(e);
- /*
- * The connection should no longer be valid, the event
- * listener should have been notified, but no abandon should
- * have been sent.
- */
- listener.awaitError(TEST_TIMEOUT, TimeUnit.SECONDS);
- assertThat(connection.isValid()).isFalse();
- verifyResultCodeIsClientSideTimeout(listener.getError());
- connection.close();
- waitForClose();
- verifyNoAbandonSent();
+ // Now check the future was completed as expected.
+ try {
+ future.getOrThrow(5, TimeUnit.SECONDS);
+ fail("The bind request succeeded unexpectedly");
+ } catch (TimeoutResultException te) {
+ verifyResultCodeIsClientSideTimeout(te);
}
+
+ /*
+ * The connection should no longer be valid, the event listener
+ * should have been notified, but no abandon should have been
+ * sent.
+ */
+ listener.awaitError(TEST_TIMEOUT, TimeUnit.SECONDS);
+ assertThat(connection.isValid()).isFalse();
+ verifyResultCodeIsClientSideTimeout(listener.getError());
+ connection.close();
+ waitForClose();
+ verifyNoAbandonSent();
} finally {
connection.close();
}
}
}
+
/**
* Unit test for OPENDJ-1247: a locally timed out request which is not a
* bind or startTLS should result in a client side timeout error, but the
@@ -262,30 +266,29 @@
waitForConnect();
final ConnectionEventListener listener = mock(ConnectionEventListener.class);
connection.addConnectionEventListener(listener);
-
- final ResultHandler<SearchResultEntry> handler = mock(ResultHandler.class);
- final FutureResult<SearchResultEntry> future =
- connection.readEntryAsync(DN.valueOf("cn=test"), null, handler);
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promise = PromiseImpl.create();
+ final FutureResult<SearchResultEntry> future = connection.readEntryAsync(DN.valueOf("cn=test"), null);
+ future.onFailure(getFailureHandler(promise));
waitForSearch();
+ ErrorResultException e = promise.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
+ verifyResultCodeIsClientSideTimeout(e);
// Wait for the request to timeout.
try {
- future.get(TEST_TIMEOUT, TimeUnit.SECONDS);
+ future.getOrThrow(TEST_TIMEOUT, TimeUnit.SECONDS);
fail("The search request succeeded unexpectedly");
- } catch (TimeoutResultException e) {
- verifyResultCodeIsClientSideTimeout(e);
- verify(handler).handleErrorResult(same(e));
-
- // The connection should still be valid.
- assertThat(connection.isValid()).isTrue();
- verifyZeroInteractions(listener);
-
- /*
- * FIXME: The search should have been abandoned (see comment
- * in LDAPConnection for explanation).
- */
- // waitForAbandon();
+ } catch (TimeoutResultException te) {
+ verifyResultCodeIsClientSideTimeout(te);
}
+
+ // The connection should still be valid.
+ assertThat(connection.isValid()).isTrue();
+ verifyZeroInteractions(listener);
+ /*
+ * FIXME: The search should have been abandoned (see comment in
+ * LDAPConnection for explanation).
+ */
+ // waitForAbandon();
} finally {
connection.close();
}
@@ -296,8 +299,7 @@
public void testCreateLDAPConnectionFactory() throws Exception {
// test no exception is thrown, which means transport provider is correctly loaded
InetSocketAddress socketAddress = findFreeSocketAddress();
- LDAPConnectionFactory factory = new LDAPConnectionFactory(socketAddress.getHostName(),
- socketAddress.getPort());
+ LDAPConnectionFactory factory = new LDAPConnectionFactory(socketAddress.getHostName(), socketAddress.getPort());
factory.close();
}
@@ -314,9 +316,7 @@
@Test
public void testCreateLDAPConnectionFactoryWithCustomClassLoader() throws Exception {
// test no exception is thrown, which means transport provider is correctly loaded
- LDAPOptions options =
- new LDAPOptions().setProviderClassLoader(Thread.currentThread()
- .getContextClassLoader());
+ LDAPOptions options = new LDAPOptions().setProviderClassLoader(Thread.currentThread().getContextClassLoader());
InetSocketAddress socketAddress = findFreeSocketAddress();
LDAPConnectionFactory factory = new LDAPConnectionFactory(socketAddress.getHostName(),
socketAddress.getPort(), options);
@@ -367,6 +367,16 @@
}
}
+ private FailureHandler<ErrorResultException> getFailureHandler(
+ final PromiseImpl<ErrorResultException, NeverThrowsException> promise) {
+ return new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ promise.handleResult(error);
+ }
+ };
+ }
+
private Stubber notifyEvent(final Semaphore latch) {
return doAnswer(new Answer<Void>() {
@Override
@@ -394,9 +404,8 @@
}
private void registerSearchEvent() {
- notifyEvent(searchLatch).when(serverConnection).handleSearch(any(Integer.class),
- any(SearchRequest.class), any(IntermediateResponseHandler.class),
- any(SearchResultHandler.class));
+ notifyEvent(searchLatch).when(serverConnection).handleSearch(any(Integer.class), any(SearchRequest.class),
+ any(IntermediateResponseHandler.class), any(SearchResultHandler.class), any(ResultHandler.class));
}
private void resetState() {
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionTestCase.java
index 2ffb2ba..9050ca0 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnectionTestCase.java
@@ -49,6 +49,7 @@
import org.forgerock.opendj.ldap.controls.PersistentSearchRequestControl;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.util.promise.FailureHandler;
import org.mockito.ArgumentCaptor;
import org.testng.annotations.Test;
@@ -100,17 +101,19 @@
if (isPersistentSearch) {
request.addControl(PersistentSearchRequestControl.newControl(true, true, true));
}
- SearchResultHandler handler = mock(SearchResultHandler.class);
- connection.searchAsync(request, null, handler);
+ SearchResultHandler searchHandler = mock(SearchResultHandler.class);
+ @SuppressWarnings("unchecked")
+ FailureHandler<ErrorResultException> failureHandler = mock(FailureHandler.class);
+ connection.searchAsync(request, searchHandler).onFailure(failureHandler);
// Pass in a time which is guaranteed to trigger expiration.
connection.handleTimeout(System.currentTimeMillis() + 1000000);
if (isPersistentSearch) {
- verifyZeroInteractions(handler);
+ verifyZeroInteractions(searchHandler);
} else {
ArgumentCaptor<ErrorResultException> arg =
ArgumentCaptor.forClass(ErrorResultException.class);
- verify(handler).handleErrorResult(arg.capture());
+ verify(failureHandler).handleError(arg.capture());
assertThat(arg.getValue()).isInstanceOf(TimeoutResultException.class);
assertThat(arg.getValue().getResult().getResultCode()).isEqualTo(
ResultCode.CLIENT_SIDE_TIMEOUT);
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
index 984af22..ee10161 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
@@ -22,15 +22,10 @@
*
*
* Copyright 2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2014 ForgeRock AS.
*/
package org.forgerock.opendj.grizzly;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
-import static org.mockito.Mockito.mock;
-
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
@@ -43,6 +38,7 @@
import org.forgerock.opendj.ldap.Connections;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.FutureResultImpl;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.LDAPClientContext;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
@@ -76,7 +72,10 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-import com.forgerock.opendj.util.AsynchronousFutureResult;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.forgerock.opendj.ldap.TestCaseUtils.findFreeSocketAddress;
+import static org.mockito.Mockito.mock;
/**
* Tests the LDAPListener class.
@@ -85,11 +84,8 @@
public class GrizzlyLDAPListenerTestCase extends SdkTestCase {
private static class MockServerConnection implements ServerConnection<Integer> {
- final AsynchronousFutureResult<Throwable, ResultHandler<Throwable>> connectionError =
- new AsynchronousFutureResult<Throwable, ResultHandler<Throwable>>(null);
- final AsynchronousFutureResult<LDAPClientContext, ResultHandler<LDAPClientContext>> context =
- new AsynchronousFutureResult<LDAPClientContext, ResultHandler<LDAPClientContext>>(
- null);
+ final FutureResultImpl<Throwable> connectionError = new FutureResultImpl<Throwable>();
+ final FutureResultImpl<LDAPClientContext> context = new FutureResultImpl<LDAPClientContext>();
final CountDownLatch isClosed = new CountDownLatch(1);
MockServerConnection() {
@@ -179,7 +175,7 @@
final ExtendedRequest<R> request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<R> resultHandler) throws UnsupportedOperationException {
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(request
+ resultHandler.handleError(ErrorResultException.newErrorResult(request
.getResultDecoder().newExtendedErrorResult(ResultCode.PROTOCOL_ERROR, "",
"Extended operation " + request.getOID() + " not supported")));
}
@@ -209,8 +205,8 @@
*/
@Override
public void handleSearch(final Integer requestContext, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) throws UnsupportedOperationException {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler) throws UnsupportedOperationException {
resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
}
@@ -458,7 +454,7 @@
resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
} catch (final Exception e) {
// Unexpected.
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
+ resultHandler.handleError(ErrorResultException.newErrorResult(
ResultCode.OTHER,
"Unexpected exception when connecting to load balancer", e));
}
@@ -615,7 +611,7 @@
try {
// This is expected to fail.
lcf.getConnection().close();
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
+ resultHandler.handleError(ErrorResultException.newErrorResult(
ResultCode.OTHER,
"Connection to offline server succeeded unexpectedly"));
} catch (final ConnectionException ce) {
@@ -627,13 +623,13 @@
resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
} catch (final Exception e) {
// Unexpected.
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
+ resultHandler.handleError(ErrorResultException.newErrorResult(
ResultCode.OTHER,
"Unexpected exception when connecting to online server", e));
}
} catch (final Exception e) {
// Unexpected.
- resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
+ resultHandler.handleError(ErrorResultException.newErrorResult(
ResultCode.OTHER,
"Unexpected exception when connecting to offline server", e));
}
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
index 1bae0e9..799b6c8 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Controls.java
@@ -862,16 +862,6 @@
private static class MySearchResultHandler implements SearchResultHandler {
@Override
- public void handleErrorResult(ErrorResultException error) {
- // Ignore.
- }
-
- @Override
- public void handleResult(Result result) {
- // Ignore.
- }
-
- @Override
public boolean handleEntry(SearchResultEntry entry) {
final LDIFEntryWriter writer = new LDIFEntryWriter(System.out);
try {
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java
index b7e2d56..abdac06 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java
@@ -22,12 +22,12 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.examples;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+import java.util.concurrent.atomic.AtomicReference;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
@@ -54,8 +54,12 @@
import org.forgerock.opendj.ldap.responses.CompareResult;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
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.promise.AsyncFunction;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
+
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.util.Utils.*;
/**
* A simple proxy back-end which forwards requests to a connection factory using
@@ -75,330 +79,186 @@
*
* <pre>
* final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory =
- * new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
- * @Override
- * public ProxyBackend handleAccept(LDAPClientContext clientContext)
- * throws ErrorResultException {
- * return new ProxyBackend(factory, bindFactory);
- * }
- * };
+ * new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
+ * @Override
+ * public ProxyBackend handleAccept(LDAPClientContext clientContext) throws ErrorResultException {
+ * return new ProxyBackend(factory, bindFactory);
+ * }
+ * };
* final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = Connections
- * .newServerConnectionFactory(proxyFactory);
+ * .newServerConnectionFactory(proxyFactory);
* </pre>
*/
final class ProxyBackend implements RequestHandler<RequestContext> {
- private abstract class AbstractRequestCompletionHandler<R extends Result, H extends ResultHandler<R>>
- implements ResultHandler<R> {
- final Connection connection;
- final H resultHandler;
-
- AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
- this.connection = connection;
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public final void handleResult(final R result) {
- connection.close();
- resultHandler.handleResult(result);
- }
-
- }
-
- private abstract class ConnectionCompletionHandler<R extends Result> implements
- ResultHandler<Connection> {
- private final ResultHandler<R> resultHandler;
-
- ConnectionCompletionHandler(final ResultHandler<R> resultHandler) {
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public abstract void handleResult(Connection connection);
-
- }
-
- private final class RequestCompletionHandler<R extends Result> extends
- AbstractRequestCompletionHandler<R, ResultHandler<R>> {
- RequestCompletionHandler(final Connection connection, final ResultHandler<R> resultHandler) {
- super(connection, resultHandler);
- }
- }
-
- private final class SearchRequestCompletionHandler extends
- AbstractRequestCompletionHandler<Result, SearchResultHandler> implements
- SearchResultHandler {
-
- SearchRequestCompletionHandler(final Connection connection,
- final SearchResultHandler resultHandler) {
- super(connection, resultHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleEntry(final SearchResultEntry entry) {
- return resultHandler.handleEntry(entry);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleReference(final SearchResultReference reference) {
- return resultHandler.handleReference(reference);
- }
-
- }
private final ConnectionFactory bindFactory;
private final ConnectionFactory factory;
- private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null;
+ private volatile ProxiedAuthV2RequestControl proxiedAuthControl;
ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) {
this.factory = factory;
this.bindFactory = bindFactory;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleAdd(final RequestContext requestContext, final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final ResultHandler<Result> resultHandler) {
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.addAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.addAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
- public void handleBind(final RequestContext requestContext, final int version,
- final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<BindResult> resultHandler) {
+ public void handleBind(final RequestContext requestContext, final int version, final BindRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler, final ResultHandler<BindResult> resultHandler) {
if (request.getAuthenticationType() != BindRequest.AUTHENTICATION_TYPE_SIMPLE) {
// TODO: SASL authentication not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR,
"non-SIMPLE authentication not supported: " + request.getAuthenticationType()));
} else {
// Authenticate using a separate bind connection pool, because
// we don't want to change the state of the pooled connection.
- final ConnectionCompletionHandler<BindResult> outerHandler =
- new ConnectionCompletionHandler<BindResult>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final ResultHandler<BindResult> innerHandler =
- new ResultHandler<BindResult>() {
-
- @Override
- public final void handleErrorResult(
- final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
-
- }
-
- @Override
- public final void handleResult(final BindResult result) {
- connection.close();
- proxiedAuthControl =
- ProxiedAuthV2RequestControl.newControl("dn:"
- + request.getName());
- resultHandler.handleResult(result);
- }
- };
- connection
- .bindAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
proxiedAuthControl = null;
- bindFactory.getConnectionAsync(outerHandler);
+ bindFactory.getConnectionAsync()
+ .thenAsync(new AsyncFunction<Connection, BindResult, ErrorResultException>() {
+ @Override
+ public Promise<BindResult, ErrorResultException> apply(Connection connection)
+ throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.bindAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(new SuccessHandler<BindResult>() {
+ @Override
+ public final void handleResult(final BindResult result) {
+ proxiedAuthControl = ProxiedAuthV2RequestControl.newControl("dn:" + request.getName());
+ resultHandler.handleResult(result);
+ }
+ }).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
+
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleCompare(final RequestContext requestContext, final CompareRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<CompareResult> resultHandler) {
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<CompareResult> outerHandler =
- new ConnectionCompletionHandler<CompareResult>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<CompareResult> innerHandler =
- new RequestCompletionHandler<CompareResult>(connection,
- resultHandler);
- connection.compareAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, CompareResult, ErrorResultException>() {
+ @Override
+ public Promise<CompareResult, ErrorResultException> apply(Connection connection)
+ throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.compareAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final ResultHandler<Result> resultHandler) {
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.deleteAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.deleteAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
- public <R extends ExtendedResult> void handleExtendedRequest(
- final RequestContext requestContext, final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<R> resultHandler) {
- if (request.getOID().equals(CancelExtendedRequest.OID)) {
+ public <R extends ExtendedResult> void handleExtendedRequest(final RequestContext requestContext,
+ final ExtendedRequest<R> request, final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<R> resultHandler) {
+ if (CancelExtendedRequest.OID.equals(request.getOID())) {
// TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "Cancel extended request operation not supported"));
- } else if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ "Cancel extended request operation not supported"));
+ } else if (StartTLSExtendedRequest.OID.equals(request.getOID())) {
// TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "StartTLS extended request operation not supported"));
+ resultHandler.handleError(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ "StartTLS extended request operation not supported"));
} else {
// Forward all other extended operations.
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<R> outerHandler =
- new ConnectionCompletionHandler<R>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<R> innerHandler =
- new RequestCompletionHandler<R>(connection, resultHandler);
- connection.extendedRequestAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, R, ErrorResultException>() {
+ @Override
+ public Promise<R, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.extendedRequestAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler)
+ .thenAlways(close(connectionHolder));
}
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleModify(final RequestContext requestContext, final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final ResultHandler<Result> resultHandler) {
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.modifyAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.modifyAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleModifyDN(final RequestContext requestContext, final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final ResultHandler<Result> resultHandler) {
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection
- .modifyDNAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.modifyDNAsync(request, intermediateResponseHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public void handleSearch(final RequestContext requestContext, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler) {
addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
- @Override
- public void handleResult(final Connection connection) {
- final SearchRequestCompletionHandler innerHandler =
- new SearchRequestCompletionHandler(connection, resultHandler);
- connection.searchAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ final AtomicReference<Connection> connectionHolder = new AtomicReference<Connection>();
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ connectionHolder.set(connection);
+ return connection.searchAsync(request, intermediateResponseHandler, entryHandler);
+ }
+ }).onSuccess(resultHandler).onFailure(resultHandler).thenAlways(close(connectionHolder));
}
private void addProxiedAuthControl(final Request request) {
@@ -407,4 +267,13 @@
request.addControl(control);
}
}
+
+ private Runnable close(final AtomicReference<Connection> c) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ closeSilently(c.get());
+ }
+ };
+ }
}
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
index dd3a01e..374294b 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.examples;
@@ -109,11 +109,11 @@
public final class RewriterProxy {
private static final class Rewriter implements RequestHandler<RequestContext> {
- // This example hard codes the attribute...
+ /** This example hard codes the attribute... */
private static final String CLIENT_ATTRIBUTE = "fullname";
private static final String SERVER_ATTRIBUTE = "cn";
- // ...and DN rewriting configuration.
+ /** ...and DN rewriting configuration. */
private static final String CLIENT_SUFFIX = "o=example";
private static final String SERVER_SUFFIX = "dc=example,dc=com";
@@ -122,7 +122,7 @@
private final AttributeDescription serverAttributeDescription = AttributeDescription
.valueOf(SERVER_ATTRIBUTE);
- // Next request handler in the chain.
+ /** Next request handler in the chain. */
private final RequestHandler<RequestContext> nextHandler;
private Rewriter(final RequestHandler<RequestContext> nextHandler) {
@@ -191,32 +191,20 @@
@Override
public void handleSearch(final RequestContext requestContext, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
+ final ResultHandler<Result> resultHandler) {
nextHandler.handleSearch(requestContext, rewrite(request), intermediateResponseHandler,
- new SearchResultHandler() {
+ new SearchResultHandler() {
+ @Override
+ public boolean handleReference(SearchResultReference reference) {
+ return entryHandler.handleReference(reference);
+ }
- @Override
- public boolean handleEntry(final SearchResultEntry entry) {
- return resultHandler.handleEntry(rewrite(entry));
- }
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public boolean handleReference(final SearchResultReference reference) {
- return resultHandler.handleReference(reference);
- }
-
- @Override
- public void handleResult(final Result result) {
- resultHandler.handleResult(result);
- }
-
- });
+ @Override
+ public boolean handleEntry(SearchResultEntry entry) {
+ return entryHandler.handleEntry(rewrite(entry));
+ }
+ }, resultHandler);
}
private AddRequest rewrite(final AddRequest request) {
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java
index 8ef61d5..6fdb62f 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/SearchAsync.java
@@ -22,7 +22,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2012 ForgeRock AS
+ * Portions copyright 2011-2014 ForgeRock AS
*/
package org.forgerock.opendj.examples;
@@ -34,21 +34,23 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.FutureResultWrapper;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
-import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
import org.forgerock.opendj.ldap.requests.Requests;
-import org.forgerock.opendj.ldap.requests.SearchRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.responses.SearchResultReference;
import org.forgerock.opendj.ldif.LDIFEntryWriter;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
/**
* An example client application which searches a Directory Server using the
@@ -60,79 +62,32 @@
* </pre>
*/
public final class SearchAsync {
- private static final class BindResultHandlerImpl implements ResultHandler<BindResult> {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- System.err.println(error.getMessage());
- resultCode = error.getResult().getResultCode().intValue();
- COMPLETION_LATCH.countDown();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleResult(final BindResult result) {
- // Bind succeeded: initiate search.
- final SearchRequest request =
- Requests.newSearchRequest(baseDN, scope, filter, attributes);
- final FutureResult<Result> futureResult =
- connection.searchAsync(request, null, new SearchResultHandlerImpl());
- requestID = futureResult.getRequestID();
- }
-
- }
-
- private static final class ConnectResultHandlerImpl implements ResultHandler<Connection> {
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- System.err.println(error.getMessage());
- resultCode = error.getResult().getResultCode().intValue();
- COMPLETION_LATCH.countDown();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleResult(final Connection connection) {
- // Connect succeeded: save connection and initiate bind.
- SearchAsync.connection = connection;
-
- final BindRequest request =
- Requests.newSimpleBindRequest(userName, password.toCharArray());
- connection.bindAsync(request, null, new BindResultHandlerImpl());
- }
-
- }
-
// --- JCite search result handler ---
private static final class SearchResultHandlerImpl implements SearchResultHandler {
-
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public synchronized boolean handleEntry(final SearchResultEntry entry) {
try {
if (entryCount < 10) {
- WRITER.writeComment("Search result entry: "
- + entry.getName().toString());
+ WRITER.writeComment("Search result entry: " + entry.getName().toString());
WRITER.writeEntry(entry);
++entryCount;
} else { // Cancel the search.
- CancelExtendedRequest request =
- Requests.newCancelExtendedRequest(requestID);
- connection.extendedRequestAsync(request, null,
- new CancelResultHandlerImpl());
+ CancelExtendedRequest request = Requests.newCancelExtendedRequest(requestID);
+ connection.extendedRequestAsync(request).onSuccess(new SuccessHandler<ExtendedResult>() {
+ @Override
+ public void handleResult(ExtendedResult result) {
+ System.err.println("Cancel request succeeded");
+ CANCEL_LATCH.countDown();
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ System.err.println("Cancel request failed with result code: "
+ + error.getResult().getResultCode().intValue());
+ CANCEL_LATCH.countDown();
+ }
+ });
return false;
}
} catch (final IOException e) {
@@ -144,25 +99,11 @@
return true;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
- public void handleErrorResult(final ErrorResultException error) {
- System.err.println(error.getMessage());
- resultCode = error.getResult().getResultCode().intValue();
- COMPLETION_LATCH.countDown();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public synchronized boolean handleReference(
- final SearchResultReference reference) {
+ public synchronized boolean handleReference(final SearchResultReference reference) {
try {
- WRITER.writeComment("Search result reference: "
- + reference.getURIs().toString());
+ WRITER.writeComment("Search result reference: " + reference.getURIs().toString());
} catch (final IOException e) {
System.err.println(e.getMessage());
resultCode = ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue();
@@ -172,18 +113,10 @@
return true;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleResult(final Result result) {
- resultCode = result.getResultCode().intValue();
- COMPLETION_LATCH.countDown();
- }
-
}
// --- JCite search result handler ---
+
// --- JCite decl1 ---
private static final CountDownLatch COMPLETION_LATCH = new CountDownLatch(1);
private static final CountDownLatch CANCEL_LATCH = new CountDownLatch(1);
@@ -203,26 +136,6 @@
static int entryCount = 0;
// --- JCite decl2 ---
- // --- JCite cancel result handler ---
- private static final class CancelResultHandlerImpl
- implements ResultHandler<ExtendedResult> {
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- System.err.println("Cancel request failed with result code: "
- + error.getResult().getResultCode().intValue());
- CANCEL_LATCH.countDown();
- }
-
- @Override
- public void handleResult(final ExtendedResult result) {
- System.err.println("Cancel request succeeded");
- CANCEL_LATCH.countDown();
- }
-
- }
- // --- JCite cancel result handler ---
-
/**
* Main method.
*
@@ -233,8 +146,7 @@
*/
public static void main(final String[] args) {
if (args.length < 7) {
- System.err.println("Usage: host port username password baseDN scope "
- + "filter [attribute ...]");
+ System.err.println("Usage: host port username password baseDN scope " + "filter [attribute ...]");
System.exit(1);
}
@@ -266,9 +178,38 @@
return;
}
+
// Initiate the asynchronous connect, bind, and search.
final LDAPConnectionFactory factory = new LDAPConnectionFactory(hostName, port);
- factory.getConnectionAsync(new ConnectResultHandlerImpl());
+
+ factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, BindResult, ErrorResultException>() {
+ @Override
+ public Promise<BindResult, ErrorResultException> apply(Connection connection) throws ErrorResultException {
+ SearchAsync.connection = connection;
+ return connection.bindAsync(Requests.newSimpleBindRequest(userName, password.toCharArray()));
+ }
+ }).thenAsync(new AsyncFunction<BindResult, Result, ErrorResultException>() {
+ @Override
+ public Promise<Result, ErrorResultException> apply(BindResult result) throws ErrorResultException {
+ FutureResult<Result> future = FutureResultWrapper.asFutureResult(connection.searchAsync(
+ Requests.newSearchRequest(baseDN, scope, filter, attributes), new SearchResultHandlerImpl()));
+ requestID = future.getRequestID();
+ return future;
+ }
+ }).onSuccess(new SuccessHandler<Result>() {
+ @Override
+ public void handleResult(Result result) {
+ resultCode = result.getResultCode().intValue();
+ COMPLETION_LATCH.countDown();
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ System.err.println(error.getMessage());
+ resultCode = error.getResult().getResultCode().intValue();
+ COMPLETION_LATCH.countDown();
+ }
+ });
// Await completion.
try {
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AddRate.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AddRate.java
index 9b29b04..1c48090 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AddRate.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AddRate.java
@@ -26,10 +26,6 @@
package com.forgerock.opendj.ldap.tools;
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-import static com.forgerock.opendj.cli.Utils.filterExitCode;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
@@ -42,13 +38,14 @@
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldif.EntryGenerator;
+import org.forgerock.util.promise.Promise;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentParser;
@@ -60,6 +57,10 @@
import com.forgerock.opendj.cli.MultiChoiceArgument;
import com.forgerock.opendj.cli.StringArgument;
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+import static com.forgerock.opendj.cli.Utils.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
/**
* A load generation tool that can be used to load a Directory Server with Add
* and Delete requests using one or more LDAP connections.
@@ -68,7 +69,7 @@
private static final class AddPerformanceRunner extends PerformanceRunner {
private final class AddStatsHandler extends UpdateStatsResultHandler<Result> {
- private String entryDN;
+ private final String entryDN;
private AddStatsHandler(final long currentTime, String entryDN) {
super(currentTime);
@@ -146,17 +147,19 @@
}
@Override
- public FutureResult<?> performOperation(Connection connection,
- DataSource[] dataSources, long currentTime) {
+ public Promise<?, ErrorResultException> performOperation(Connection connection, DataSource[] dataSources,
+ long currentTime) {
if (needsDelete(currentTime)) {
DeleteRequest dr = Requests.newDeleteRequest(getDNEntryToRemove());
- return connection.deleteAsync(dr, null, new DeleteStatsHandler(currentTime));
+ ResultHandler<Result> deleteHandler = new DeleteStatsHandler(currentTime);
+
+ return connection.deleteAsync(dr).onSuccess(deleteHandler).onFailure(deleteHandler);
} else {
return performAddOperation(connection, currentTime);
}
}
- private FutureResult<?> performAddOperation(Connection connection, long currentTime) {
+ private Promise<Result, ErrorResultException> performAddOperation(Connection connection, long currentTime) {
try {
Entry entry;
synchronized (generator) {
@@ -164,12 +167,12 @@
}
AddRequest ar = Requests.newAddRequest(entry);
- return connection
- .addAsync(ar, null, new AddStatsHandler(currentTime, entry.getName().toString()));
+ ResultHandler<Result> addHandler = new AddStatsHandler(currentTime, entry.getName().toString());
+ return connection.addAsync(ar).onSuccess(addHandler).onFailure(addHandler);
} catch (IOException e) {
// faking an error result by notifying the Handler
UpdateStatsResultHandler<Result> resHandler = new UpdateStatsResultHandler<Result>(currentTime);
- resHandler.handleErrorResult(ErrorResultException.newErrorResult(ResultCode.OTHER, e));
+ resHandler.handleError(ErrorResultException.newErrorResult(ResultCode.OTHER, e));
return null;
}
}
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java
index 130e453..762f679 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/AuthRate.java
@@ -26,11 +26,6 @@
*/
package com.forgerock.opendj.ldap.tools;
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-import static com.forgerock.opendj.ldap.tools.Utils.setDefaultPerfToolProperties;
-import static com.forgerock.opendj.cli.Utils.filterExitCode;
-
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -40,24 +35,11 @@
import java.util.concurrent.atomic.AtomicLong;
import org.forgerock.i18n.LocalizableMessage;
-
-import com.forgerock.opendj.cli.BooleanArgument;
-import com.forgerock.opendj.cli.CommonArguments;
-import com.forgerock.opendj.cli.ConnectionFactoryProvider;
-import com.forgerock.opendj.cli.ConsoleApplication;
-import com.forgerock.opendj.cli.ArgumentParser;
-import com.forgerock.opendj.cli.ArgumentException;
-import com.forgerock.opendj.cli.IntegerArgument;
-import com.forgerock.opendj.cli.MultiChoiceArgument;
-import com.forgerock.opendj.cli.StringArgument;
-
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.CRAMMD5SASLBindRequest;
@@ -70,8 +52,23 @@
import org.forgerock.opendj.ldap.requests.SimpleBindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.Promise;
-import com.forgerock.opendj.util.RecursiveFutureResult;
+import com.forgerock.opendj.cli.ArgumentException;
+import com.forgerock.opendj.cli.ArgumentParser;
+import com.forgerock.opendj.cli.BooleanArgument;
+import com.forgerock.opendj.cli.CommonArguments;
+import com.forgerock.opendj.cli.ConnectionFactoryProvider;
+import com.forgerock.opendj.cli.ConsoleApplication;
+import com.forgerock.opendj.cli.IntegerArgument;
+import com.forgerock.opendj.cli.MultiChoiceArgument;
+import com.forgerock.opendj.cli.StringArgument;
+
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+import static com.forgerock.opendj.cli.Utils.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+import static com.forgerock.opendj.ldap.tools.Utils.*;
/**
* A load generation tool that can be used to load a Directory Server with Bind
@@ -107,8 +104,8 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
- super.handleErrorResult(error);
+ public void handleError(final ErrorResultException error) {
+ super.handleError(error);
if (error.getResult().getResultCode() == ResultCode.INVALID_CREDENTIALS) {
invalidCredRecentCount.getAndIncrement();
@@ -137,7 +134,7 @@
}
@Override
- public FutureResult<?> performOperation(final Connection connection,
+ public Promise<?, ErrorResultException> performOperation(final Connection connection,
final DataSource[] dataSources, final long startTime) {
if (dataSources != null) {
data = DataSource.generateData(dataSources, data);
@@ -147,14 +144,15 @@
data = newData;
}
}
+
+ Promise<BindResult, ErrorResultException> returnedPromise;
if (filter != null && baseDN != null) {
if (sr == null) {
if (dataSources == null) {
sr = Requests.newSearchRequest(baseDN, scope, filter, attributes);
} else {
- sr =
- Requests.newSearchRequest(String.format(baseDN, data), scope,
- String.format(filter, data), attributes);
+ sr = Requests.newSearchRequest(String.format(baseDN, data), scope,
+ String.format(filter, data), attributes);
}
sr.setDereferenceAliasesPolicy(dereferencesAliasesPolicy);
} else if (dataSources != null) {
@@ -162,32 +160,30 @@
sr.setName(String.format(baseDN, data));
}
- final RecursiveFutureResult<SearchResultEntry, BindResult> future =
- new RecursiveFutureResult<SearchResultEntry, BindResult>(
- new BindUpdateStatsResultHandler(startTime)) {
+ returnedPromise = connection.searchSingleEntryAsync(sr).thenAsync(
+ new AsyncFunction<SearchResultEntry, BindResult, ErrorResultException>() {
@Override
- protected FutureResult<? extends BindResult> chainResult(
- final SearchResultEntry innerResult,
- final ResultHandler<? super BindResult> resultHandler)
+ public Promise<BindResult, ErrorResultException> apply(SearchResultEntry result)
throws ErrorResultException {
searchWaitRecentTime.getAndAdd(System.nanoTime() - startTime);
if (data == null) {
data = new Object[1];
}
- data[data.length - 1] = innerResult.getName().toString();
- return performBind(connection, data, resultHandler);
+ data[data.length - 1] = result.getName().toString();
+
+ return performBind(connection, data);
}
- };
- connection.searchSingleEntryAsync(sr, future);
- return future;
+ });
} else {
- return performBind(connection, data,
- new BindUpdateStatsResultHandler(startTime));
+ returnedPromise = performBind(connection, data);
}
+
+ return returnedPromise.onSuccess(new UpdateStatsResultHandler<BindResult>(startTime)).onFailure(
+ new BindUpdateStatsResultHandler(startTime));
}
- private FutureResult<BindResult> performBind(final Connection connection,
- final Object[] data, final ResultHandler<? super BindResult> handler) {
+ private Promise<BindResult, ErrorResultException> performBind(final Connection connection,
+ final Object[] data) {
final boolean useInvalidPassword;
// Avoid rng if possible.
@@ -307,7 +303,7 @@
}
}
- return connection.bindAsync(br, null, handler);
+ return connection.bindAsync(br);
}
}
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java
index 7cdf527..fb754fa 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/LDAPSearch.java
@@ -26,12 +26,6 @@
*/
package com.forgerock.opendj.ldap.tools;
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-import static com.forgerock.opendj.cli.Utils.filterExitCode;
-import static com.forgerock.opendj.cli.Utils.secondsToTimeString;
-import static org.forgerock.util.Utils.closeSilently;
-
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
@@ -89,6 +83,12 @@
import com.forgerock.opendj.ldap.controls.AccountUsabilityResponseControl;
import com.forgerock.opendj.util.StaticUtils;
+import static org.forgerock.util.Utils.*;
+
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+import static com.forgerock.opendj.cli.Utils.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
/**
* A tool that can be used to issue Search requests to the Directory Server.
*/
@@ -97,6 +97,7 @@
private int entryCount;
/** {@inheritDoc} */
+ @Override
public boolean handleEntry(final SearchResultEntry entry) {
entryCount++;
@@ -179,20 +180,11 @@
}
/** {@inheritDoc} */
+ @Override
public boolean handleReference(final SearchResultReference reference) {
println(LocalizableMessage.raw(reference.toString()));
return true;
}
-
- /** {@inheritDoc} */
- public void handleErrorResult(ErrorResultException error) {
- // Ignore.
- }
-
- /** {@inheritDoc} */
- public void handleResult(Result result) {
- // Ignore.
- }
}
/**
@@ -226,6 +218,7 @@
}
/** {@inheritDoc} */
+ @Override
public boolean isInteractive() {
return false;
}
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java
index 1058ad1..0eeaa1f 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/ModRate.java
@@ -26,19 +26,17 @@
*/
package com.forgerock.opendj.ldap.tools;
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-import static com.forgerock.opendj.cli.Utils.filterExitCode;
-
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
-import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.util.promise.Promise;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentParser;
@@ -48,6 +46,10 @@
import com.forgerock.opendj.cli.ConsoleApplication;
import com.forgerock.opendj.cli.StringArgument;
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+import static com.forgerock.opendj.cli.Utils.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
/**
* A load generation tool that can be used to load a Directory Server with
* Modify requests using one or more LDAP connections.
@@ -64,14 +66,15 @@
}
@Override
- public FutureResult<?> performOperation(final Connection connection,
+ public Promise<?, ErrorResultException> performOperation(final Connection connection,
final DataSource[] dataSources, final long startTime) {
if (dataSources != null) {
data = DataSource.generateData(dataSources, data);
}
mr = newModifyRequest(data);
- return connection.modifyAsync(mr, null, new UpdateStatsResultHandler<Result>(
- startTime));
+ ResultHandler<Result> modRes = new UpdateStatsResultHandler<Result>(startTime);
+
+ return connection.modifyAsync(mr).onSuccess(modRes).onFailure(modRes);
}
private ModifyRequest newModifyRequest(final Object[] data) {
@@ -139,6 +142,7 @@
}
/** {@inheritDoc} */
+ @Override
public boolean isInteractive() {
return false;
}
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java
index da50960..0f22a0e 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/PerformanceRunner.java
@@ -26,9 +26,6 @@
*/
package com.forgerock.opendj.ldap.tools;
-import static org.forgerock.util.Utils.closeSilently;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-
import java.io.IOException;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
@@ -46,21 +43,25 @@
import org.forgerock.opendj.ldap.ConnectionEventListener;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.util.promise.Promise;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentParser;
+import com.forgerock.opendj.cli.AuthenticatedConnectionFactory.AuthenticatedConnection;
import com.forgerock.opendj.cli.BooleanArgument;
import com.forgerock.opendj.cli.ConsoleApplication;
import com.forgerock.opendj.cli.IntegerArgument;
import com.forgerock.opendj.cli.MultiColumnPrinter;
import com.forgerock.opendj.cli.StringArgument;
-import com.forgerock.opendj.cli.AuthenticatedConnectionFactory.AuthenticatedConnection;
import com.forgerock.opendj.util.StaticUtils;
+import static org.forgerock.util.Utils.*;
+
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
/**
* Benchmark application framework.
*/
@@ -338,7 +339,7 @@
}
private class TimerThread extends Thread {
- private long timeToWait;
+ private final long timeToWait;
public TimerThread(long timeToWait) {
this.timeToWait = timeToWait;
@@ -370,7 +371,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
failedRecentCount.getAndIncrement();
updateStats();
app.errPrintVerboseMessage(LocalizableMessage.raw(error.getResult().toString()));
@@ -410,22 +411,21 @@
this.connectionFactory = connectionFactory;
}
- public abstract FutureResult<?> performOperation(Connection connection,
+ public abstract Promise<?, ErrorResultException> performOperation(Connection connection,
DataSource[] dataSources, long startTime);
@Override
public void run() {
- FutureResult<?> future;
+ Promise<?, ErrorResultException> promise;
Connection connection;
- final double targetTimeInMS =
- 1000.0 / (targetThroughput / (double) (numThreads * numConnections));
+ final double targetTimeInMS = 1000.0 / (targetThroughput / (double) (numThreads * numConnections));
double sleepTimeInMS = 0;
long start;
while (!stopRequested && !(maxIterations > 0 && count >= maxIterations)) {
if (this.connection == null) {
try {
- connection = connectionFactory.getConnectionAsync(null).get();
+ connection = connectionFactory.getConnectionAsync().getOrThrow();
} catch (final InterruptedException e) {
// Ignore and check stop requested
continue;
@@ -442,7 +442,7 @@
if (!noRebind && connection instanceof AuthenticatedConnection) {
final AuthenticatedConnection ac = (AuthenticatedConnection) connection;
try {
- ac.rebindAsync(null).get();
+ ac.rebindAsync().getOrThrow();
} catch (final InterruptedException e) {
// Ignore and check stop requested
continue;
@@ -458,13 +458,13 @@
}
start = System.nanoTime();
- future = performOperation(connection, dataSources.get(), start);
+ promise = performOperation(connection, dataSources.get(), start);
operationRecentCount.getAndIncrement();
count++;
if (!isAsync) {
try {
- if (future != null) {
- future.get();
+ if (promise != null) {
+ promise.getOrThrow();
}
} catch (final InterruptedException e) {
// Ignore and check stop requested
@@ -857,7 +857,7 @@
isWarmingUp = warmUpDuration > 0;
for (int i = 0; i < numConnections; i++) {
if (keepConnectionsOpen.isPresent() || noRebindArgument.isPresent()) {
- connection = connectionFactory.getConnectionAsync(null).get();
+ connection = connectionFactory.getConnectionAsync().getOrThrow();
connection.addConnectionEventListener(this);
connections.add(connection);
}
diff --git a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java
index e1d4a5e..c1d6803 100644
--- a/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java
+++ b/opendj-ldap-toolkit/src/main/java/com/forgerock/opendj/ldap/tools/SearchRate.java
@@ -26,10 +26,6 @@
*/
package com.forgerock.opendj.ldap.tools;
-import static com.forgerock.opendj.cli.ArgumentConstants.*;
-import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
-import static com.forgerock.opendj.cli.Utils.filterExitCode;
-
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -39,7 +35,7 @@
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
-import org.forgerock.opendj.ldap.FutureResult;
+import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
@@ -48,6 +44,7 @@
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.promise.Promise;
import com.forgerock.opendj.cli.ArgumentException;
import com.forgerock.opendj.cli.ArgumentParser;
@@ -58,6 +55,10 @@
import com.forgerock.opendj.cli.MultiChoiceArgument;
import com.forgerock.opendj.cli.StringArgument;
+import static com.forgerock.opendj.cli.ArgumentConstants.*;
+import static com.forgerock.opendj.cli.Utils.*;
+import static com.forgerock.opendj.ldap.tools.ToolsMessages.*;
+
/**
* A load generation tool that can be used to load a Directory Server with
* Search requests using one or more LDAP connections.
@@ -117,7 +118,7 @@
}
@Override
- public FutureResult<?> performOperation(final Connection connection,
+ public Promise<?, ErrorResultException> performOperation(final Connection connection,
final DataSource[] dataSources, final long startTime) {
if (sr == null) {
if (dataSources == null) {
@@ -134,7 +135,10 @@
sr.setFilter(String.format(filter, data));
sr.setName(String.format(baseDN, data));
}
- return connection.searchAsync(sr, null, new SearchStatsHandler(startTime));
+
+ final SearchStatsHandler handler = new SearchStatsHandler(startTime);
+
+ return connection.searchAsync(sr, handler).onSuccess(handler).onFailure(handler);
}
}
diff --git a/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPAuthnFilter.java b/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPAuthnFilter.java
index 28b2ef2..45e9194 100644
--- a/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPAuthnFilter.java
+++ b/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPAuthnFilter.java
@@ -11,22 +11,11 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.rest2ldap.servlet;
-import static org.forgerock.json.resource.SecurityContext.AUTHZID_DN;
-import static org.forgerock.json.resource.SecurityContext.AUTHZID_ID;
-import static org.forgerock.json.resource.servlet.SecurityContextFactory.ATTRIBUTE_AUTHCID;
-import static org.forgerock.json.resource.servlet.SecurityContextFactory.ATTRIBUTE_AUTHZID;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.requests.Requests.newPlainSASLBindRequest;
-import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
-import static org.forgerock.opendj.ldap.requests.Requests.newSimpleBindRequest;
-import static org.forgerock.opendj.rest2ldap.Rest2LDAP.asResourceException;
-import static org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory.ATTRIBUTE_AUTHN_CONNECTION;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
@@ -49,8 +38,8 @@
import org.forgerock.json.fluent.JsonValue;
import org.forgerock.json.fluent.JsonValueException;
import org.forgerock.json.resource.ResourceException;
-import org.forgerock.json.resource.servlet.ServletSynchronizer;
import org.forgerock.json.resource.servlet.ServletApiVersionAdapter;
+import org.forgerock.json.resource.servlet.ServletSynchronizer;
import org.forgerock.opendj.ldap.AuthenticationException;
import org.forgerock.opendj.ldap.AuthorizationException;
import org.forgerock.opendj.ldap.ByteString;
@@ -62,7 +51,6 @@
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.MultipleEntriesFoundException;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.SearchRequest;
@@ -70,6 +58,17 @@
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.rest2ldap.Rest2LDAP;
+import org.forgerock.util.promise.AsyncFunction;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.SuccessHandler;
+
+import static org.forgerock.json.resource.SecurityContext.*;
+import static org.forgerock.json.resource.servlet.SecurityContextFactory.*;
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.*;
+import static org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory.*;
/**
* An LDAP based authentication Servlet filter.
@@ -115,8 +114,8 @@
}
@Override
- public void doFilter(final ServletRequest request, final ServletResponse response,
- final FilterChain chain) throws IOException, ServletException {
+ public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
+ throws IOException, ServletException {
// Skip this filter if authentication has not been configured.
if (!isEnabled) {
chain.doFilter(request, response);
@@ -149,14 +148,11 @@
});
try {
- final String headerUsername =
- supportAltAuthentication ? req.getHeader(altAuthenticationUsernameHeader)
- : null;
- final String headerPassword =
- supportAltAuthentication ? req.getHeader(altAuthenticationPasswordHeader)
- : null;
- final String headerAuthorization =
- supportHTTPBasicAuthentication ? req.getHeader("Authorization") : null;
+ final String headerUsername = supportAltAuthentication ? req.getHeader(altAuthenticationUsernameHeader)
+ : null;
+ final String headerPassword = supportAltAuthentication ? req.getHeader(altAuthenticationPasswordHeader)
+ : null;
+ final String headerAuthorization = supportHTTPBasicAuthentication ? req.getHeader("Authorization") : null;
final String username;
final char[] password;
@@ -194,17 +190,15 @@
authzid = new LinkedHashMap<String, Object>(2);
authzid.put(AUTHZID_DN, username);
authzid.put(AUTHZID_ID, username);
- doBind(req, res, newSimpleBindRequest(username, password), chain, savedConnection,
- sync, username, authzid);
+ doBind(req, res, newSimpleBindRequest(username, password), chain, savedConnection, sync, username,
+ authzid);
break;
}
case SASL_PLAIN: {
final Map<String, Object> authzid;
final String bindId;
if (saslAuthzIdTemplate.startsWith("dn:")) {
- final String bindDN =
- DN.format(saslAuthzIdTemplate.substring(3), schema, username)
- .toString();
+ final String bindDN = DN.format(saslAuthzIdTemplate.substring(3), schema, username).toString();
bindId = "dn:" + bindDN;
authzid = new LinkedHashMap<String, Object>(2);
authzid.put(AUTHZID_DN, bindDN);
@@ -213,8 +207,8 @@
bindId = String.format(saslAuthzIdTemplate, username);
authzid = Collections.singletonMap(AUTHZID_ID, (Object) username);
}
- doBind(req, res, newPlainSASLBindRequest(bindId, password), chain, savedConnection,
- sync, username, authzid);
+ doBind(req, res, newPlainSASLBindRequest(bindId, password), chain, savedConnection, sync, username,
+ authzid);
break;
}
default: // SEARCH_SIMPLE
@@ -223,61 +217,52 @@
* First do a search to find the user's entry and then perform a
* bind request using the user's DN.
*/
- final org.forgerock.opendj.ldap.Filter filter =
- org.forgerock.opendj.ldap.Filter.format(searchFilterTemplate, username);
- final SearchRequest searchRequest =
- newSearchRequest(searchBaseDN, searchScope, filter, "1.1");
- searchLDAPConnectionFactory.getConnectionAsync(new ResultHandler<Connection>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- sync.signalAndComplete(asResourceException(error));
- }
-
- @Override
- public void handleResult(final Connection connection) {
- // Do the search.
- connection.searchSingleEntryAsync(searchRequest,
- new ResultHandler<SearchResultEntry>() {
-
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- connection.close();
- /*
- * The search error should not be passed
- * as-is back to the user.
- */
- final ErrorResultException normalizedError;
- if (error instanceof EntryNotFoundException
- || error instanceof MultipleEntriesFoundException) {
- normalizedError =
- newErrorResult(ResultCode.INVALID_CREDENTIALS,
- error);
- } else if (error instanceof AuthenticationException
- || error instanceof AuthorizationException) {
- normalizedError =
- newErrorResult(
- ResultCode.CLIENT_SIDE_LOCAL_ERROR,
- error);
- } else {
- normalizedError = error;
- }
- sync.signalAndComplete(asResourceException(normalizedError));
+ final org.forgerock.opendj.ldap.Filter filter = org.forgerock.opendj.ldap.Filter.format(
+ searchFilterTemplate, username);
+ final SearchRequest searchRequest = newSearchRequest(searchBaseDN, searchScope, filter, "1.1");
+ searchLDAPConnectionFactory.getConnectionAsync()
+ .thenAsync(new AsyncFunction<Connection, SearchResultEntry, ErrorResultException>() {
+ @Override
+ public Promise<SearchResultEntry, ErrorResultException> apply(Connection connection)
+ throws ErrorResultException {
+ savedConnection.set(connection);
+ // Do the search.
+ return connection.searchSingleEntryAsync(searchRequest);
+ }
+ }).onSuccess(new SuccessHandler<SearchResultEntry>() {
+ @Override
+ public void handleResult(final SearchResultEntry result) {
+ savedConnection.get().close();
+ final String bindDN = result.getName().toString();
+ final Map<String, Object> authzid = new LinkedHashMap<String, Object>(2);
+ authzid.put(AUTHZID_DN, bindDN);
+ authzid.put(AUTHZID_ID, username);
+ doBind(req, res, newSimpleBindRequest(bindDN, password), chain, savedConnection, sync,
+ username, authzid);
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ ErrorResultException normalizedError = error;
+ if (savedConnection.get() != null) {
+ savedConnection.get().close();
+ /*
+ * The search error should not be passed
+ * as-is back to the user.
+ */
+ if (error instanceof EntryNotFoundException
+ || error instanceof MultipleEntriesFoundException) {
+ normalizedError = newErrorResult(ResultCode.INVALID_CREDENTIALS, error);
+ } else if (error instanceof AuthenticationException
+ || error instanceof AuthorizationException) {
+ normalizedError = newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, error);
+ } else {
+ normalizedError = error;
}
-
- @Override
- public void handleResult(final SearchResultEntry result) {
- connection.close();
- final String bindDN = result.getName().toString();
- final Map<String, Object> authzid =
- new LinkedHashMap<String, Object>(2);
- authzid.put(AUTHZID_DN, bindDN);
- authzid.put(AUTHZID_ID, username);
- doBind(req, res, newSimpleBindRequest(bindDN, password),
- chain, savedConnection, sync, username, authzid);
- }
- });
- }
- });
+ }
+ sync.signalAndComplete(asResourceException(normalizedError));
+ }
+ });
break;
}
}
@@ -406,25 +391,17 @@
* cached connection and authorization credentials on completion.
*/
private void doBind(final HttpServletRequest request, final ServletResponse response,
- final BindRequest bindRequest, final FilterChain chain,
- final AtomicReference<Connection> savedConnection, final ServletSynchronizer sync,
- final String authcid, final Map<String, Object> authzid) {
- bindLDAPConnectionFactory.getConnectionAsync(new ResultHandler<Connection>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- sync.signalAndComplete(asResourceException(error));
- }
-
- @Override
- public void handleResult(final Connection connection) {
- savedConnection.set(connection);
- connection.bindAsync(bindRequest, null, new ResultHandler<BindResult>() {
-
+ final BindRequest bindRequest, final FilterChain chain, final AtomicReference<Connection> savedConnection,
+ final ServletSynchronizer sync, final String authcid, final Map<String, Object> authzid) {
+ bindLDAPConnectionFactory.getConnectionAsync()
+ .thenAsync(new AsyncFunction<Connection, BindResult, ErrorResultException>() {
@Override
- public void handleErrorResult(final ErrorResultException error) {
- sync.signalAndComplete(asResourceException(error));
+ public Promise<BindResult, ErrorResultException> apply(Connection connection)
+ throws ErrorResultException {
+ savedConnection.set(connection);
+ return connection.bindAsync(bindRequest);
}
-
+ }).onSuccess(new SuccessHandler<BindResult>() {
@Override
public void handleResult(final BindResult result) {
/*
@@ -433,8 +410,8 @@
* filter will close it.
*/
if (reuseAuthenticatedConnection) {
- request.setAttribute(ATTRIBUTE_AUTHN_CONNECTION, Connections
- .uncloseable(connection));
+ request.setAttribute(ATTRIBUTE_AUTHN_CONNECTION,
+ Connections.uncloseable(savedConnection.get()));
}
// Pass through the authentication ID and authorization principals.
@@ -462,9 +439,12 @@
}
}
}
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ sync.signalAndComplete(asResourceException(error));
+ }
});
- }
- });
}
private AuthenticationMethod parseAuthenticationMethod(final JsonValue configuration) {
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
index 498e84a..94a42e4 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
@@ -11,14 +11,10 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.rest2ldap;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.rest2ldap.Rest2LDAP.asResourceException;
-import static org.forgerock.opendj.rest2ldap.Utils.i18n;
-
import java.io.Closeable;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -58,6 +54,11 @@
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.promise.FailureHandler;
+import org.forgerock.util.promise.SuccessHandler;
+
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.*;
+import static org.forgerock.opendj.rest2ldap.Utils.*;
/**
* Common context information passed to containers and mappers. A new context is
@@ -68,7 +69,7 @@
/*
* A cached read request - see cachedReads for more information.
*/
- private static final class CachedRead implements SearchResultHandler {
+ private static final class CachedRead implements SearchResultHandler, ResultHandler<Result> {
private SearchResultEntry cachedEntry;
private final String cachedFilterString;
private FutureResult<Result> cachedFuture; // Guarded by latch.
@@ -91,7 +92,7 @@
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleError(final ErrorResultException error) {
handleResult(error.getResult());
}
@@ -171,14 +172,9 @@
}
}
- private void invokeResultHandler(final SearchResultHandler resultHandler) {
+ private void invokeResultHandler(final SearchResultHandler searchResultHandler) {
if (cachedEntry != null) {
- resultHandler.handleEntry(cachedEntry);
- }
- if (cachedResult.isSuccess()) {
- resultHandler.handleResult(cachedResult);
- } else {
- resultHandler.handleErrorResult(newErrorResult(cachedResult));
+ searchResultHandler.handleEntry(cachedEntry);
}
}
@@ -214,9 +210,7 @@
*/
if (config.getAuthorizationPolicy() != AuthorizationPolicy.NONE
&& context.containsContext(AuthenticatedConnectionContext.class)) {
- final Connection connection =
- context.asContext(AuthenticatedConnectionContext.class).getConnection();
- this.connection = wrap(connection);
+ this.connection = wrap(context.asContext(AuthenticatedConnectionContext.class).getConnection());
} else {
this.connection = null; // We'll allocate the connection.
}
@@ -268,11 +262,9 @@
if (connection == null && config.getAuthorizationPolicy() == AuthorizationPolicy.PROXY) {
if (context.containsContext(SecurityContext.class)) {
try {
- final SecurityContext securityContext =
- context.asContext(SecurityContext.class);
- final String authzId =
- config.getProxiedAuthorizationTemplate().formatAsAuthzId(
- securityContext.getAuthorizationId(), config.schema());
+ final SecurityContext securityContext = context.asContext(SecurityContext.class);
+ final String authzId = config.getProxiedAuthorizationTemplate().formatAsAuthzId(
+ securityContext.getAuthorizationId(), config.schema());
proxiedAuthzControl = ProxiedAuthV2RequestControl.newControl(authzId);
} catch (final ResourceException e) {
handler.handleError(e);
@@ -280,8 +272,7 @@
}
} else {
handler.handleError(new InternalServerErrorException(
- i18n("The request could not be authorized because it did "
- + "not contain a security context")));
+ i18n("The request could not be authorized because it did not contain a security context")));
return;
}
}
@@ -295,22 +286,21 @@
// Invoke the handler immediately since a connection is available.
runnable.run();
} else if (config.connectionFactory() != null) {
- config.connectionFactory().getConnectionAsync(new ResultHandler<Connection>() {
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- handler.handleError(asResourceException(error));
- }
-
+ config.connectionFactory().getConnectionAsync().onSuccess(new SuccessHandler<Connection>() {
@Override
public final void handleResult(final Connection result) {
connection = wrap(result);
runnable.run();
}
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public final void handleError(final ErrorResultException error) {
+ handler.handleError(asResourceException(error));
+ }
});
} else {
handler.handleError(new InternalServerErrorException(
- i18n("The request could not be processed because there was no LDAP "
- + "connection available for use")));
+ i18n("The request could not be processed because there was no LDAP connection available for use")));
}
}
@@ -331,10 +321,8 @@
@Override
public FutureResult<Result> addAsync(final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
- return connection.addAsync(withControls(request), intermediateResponseHandler,
- resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.addAsync(withControls(request), intermediateResponseHandler);
}
@Override
@@ -344,14 +332,13 @@
@Override
public FutureResult<BindResult> bindAsync(final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super BindResult> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
/*
* Simple brute force implementation in case the bind operation
* modifies an entry: clear the cachedReads.
*/
evictAll();
- return connection.bindAsync(request, intermediateResponseHandler, resultHandler);
+ return connection.bindAsync(request, intermediateResponseHandler);
}
@Override
@@ -366,33 +353,26 @@
@Override
public FutureResult<CompareResult> compareAsync(final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super CompareResult> resultHandler) {
- return connection.compareAsync(withControls(request), intermediateResponseHandler,
- resultHandler);
+ final IntermediateResponseHandler intermediateResponseHandler) {
+ return connection.compareAsync(withControls(request), intermediateResponseHandler);
}
@Override
public FutureResult<Result> deleteAsync(final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
evict(request.getName());
- return connection.deleteAsync(withControls(request), intermediateResponseHandler,
- resultHandler);
+ return connection.deleteAsync(withControls(request), intermediateResponseHandler);
}
@Override
- public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(
- final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super R> resultHandler) {
+ public <R extends ExtendedResult> FutureResult<R> extendedRequestAsync(final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler) {
/*
* Simple brute force implementation in case the extended
* operation modifies an entry: clear the cachedReads.
*/
evictAll();
- return connection.extendedRequestAsync(withControls(request),
- intermediateResponseHandler, resultHandler);
+ return connection.extendedRequestAsync(withControls(request), intermediateResponseHandler);
}
@Override
@@ -407,21 +387,17 @@
@Override
public FutureResult<Result> modifyAsync(final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
evict(request.getName());
- return connection.modifyAsync(withControls(request), intermediateResponseHandler,
- resultHandler);
+ return connection.modifyAsync(withControls(request), intermediateResponseHandler);
}
@Override
public FutureResult<Result> modifyDNAsync(final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<? super Result> resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler) {
// Simple brute force implementation: clear the cachedReads.
evictAll();
- return connection.modifyDNAsync(withControls(request), intermediateResponseHandler,
- resultHandler);
+ return connection.modifyDNAsync(withControls(request), intermediateResponseHandler);
}
@Override
@@ -434,17 +410,14 @@
*/
@Override
public FutureResult<Result> searchAsync(final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
+ final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler) {
/*
* Don't attempt caching if this search is not a read (base
* object), or if the search request passed in an intermediate
* response handler.
*/
- if (!request.getScope().equals(SearchScope.BASE_OBJECT)
- || intermediateResponseHandler != null) {
- return connection.searchAsync(withControls(request),
- intermediateResponseHandler, resultHandler);
+ if (!request.getScope().equals(SearchScope.BASE_OBJECT) || intermediateResponseHandler != null) {
+ return connection.searchAsync(withControls(request), intermediateResponseHandler, entryHandler);
}
// This is a read request and a candidate for caching.
@@ -454,17 +427,17 @@
}
if (cachedRead != null && cachedRead.isMatchingRead(request)) {
// The cached read matches this read request.
- cachedRead.addResultHandler(resultHandler);
+ cachedRead.addResultHandler(entryHandler);
return cachedRead.getFutureResult();
} else {
// Cache the read, possibly evicting a non-matching cached read.
- final CachedRead pendingCachedRead = new CachedRead(request, resultHandler);
+ final CachedRead pendingCachedRead = new CachedRead(request, entryHandler);
synchronized (cachedReads) {
cachedReads.put(request.getName(), pendingCachedRead);
}
- final FutureResult<Result> future =
- connection.searchAsync(withControls(request),
- intermediateResponseHandler, pendingCachedRead);
+ final FutureResult<Result> future = (FutureResult<Result>) connection
+ .searchAsync(withControls(request), intermediateResponseHandler, pendingCachedRead)
+ .onSuccess(pendingCachedRead).onFailure(pendingCachedRead);
pendingCachedRead.setFuture(future);
return future;
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
index 69742ff..2d2d3e8 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
@@ -11,24 +11,11 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2012-2013 ForgeRock AS.
+ * Copyright 2012-2014 ForgeRock AS.
*/
package org.forgerock.opendj.rest2ldap;
-import static java.util.Arrays.asList;
-import static org.forgerock.opendj.ldap.Filter.alwaysFalse;
-import static org.forgerock.opendj.ldap.Filter.alwaysTrue;
-import static org.forgerock.opendj.ldap.requests.Requests.newAddRequest;
-import static org.forgerock.opendj.ldap.requests.Requests.newDeleteRequest;
-import static org.forgerock.opendj.ldap.requests.Requests.newModifyRequest;
-import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
-import static org.forgerock.opendj.rest2ldap.ReadOnUpdatePolicy.CONTROLS;
-import static org.forgerock.opendj.rest2ldap.Rest2LDAP.asResourceException;
-import static org.forgerock.opendj.rest2ldap.Utils.accumulate;
-import static org.forgerock.opendj.rest2ldap.Utils.i18n;
-import static org.forgerock.opendj.rest2ldap.Utils.toFilter;
-import static org.forgerock.opendj.rest2ldap.Utils.transform;
-
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
@@ -86,16 +73,48 @@
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.responses.SearchResultReference;
import org.forgerock.opendj.ldif.ChangeRecord;
+import org.forgerock.util.promise.FailureHandler;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.PromiseImpl;
+import org.forgerock.util.promise.Promises;
+import org.forgerock.util.promise.SuccessHandler;
+
+import static java.util.Arrays.*;
+
+import static org.forgerock.opendj.ldap.Filter.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+import static org.forgerock.opendj.rest2ldap.ReadOnUpdatePolicy.*;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.*;
+import static org.forgerock.opendj.rest2ldap.Utils.*;
/**
* A {@code CollectionResourceProvider} implementation which maps a JSON
* resource collection to LDAP entries beneath a base DN.
*/
final class LDAPCollectionResourceProvider implements CollectionResourceProvider {
- // Dummy exception used for signalling search success.
+ private static class ResultHandlerFromPromise<T> implements ResultHandler<T> {
+ private final PromiseImpl<T, ResourceException> promise;
+
+ ResultHandlerFromPromise() {
+ promise = PromiseImpl.create();
+ }
+
+ @Override
+ public void handleError(ResourceException error) {
+ promise.handleError(error);
+
+ }
+
+ @Override
+ public void handleResult(T result) {
+ promise.handleResult(result);
+ }
+ }
+
+ /** Dummy exception used for signalling search success. */
private static final ResourceException SUCCESS = new UncategorizedException(0, null, null);
- // Empty decode options required for decoding response controls.
+ /** Empty decode options required for decoding response controls. */
private static final DecodeOptions DECODE_OPTIONS = new DecodeOptions();
private final List<Attribute> additionalLDAPAttributes;
@@ -140,39 +159,37 @@
public void run() {
// Calculate entry content.
attributeMapper.create(c, new JsonPointer(), request.getContent(),
- new ResultHandler<List<Attribute>>() {
- @Override
- public void handleError(final ResourceException error) {
- h.handleError(error);
- }
+ new ResultHandler<List<Attribute>>() {
+ @Override
+ public void handleError(final ResourceException error) {
+ h.handleError(error);
+ }
- @Override
- public void handleResult(final List<Attribute> result) {
- // Perform add operation.
- final AddRequest addRequest = newAddRequest(DN.rootDN());
- for (final Attribute attribute : additionalLDAPAttributes) {
- addRequest.addAttribute(attribute);
- }
- for (final Attribute attribute : result) {
- addRequest.addAttribute(attribute);
- }
- try {
- nameStrategy.setResourceId(c, getBaseDN(c), request
- .getNewResourceId(), addRequest);
- } catch (final ResourceException e) {
- h.handleError(e);
- return;
- }
- if (config.readOnUpdatePolicy() == CONTROLS) {
- final String[] attributes =
- getLDAPAttributes(c, request.getFields());
- addRequest.addControl(PostReadRequestControl.newControl(false,
- attributes));
- }
- c.getConnection().applyChangeAsync(addRequest, null,
- postUpdateHandler(c, h));
+ @Override
+ public void handleResult(final List<Attribute> result) {
+ // Perform add operation.
+ final AddRequest addRequest = newAddRequest(DN.rootDN());
+ for (final Attribute attribute : additionalLDAPAttributes) {
+ addRequest.addAttribute(attribute);
}
- });
+ for (final Attribute attribute : result) {
+ addRequest.addAttribute(attribute);
+ }
+ try {
+ nameStrategy.setResourceId(c, getBaseDN(c), request.getNewResourceId(), addRequest);
+ } catch (final ResourceException e) {
+ h.handleError(e);
+ return;
+ }
+ if (config.readOnUpdatePolicy() == CONTROLS) {
+ final String[] attributes = getLDAPAttributes(c, request.getFields());
+ addRequest.addControl(PostReadRequestControl.newControl(false, attributes));
+ }
+ c.getConnection().applyChangeAsync(addRequest)
+ .onSuccess(postUpdateSuccessHandler(c, h))
+ .onFailure(postUpdateFailureHandler(h));
+ }
+ });
}
});
}
@@ -196,15 +213,14 @@
final ChangeRecord deleteRequest = newDeleteRequest(dn);
if (config.readOnUpdatePolicy() == CONTROLS) {
final String[] attributes = getLDAPAttributes(c, request.getFields());
- deleteRequest.addControl(PreReadRequestControl
- .newControl(false, attributes));
+ deleteRequest.addControl(PreReadRequestControl.newControl(false, attributes));
}
if (config.useSubtreeDelete()) {
deleteRequest.addControl(SubtreeDeleteRequestControl.newControl(true));
}
addAssertionControl(deleteRequest, request.getRevision());
- c.getConnection()
- .applyChangeAsync(deleteRequest, null, postUpdateHandler(c, h));
+ c.getConnection().applyChangeAsync(deleteRequest).onSuccess(postUpdateSuccessHandler(c, h))
+ .onFailure(postUpdateFailureHandler(h));
} catch (final Exception e) {
h.handleError(asResourceException(e));
}
@@ -213,31 +229,29 @@
}
@Override
- public void patchInstance(final ServerContext context, final String resourceId,
- final PatchRequest request, final ResultHandler<Resource> handler) {
+ public void patchInstance(final ServerContext context, final String resourceId, final PatchRequest request,
+ final ResultHandler<Resource> handler) {
final Context c = wrap(context);
final ResultHandler<Resource> h = wrap(c, handler);
if (request.getPatchOperations().isEmpty()) {
/*
- * This patch is a no-op so just read the entry and check its
- * version.
+ * This patch is a no-op so just read the entry and check its version.
*/
c.run(h, new Runnable() {
@Override
public void run() {
final String[] attributes = getLDAPAttributes(c, request.getFields());
- final SearchRequest searchRequest =
- nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId)
- .addAttribute(attributes);
- c.getConnection().searchSingleEntryAsync(searchRequest,
- postEmptyPatchHandler(c, request, h));
+ final SearchRequest searchRequest = nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId)
+ .addAttribute(attributes);
+ c.getConnection().searchSingleEntryAsync(searchRequest)
+ .onSuccess(postEmptyPatchSuccessHandler(c, request, h))
+ .onFailure(postEmptyPatchFailureHandler(h));
}
});
} else {
/*
- * Get the connection, search if needed, then determine
- * modifications, then perform modify.
+ * Get the connection, search if needed, then determine modifications, then perform modify.
*/
c.run(h, doUpdate(c, resourceId, request.getRevision(), new ResultHandler<DN>() {
@Override
@@ -247,71 +261,62 @@
@Override
public void handleResult(final DN dn) {
- // Convert the patch operations to LDAP modifications.
- final ResultHandler<List<Modification>> handler =
- accumulate(request.getPatchOperations().size(),
- new ResultHandler<List<List<Modification>>>() {
- @Override
- public void handleError(final ResourceException error) {
- h.handleError(error);
- }
-
- @Override
- public void handleResult(
- final List<List<Modification>> result) {
- // The patch operations have been converted successfully.
- try {
- final ModifyRequest modifyRequest =
- newModifyRequest(dn);
-
- // Add the modifications.
- for (final List<Modification> modifications : result) {
- if (modifications != null) {
- modifyRequest.getModifications().addAll(
- modifications);
- }
- }
-
- final List<String> attributes =
- asList(getLDAPAttributes(c, request
- .getFields()));
- if (modifyRequest.getModifications().isEmpty()) {
- /*
- * This patch is a no-op so
- * just read the entry and
- * check its version.
- */
- c.getConnection().readEntryAsync(dn,
- attributes,
- postEmptyPatchHandler(c, request, h));
- } else {
- // Add controls and perform the modify request.
- if (config.readOnUpdatePolicy() == CONTROLS) {
- modifyRequest
- .addControl(PostReadRequestControl
- .newControl(false,
- attributes));
- }
- if (config.usePermissiveModify()) {
- modifyRequest
- .addControl(PermissiveModifyRequestControl
- .newControl(true));
- }
- addAssertionControl(modifyRequest, request
- .getRevision());
- c.getConnection().applyChangeAsync(
- modifyRequest, null,
- postUpdateHandler(c, h));
- }
- } catch (final Exception e) {
- h.handleError(asResourceException(e));
- }
- }
- });
-
+ // Convert the patch operations to LDAP modifications.
+ List<Promise<List<Modification>, ResourceException>> promises =
+ new ArrayList<Promise<List<Modification>, ResourceException>>(
+ request.getPatchOperations().size());
for (final PatchOperation operation : request.getPatchOperations()) {
+ final ResultHandlerFromPromise<List<Modification>> handler =
+ new ResultHandlerFromPromise<List<Modification>>();
attributeMapper.patch(c, new JsonPointer(), operation, handler);
+ promises.add(handler.promise);
}
+
+ Promises.when(promises).onSuccess(new SuccessHandler<List<List<Modification>>>() {
+ @Override
+ public void handleResult(final List<List<Modification>> result) {
+ // The patch operations have been converted successfully.
+ try {
+ final ModifyRequest modifyRequest = newModifyRequest(dn);
+
+ // Add the modifications.
+ for (final List<Modification> modifications : result) {
+ if (modifications != null) {
+ modifyRequest.getModifications().addAll(modifications);
+ }
+ }
+
+ final List<String> attributes = asList(getLDAPAttributes(c, request.getFields()));
+ if (modifyRequest.getModifications().isEmpty()) {
+ /*
+ * This patch is a no-op so just read the entry and check its version.
+ */
+ c.getConnection().readEntryAsync(dn, attributes)
+ .onSuccess(postEmptyPatchSuccessHandler(c, request, h))
+ .onFailure(postEmptyPatchFailureHandler(h));
+ } else {
+ // Add controls and perform the modify request.
+ if (config.readOnUpdatePolicy() == CONTROLS) {
+ modifyRequest.addControl(PostReadRequestControl.newControl(false, attributes));
+ }
+ if (config.usePermissiveModify()) {
+ modifyRequest.addControl(PermissiveModifyRequestControl.newControl(true));
+ }
+ addAssertionControl(modifyRequest, request.getRevision());
+ c.getConnection().applyChangeAsync(modifyRequest)
+ .onSuccess(postUpdateSuccessHandler(c, h))
+ .onFailure(postUpdateFailureHandler(h));
+ }
+ } catch (final Exception e) {
+ h.handleError(asResourceException(e));
+ }
+ }
+ }).onFailure(new FailureHandler<ResourceException>() {
+ @Override
+ public void handleError(ResourceException error) {
+ h.handleError(asResourceException(error));
+ }
+ });
}
}));
}
@@ -324,14 +329,25 @@
final QueryResultHandler h = wrap(c, handler);
/*
- * Get the connection, then calculate the search filter, then perform
- * the search.
+ * Get the connection, then calculate the search filter, then perform the search.
*/
c.run(h, new Runnable() {
@Override
public void run() {
// Calculate the filter (this may require the connection).
getLDAPFilter(c, request.getQueryFilter(), new ResultHandler<Filter>() {
+ /**
+ * The following fields are guarded by sequenceLock. In
+ * addition, the sequenceLock ensures that we send one JSON
+ * resource at a time back to the client.
+ */
+ private final Object sequenceLock = new Object();
+ private String cookie;
+ private ResourceException pendingResult;
+ private int pendingResourceCount;
+ private boolean resultSent;
+ private int totalResourceCount;
+
@Override
public void handleError(final ResourceException error) {
h.handleError(error);
@@ -340,23 +356,21 @@
@Override
public void handleResult(final Filter ldapFilter) {
/*
- * Avoid performing a search if the filter could not be
- * mapped or if it will never match.
+ * Avoid performing a search if the filter could not be mapped or if it will never match.
*/
if (ldapFilter == null || ldapFilter == alwaysFalse()) {
h.handleResult(new QueryResult());
} else {
// Perform the search.
final String[] attributes = getLDAPAttributes(c, request.getFields());
+ final Filter searchFilter =
+ ldapFilter == Filter.alwaysTrue() ? Filter.objectClassPresent() : ldapFilter;
final SearchRequest searchRequest =
- newSearchRequest(getBaseDN(c), SearchScope.SINGLE_LEVEL,
- ldapFilter == Filter.alwaysTrue() ? Filter
- .objectClassPresent() : ldapFilter, attributes);
+ newSearchRequest(getBaseDN(c), SearchScope.SINGLE_LEVEL, 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.
+ * Add the page results control. We can support the page offset by
+ * reading the next offset pages, or offset x page size resources.
*/
final int pageResultStartIndex;
final int pageSize = request.getPageSize();
@@ -374,35 +388,18 @@
.valueOfBase64(request.getPagedResultsCookie())
: ByteString.empty();
final SimplePagedResultsControl control =
- SimplePagedResultsControl.newControl(true,
- pageResultEndIndex, cookie);
+ SimplePagedResultsControl.newControl(true, pageResultEndIndex, cookie);
searchRequest.addControl(control);
} else {
pageResultStartIndex = 0;
}
- c.getConnection().searchAsync(searchRequest, null, new SearchResultHandler() {
- /*
- * The following fields are guarded by
- * sequenceLock. In addition, the sequenceLock
- * ensures that we send one JSON resource at a
- * time back to the client.
- */
- private final Object sequenceLock = new Object();
- private int pendingResourceCount = 0;
- private ResourceException pendingResult = null;
- private boolean resultSent = false;
- private int totalResourceCount = 0;
- private String cookie = null;
-
+ c.getConnection().searchAsync(searchRequest, new SearchResultHandler() {
@Override
public boolean handleEntry(final SearchResultEntry entry) {
/*
- * Search result entries will be returned
- * before the search result/error so the
- * only reason pendingResult will be
- * non-null is if a mapping error has
- * occurred.
+ * Search result entries will be returned before the search result/error so the
+ * only reason pendingResult will be non-null is if a mapping error has occurred.
*/
synchronized (sequenceLock) {
if (pendingResult != null) {
@@ -416,75 +413,59 @@
}
/*
- * FIXME: secondary asynchronous searches
- * will complete in a non-deterministic
- * order and may cause the JSON resources to
- * be returned in a different order to the
- * order in which the primary LDAP search
- * results were received. This is benign at
- * the moment, but will need resolving when
- * we implement server side sorting. A
- * possible fix will be to use a queue of
- * pending resources (futures?). However,
- * the queue cannot be unbounded in case it
- * grows very large, but it cannot be
- * bounded either since that could cause a
- * deadlock between rest2ldap and the LDAP
- * server (imagine the case where the server
- * has a single worker thread which is
+ * FIXME: secondary asynchronous searches will complete in a non-deterministic
+ * order and may cause the JSON resources to be returned in a different order to the
+ * order in which the primary LDAP search results were received. This is benign at
+ * the moment, but will need resolving when we implement server side sorting. A
+ * possible fix will be to use a queue of pending resources (futures?). However,
+ * the queue cannot be unbounded in case it grows very large, but it cannot be
+ * bounded either since that could cause a deadlock between rest2ldap and the LDAP
+ * server (imagine the case where the server has a single worker thread which is
* occupied processing the primary search).
- * The best solution is probably to process
- * the primary search results in batches
+ * The best solution is probably to process the primary search results in batches
* using the paged results control.
*/
final String id = nameStrategy.getResourceId(c, entry);
final String revision = getRevisionFromEntry(entry);
- attributeMapper.read(c, new JsonPointer(), entry,
- new ResultHandler<JsonValue>() {
- @Override
- public void handleError(final ResourceException e) {
- synchronized (sequenceLock) {
- pendingResourceCount--;
- completeIfNecessary(e);
- }
- }
+ attributeMapper.read(c, new JsonPointer(), entry, new ResultHandler<JsonValue>() {
+ @Override
+ public void handleError(final ResourceException e) {
+ synchronized (sequenceLock) {
+ pendingResourceCount--;
+ completeIfNecessary(e);
+ }
+ }
- @Override
- public void handleResult(final JsonValue result) {
- synchronized (sequenceLock) {
- pendingResourceCount--;
- if (!resultSent) {
- h.handleResource(new Resource(id,
- revision, result));
- }
- completeIfNecessary();
- }
+ @Override
+ public void handleResult(final JsonValue result) {
+ synchronized (sequenceLock) {
+ pendingResourceCount--;
+ if (!resultSent) {
+ h.handleResource(new Resource(id, revision, result));
}
- });
+ completeIfNecessary();
+ }
+ }
+ });
return true;
}
@Override
- public void handleErrorResult(final ErrorResultException error) {
- synchronized (sequenceLock) {
- completeIfNecessary(asResourceException(error));
- }
- }
-
- @Override
public boolean handleReference(final SearchResultReference reference) {
// TODO: should this be classed as an error since rest2ldap
// assumes entries are all colocated?
return true;
}
+ }).onSuccess(new SuccessHandler<Result>() {
@Override
- public void handleResult(final Result result) {
+ public void handleResult(Result result) {
synchronized (sequenceLock) {
if (request.getPageSize() > 0) {
try {
- final SimplePagedResultsControl control = result.getControl(
- SimplePagedResultsControl.DECODER, DECODE_OPTIONS);
+ final SimplePagedResultsControl control =
+ result.getControl(SimplePagedResultsControl.DECODER,
+ DECODE_OPTIONS);
if (control != null && !control.getCookie().isEmpty()) {
cookie = control.getCookie().toBase64String();
}
@@ -495,46 +476,50 @@
completeIfNecessary(SUCCESS);
}
}
-
- /*
- * This method must be invoked with the
- * sequenceLock held.
- */
- private void completeIfNecessary(final ResourceException e) {
- if (pendingResult == null) {
- pendingResult = e;
- }
- completeIfNecessary();
- }
-
- /*
- * Close out the query result set if there are
- * no more pending resources and the LDAP result
- * has been received. This method must be
- * invoked with the sequenceLock held.
- */
- private void completeIfNecessary() {
- if (pendingResourceCount == 0 && pendingResult != null
- && !resultSent) {
- if (pendingResult == SUCCESS) {
- h.handleResult(new QueryResult(cookie, -1));
- } else {
- h.handleError(pendingResult);
- }
- resultSent = true;
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ synchronized (sequenceLock) {
+ completeIfNecessary(asResourceException(error));
}
}
});
}
}
+
+ /**
+ * This method must be invoked with the sequenceLock held.
+ */
+ private void completeIfNecessary(final ResourceException e) {
+ if (pendingResult == null) {
+ pendingResult = e;
+ }
+ completeIfNecessary();
+ }
+
+ /**
+ * Close out the query result set if there are no more
+ * pending resources and the LDAP result has been received.
+ * This method must be invoked with the sequenceLock held.
+ */
+ private void completeIfNecessary() {
+ if (pendingResourceCount == 0 && pendingResult != null && !resultSent) {
+ if (pendingResult == SUCCESS) {
+ h.handleResult(new QueryResult(cookie, -1));
+ } else {
+ h.handleError(pendingResult);
+ }
+ resultSent = true;
+ }
+ }
});
}
});
}
@Override
- public void readInstance(final ServerContext context, final String resourceId,
- final ReadRequest request, final ResultHandler<Resource> handler) {
+ public void readInstance(final ServerContext context, final String resourceId, final ReadRequest request,
+ final ResultHandler<Resource> handler) {
final Context c = wrap(context);
final ResultHandler<Resource> h = wrap(c, handler);
@@ -545,27 +530,27 @@
// Do the search.
final String[] attributes = getLDAPAttributes(c, request.getFields());
final SearchRequest request =
- nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId).addAttribute(
- attributes);
- c.getConnection().searchSingleEntryAsync(request,
- new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- h.handleError(asResourceException(error));
- }
+ nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId).addAttribute(attributes);
- @Override
- public void handleResult(final SearchResultEntry entry) {
- adaptEntry(c, entry, h);
- }
- });
- }
+ c.getConnection().searchSingleEntryAsync(request).onSuccess(new SuccessHandler<SearchResultEntry>() {
+ @Override
+ public void handleResult(final SearchResultEntry entry) {
+ adaptEntry(c, entry, h);
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ h.handleError(asResourceException(error));
+ }
+ });
+
+ };
});
}
@Override
- public void updateInstance(final ServerContext context, final String resourceId,
- final UpdateRequest request, final ResultHandler<Resource> handler) {
+ public void updateInstance(final ServerContext context, final String resourceId, final UpdateRequest request,
+ final ResultHandler<Resource> handler) {
/*
* Update operations are a bit awkward because there is no direct
* mapping to LDAP. We need to convert the update request into an LDAP
@@ -582,70 +567,53 @@
c.run(h, new Runnable() {
@Override
public void run() {
- final String[] attributes =
- getLDAPAttributes(c, Collections.<JsonPointer> emptyList());
- final SearchRequest searchRequest =
- nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId).addAttribute(
- attributes);
- c.getConnection().searchSingleEntryAsync(searchRequest,
- new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- h.handleError(asResourceException(error));
- }
+ final String[] attributes = getLDAPAttributes(c, Collections.<JsonPointer> emptyList());
+ final SearchRequest searchRequest = nameStrategy.createSearchRequest(c, getBaseDN(c), resourceId)
+ .addAttribute(attributes);
+ c.getConnection().searchSingleEntryAsync(searchRequest)
+ .onSuccess(new SuccessHandler<SearchResultEntry>() {
@Override
public void handleResult(final SearchResultEntry entry) {
try {
// Fail-fast if there is a version mismatch.
ensureMVCCVersionMatches(entry, request.getRevision());
- // Create the modify request.
- final ModifyRequest modifyRequest =
- newModifyRequest(entry.getName());
+ // Create the modify request.
+ final ModifyRequest modifyRequest = newModifyRequest(entry.getName());
if (config.readOnUpdatePolicy() == CONTROLS) {
- final String[] attributes =
- getLDAPAttributes(c, request.getFields());
- modifyRequest.addControl(PostReadRequestControl.newControl(
- false, attributes));
+ final String[] attributes = getLDAPAttributes(c, request.getFields());
+ modifyRequest.addControl(PostReadRequestControl.newControl(false, attributes));
}
if (config.usePermissiveModify()) {
- modifyRequest.addControl(PermissiveModifyRequestControl
- .newControl(true));
+ modifyRequest.addControl(PermissiveModifyRequestControl.newControl(true));
}
addAssertionControl(modifyRequest, request.getRevision());
/*
- * Determine the set of changes that need to
- * be performed.
+ * Determine the set of changes that need to be performed.
*/
- attributeMapper.update(c, new JsonPointer(), entry, request
- .getNewContent(),
+ attributeMapper.update(c, new JsonPointer(), entry, request.getNewContent(),
new ResultHandler<List<Modification>>() {
@Override
- public void handleError(
- final ResourceException error) {
+ public void handleError(final ResourceException error) {
h.handleError(error);
}
@Override
- public void handleResult(
- final List<Modification> result) {
+ public void handleResult(final List<Modification> result) {
// Perform the modify operation.
if (result.isEmpty()) {
/*
- * No changes to be
- * performed, so just
- * return the entry that
- * we read.
+ * No changes to be performed, so just return
+ * the entry that we read.
*/
adaptEntry(c, entry, h);
} else {
- modifyRequest.getModifications().addAll(
- result);
- c.getConnection().applyChangeAsync(
- modifyRequest, null,
- postUpdateHandler(c, h));
+ modifyRequest.getModifications().addAll(result);
+ c.getConnection().applyChangeAsync(modifyRequest)
+ .onSuccess(postUpdateSuccessHandler(c, h))
+ .onFailure(postUpdateFailureHandler(h));
}
}
});
@@ -653,13 +621,17 @@
h.handleError(asResourceException(e));
}
}
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ h.handleError(asResourceException(error));
+ }
});
}
});
}
- private void adaptEntry(final Context c, final Entry entry,
- final ResultHandler<Resource> handler) {
+ private void adaptEntry(final Context c, final Entry entry, final ResultHandler<Resource> handler) {
final String actualResourceId = nameStrategy.getResourceId(c, entry);
final String revision = getRevisionFromEntry(entry);
attributeMapper.read(c, new JsonPointer(), entry, transform(
@@ -695,13 +667,8 @@
// There's no point in doing a search because we already know the DN.
updateHandler.handleResult(searchRequest.getName());
} else {
- c.getConnection().searchSingleEntryAsync(searchRequest,
- new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- updateHandler.handleError(asResourceException(error));
- }
-
+ c.getConnection().searchSingleEntryAsync(searchRequest)
+ .onSuccess(new SuccessHandler<SearchResultEntry>() {
@Override
public void handleResult(final SearchResultEntry entry) {
try {
@@ -714,6 +681,11 @@
updateHandler.handleError(asResourceException(e));
}
}
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ updateHandler.handleError(asResourceException(error));
+ }
});
}
}
@@ -727,21 +699,18 @@
}
}
- private void ensureMVCCVersionMatches(final Entry entry, final String expectedRevision)
- throws ResourceException {
+ private void ensureMVCCVersionMatches(final Entry entry, final String expectedRevision) throws ResourceException {
if (expectedRevision != null) {
ensureMVCCSupported();
final String actualRevision = entry.parseAttribute(etagAttribute).asString();
if (actualRevision == null) {
throw new PreconditionFailedException(i18n(
"The resource could not be accessed because it did not contain any "
- + "version information, when the version '%s' was expected",
- expectedRevision));
+ + "version information, when the version '%s' was expected", expectedRevision));
} else if (!expectedRevision.equals(actualRevision)) {
throw new PreconditionFailedException(i18n(
"The resource could not be accessed because the expected version '%s' "
- + "does not match the current version '%s'", expectedRevision,
- actualRevision));
+ + "does not match the current version '%s'", expectedRevision, actualRevision));
}
}
}
@@ -785,42 +754,55 @@
return requestedLDAPAttributes.toArray(new String[requestedLDAPAttributes.size()]);
}
- private void getLDAPFilter(final Context c, final QueryFilter queryFilter,
- final ResultHandler<Filter> h) {
+ private void getLDAPFilter(final Context c, final QueryFilter queryFilter, final ResultHandler<Filter> h) {
final QueryFilterVisitor<Void, ResultHandler<Filter>> visitor =
new QueryFilterVisitor<Void, ResultHandler<Filter>>() {
@Override
- public Void visitAndFilter(final ResultHandler<Filter> p,
- final List<QueryFilter> subFilters) {
- final ResultHandler<Filter> handler =
- accumulate(subFilters.size(), transform(
- new Function<List<Filter>, Filter, Void>() {
- @Override
- public Filter apply(final List<Filter> value,
- final Void p) {
- // 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();
- case 1:
- return value.get(0);
- default:
- return Filter.and(value);
- }
- }
- }, p));
+ public Void visitAndFilter(final ResultHandler<Filter> p, final List<QueryFilter> subFilters) {
+ List<Promise<Filter, ResourceException>> promises =
+ new ArrayList<Promise<Filter, ResourceException>>(subFilters.size());
for (final QueryFilter subFilter : subFilters) {
+ final ResultHandlerFromPromise<Filter> handler = new ResultHandlerFromPromise<Filter>();
subFilter.accept(this, handler);
+ promises.add(handler.promise);
}
+
+ Promises.when(promises)
+ .then(new org.forgerock.util.promise.Function<List<Filter>, Filter,
+ ResourceException>() {
+ @Override
+ 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();
+ case 1:
+ return value.get(0);
+ default:
+ return Filter.and(value);
+ }
+ }
+ }).onSuccess(new SuccessHandler<Filter>() {
+ @Override
+ public void handleResult(Filter result) {
+ p.handleResult(result);
+ }
+ }).onFailure(new FailureHandler<ResourceException>() {
+ @Override
+ public void handleError(ResourceException error) {
+ p.handleError(error);
+ }
+ });
+
return null;
}
@@ -907,37 +889,51 @@
}
@Override
- public Void visitOrFilter(final ResultHandler<Filter> p,
- final List<QueryFilter> subFilters) {
- final ResultHandler<Filter> handler =
- accumulate(subFilters.size(), transform(
- new Function<List<Filter>, Filter, Void>() {
- @Override
- public Filter apply(final List<Filter> value,
- final Void p) {
- // Check for unmapped filter components and optimize.
- final Iterator<Filter> i = value.iterator();
- while (i.hasNext()) {
- final Filter f = i.next();
- if (f == alwaysFalse()) {
- i.remove();
- } else if (f == alwaysTrue()) {
- return alwaysTrue();
- }
- }
- switch (value.size()) {
- case 0:
- return alwaysFalse();
- case 1:
- return value.get(0);
- default:
- return Filter.or(value);
- }
- }
- }, p));
+ public Void visitOrFilter(final ResultHandler<Filter> p, final List<QueryFilter> subFilters) {
+ List<Promise<Filter, ResourceException>> promises =
+ new ArrayList<Promise<Filter, ResourceException>>(subFilters.size());
for (final QueryFilter subFilter : subFilters) {
+ final ResultHandlerFromPromise<Filter> handler = new ResultHandlerFromPromise<Filter>();
subFilter.accept(this, handler);
+ promises.add(handler.promise);
}
+
+ Promises.when(promises)
+ .then(new org.forgerock.util.promise.Function<List<Filter>, Filter,
+ ResourceException>() {
+ @Override
+ 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()) {
+ i.remove();
+ } else if (f == alwaysTrue()) {
+ return alwaysTrue();
+ }
+ }
+ switch (value.size()) {
+ case 0:
+ return alwaysFalse();
+ case 1:
+ return value.get(0);
+ default:
+ return Filter.or(value);
+ }
+ }
+ }).onSuccess(new SuccessHandler<Filter>() {
+ @Override
+ public void handleResult(Filter result) {
+ p.handleResult(result);
+ }
+ }).onFailure(new FailureHandler<ResourceException>() {
+ @Override
+ public void handleError(ResourceException error) {
+ p.handleError(error);
+ }
+ });
+
return null;
}
@@ -959,8 +955,7 @@
};
/*
- * Note that the returned LDAP filter may be null if it could not be
- * mapped by any attribute mappers.
+ * Note that the returned LDAP filter may be null if it could not be mapped by any attribute mappers.
*/
queryFilter.accept(visitor, h);
}
@@ -969,14 +964,9 @@
return etagAttribute != null ? entry.parseAttribute(etagAttribute).asString() : null;
}
- private org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry> postEmptyPatchHandler(
- final Context c, final PatchRequest request, final ResultHandler<Resource> h) {
- return new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
- @Override
- public void handleErrorResult(final ErrorResultException error) {
- h.handleError(asResourceException(error));
- }
-
+ private SuccessHandler<SearchResultEntry> postEmptyPatchSuccessHandler(final Context c,
+ final PatchRequest request, final ResultHandler<Resource> h) {
+ return new SuccessHandler<SearchResultEntry>() {
@Override
public void handleResult(final SearchResultEntry entry) {
try {
@@ -990,29 +980,30 @@
};
}
- private org.forgerock.opendj.ldap.ResultHandler<Result> postUpdateHandler(final Context c,
- final ResultHandler<Resource> handler) {
- // The handler which will be invoked for the LDAP add result.
- return new org.forgerock.opendj.ldap.ResultHandler<Result>() {
+ private FailureHandler<ErrorResultException> postEmptyPatchFailureHandler(final ResultHandler<Resource> h) {
+ return new FailureHandler<ErrorResultException>() {
@Override
- public void handleErrorResult(final ErrorResultException error) {
- handler.handleError(asResourceException(error));
+ public void handleError(final ErrorResultException error) {
+ h.handleError(asResourceException(error));
}
+ };
+ }
+ private SuccessHandler<Result> postUpdateSuccessHandler(final Context c, final ResultHandler<Resource> handler) {
+ // The handler which will be invoked for the LDAP add result.
+ return new SuccessHandler<Result>() {
@Override
public void handleResult(final Result result) {
// FIXME: handle USE_SEARCH policy.
Entry entry;
try {
final PostReadResponseControl postReadControl =
- result.getControl(PostReadResponseControl.DECODER, config
- .decodeOptions());
+ result.getControl(PostReadResponseControl.DECODER, config.decodeOptions());
if (postReadControl != null) {
entry = postReadControl.getEntry();
} else {
final PreReadResponseControl preReadControl =
- result.getControl(PreReadResponseControl.DECODER, config
- .decodeOptions());
+ result.getControl(PreReadResponseControl.DECODER, config.decodeOptions());
if (preReadControl != null) {
entry = preReadControl.getEntry();
} else {
@@ -1026,8 +1017,7 @@
if (entry != null) {
adaptEntry(c, entry, handler);
} else {
- final Resource resource =
- new Resource(null, null, new JsonValue(Collections.emptyMap()));
+ final Resource resource = new Resource(null, null, new JsonValue(Collections.emptyMap()));
handler.handleResult(resource);
}
}
@@ -1035,6 +1025,16 @@
};
}
+ private FailureHandler<ErrorResultException> postUpdateFailureHandler(final ResultHandler<Resource> handler) {
+ // The handler which will be invoked for the LDAP add result.
+ return new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
+ handler.handleError(asResourceException(error));
+ }
+ };
+ }
+
private QueryResultHandler wrap(final Context c, final QueryResultHandler handler) {
return new QueryResultHandler() {
@Override
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 230359a..e8b21b1 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
@@ -11,18 +11,10 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2012-2013 ForgeRock AS.
+ * Copyright 2012-2014 ForgeRock AS.
*/
package org.forgerock.opendj.rest2ldap;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-import static org.forgerock.opendj.ldap.requests.Requests.newSearchRequest;
-import static org.forgerock.opendj.rest2ldap.Rest2LDAP.asResourceException;
-import static org.forgerock.opendj.rest2ldap.Utils.accumulate;
-import static org.forgerock.opendj.rest2ldap.Utils.ensureNotNull;
-import static org.forgerock.opendj.rest2ldap.Utils.i18n;
-import static org.forgerock.opendj.rest2ldap.Utils.transform;
-
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -54,13 +46,19 @@
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.promise.FailureHandler;
+import org.forgerock.util.promise.SuccessHandler;
+
+import static org.forgerock.opendj.ldap.ErrorResultException.*;
+import static org.forgerock.opendj.ldap.requests.Requests.*;
+import static org.forgerock.opendj.rest2ldap.Rest2LDAP.*;
+import static org.forgerock.opendj.rest2ldap.Utils.*;
/**
* An attribute mapper which provides a mapping from a JSON value to a single DN
* valued LDAP attribute.
*/
-public final class ReferenceAttributeMapper extends
- AbstractLDAPAttributeMapper<ReferenceAttributeMapper> {
+public final class ReferenceAttributeMapper extends AbstractLDAPAttributeMapper<ReferenceAttributeMapper> {
/**
* The maximum number of candidate references to allow in search filters.
*/
@@ -73,7 +71,7 @@
private SearchScope scope = SearchScope.WHOLE_SUBTREE;
ReferenceAttributeMapper(final AttributeDescription ldapAttributeName, final DN baseDN,
- final AttributeDescription primaryKey, final AttributeMapper mapper) {
+ final AttributeDescription primaryKey, final AttributeMapper mapper) {
super(ldapAttributeName);
this.baseDN = baseDN;
this.primaryKey = primaryKey;
@@ -127,65 +125,65 @@
}
@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) {
+ 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>() {
+ mapper.getLDAPFilter(c, path, subPath, type, operator, valueAssertion, new ResultHandler<Filter>() {
+ @Override
+ public void handleError(final ResourceException error) {
+ h.handleError(error); // Propagate.
+ }
+
+ @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<Filter>();
+
+ final FailureHandler<ErrorResultException> failureHandler =
+ new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(ErrorResultException error) {
+ h.handleError(asResourceException(error)); // Propagate.
+ }
+ };
+
+ c.getConnection().searchAsync(request, new SearchResultHandler() {
@Override
- public void handleError(final ResourceException error) {
- h.handleError(error); // Propagate.
+ 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 void handleResult(final Filter result) {
- // Search for all referenced entries and construct a filter.
- final SearchRequest request = createSearchRequest(result);
- c.getConnection().searchAsync(request, null, new SearchResultHandler() {
- final List<Filter> subFilters = new LinkedList<Filter>();
-
- @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 void handleErrorResult(final ErrorResultException error) {
- h.handleError(asResourceException(error)); // Propagate.
- }
-
- @Override
- public boolean handleReference(final SearchResultReference reference) {
- // Ignore references.
- return true;
- }
-
- @Override
- public void handleResult(final Result result) {
- if (subFilters.size() >= SEARCH_MAX_CANDIDATES) {
- handleErrorResult(newErrorResult(ResultCode.ADMIN_LIMIT_EXCEEDED));
- } else if (subFilters.size() == 1) {
- h.handleResult(subFilters.get(0));
- } else {
- h.handleResult(Filter.or(subFilters));
- }
- }
- });
+ public boolean handleReference(final SearchResultReference reference) {
+ // Ignore references.
+ return true;
}
- });
+ }).onSuccess(new SuccessHandler<Result>() {
+ @Override
+ public void handleResult(Result result) {
+ if (subFilters.size() >= SEARCH_MAX_CANDIDATES) {
+ failureHandler.handleError(newErrorResult(ResultCode.ADMIN_LIMIT_EXCEEDED));
+ } else if (subFilters.size() == 1) {
+ h.handleResult(subFilters.get(0));
+ } else {
+ h.handleResult(Filter.or(subFilters));
+ }
+ }
+ }).onFailure(failureHandler);
+ }
+ });
}
@Override
- void getNewLDAPAttributes(final Context c, final JsonPointer path,
- final List<Object> newValues, final ResultHandler<Attribute> h) {
+ void getNewLDAPAttributes(final Context c, final JsonPointer path, final List<Object> newValues,
+ final ResultHandler<Attribute> h) {
/*
* For each value use the subordinate mapper to obtain the LDAP primary
* key, the perform a search for each one to find the corresponding
@@ -193,8 +191,7 @@
*/
final Attribute newLDAPAttribute = new LinkedAttribute(ldapAttributeName);
final AtomicInteger pendingSearches = new AtomicInteger(newValues.size());
- final AtomicReference<ResourceException> exception =
- new AtomicReference<ResourceException>();
+ final AtomicReference<ResourceException> exception = new AtomicReference<ResourceException>();
for (final Object value : newValues) {
mapper.create(c, path, new JsonValue(value), new ResultHandler<List<Attribute>>() {
@@ -216,17 +213,15 @@
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)));
+ "The request cannot be processed because the reference "
+ + "field '%s' contains a value which does not contain " + "a primary key", path)));
return;
}
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)));
+ "The request cannot be processed because the reference "
+ + "field '%s' contains a value which contains multiple " + "primary keys", path)));
return;
}
@@ -234,45 +229,39 @@
final ByteString primaryKeyValue = primaryKeyAttribute.firstValue();
final Filter filter = Filter.equality(primaryKey.toString(), primaryKeyValue);
final SearchRequest search = createSearchRequest(filter);
- c.getConnection().searchSingleEntryAsync(search,
- new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
+ c.getConnection().searchSingleEntryAsync(search).onSuccess(new SuccessHandler<SearchResultEntry>() {
+ @Override
+ public void handleResult(final SearchResultEntry result) {
+ synchronized (newLDAPAttribute) {
+ newLDAPAttribute.add(result.getName());
+ }
+ completeIfNecessary();
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException 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 ErrorResultException e) {
+ re = asResourceException(e);
+ }
+ exception.compareAndSet(null, re);
+ completeIfNecessary();
+ }
- @Override
- public void handleErrorResult(final ErrorResultException 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 ErrorResultException e) {
- re = asResourceException(e);
- }
- exception.compareAndSet(null, re);
- completeIfNecessary();
- }
-
- @Override
- public void handleResult(final SearchResultEntry result) {
- synchronized (newLDAPAttribute) {
- newLDAPAttribute.add(result.getName());
- }
- completeIfNecessary();
- }
- });
+ });
}
private void completeIfNecessary() {
@@ -294,8 +283,7 @@
}
@Override
- void read(final Context c, final JsonPointer path, final Entry e,
- final ResultHandler<JsonValue> h) {
+ void read(final Context c, final JsonPointer path, final Entry e, final ResultHandler<JsonValue> h) {
final Attribute attribute = e.getAttribute(ldapAttributeName);
if (attribute == null || attribute.isEmpty()) {
h.handleResult(null);
@@ -309,30 +297,27 @@
}
} else {
try {
- final Set<DN> dns =
- attribute.parse().usingSchema(c.getConfig().schema()).asSetOfDN();
+ final Set<DN> dns = attribute.parse().usingSchema(c.getConfig().schema()).asSetOfDN();
final ResultHandler<JsonValue> handler =
- accumulate(dns.size(), transform(
- new Function<List<JsonValue>, JsonValue, Void>() {
- @Override
- public JsonValue apply(final List<JsonValue> value, final Void p) {
- 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<Object>(value.size());
- for (final JsonValue e : value) {
- result.add(e.getObject());
- }
- return new JsonValue(result);
- }
- }
- }, h));
+ accumulate(dns.size(), transform(new Function<List<JsonValue>, JsonValue, Void>() {
+ @Override
+ public JsonValue apply(final List<JsonValue> value, final Void p) {
+ 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<Object>(value.size());
+ for (final JsonValue e : value) {
+ result.add(e.getObject());
+ }
+ return new JsonValue(result);
+ }
+ }
+ }, h));
for (final DN dn : dns) {
readEntry(c, path, dn, handler);
}
@@ -349,14 +334,18 @@
}
private void readEntry(final Context c, final JsonPointer path, final DN dn,
- final ResultHandler<JsonValue> handler) {
+ final ResultHandler<JsonValue> handler) {
final Set<String> requestedLDAPAttributes = new LinkedHashSet<String>();
mapper.getLDAPAttributes(c, path, new JsonPointer(), requestedLDAPAttributes);
- c.getConnection().readEntryAsync(dn, requestedLDAPAttributes,
- new org.forgerock.opendj.ldap.ResultHandler<SearchResultEntry>() {
-
+ c.getConnection().readEntryAsync(dn, requestedLDAPAttributes)
+ .onSuccess(new SuccessHandler<SearchResultEntry>() {
@Override
- public void handleErrorResult(final ErrorResultException error) {
+ public void handleResult(final SearchResultEntry result) {
+ mapper.read(c, path, result, handler);
+ }
+ }).onFailure(new FailureHandler<ErrorResultException>() {
+ @Override
+ public void handleError(final ErrorResultException error) {
if (!(error instanceof EntryNotFoundException)) {
handler.handleError(asResourceException(error));
} else {
@@ -367,11 +356,6 @@
handler.handleResult(null);
}
}
-
- @Override
- public void handleResult(final SearchResultEntry result) {
- mapper.read(c, path, result, handler);
- }
});
}
diff --git a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java
index ce3b916..16b4f14 100644
--- a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java
+++ b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/BasicRequestsTest.java
@@ -11,7 +11,7 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.rest2ldap;
@@ -779,11 +779,11 @@
@Override
public void handleSearch(RequestContext requestContext, SearchRequest request,
- IntermediateResponseHandler intermediateResponseHandler,
- SearchResultHandler resultHandler) {
+ IntermediateResponseHandler intermediateResponseHandler, SearchResultHandler entryHandler,
+ ResultHandler<Result> resultHandler) {
requests.add(request);
- handler.handleSearch(requestContext, request, intermediateResponseHandler,
- resultHandler);
+ handler.handleSearch(requestContext, request, intermediateResponseHandler, entryHandler,
+ resultHandler);
}
};
diff --git a/opendj-server2x-adapter/src/main/java/org/forgerock/opendj/adapter/server2x/Adapters.java b/opendj-server2x-adapter/src/main/java/org/forgerock/opendj/adapter/server2x/Adapters.java
index c8dadfb..52d100f 100644
--- a/opendj-server2x-adapter/src/main/java/org/forgerock/opendj/adapter/server2x/Adapters.java
+++ b/opendj-server2x-adapter/src/main/java/org/forgerock/opendj/adapter/server2x/Adapters.java
@@ -21,7 +21,7 @@
* CDDL HEADER END
*
*
- * Copyright 2013 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.forgerock.opendj.adapter.server2x;
@@ -37,10 +37,8 @@
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.controls.Control;
import org.forgerock.opendj.ldap.requests.AddRequest;
@@ -62,6 +60,7 @@
import org.forgerock.opendj.ldap.responses.GenericExtendedResult;
import org.forgerock.opendj.ldap.responses.Responses;
import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.util.promise.Promise;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
import org.opends.server.core.CompareOperation;
@@ -78,10 +77,9 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
-import com.forgerock.opendj.util.CompletedFutureResult;
-
import static org.forgerock.opendj.adapter.server2x.Converters.*;
import static org.forgerock.opendj.ldap.ByteString.*;
+import static org.forgerock.util.promise.Promises.*;
/**
* This class provides a connection factory and an adapter for the OpenDJ 2.x
@@ -141,8 +139,7 @@
* @return A new SDK connection factory.
*/
public static ConnectionFactory newConnectionFactory(final InternalClientConnection icc) {
- final Connection connection = newConnection(icc);
- ConnectionFactory factory = new ConnectionFactory() {
+ return new ConnectionFactory() {
@Override
public void close() {
@@ -150,20 +147,16 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- ResultHandler<? super Connection> handler) {
- if (handler != null) {
- handler.handleResult(connection);
- } // TODO change the path...
- return new CompletedFutureResult<Connection>(connection);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ // TODO change the path...
+ return newSuccessfulPromise(newConnection(icc));
}
@Override
public Connection getConnection() throws ErrorResultException {
- return connection;
+ return newConnection(icc);
}
};
- return factory;
}
/**
diff --git a/opendj-server3x-adapter/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java b/opendj-server3x-adapter/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
index f6abb09..e5b62bb 100644
--- a/opendj-server3x-adapter/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
+++ b/opendj-server3x-adapter/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
@@ -38,10 +38,8 @@
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.FutureResult;
import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.controls.Control;
import org.forgerock.opendj.ldap.requests.AddRequest;
@@ -63,6 +61,7 @@
import org.forgerock.opendj.ldap.responses.GenericExtendedResult;
import org.forgerock.opendj.ldap.responses.Responses;
import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.util.promise.Promise;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
import org.opends.server.core.CompareOperation;
@@ -78,10 +77,9 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
-import com.forgerock.opendj.util.CompletedFutureResult;
-
import static org.forgerock.opendj.adapter.server3x.Converters.*;
import static org.forgerock.opendj.ldap.ByteString.*;
+import static org.forgerock.util.promise.Promises.*;
/**
* This class provides a connection factory and an adapter for the OpenDJ 2.x
@@ -141,8 +139,7 @@
* @return A new SDK connection factory.
*/
public static ConnectionFactory newConnectionFactory(final InternalClientConnection icc) {
- final Connection connection = newConnection(icc);
- ConnectionFactory factory = new ConnectionFactory() {
+ return new ConnectionFactory() {
@Override
public void close() {
@@ -150,20 +147,16 @@
}
@Override
- public FutureResult<Connection> getConnectionAsync(
- ResultHandler<? super Connection> handler) {
- if (handler != null) {
- handler.handleResult(connection);
- } // TODO change the path...
- return new CompletedFutureResult<Connection>(connection);
+ public Promise<Connection, ErrorResultException> getConnectionAsync() {
+ // TODO change the path...
+ return newSuccessfulPromise(newConnection(icc));
}
@Override
public Connection getConnection() throws ErrorResultException {
- return connection;
+ return newConnection(icc);
}
};
- return factory;
}
/**
diff --git a/pom.xml b/pom.xml
index 6bc1ffc..2c814859 100644
--- a/pom.xml
+++ b/pom.xml
@@ -438,7 +438,7 @@
<dependency>
<groupId>org.forgerock.commons</groupId>
<artifactId>forgerock-util</artifactId>
- <version>1.3.0-SNAPSHOT</version>
+ <version>1.3.5-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
--
Gitblit v1.10.0