OPENDJ-1285 CR-4409 Migrate SDK from Futures to Promises
Connection, ConnectionFactory, ResultHandler and SearchResultHandler public APIs have been changed.
* Connection.java
In all xxxAsync method, the final handler parameter will be removed and the client is expected to register the handler with the returned promise. For search request, a SearchResultHandler is still required because it needs to handle search result entries/references.
* ConnectionFactory.java
In the method getConnectionAsync(), the final handler parameter will be removed.
* ResultHandler.java
Now extends SuccessHandler and FailureHandler in order to allow usage of then() method call.
* SearchResultHandler.java
Remove the inheritance link with ResultHandler. So client needs to register a ResultHandler instance when he calls searchAsync in addition to register a SearchResultHandler.
5 files deleted
2 files added
70 files modified
| | |
| | | */ |
| | | 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. |
| | |
| | | * 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(); |
| | | } |
| | | |
| | |
| | | * 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. |
| | |
| | | * 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(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @return The string representation of this authenticated connection factory. |
| | | */ |
| | | @Override |
| | | public String toString() { |
| | | StringBuilder builder = new StringBuilder(); |
| | | builder.append("AuthenticatedConnection("); |
| | |
| | | |
| | | } |
| | | |
| | | 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 |
| | |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public Connection getConnection() throws ErrorResultException { |
| | | final Connection connection = parentFactory.getConnection(); |
| | | BindResult bindResult = null; |
| | |
| | | } |
| | | |
| | | /** {@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; |
| | | } |
| | | } |
| | | ); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @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(); |
| | | } |
| | |
| | | <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> |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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. |
| | |
| | | // 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); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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} |
| | |
| | | */ |
| | | 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) { |
| | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | // Ignore |
| | | } |
| | | |
| | | @Override |
| | | public boolean handleReference(final SearchResultReference reference) { |
| | | if (firstReference == null) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * {@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()); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 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>() { |
| | | |
| | |
| | | } |
| | | |
| | | @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; |
| | | } |
| | |
| | | // 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); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@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) { |
| | |
| | | } |
| | | 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); |
| | | } |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | * <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(); |
| | |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | * Portions copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | |
| | | |
| | | 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) { |
| | |
| | | } |
| | | |
| | | @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); |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | | } |
| | | |
| | |
| | | * 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, |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2012 ForgeRock AS |
| | | * Copyright 2012-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | 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 |
| | |
| | | */ |
| | | @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); |
| | | } |
| | | |
| | | } |
| | |
| | | * |
| | | * |
| | | * 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 |
| | |
| | | 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("); |
| | |
| | | |
| | | } |
| | | |
| | | 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; |
| | | |
| | |
| | | parentFactory.close(); |
| | | } |
| | | |
| | | @Override |
| | | public Connection getConnection() throws ErrorResultException { |
| | | final Connection connection = parentFactory.getConnection(); |
| | | boolean bindSucceeded = false; |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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 |
| | |
| | | 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(); |
| | |
| | | } |
| | | } |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | */ |
| | | 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", |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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; |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | |
| | | @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 |
| | |
| | | } |
| | | |
| | | @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); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | 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; |
| | | } |
| | |
| | | } |
| | | |
| | | @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) { |
| | |
| | | } |
| | | |
| | | boolean isWaitingFuture() { |
| | | return value instanceof AsynchronousFutureResult; |
| | | return value instanceof FutureResultImpl; |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | |
| | | @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; |
| | |
| | | } else if (hasWaitingConnections()) { |
| | | holder = queue.removeFirst(); |
| | | } else { |
| | | holder = |
| | | new QueueElement(handler, timeSource.currentTimeMillis(), |
| | | getStackTraceIfDebugEnabled()); |
| | | holder = new QueueElement(timeSource.currentTimeMillis(), getStackTraceIfDebugEnabled()); |
| | | queue.add(holder); |
| | | } |
| | | } |
| | |
| | | final FutureResult<Connection> future = holder.getWaitingFuture(); |
| | | if (!future.isDone() && availableConnections.tryAcquire()) { |
| | | pendingConnectionAttempts.incrementAndGet(); |
| | | factory.getConnectionAsync(connectionResultHandler); |
| | | factory.getConnectionAsync().onSuccess(connectionSuccessHandler) |
| | | .onFailure(connectionFailureHandler); |
| | | } |
| | | return future; |
| | | } |
| | |
| | | // 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)); |
| | | } |
| | | } |
| | |
| | | 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", |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | * Portions copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | * |
| | | * @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. |
| | |
| | | * @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 |
| | |
| | | * |
| | | * @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 |
| | |
| | | * 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. |
| | |
| | | * |
| | | * @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. |
| | |
| | | * @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 |
| | |
| | | * |
| | | * @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. |
| | |
| | | * 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 |
| | |
| | | * |
| | | * @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. |
| | |
| | | * @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 |
| | |
| | | * @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 |
| | |
| | | * 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. |
| | |
| | | * 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 |
| | |
| | | * |
| | | * @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. |
| | |
| | | * @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 |
| | |
| | | * |
| | | * @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. |
| | |
| | | * 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. |
| | |
| | | * 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> |
| | | * |
| | |
| | | * 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. |
| | |
| | | * @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 |
| | |
| | | * |
| | | * @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}. |
| | |
| | | * @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 |
| | |
| | | * |
| | | * @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. |
| | |
| | | * @throws NullPointerException |
| | | * If the {@code request} was {@code null}. |
| | | */ |
| | | FutureResult<SearchResultEntry> searchSingleEntryAsync(SearchRequest request, |
| | | ResultHandler<? super SearchResultEntry> handler); |
| | | FutureResult<SearchResultEntry> searchSingleEntryAsync(SearchRequest request); |
| | | } |
| | |
| | | * |
| | | * |
| | | * 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 |
| | |
| | | |
| | | /** |
| | | * 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 |
| | |
| | | |
| | | 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 |
| | |
| | | * 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 |
| | |
| | | * @throws IllegalStateException |
| | | * If this connection pool has already been closed. |
| | | */ |
| | | @Override |
| | | Connection getConnection() throws ErrorResultException; |
| | | } |
| | |
| | | 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 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public FutureResult<Connection> getConnectionAsync( |
| | | final ResultHandler<? super Connection> handler) { |
| | | return factory.getConnectionAsync(handler); |
| | | public Promise<Connection, ErrorResultException> getConnectionAsync() { |
| | | return factory.getConnectionAsync(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | // Do nothing. |
| | | } |
| | | |
| | | @Override |
| | | public void close(org.forgerock.opendj.ldap.requests.UnbindRequest request, |
| | | String reason) { |
| | | // Do nothing. |
| | |
| | | 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 |
| | |
| | | * |
| | | * |
| | | * 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. |
| | | * |
| | |
| | | */ |
| | | 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(); |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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; |
| | | } |
| | | } |
| New file |
| | |
| | | /* |
| | | * 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() { |
| | | } |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | |
| | | * 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); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | * 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; |
| | |
| | | * @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; |
| | |
| | | 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); |
| | | } |
| | |
| | | * 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(); |
| | |
| | | * 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. |
| | |
| | | * 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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | /** |
| | | * 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(); |
| | | } |
| | | }; |
| | | |
| | | /** |
| | |
| | | * 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(); |
| | |
| | | |
| | | @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(); |
| | | } |
| | |
| | | |
| | | @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. |
| | |
| | | |
| | | @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(); |
| | | } |
| | |
| | | |
| | | @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()); |
| | | } |
| | | }; |
| | | |
| | |
| | | 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(); |
| | |
| | | |
| | | @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(); |
| | | } |
| | |
| | | |
| | | @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(); |
| | | } |
| | |
| | | @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(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | 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) { |
| | |
| | | * 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); |
| | | } |
| | | } |
| | | |
| | |
| | | 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() { |
| | |
| | | */ |
| | | 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 |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | | } |
| | |
| | | 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); |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | } |
| | | } |
| | | |
| | | 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; |
| | |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS. |
| | | * Portions copyright 2011-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | * {@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; |
| | | } |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | */ |
| | | @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; |
| | | } |
| | |
| | | */ |
| | | @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("); |
| | |
| | | * |
| | | * |
| | | * 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 |
| | |
| | | // 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("); |
| | |
| | | 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 |
| | |
| | | /* |
| | | * 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 |
| | |
| | | } |
| | | |
| | | @Override |
| | | public FutureResult<Connection> getConnectionAsync( |
| | | final ResultHandler<? super Connection> handler) { |
| | | return impl.getConnectionAsync(handler); |
| | | public Promise<Connection, ErrorResultException> getConnectionAsync() { |
| | | return impl.getConnectionAsync(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | * |
| | | * |
| | | * 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 |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * Copyright 2013 ForgeRock AS. |
| | | * Copyright 2013-2014 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | |
| | | } |
| | | resultHandler.handleResult(getResult(request, null, request)); |
| | | } catch (final ErrorResultException e) { |
| | | resultHandler.handleErrorResult(e); |
| | | resultHandler.handleError(e); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | resultHandler.handleResult(getCompareResult(request, entry, entry.containsAttribute( |
| | | assertion, null))); |
| | | } catch (final ErrorResultException e) { |
| | | resultHandler.handleErrorResult(e); |
| | | resultHandler.handleError(e); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | 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")); |
| | | } |
| | | |
| | |
| | | } |
| | | resultHandler.handleResult(getResult(request, entry, newEntry)); |
| | | } catch (final ErrorResultException e) { |
| | | resultHandler.handleErrorResult(e); |
| | | resultHandler.handleError(e); |
| | | } |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | * @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; |
| | |
| | | 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 |
| | |
| | | } |
| | | |
| | | // Send the entry back to the client. |
| | | if (!sendEntry(attributeFilter, resultHandler, entry)) { |
| | | if (!sendEntry(attributeFilter, entryHandler, entry)) { |
| | | // Client has disconnected or cancelled. |
| | | break; |
| | | } |
| | |
| | | } |
| | | 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); |
| | |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS. |
| | | * Portions copyright 2011-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | * @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); |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2011-2013 ForgeRock AS |
| | | * Copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | final R cancelResult = |
| | | request.getResultDecoder().newExtendedErrorResult(ResultCode.TOO_LATE, "", |
| | | ""); |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult(cancelResult)); |
| | | resultHandler.handleError(ErrorResultException.newErrorResult(cancelResult)); |
| | | } |
| | | } |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | if (clientConnection.removePendingRequest(this)) { |
| | | if (setResult(error.getResult())) { |
| | | /* |
| | |
| | | * not be sent to the client. |
| | | */ |
| | | } |
| | | resultHandler.handleErrorResult(error); |
| | | resultHandler.handleError(error); |
| | | } |
| | | } |
| | | |
| | |
| | | if (cancelResultHandler != null) { |
| | | final Result result = |
| | | Responses.newGenericExtendedResult(ResultCode.CANNOT_CANCEL); |
| | | cancelResultHandler.handleErrorResult(newErrorResult(result)); |
| | | cancelResultHandler.handleError(newErrorResult(result)); |
| | | } |
| | | return; |
| | | } |
| | |
| | | cancelResultHandler.handleResult(result); |
| | | } else { |
| | | final Result result = Responses.newGenericExtendedResult(ResultCode.TOO_LATE); |
| | | cancelResultHandler.handleErrorResult(ErrorResultException |
| | | cancelResultHandler.handleError(ErrorResultException |
| | | .newErrorResult(result)); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * 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; |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Override |
| | | public boolean handleEntry(final SearchResultEntry entry) { |
| | | return resultHandler.handleEntry(entry); |
| | | return entryHandler.handleEntry(entry); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Override |
| | | public boolean handleReference(final SearchResultReference reference) { |
| | | return resultHandler.handleReference(reference); |
| | | return entryHandler.handleReference(reference); |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | | } |
| | |
| | | * 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 { |
| | |
| | | */ |
| | | @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); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | 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()) { |
| | | /* |
| | |
| | | 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 { |
| | | /* |
| | |
| | | * |
| | | * |
| | | * 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. |
| | |
| | | * @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. |
| | | * |
| | |
| | | * 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. |
| | |
| | | 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 |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | 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 |
| | |
| | | } |
| | | |
| | | 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; |
| | |
| | | * |
| | | * |
| | | * 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; |
| | | |
| | |
| | | * 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. |
| | |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2012 ForgeRock AS. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap.responses; |
| | |
| | | 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 |
| | |
| | | resultHandler.handleResult(adaptedResult); |
| | | } catch (final DecodeException e) { |
| | | final R adaptedResult = request.getResultDecoder().adaptDecodeException(e); |
| | | resultHandler.handleErrorResult(newErrorResult(adaptedResult)); |
| | | resultHandler.handleError(newErrorResult(adaptedResult)); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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 |
| | |
| | | * 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 |
| | |
| | | * @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; |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @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. |
| | |
| | | * @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(); |
| | | } |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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); |
| | |
| | | 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(); |
| | | |
| | | /** |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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 |
| | |
| | | // 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", |
| | |
| | | |
| | | 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_-]+$")) { |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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_-]+$")) { |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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 |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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_-]+$")) { |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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 |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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_-]+$")) { |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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_-]+$")) { |
| | |
| | | } |
| | | } |
| | | |
| | | 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()) { |
| | |
| | | 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 { |
| | |
| | | * 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 |
| | |
| | | * 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; |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | * @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. |
| | |
| | | * @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); |
| | | } |
| | | })); |
| | | } |
| | | |
| | | /** |
| | |
| | | // 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); |
| | | } |
| | | |
| | |
| | | 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)); |
| | |
| | | |
| | | // 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); |
| | | |
| | |
| | | * |
| | | * |
| | | * 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. |
| | |
| | | * @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; |
| | |
| | | * |
| | | * @param requestID |
| | | * identifier of the request |
| | | * @param resultHandler |
| | | * handler that consumes the result |
| | | * @param intermediateResponseHandler |
| | | * handler that consumes intermediate responses from extended |
| | | * operations |
| | |
| | | * 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(); |
| | |
| | | // 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}. |
| | |
| | | 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | |
| | |
| | | * 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. |
| | |
| | | */ |
| | | public final void setResultOrError(final S result) { |
| | | if (result.getResultCode().isExceptional()) { |
| | | handleErrorResult(ErrorResultException.newErrorResult(result)); |
| | | handleError(ErrorResultException.newErrorResult(result)); |
| | | } else { |
| | | handleResult(result); |
| | | } |
| | |
| | | * |
| | | * |
| | | * 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.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; |
| | |
| | | * 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 |
| | |
| | | * 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; |
| | | } |
| | | |
| | |
| | | return bindClient; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected BindResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | |
| | | * |
| | | * |
| | | * 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.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; |
| | |
| | | * 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 |
| | |
| | | * 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; |
| | | } |
| | | |
| | |
| | | return request; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | protected CompareResult newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | |
| | | * |
| | | * |
| | | * 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.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; |
| | |
| | | * identifier of the request |
| | | * @param request |
| | | * extended request |
| | | * @param resultHandler |
| | | * handler that consumes result |
| | | * @param intermediateResponseHandler |
| | | * handler that consumes intermediate responses from extended |
| | | * operations |
| | |
| | | * 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; |
| | | } |
| | | |
| | |
| | | |
| | | @Override |
| | | public boolean isBindOrStartTLS() { |
| | | return request.getOID().equals(StartTLSExtendedRequest.OID); |
| | | return StartTLSExtendedRequest.OID.equals(request.getOID()); |
| | | } |
| | | |
| | | /** |
| | |
| | | return request; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | protected R newErrorResult(final ResultCode resultCode, final String diagnosticMessage, |
| | | final Throwable cause) { |
| | |
| | | * |
| | | * |
| | | * 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.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; |
| | |
| | | * 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 |
| | |
| | | * 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; |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS. |
| | | * Portions copyright 2011-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap.spi; |
| | |
| | | * 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); |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | /** |
| | | * 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; |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | try { |
| | | responses.put(error.getResult()); |
| | | } catch (final InterruptedException e) { |
| | |
| | | * 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); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * |
| | | * 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; |
| | | |
| | |
| | | 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 |
| | |
| | | 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"; |
| | | } |
| | |
| | | @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(); |
| | |
| | | @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(); |
| | |
| | | @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); |
| | | } |
| | |
| | | @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(); |
| | |
| | | @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); |
| | | } |
| | |
| | | @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(); |
| | |
| | | @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); |
| | | } |
| | |
| | | @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(); |
| | |
| | | @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); |
| | | } |
| | |
| | | @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(); |
| | |
| | | @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); |
| | | } |
| | |
| | | @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(); |
| | |
| | | |
| | | @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); |
| | |
| | | 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()); |
| | |
| | | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | @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); |
| | | } |
| | |
| | | @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)); |
| | | } |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | |
| | | 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)); |
| | | } |
| | | } |
| | | |
| | |
| | | * 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 { |
| | |
| | | } |
| | | |
| | | @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); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | 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; |
| | |
| | | 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.. |
| | | */ |
| | |
| | | * 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 |
| | |
| | | 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); |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2013 ForgeRock AS. |
| | | * Copyright 2013-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | |
| | | |
| | | 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; |
| | |
| | | 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.*; |
| | |
| | | } |
| | | } |
| | | |
| | | @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 |
| | |
| | | @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 |
| | |
| | | |
| | | // 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); |
| | | |
| | |
| | | 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(); |
| | | |
| | | /* |
| | |
| | | * 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(); |
| | |
| | | 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(); |
| | |
| | | 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 |
| | |
| | | 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)); |
| | | } |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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. |
| | |
| | | // No response is needed. |
| | | } |
| | | |
| | | @Override |
| | | public void handleAdd(final Integer context, final AddRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<Result> handler) throws UnsupportedOperationException { |
| | |
| | | // 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; |
| | |
| | | if (abReq.isCanceled()) { |
| | | result = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | handler.handleError(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | | } |
| | |
| | | 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 { |
| | |
| | | Sasl.createSaslServer(saslMech, "ldap", |
| | | listener.getHostName(), props, |
| | | new CallbackHandler() { |
| | | @Override |
| | | public void handle(Callback[] callbacks) |
| | | throws IOException, |
| | | UnsupportedCallbackException { |
| | |
| | | && (qop.equalsIgnoreCase("auth-int") || qop |
| | | .equalsIgnoreCase("auth-conf"))) { |
| | | ConnectionSecurityLayer csl = new ConnectionSecurityLayer() { |
| | | @Override |
| | | public void dispose() { |
| | | try { |
| | | saslServer.dispose(); |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public byte[] unwrap(byte[] incoming, int offset, int len) |
| | | throws ErrorResultException { |
| | | try { |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public byte[] wrap(byte[] outgoing, int offset, int len) |
| | | throws ErrorResultException { |
| | | try { |
| | |
| | | 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()))); |
| | | } |
| | |
| | | requestsInProgress.remove(context); |
| | | } |
| | | |
| | | @Override |
| | | public void handleConnectionClosed(final Integer context, final UnbindRequest request) { |
| | | close(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | @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) |
| | |
| | | // 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; |
| | |
| | | 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; |
| | | } |
| | |
| | | requestsInProgress.remove(context); |
| | | } |
| | | |
| | | @Override |
| | | public void handleDelete(final Integer context, final DeleteRequest request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | | final ResultHandler<Result> handler) throws UnsupportedOperationException { |
| | |
| | | // 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; |
| | |
| | | if (abReq.isCanceled()) { |
| | | result = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | handler.handleError(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | | } |
| | |
| | | handler.handleResult(result); |
| | | } |
| | | |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest(final Integer context, |
| | | final ExtendedRequest<R> request, |
| | | final IntermediateResponseHandler intermediateResponseHandler, |
| | |
| | | } |
| | | } |
| | | |
| | | @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); |
| | |
| | | // 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. |
| | |
| | | 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); |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept(final LDAPClientContext context) { |
| | | return new LDAPServerConnection(context); |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | * 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; |
| | | } |
| | | |
| | |
| | | */ |
| | | 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. |
| | |
| | | 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 = |
| | |
| | | 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; |
| | | |
| | | /** |
| | |
| | | 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(); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | 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. |
| | |
| | | @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)); |
| | | } |
| | | |
| | | /** |
| | |
| | | * |
| | | * @return The address of the Directory Server. |
| | | */ |
| | | @Override |
| | | public InetSocketAddress getSocketAddress() { |
| | | return new InetSocketAddress(host, port); |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2011 ForgeRock AS |
| | | * Portions copyright 2012 ForgeRock AS. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldif; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | import org.mockito.stubbing.Answer; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import com.forgerock.opendj.util.CompletedFutureResult; |
| | | |
| | | /** |
| | | * This class tests the ConnectionEntryReader functionality. |
| | | */ |
| | |
| | | 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); |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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 |
| | |
| | | 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); |
| | | } |
| | | |
| | | /* |
| | |
| | | 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); |
| | | } |
| | |
| | | |
| | | @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(); |
| | |
| | | |
| | | @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); |
| | |
| | | |
| | | @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(); |
| | |
| | | |
| | | @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(); |
| | |
| | | } |
| | | |
| | | @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 { |
| | |
| | | |
| | | @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(); |
| | |
| | | |
| | | @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(); |
| | |
| | | } |
| | | } |
| | | |
| | | /** {@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(); |
| | |
| | | */ |
| | | 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); |
| | | |
| | | /* |
| | |
| | | * 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; |
| | |
| | | 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); |
| | | } |
| | |
| | | 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"); |
| | | } |
| | | } |
| | | |
| | |
| | | * 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); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | @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; |
| | |
| | | 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); |
| | | } |
| | |
| | | public void failed(final Throwable throwable) { |
| | | // Adapt and forward. |
| | | timeoutChecker.get().removeListener(this); |
| | | future.handleErrorResult(adaptConnectionException(throwable)); |
| | | future.handleError(adaptConnectionException(throwable)); |
| | | releaseTransportAndTimeoutChecker(); |
| | | } |
| | | |
| | |
| | | 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(); |
| | | } |
| | | |
| | |
| | | } 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; |
| | | } |
| | |
| | | @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; |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2012-2013 ForgeRock AS. |
| | | * Portions copyright 2012-2014 ForgeRock AS. |
| | | */ |
| | | |
| | | package org.forgerock.opendj.grizzly; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | | * |
| | |
| | | // 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(); |
| | |
| | | */ |
| | | @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(); |
| | | } |
| | | |
| | |
| | | @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? |
| | | } |
| | | |
| | | /** |
| | |
| | | * @throws Exception |
| | | * If an unexpected exception occurred. |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | @Test |
| | | public void testConnectionPoolClose() throws Exception { |
| | | // We'll use a pool of 4 connections. |
| | |
| | | |
| | | // 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]; |
| | |
| | | } |
| | | |
| | | 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) { |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | @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 { |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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 |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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(); |
| | | } |
| | | |
| | |
| | | @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); |
| | |
| | | } |
| | | } |
| | | |
| | | 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 |
| | |
| | | } |
| | | |
| | | 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() { |
| | |
| | | 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; |
| | | |
| | |
| | | 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); |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | 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() { |
| | |
| | | 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"))); |
| | | } |
| | |
| | | */ |
| | | @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)); |
| | | } |
| | | |
| | |
| | | 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)); |
| | | } |
| | |
| | | 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) { |
| | |
| | | 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)); |
| | | } |
| | |
| | | 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 { |
| | |
| | | * |
| | | * |
| | | * 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; |
| | |
| | | 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 |
| | |
| | | * |
| | | * <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) { |
| | |
| | | request.addControl(control); |
| | | } |
| | | } |
| | | |
| | | private Runnable close(final AtomicReference<Connection> c) { |
| | | return new Runnable() { |
| | | @Override |
| | | public void run() { |
| | | closeSilently(c.get()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2013 ForgeRock AS |
| | | * Portions copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.examples; |
| | |
| | | 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"; |
| | | |
| | |
| | | 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) { |
| | |
| | | |
| | | @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) { |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions copyright 2011-2012 ForgeRock AS |
| | | * Portions copyright 2011-2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.examples; |
| | |
| | | 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 |
| | |
| | | * </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) { |
| | |
| | | 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(); |
| | |
| | | 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); |
| | |
| | | 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. |
| | | * |
| | |
| | | */ |
| | | 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); |
| | | } |
| | | |
| | |
| | | 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 { |
| | |
| | | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | |
| | | 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); |
| | |
| | | } |
| | | |
| | | @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) { |
| | |
| | | } |
| | | |
| | | 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; |
| | | } |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | } |
| | | |
| | | @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(); |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | 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) { |
| | |
| | | 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. |
| | |
| | | } |
| | | } |
| | | |
| | | return connection.bindAsync(br, null, handler); |
| | | return connection.bindAsync(br); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | private int entryCount; |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean handleEntry(final SearchResultEntry entry) { |
| | | entryCount++; |
| | | |
| | |
| | | } |
| | | |
| | | /** {@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. |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isInteractive() { |
| | | return false; |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | |
| | | } |
| | | |
| | | @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) { |
| | |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean isInteractive() { |
| | | return false; |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | } |
| | | |
| | | private class TimerThread extends Thread { |
| | | private long timeToWait; |
| | | private final long timeToWait; |
| | | |
| | | public TimerThread(long timeToWait) { |
| | | this.timeToWait = timeToWait; |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | failedRecentCount.getAndIncrement(); |
| | | updateStats(); |
| | | app.errPrintVerboseMessage(LocalizableMessage.raw(error.getResult().toString())); |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | 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 |
| | |
| | | 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); |
| | | } |
| | |
| | | */ |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | } |
| | | |
| | | @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) { |
| | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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. |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | }); |
| | | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | 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 |
| | |
| | | * 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; |
| | | } |
| | | } |
| | |
| | | * 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) { |
| | | /* |
| | |
| | | * 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. |
| | |
| | | } |
| | | } |
| | | } |
| | | }).onFailure(new FailureHandler<ErrorResultException>() { |
| | | @Override |
| | | public void handleError(final ErrorResultException error) { |
| | | sync.signalAndComplete(asResourceException(error)); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | private AuthenticationMethod parseAuthenticationMethod(final JsonValue configuration) { |
| | |
| | | * 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; |
| | |
| | | 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 |
| | |
| | | /* |
| | | * 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. |
| | |
| | | } |
| | | |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) { |
| | | public void handleError(final ErrorResultException error) { |
| | | handleResult(error.getResult()); |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | 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. |
| | | } |
| | |
| | | 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); |
| | |
| | | } |
| | | } 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; |
| | | } |
| | | } |
| | |
| | | // 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"))); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | @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 |
| | |
| | | |
| | | @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 |
| | |
| | | |
| | | @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 |
| | |
| | | |
| | | @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 |
| | |
| | | */ |
| | | @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. |
| | |
| | | } |
| | | 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; |
| | | } |
| | |
| | | * 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; |
| | |
| | | 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; |
| | |
| | | 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)); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | |
| | | 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)); |
| | | } |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | |
| | | @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)); |
| | | } |
| | | }); |
| | | } |
| | | })); |
| | | } |
| | |
| | | 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); |
| | |
| | | @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(); |
| | |
| | | .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) { |
| | |
| | | } |
| | | |
| | | /* |
| | | * 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(); |
| | | } |
| | |
| | | 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); |
| | | |
| | |
| | | // 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 |
| | |
| | | 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)); |
| | | } |
| | | } |
| | | }); |
| | |
| | | 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( |
| | |
| | | // 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 { |
| | |
| | | updateHandler.handleError(asResourceException(e)); |
| | | } |
| | | } |
| | | }).onFailure(new FailureHandler<ErrorResultException>() { |
| | | @Override |
| | | public void handleError(final ErrorResultException error) { |
| | | updateHandler.handleError(asResourceException(error)); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | 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)); |
| | | } |
| | | } |
| | | } |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | @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; |
| | | } |
| | | |
| | |
| | | |
| | | }; |
| | | /* |
| | | * 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); |
| | | } |
| | |
| | | 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 { |
| | |
| | | }; |
| | | } |
| | | |
| | | 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 { |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | }; |
| | | } |
| | | |
| | | 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 |
| | |
| | | * 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; |
| | |
| | | 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. |
| | | */ |
| | |
| | | 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; |
| | |
| | | } |
| | | |
| | | @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 |
| | |
| | | */ |
| | | 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>>() { |
| | |
| | | |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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() { |
| | |
| | | } |
| | | |
| | | @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); |
| | |
| | | } |
| | | } 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); |
| | | } |
| | |
| | | } |
| | | |
| | | 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 { |
| | |
| | | handler.handleResult(null); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void handleResult(final SearchResultEntry result) { |
| | | mapper.read(c, path, result, handler); |
| | | } |
| | | }); |
| | | } |
| | | |
| | |
| | | * 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; |
| | | |
| | |
| | | |
| | | @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); |
| | | } |
| | | |
| | | }; |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2013 ForgeRock AS. |
| | | * Copyright 2013-2014 ForgeRock AS. |
| | | */ |
| | | package org.forgerock.opendj.adapter.server2x; |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | * @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() { |
| | |
| | | } |
| | | |
| | | @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; |
| | | } |
| | | |
| | | /** |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | * @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() { |
| | |
| | | } |
| | | |
| | | @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; |
| | | } |
| | | |
| | | /** |
| | |
| | | <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> |