| | |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * Proxy server connection factory implementation. |
| | | */ |
| | | private static final class Proxy implements |
| | | ServerConnectionFactory<LDAPClientContext, Integer> |
| | | private static final class ProxyBackend implements |
| | | RequestHandler<RequestContext> |
| | | { |
| | | private final class ServerConnectionImpl implements |
| | | ServerConnection<Integer> |
| | | { |
| | | |
| | | private abstract class AbstractRequestCompletionHandler<R extends Result, |
| | | H extends ResultHandler<? super R>> |
| | | implements ResultHandler<R> |
| | | { |
| | | final H resultHandler; |
| | | final AsynchronousConnection connection; |
| | | |
| | | |
| | | |
| | | AbstractRequestCompletionHandler( |
| | | final AsynchronousConnection 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<AsynchronousConnection> |
| | | { |
| | | private final ResultHandler<? super R> resultHandler; |
| | | |
| | | |
| | | |
| | | ConnectionCompletionHandler( |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleErrorResult( |
| | | final ErrorResultException error) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public abstract void handleResult( |
| | | AsynchronousConnection connection); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final class RequestCompletionHandler<R extends Result> |
| | | extends |
| | | AbstractRequestCompletionHandler<R, ResultHandler<? super R>> |
| | | { |
| | | RequestCompletionHandler( |
| | | final AsynchronousConnection connection, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | super(connection, resultHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class SearchRequestCompletionHandler |
| | | extends |
| | | AbstractRequestCompletionHandler<Result, SearchResultHandler> |
| | | implements SearchResultHandler |
| | | { |
| | | |
| | | SearchRequestCompletionHandler( |
| | | final AsynchronousConnection 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 volatile ProxiedAuthV2RequestControl proxiedAuthControl = null; |
| | | |
| | | |
| | | |
| | | private ServerConnectionImpl( |
| | | final LDAPClientContext clientContext) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer requestContext, |
| | | final AbandonRequest request) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // Not implemented. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd( |
| | | final Integer requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.add(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind( |
| | | final Integer requestContext, |
| | | final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(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 AsynchronousConnection 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.bind(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | proxiedAuthControl = null; |
| | | bindFactory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare( |
| | | final Integer requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<CompareResult> outerHandler = |
| | | new ConnectionCompletionHandler<CompareResult>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<CompareResult> innerHandler = |
| | | new RequestCompletionHandler<CompareResult>(connection, resultHandler); |
| | | connection.compare(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed( |
| | | final Integer requestContext, final UnbindRequest request) |
| | | { |
| | | // Client connection closed. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected( |
| | | final ResultCode resultCode, final String message) |
| | | { |
| | | // Client disconnected by server. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | // Client connection failed. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete( |
| | | final Integer requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.delete(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final Integer requestContext, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getOID().equals(CancelExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Cancel extended request operation not supported")); |
| | | } |
| | | else if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(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 AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<R> innerHandler = |
| | | new RequestCompletionHandler<R>(connection, resultHandler); |
| | | connection.extendedRequest(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify( |
| | | final Integer requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modify(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN( |
| | | final Integer requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyDN(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch( |
| | | final Integer requestContext, |
| | | final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final SearchRequestCompletionHandler innerHandler = |
| | | new SearchRequestCompletionHandler(connection, resultHandler); |
| | | connection.search(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | private void addProxiedAuthControl(final Request request) |
| | | { |
| | | final ProxiedAuthV2RequestControl control = proxiedAuthControl; |
| | | if (control != null) |
| | | { |
| | | request.addControl(control); |
| | | } |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final ConnectionFactory factory; |
| | | private final ConnectionFactory bindFactory; |
| | | |
| | | |
| | | |
| | | private Proxy(final ConnectionFactory factory, |
| | | private ProxyBackend(final ConnectionFactory factory, |
| | | final ConnectionFactory bindFactory) |
| | | { |
| | | this.factory = factory; |
| | |
| | | |
| | | |
| | | |
| | | private abstract class AbstractRequestCompletionHandler |
| | | <R extends Result, H extends ResultHandler<? super R>> |
| | | implements ResultHandler<R> |
| | | { |
| | | final H resultHandler; |
| | | final AsynchronousConnection connection; |
| | | |
| | | |
| | | |
| | | AbstractRequestCompletionHandler( |
| | | final AsynchronousConnection 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<AsynchronousConnection> |
| | | { |
| | | private final ResultHandler<? super R> resultHandler; |
| | | |
| | | |
| | | |
| | | ConnectionCompletionHandler( |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public final void handleErrorResult( |
| | | final ErrorResultException error) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | |
| | | |
| | | |
| | | @Override |
| | | public abstract void handleResult( |
| | | AsynchronousConnection connection); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final class RequestCompletionHandler<R extends Result> |
| | | extends |
| | | AbstractRequestCompletionHandler<R, ResultHandler<? super R>> |
| | | { |
| | | RequestCompletionHandler( |
| | | final AsynchronousConnection connection, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | super(connection, resultHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final class SearchRequestCompletionHandler extends |
| | | AbstractRequestCompletionHandler<Result, SearchResultHandler> |
| | | implements SearchResultHandler |
| | | { |
| | | |
| | | SearchRequestCompletionHandler( |
| | | final AsynchronousConnection 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 volatile ProxiedAuthV2RequestControl proxiedAuthControl = null; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) |
| | | throws ErrorResultException |
| | | public void handleAdd(final RequestContext requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | return new ServerConnectionImpl(clientContext); |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.add(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, |
| | | final int version, final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(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 AsynchronousConnection 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.bind(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | proxiedAuthControl = null; |
| | | bindFactory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<CompareResult> outerHandler = |
| | | new ConnectionCompletionHandler<CompareResult>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<CompareResult> innerHandler = |
| | | new RequestCompletionHandler<CompareResult>(connection, resultHandler); |
| | | connection.compare(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.delete(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getOID().equals(CancelExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Cancel extended request operation not supported")); |
| | | } |
| | | else if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(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 AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<R> innerHandler = |
| | | new RequestCompletionHandler<R>(connection, resultHandler); |
| | | connection.extendedRequest(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modify(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final RequestCompletionHandler<Result> innerHandler = |
| | | new RequestCompletionHandler<Result>(connection, resultHandler); |
| | | connection.modifyDN(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, |
| | | final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | addProxiedAuthControl(request); |
| | | final ConnectionCompletionHandler<Result> outerHandler = |
| | | new ConnectionCompletionHandler<Result>(resultHandler) |
| | | { |
| | | |
| | | @Override |
| | | public void handleResult( |
| | | final AsynchronousConnection connection) |
| | | { |
| | | final SearchRequestCompletionHandler innerHandler = |
| | | new SearchRequestCompletionHandler(connection, resultHandler); |
| | | connection.search(request, innerHandler, |
| | | intermediateResponseHandler); |
| | | } |
| | | |
| | | }; |
| | | |
| | | factory.getAsynchronousConnection(outerHandler); |
| | | } |
| | | |
| | | |
| | | |
| | | private void addProxiedAuthControl(final Request request) |
| | | { |
| | | final ProxiedAuthV2RequestControl control = proxiedAuthControl; |
| | | if (control != null) |
| | | { |
| | | request.addControl(control); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | new LDAPConnectionFactory(remoteAddress, remotePort), |
| | | Integer.MAX_VALUE)); |
| | | } |
| | | final RoundRobinLoadBalancingAlgorithm algorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(factories); |
| | | final RoundRobinLoadBalancingAlgorithm bindAlgorithm = |
| | | new RoundRobinLoadBalancingAlgorithm(bindFactories); |
| | | final RoundRobinLoadBalancingAlgorithm algorithm = new RoundRobinLoadBalancingAlgorithm( |
| | | factories); |
| | | final RoundRobinLoadBalancingAlgorithm bindAlgorithm = new RoundRobinLoadBalancingAlgorithm( |
| | | bindFactories); |
| | | final ConnectionFactory factory = Connections |
| | | .newLoadBalancer(algorithm); |
| | | final ConnectionFactory bindFactory = Connections |
| | | .newLoadBalancer(bindAlgorithm); |
| | | |
| | | // Create a server connection adapter. |
| | | final ProxyBackend backend = new ProxyBackend(factory, bindFactory); |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = |
| | | Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, new Proxy( |
| | | factory, bindFactory), options); |
| | | listener = new LDAPListener(localAddress, localPort, |
| | | connectionHandler, options); |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } |
| | |
| | | */ |
| | | public final class Main |
| | | { |
| | | /** |
| | | * Proxy server connection factory implementation. |
| | | */ |
| | | private static final class Store implements |
| | | ServerConnectionFactory<LDAPClientContext, Integer> |
| | | private static final class MemoryBackend implements |
| | | RequestHandler<RequestContext> |
| | | { |
| | | private final class ServerConnectionImpl implements |
| | | ServerConnection<Integer> |
| | | { |
| | | |
| | | private ServerConnectionImpl( |
| | | final LDAPClientContext clientContext) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer requestContext, |
| | | final AbandonRequest request) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // Not implemented. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd( |
| | | final Integer requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | if (entries.containsKey(dn)) |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | "The entry " + dn.toString() |
| | | + " already exists")); |
| | | } |
| | | |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, |
| | | "The parent entry " + parent.toString() |
| | | + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.put(dn, request); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind( |
| | | final Integer requestContext, |
| | | final int version, |
| | | final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } |
| | | else |
| | | { |
| | | // TODO: always succeed. |
| | | resultHandler.handleResult(Responses |
| | | .newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare( |
| | | final Integer requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed( |
| | | final Integer requestContext, final UnbindRequest request) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected( |
| | | final ResultCode resultCode, final String message) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | // Nothing to do. |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete( |
| | | final Integer requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | // TODO: check for children. |
| | | DN dn = request.getName(); |
| | | if (!entries.containsKey(dn)) |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, |
| | | "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.remove(dn); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final Integer requestContext, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Extended request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify( |
| | | final Integer requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls. |
| | | // TODO: read lock is not really enough since concurrent updates may |
| | | // still occur to the same entry. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry entry = entries.get(dn); |
| | | if (entry == null) |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, |
| | | "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | |
| | | Entry newEntry = new LinkedHashMapEntry(entry); |
| | | for (Modification mod : request.getModifications()) |
| | | { |
| | | ModificationType modType = mod.getModificationType(); |
| | | if (modType.equals(ModificationType.ADD)) |
| | | { |
| | | // TODO: Reject empty attribute and duplicate values. |
| | | newEntry.addAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.DELETE)) |
| | | { |
| | | // TODO: Reject missing values. |
| | | newEntry.removeAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.REPLACE)) |
| | | { |
| | | newEntry.replaceAttribute(mod.getAttribute()); |
| | | } |
| | | else |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Modify request contains an unsupported modification type")); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | entries.put(dn, newEntry); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN( |
| | | final Integer requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "ModifyDN request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch( |
| | | final Integer requestContext, |
| | | final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls, limits, etc. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry baseEntry = entries.get(dn); |
| | | if (baseEntry == null) |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, |
| | | "The entry " + dn.toString() |
| | | + " does not exist")); |
| | | } |
| | | |
| | | SearchScope scope = request.getScope(); |
| | | Filter filter = request.getFilter(); |
| | | Matcher matcher = filter.matcher(); |
| | | |
| | | if (scope.equals(SearchScope.BASE_OBJECT)) |
| | | { |
| | | if (matcher.matches(baseEntry).toBoolean()) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.SINGLE_LEVEL)) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn, |
| | | false); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isChildOf(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } |
| | | else if (!childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.WHOLE_SUBTREE)) |
| | | { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Search request contains an unsupported search scope")); |
| | | return; |
| | | } |
| | | |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean sendEntry(SearchRequest request, |
| | | SearchResultHandler resultHandler, Entry entry) |
| | | { |
| | | // TODO: check filter, strip attributes. |
| | | return resultHandler.handleEntry(Responses |
| | | .newSearchResultEntry(entry)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private final ConcurrentSkipListMap<DN, Entry> entries; |
| | | |
| | | private final ReentrantReadWriteLock entryLock = new ReentrantReadWriteLock(); |
| | | |
| | | |
| | | |
| | | private Store(final ConcurrentSkipListMap<DN, Entry> entries) |
| | | private MemoryBackend( |
| | | final ConcurrentSkipListMap<DN, Entry> entries) |
| | | { |
| | | this.entries = entries; |
| | | } |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept( |
| | | final LDAPClientContext clientContext) |
| | | throws ErrorResultException |
| | | public void handleAdd(final RequestContext requestContext, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | return new ServerConnectionImpl(clientContext); |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | if (entries.containsKey(dn)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.ENTRY_ALREADY_EXISTS, |
| | | "The entry " + dn.toString() + " already exists")); |
| | | } |
| | | |
| | | DN parent = dn.parent(); |
| | | if (!entries.containsKey(parent)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, |
| | | "The parent entry " + parent.toString() |
| | | + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.put(dn, request); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final RequestContext requestContext, |
| | | final int version, final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getAuthenticationType() != ((byte) 0x80)) |
| | | { |
| | | // TODO: SASL authentication not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "non-SIMPLE authentication not supported: " |
| | | + request.getAuthenticationType())); |
| | | } |
| | | else |
| | | { |
| | | // TODO: always succeed. |
| | | resultHandler.handleResult(Responses |
| | | .newBindResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final RequestContext requestContext, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final RequestContext requestContext, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls. |
| | | entryLock.writeLock().lock(); |
| | | try |
| | | { |
| | | // TODO: check for children. |
| | | DN dn = request.getName(); |
| | | if (!entries.containsKey(dn)) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry " |
| | | + dn.toString() + " does not exist")); |
| | | } |
| | | else |
| | | { |
| | | entries.remove(dn); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | entryLock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final RequestContext requestContext, |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Extended request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final RequestContext requestContext, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls. |
| | | // TODO: read lock is not really enough since concurrent updates may |
| | | // still occur to the same entry. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry entry = entries.get(dn); |
| | | if (entry == null) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry " |
| | | + dn.toString() + " does not exist")); |
| | | } |
| | | |
| | | Entry newEntry = new LinkedHashMapEntry(entry); |
| | | for (Modification mod : request.getModifications()) |
| | | { |
| | | ModificationType modType = mod.getModificationType(); |
| | | if (modType.equals(ModificationType.ADD)) |
| | | { |
| | | // TODO: Reject empty attribute and duplicate values. |
| | | newEntry.addAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.DELETE)) |
| | | { |
| | | // TODO: Reject missing values. |
| | | newEntry.removeAttribute(mod.getAttribute(), null); |
| | | } |
| | | else if (modType.equals(ModificationType.REPLACE)) |
| | | { |
| | | newEntry.replaceAttribute(mod.getAttribute()); |
| | | } |
| | | else |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Modify request contains an unsupported modification type")); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | entries.put(dn, newEntry); |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final RequestContext requestContext, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: not implemented. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "ModifyDN request operation not supported")); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final RequestContext requestContext, |
| | | final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | // TODO: controls, limits, etc. |
| | | entryLock.readLock().lock(); |
| | | try |
| | | { |
| | | DN dn = request.getName(); |
| | | Entry baseEntry = entries.get(dn); |
| | | if (baseEntry == null) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry " |
| | | + dn.toString() + " does not exist")); |
| | | } |
| | | |
| | | SearchScope scope = request.getScope(); |
| | | Filter filter = request.getFilter(); |
| | | Matcher matcher = filter.matcher(); |
| | | |
| | | if (scope.equals(SearchScope.BASE_OBJECT)) |
| | | { |
| | | if (matcher.matches(baseEntry).toBoolean()) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.SINGLE_LEVEL)) |
| | | { |
| | | sendEntry(request, resultHandler, baseEntry); |
| | | |
| | | NavigableMap<DN, Entry> subtree = entries |
| | | .tailMap(dn, false); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isChildOf(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } |
| | | else if (!childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else if (scope.equals(SearchScope.WHOLE_SUBTREE)) |
| | | { |
| | | NavigableMap<DN, Entry> subtree = entries.tailMap(dn); |
| | | for (Entry entry : subtree.values()) |
| | | { |
| | | // Check for cancellation. |
| | | requestContext.checkIfCancelled(false); |
| | | |
| | | DN childDN = entry.getName(); |
| | | if (childDN.isSubordinateOrEqualTo(dn)) |
| | | { |
| | | if (!matcher.matches(entry).toBoolean()) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | if (!sendEntry(request, resultHandler, entry)) |
| | | { |
| | | // Caller has asked to stop sending results. |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // The remaining entries will be out of scope. |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, |
| | | "Search request contains an unsupported search scope")); |
| | | return; |
| | | } |
| | | |
| | | resultHandler.handleResult(Responses |
| | | .newResult(ResultCode.SUCCESS)); |
| | | } |
| | | catch (CancelledResultException e) |
| | | { |
| | | resultHandler.handleErrorResult(e); |
| | | } |
| | | finally |
| | | { |
| | | entryLock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean sendEntry(SearchRequest request, |
| | | SearchResultHandler resultHandler, Entry entry) |
| | | { |
| | | // TODO: check filter, strip attributes. |
| | | return resultHandler.handleEntry(Responses |
| | | .newSearchResultEntry(entry)); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | // Parse command line arguments. |
| | | final String localAddress = args[0]; |
| | | final int localPort = Integer.parseInt(args[1]); |
| | | final String ldifFileName = args[2]; |
| | | |
| | | // Create the memory backend. |
| | | final ConcurrentSkipListMap<DN, Entry> entries = readEntriesFromLDIF(ldifFileName); |
| | | final MemoryBackend backend = new MemoryBackend(entries); |
| | | |
| | | // Create a server connection adapter. |
| | | final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = |
| | | Connections.newServerConnectionFactory(backend); |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, |
| | | connectionHandler, options); |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.out.println("Error listening on " + localAddress + ":" |
| | | + localPort); |
| | | e.printStackTrace(); |
| | | } |
| | | finally |
| | | { |
| | | if (listener != null) |
| | | { |
| | | listener.close(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Reads the entries from the named LDIF file. |
| | | * |
| | | * @param ldifFileName |
| | | * The name of the LDIF file. |
| | | * @return The entries. |
| | | */ |
| | | private static ConcurrentSkipListMap<DN, Entry> readEntriesFromLDIF( |
| | | final String ldifFileName) |
| | | { |
| | | final ConcurrentSkipListMap<DN, Entry> entries; |
| | | // Read the LDIF. |
| | | InputStream ldif; |
| | | try |
| | | { |
| | | ldif = new FileInputStream(args[2]); |
| | | ldif = new FileInputStream(ldifFileName); |
| | | } |
| | | catch (final FileNotFoundException e) |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_PARAM_ERROR.intValue()); |
| | | return; |
| | | return null; // Satisfy compiler. |
| | | } |
| | | |
| | | entries = new ConcurrentSkipListMap<DN, Entry>(); |
| | | final LDIFEntryReader reader = new LDIFEntryReader(ldif); |
| | | ConcurrentSkipListMap<DN, Entry> entries = new ConcurrentSkipListMap<DN, Entry>(); |
| | | try |
| | | { |
| | | while (reader.hasNext()) |
| | |
| | | { |
| | | System.err.println(e.getMessage()); |
| | | System.exit(ResultCode.CLIENT_SIDE_LOCAL_ERROR.intValue()); |
| | | return; |
| | | return null; // Satisfy compiler. |
| | | } |
| | | finally |
| | | { |
| | |
| | | { |
| | | System.exit(1); |
| | | } |
| | | |
| | | // Create listener. |
| | | final LDAPListenerOptions options = new LDAPListenerOptions() |
| | | .setBacklog(4096); |
| | | LDAPListener listener = null; |
| | | try |
| | | { |
| | | listener = new LDAPListener(localAddress, localPort, new Store( |
| | | entries), options); |
| | | System.out.println("Press any key to stop the server..."); |
| | | System.in.read(); |
| | | } |
| | | catch (final IOException e) |
| | | { |
| | | System.out.println("Error listening on " + localAddress + ":" |
| | | + localPort); |
| | | e.printStackTrace(); |
| | | } |
| | | finally |
| | | { |
| | | if (listener != null) |
| | | { |
| | | listener.close(); |
| | | } |
| | | } |
| | | return entries; |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | if (result.getResultCode().isExceptional()) |
| | | { |
| | | handleErrorResult(ErrorResultException.wrap(result)); |
| | | handleErrorResult(ErrorResultException.newErrorResult(result)); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | | import java.net.InetSocketAddress; |
| | | import java.util.List; |
| | |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(connectionInvalidReason), messageID); |
| | | newErrorResult(connectionInvalidReason), messageID); |
| | | } |
| | | if (bindOrStartTLSInProgress.get()) |
| | | { |
| | |
| | | ResultCode.OPERATIONS_ERROR).setDiagnosticMessage( |
| | | "Bind or Start TLS operation in progress"); |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(errorResult), messageID); |
| | | newErrorResult(errorResult), messageID); |
| | | } |
| | | |
| | | // First remove the future associated with the request to be abandoned. |
| | |
| | | ResultCode.CLIENT_SIDE_ENCODING_ERROR).setCause(e); |
| | | connectionErrorOccurred(errorResult); |
| | | return new CompletedFutureResult<Void>( |
| | | ErrorResultException.wrap(errorResult), messageID); |
| | | newErrorResult(errorResult), messageID); |
| | | } |
| | | } |
| | | |
| | |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred while creating a bind context").setCause(e); |
| | | final ErrorResultException error = ErrorResultException.wrap(errorResult); |
| | | final ErrorResultException error = ErrorResultException.newErrorResult(errorResult); |
| | | if (resultHandler != null) |
| | | { |
| | | resultHandler.handleErrorResult(error); |
| | |
| | | { |
| | | if (connectionInvalidReason != null) |
| | | { |
| | | throw ErrorResultException.wrap(connectionInvalidReason); |
| | | throw newErrorResult(connectionInvalidReason); |
| | | } |
| | | pendingRequests.put(newMsgID, request); |
| | | } |
| | |
| | | for (final ConnectionEventListener listener : listeners) |
| | | { |
| | | listener.handleConnectionError(isDisconnectNotification, |
| | | ErrorResultException.wrap(reason)); |
| | | newErrorResult(reason)); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.IOException; |
| | | import java.net.SocketAddress; |
| | | import java.util.concurrent.ExecutionException; |
| | |
| | | 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.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.glassfish.grizzly.CompletionHandler; |
| | | import org.glassfish.grizzly.Connection; |
| | |
| | | @Override |
| | | public void failed(final Throwable throwable) |
| | | { |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR) |
| | | .setCause(throwable) |
| | | .setDiagnosticMessage(throwable.getMessage()); |
| | | handler.handleErrorResult(ErrorResultException |
| | | .wrap(errorResult)); |
| | | handler.handleErrorResult(newErrorResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | throwable.getMessage(), throwable)); |
| | | } |
| | | }); |
| | | return null; |
| | | } |
| | | catch (final IOException ioe) |
| | | { |
| | | final Result errorResult = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR) |
| | | .setCause(ioe).setDiagnosticMessage(ioe.getMessage()); |
| | | throw ErrorResultException.wrap(errorResult); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | ioe.getMessage(), ioe); |
| | | } |
| | | } |
| | | handler.handleResult(null); |
| | |
| | | t = t.getCause(); |
| | | } |
| | | |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR).setCause(t) |
| | | .setDiagnosticMessage(t.getMessage()); |
| | | return ErrorResultException.wrap(result); |
| | | return newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | t.getMessage(), t); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.concurrent.TimeoutException; |
| | | import java.util.concurrent.locks.AbstractQueuedSynchronizer; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | |
| | | |
| | | |
| | |
| | | ErrorResultException errorResult = handleCancelRequest(mayInterruptIfRunning); |
| | | if (errorResult == null) |
| | | { |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED); |
| | | errorResult = ErrorResultException.wrap(result); |
| | | errorResult = newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED); |
| | | } |
| | | this.errorResult = errorResult; |
| | | |
| | |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_NO_SEARCH_RESULT_ENTRIES; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES; |
| | | import static org.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; |
| | |
| | | if (entryCount == 0) |
| | | { |
| | | // Did not find any entries. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage( |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, |
| | | ERR_NO_SEARCH_RESULT_ENTRIES.get().toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | } |
| | | else if (entryCount > 1) |
| | | { |
| | | // Got more entries than expected. |
| | | final Result result = Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED) |
| | | .setDiagnosticMessage( |
| | | ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(entryCount).toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | 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. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED) |
| | | .setDiagnosticMessage( |
| | | ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( |
| | | firstReference.getURIs().iterator().next()).toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, |
| | | ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( |
| | | firstReference.getURIs().iterator().next()) |
| | | .toString()); |
| | | } |
| | | else |
| | | { |
| | |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_NO_SEARCH_RESULT_ENTRIES; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES; |
| | | import static org.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.BlockingQueue; |
| | |
| | | if (handler.entryCount == 0) |
| | | { |
| | | // Did not find any entries. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage( |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, |
| | | ERR_NO_SEARCH_RESULT_ENTRIES.get().toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | } |
| | | else if (handler.entryCount > 1) |
| | | { |
| | | // Got more entries than expected. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED) |
| | | .setDiagnosticMessage( |
| | | ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES.get(handler.entryCount) |
| | | .toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, |
| | | ERR_UNEXPECTED_SEARCH_RESULT_ENTRIES |
| | | .get(handler.entryCount).toString()); |
| | | } |
| | | else if (handler.firstReference != null) |
| | | { |
| | | // Got an unexpected search result reference. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED) |
| | | .setDiagnosticMessage( |
| | | ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( |
| | | handler.firstReference.getURIs().iterator().next()) |
| | | .toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_UNEXPECTED_RESULTS_RETURNED, |
| | | ERR_UNEXPECTED_SEARCH_RESULT_REFERENCES.get( |
| | | handler.firstReference.getURIs().iterator().next()) |
| | | .toString()); |
| | | } |
| | | else |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | import java.util.logging.Level; |
| | | |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | import com.forgerock.opendj.util.AsynchronousFutureResult; |
| | | import com.forgerock.opendj.util.StaticUtils; |
| | | import com.forgerock.opendj.util.Validator; |
| | |
| | | // All factories are offline so give up. We could have a |
| | | // configurable policy here such as waiting indefinitely, or for a |
| | | // configurable timeout period. |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_CONNECT_ERROR).setDiagnosticMessage( |
| | | "No operational connection factories available")); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_CONNECT_ERROR, |
| | | "No operational connection factories available"); |
| | | } |
| | | } |
| 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 |
| | | * trunk/opendj3/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 |
| | | * trunk/opendj3/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 2011 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import java.util.EventListener; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An object that registers to be notified when a cancellation request has been |
| | | * received and processing of the request should be aborted if possible. |
| | | * <p> |
| | | * Requests may be cancelled as a result of an abandon request or a cancel |
| | | * extended request sent from the client, or by the server itself (e.g. during |
| | | * server shutdown). |
| | | */ |
| | | public interface CancelRequestListener extends EventListener |
| | | { |
| | | /** |
| | | * Invoked when a cancellation request has been received and processing of the |
| | | * request should be aborted if possible. |
| | | * <p> |
| | | * Requests may be cancelled as a result of an abandon request or a cancel |
| | | * extended request sent from the client, or by the server itself (e.g. during |
| | | * server shutdown). |
| | | * <p> |
| | | * Implementations should, if possible, abort further processing of the |
| | | * request and return an appropriate cancellation result. |
| | | * |
| | | * @param cancellationReason |
| | | * A message describing the reason why the request is being |
| | | * cancelled. |
| | | */ |
| | | void handleCancelRequest(LocalizableMessage cancellationReason); |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server connection factory using the provided |
| | | * {@link RequestHandler}. The returned factory will manage connection and |
| | | * request life-cycle, including request cancellation. |
| | | * <p> |
| | | * When processing requests, {@link RequestHandler} implementations are passed |
| | | * a {@link RequestContext} as the first parameter which may be used for |
| | | * detecting whether or not the request should be aborted due to cancellation |
| | | * requests or other events, such as connection failure. |
| | | * <p> |
| | | * The returned factory maintains state information which includes a table of |
| | | * active requests. Therefore, {@code RequestHandler} implementations are |
| | | * required to always return results in order to avoid potential memory leaks. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | | * @param requestHandler |
| | | * The request handler which will be used for all client connections. |
| | | * @return The new server connection factory. |
| | | * @throws NullPointerException |
| | | * If {@code requestHandler} was {@code null}. |
| | | */ |
| | | public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory( |
| | | final RequestHandler<RequestContext> requestHandler) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(requestHandler); |
| | | |
| | | final RequestHandlerFactory<C, RequestContext> factory = |
| | | new RequestHandlerFactory<C, RequestContext>() |
| | | { |
| | | |
| | | public RequestHandler<RequestContext> handleAccept( |
| | | C clientContext) throws ErrorResultException |
| | | { |
| | | return requestHandler; |
| | | } |
| | | }; |
| | | |
| | | return new RequestHandlerFactoryAdapter<C>(factory); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server connection factory using the provided |
| | | * {@link RequestHandlerFactory}. The returned factory will manage connection |
| | | * and request life-cycle, including request cancellation. |
| | | * <p> |
| | | * When processing requests, {@link RequestHandler} implementations are passed |
| | | * a {@link RequestContext} as the first parameter which may be used for |
| | | * detecting whether or not the request should be aborted due to cancellation |
| | | * requests or other events, such as connection failure. |
| | | * <p> |
| | | * The returned factory maintains state information which includes a table of |
| | | * active requests. Therefore, {@code RequestHandler} implementations are |
| | | * required to always return results in order to avoid potential memory leaks. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | | * @param factory |
| | | * The request handler factory to use for associating request |
| | | * handlers with client connections. |
| | | * @return The new server connection factory. |
| | | * @throws NullPointerException |
| | | * If {@code factory} was {@code null}. |
| | | */ |
| | | public static <C> ServerConnectionFactory<C, Integer> newServerConnectionFactory( |
| | | final RequestHandlerFactory<C, RequestContext> factory) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(factory); |
| | | return new RequestHandlerFactoryAdapter<C>(factory); |
| | | } |
| | | |
| | | |
| | | |
| | | // Prevent instantiation. |
| | | private Connections() |
| | | { |
| | |
| | | { |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code and an |
| | | * empty diagnostic message. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @return The new error result exception. |
| | | * @throws IllegalArgumentException |
| | | * If the provided result code does not represent a failure. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult( |
| | | ResultCode resultCode) throws IllegalArgumentException, |
| | | NullPointerException |
| | | { |
| | | return newErrorResult(resultCode, null, null); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code and |
| | | * diagnostic message. |
| | | * |
| | |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult(ResultCode resultCode, |
| | | String diagnosticMessage) throws IllegalArgumentException, |
| | | NullPointerException |
| | | public static ErrorResultException newErrorResult( |
| | | ResultCode resultCode, String diagnosticMessage) |
| | | throws IllegalArgumentException, NullPointerException |
| | | { |
| | | return newErrorResult(resultCode, diagnosticMessage, null); |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code and |
| | | * cause. The diagnostic message will be taken from the cause, if provided. |
| | | * |
| | | * @param resultCode |
| | | * The result code. |
| | | * @param cause |
| | | * The throwable cause, which may be {@code null} indicating that |
| | | * none was provided. |
| | | * @return The new error result exception. |
| | | * @throws IllegalArgumentException |
| | | * If the provided result code does not represent a failure. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult( |
| | | ResultCode resultCode, Throwable cause) |
| | | throws IllegalArgumentException, NullPointerException |
| | | { |
| | | return newErrorResult(resultCode, null, cause); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new error result exception with the provided result code, |
| | | * diagnostic message, and cause. |
| | | * |
| | |
| | | * The diagnostic message, which may be empty or {@code null} |
| | | * indicating that none was provided. |
| | | * @param cause |
| | | * The throwable cause, which may be null indicating that none was |
| | | * provided. |
| | | * The throwable cause, which may be {@code null} indicating that |
| | | * none was provided. |
| | | * @return The new error result exception. |
| | | * @throws IllegalArgumentException |
| | | * If the provided result code does not represent a failure. |
| | | * @throws NullPointerException |
| | | * If {@code resultCode} was {@code null}. |
| | | */ |
| | | public static ErrorResultException newErrorResult(ResultCode resultCode, |
| | | String diagnosticMessage, Throwable cause) |
| | | public static ErrorResultException newErrorResult( |
| | | ResultCode resultCode, String diagnosticMessage, Throwable cause) |
| | | throws IllegalArgumentException, NullPointerException |
| | | { |
| | | Result result = Responses.newResult(resultCode) |
| | | .setDiagnosticMessage(diagnosticMessage).setCause(cause); |
| | | return wrap(result); |
| | | final Result result = Responses.newResult(resultCode); |
| | | if (diagnosticMessage != null) |
| | | { |
| | | result.setDiagnosticMessage(diagnosticMessage); |
| | | } |
| | | else if (cause != null) |
| | | { |
| | | result.setDiagnosticMessage(cause.getLocalizedMessage()); |
| | | } |
| | | result.setCause(cause); |
| | | return newErrorResult(result); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Wraps the provided result in an appropriate error result exception. The |
| | | * type of error result exception used depends on the underlying result code. |
| | | * Creates a new error result exception using the provided result. |
| | | * |
| | | * @param result |
| | | * The result whose result code indicates a failure. |
| | |
| | | * @throws NullPointerException |
| | | * If {@code result} was {@code null}. |
| | | */ |
| | | public static ErrorResultException wrap(final Result result) |
| | | throws IllegalArgumentException, NullPointerException |
| | | public static ErrorResultException newErrorResult( |
| | | final Result result) throws IllegalArgumentException, |
| | | NullPointerException |
| | | { |
| | | if (!result.getResultCode().isExceptional()) |
| | | { |
| | |
| | | */ |
| | | ErrorResultException(final Result result) |
| | | { |
| | | super(result.getResultCode() + ": " + result.getDiagnosticMessage()); |
| | | super(result.getResultCode() + ": " |
| | | + result.getDiagnosticMessage()); |
| | | this.result = result; |
| | | } |
| | | |
| 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 |
| | | * trunk/opendj3/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 |
| | | * trunk/opendj3/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 2011 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | /** |
| | | * The context associated with a request currently being processed by a request |
| | | * handler. A request context can be used to query state information about the |
| | | * request, such as whether or not it has been cancelled, as well as registering |
| | | * to be notified if the request has been cancelled. Implementations may provide |
| | | * additional information, such as the associated schema, time-stamp |
| | | * information, etc. |
| | | */ |
| | | public interface RequestContext |
| | | { |
| | | |
| | | /** |
| | | * Registers the provided cancellation listener with this request context so |
| | | * that it can be notified if a cancellation request is received and |
| | | * processing of the request should be aborted if possible. |
| | | * <p> |
| | | * Requests may be cancelled as a result of an abandon request or a cancel |
| | | * extended request sent from the client, or by the server itself (e.g. during |
| | | * server shutdown). |
| | | * <p> |
| | | * This method provides a event notification mechanism which can be used by |
| | | * asynchronous request handler implementations to detect cancellation of |
| | | * requests. |
| | | * |
| | | * @param listener |
| | | * The listener which wants to be notified if a cancellation request |
| | | * is received and processing of the request should be aborted if |
| | | * possible. |
| | | * @throws NullPointerException |
| | | * If the {@code listener} was {@code null}. |
| | | * @see #checkIfCancelled |
| | | */ |
| | | void addCancelRequestListener(CancelRequestListener listener) |
| | | throws NullPointerException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Throws {@link CancelledResultException} if a cancellation request has been |
| | | * received and processing of the request should be aborted if possible. |
| | | * <p> |
| | | * Requests may be cancelled as a result of an abandon request or a cancel |
| | | * extended request sent from the client, or by the server itself (e.g. during |
| | | * server shutdown). |
| | | * <p> |
| | | * This method provides a polling mechanism which can be used by synchronous |
| | | * request handler implementations to detect cancellation of requests. |
| | | * |
| | | * @param signalTooLate |
| | | * {@code true} to signal that, after this method returns, processing |
| | | * of the request will have proceeded too far for it to be aborted by |
| | | * subsequent cancellation requests. |
| | | * @throws CancelledResultException |
| | | * If a cancellation request has been received and processing of the |
| | | * request should be aborted if possible. |
| | | * @see #addCancelRequestListener |
| | | */ |
| | | void checkIfCancelled(boolean signalTooLate) |
| | | throws CancelledResultException; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the message ID of the request, if available. Protocols, such as |
| | | * LDAP and internal connections, include a unique message ID with each |
| | | * request which may be useful for logging and auditing. |
| | | * |
| | | * @return The message ID of the request, or {@code -1} if there is no message |
| | | * ID associated with the request. |
| | | */ |
| | | int getMessageID(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Removes the provided cancellation listener from this request context so |
| | | * that it will not be notified if a cancellation request has been received. |
| | | * |
| | | * @param listener |
| | | * The listener which no longer wants to be notified if a |
| | | * cancellation request has been received. |
| | | * @throws NullPointerException |
| | | * If the {@code listener} was {@code null}. |
| | | */ |
| | | void removeCancelRequestListener(CancelRequestListener listener) |
| | | throws NullPointerException; |
| | | } |
| 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 |
| | | * trunk/opendj3/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 |
| | | * trunk/opendj3/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 2011 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | /** |
| | | * A handler interface for accepting new connections from clients. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | | * @param <R> |
| | | * The type of request context. |
| | | */ |
| | | public interface RequestHandlerFactory<C, R extends RequestContext> |
| | | { |
| | | /** |
| | | * Invoked when a new client connection is accepted by the associated |
| | | * listener. Implementations should return a {@code RequestHandler} which will |
| | | * be used to handle requests from the client connection. |
| | | * |
| | | * @param clientContext |
| | | * The protocol dependent context information associated with the |
| | | * client connection. Depending on the protocol this may contain |
| | | * information about the client such as their address and level |
| | | * connection security. It may also be used to manage the state of |
| | | * the client's connection. |
| | | * @return A {@code RequestHandler} which will be used to handle requests from |
| | | * a client connection. |
| | | * @throws ErrorResultException |
| | | * If this request handler factory cannot accept the client |
| | | * connection. |
| | | */ |
| | | RequestHandler<R> handleAccept(C clientContext) |
| | | throws ErrorResultException; |
| | | } |
| 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 |
| | | * trunk/opendj3/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 |
| | | * trunk/opendj3/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 2011 ForgeRock AS |
| | | */ |
| | | |
| | | package org.forgerock.opendj.ldap; |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.util.Iterator; |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.opendj.ldap.requests.*; |
| | | import org.forgerock.opendj.ldap.responses.*; |
| | | |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An adapter which converts a {@code RequestHandlerFactory} into a |
| | | * {@code ServerConnectionFactory}. |
| | | * |
| | | * @param <C> |
| | | * The type of client context. |
| | | */ |
| | | final class RequestHandlerFactoryAdapter<C> implements |
| | | ServerConnectionFactory<C, Integer> |
| | | { |
| | | /** |
| | | * Request context implementation. |
| | | */ |
| | | private static class RequestContextImpl<S extends Result, H extends ResultHandler<? super S>> |
| | | implements RequestContext, ResultHandler<S> |
| | | { |
| | | |
| | | // Adapter class which invokes cancel result handlers with correct result |
| | | // type. |
| | | private static final class ExtendedResultHandlerHolder<R extends ExtendedResult> |
| | | { |
| | | private final ExtendedRequest<R> request; |
| | | private final ResultHandler<? super R> resultHandler; |
| | | |
| | | |
| | | |
| | | private ExtendedResultHandlerHolder( |
| | | final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler) |
| | | { |
| | | this.request = request; |
| | | this.resultHandler = resultHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | private void handleSuccess() |
| | | { |
| | | final R cancelResult = request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.SUCCESS, "", ""); |
| | | resultHandler.handleResult(cancelResult); |
| | | } |
| | | |
| | | |
| | | |
| | | private void handleTooLate() |
| | | { |
| | | final R cancelResult = request.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.TOO_LATE, "", ""); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(cancelResult)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static enum RequestState |
| | | { |
| | | // Request active |
| | | PENDING, |
| | | |
| | | // Request active, cancel requested |
| | | CANCEL_REQUESTED, |
| | | |
| | | // Request active, too late to cancel |
| | | TOO_LATE, |
| | | |
| | | // Result sent, not cancelled |
| | | RESULT_SENT, |
| | | |
| | | // Result sent, was cancelled |
| | | CANCELLED; |
| | | } |
| | | |
| | | |
| | | |
| | | private final int messageID; |
| | | |
| | | // Cancellation state guarded by lock. |
| | | private final Object stateLock = new Object(); |
| | | |
| | | // These should be notified when a cancel request arrives, at most once. |
| | | private List<CancelRequestListener> cancelRequestListeners = null; |
| | | |
| | | // These should be notified when the result is set. |
| | | private List<ExtendedResultHandlerHolder<?>> cancelResultHandlers = null; |
| | | |
| | | private RequestState state = RequestState.PENDING; |
| | | |
| | | private LocalizableMessage cancelRequestReason = null; |
| | | |
| | | private boolean sendResult = true; |
| | | |
| | | private final boolean isCancelSupported; |
| | | |
| | | private final ServerConnectionImpl<?> clientConnection; |
| | | |
| | | protected final H resultHandler; |
| | | |
| | | |
| | | |
| | | protected RequestContextImpl( |
| | | final ServerConnectionImpl<?> clientConnection, |
| | | final H resultHandler, final int messageID, |
| | | final boolean isCancelSupported) |
| | | { |
| | | this.clientConnection = clientConnection; |
| | | this.resultHandler = resultHandler; |
| | | this.messageID = messageID; |
| | | this.isCancelSupported = isCancelSupported; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void addCancelRequestListener( |
| | | final CancelRequestListener listener) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | |
| | | boolean invokeImmediately = false; |
| | | synchronized (stateLock) |
| | | { |
| | | switch (state) |
| | | { |
| | | case PENDING: |
| | | if (cancelRequestListeners == null) |
| | | { |
| | | cancelRequestListeners = new LinkedList<CancelRequestListener>(); |
| | | } |
| | | cancelRequestListeners.add(listener); |
| | | break; |
| | | case CANCEL_REQUESTED: |
| | | // Signal immediately outside lock. |
| | | invokeImmediately = true; |
| | | break; |
| | | case TOO_LATE: |
| | | case RESULT_SENT: |
| | | case CANCELLED: |
| | | // No point in registering the callback since the request can never be |
| | | // cancelled now. |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (invokeImmediately) |
| | | { |
| | | listener.handleCancelRequest(cancelRequestReason); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void checkIfCancelled(final boolean signalTooLate) |
| | | throws CancelledResultException |
| | | { |
| | | synchronized (stateLock) |
| | | { |
| | | switch (state) |
| | | { |
| | | case PENDING: |
| | | // No cancel request, so no handlers, just switch state. |
| | | if (signalTooLate) |
| | | { |
| | | cancelRequestListeners = null; |
| | | state = RequestState.TOO_LATE; |
| | | } |
| | | break; |
| | | case CANCEL_REQUESTED: |
| | | // Don't change state: let the handler ack the cancellation request. |
| | | throw (CancelledResultException) newErrorResult( |
| | | ResultCode.CANCELLED, cancelRequestReason.toString()); |
| | | case TOO_LATE: |
| | | // Already too late. Nothing to do. |
| | | break; |
| | | case RESULT_SENT: |
| | | case CANCELLED: |
| | | // This should not happen - could throw an illegal state exception? |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int getMessageID() |
| | | { |
| | | return messageID; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleErrorResult(final ErrorResultException error) |
| | | { |
| | | if (clientConnection.removePendingRequest(this)) |
| | | { |
| | | if (setResult(error.getResult())) |
| | | { |
| | | // FIXME: we must invoke the result handler even when abandoned so |
| | | // that chained result handlers may clean up, log, etc. We really need |
| | | // to signal that the result must not be sent to the client. |
| | | } |
| | | resultHandler.handleErrorResult(error); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleResult(final S result) |
| | | { |
| | | if (clientConnection.removePendingRequest(this)) |
| | | { |
| | | if (setResult(result)) |
| | | { |
| | | // FIXME: we must invoke the result handler even when abandoned so |
| | | // that chained result handlers may clean up, log, etc. We really need |
| | | // to signal that the result must not be sent to the client. |
| | | } |
| | | resultHandler.handleResult(result); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void removeCancelRequestListener( |
| | | final CancelRequestListener listener) |
| | | throws NullPointerException |
| | | { |
| | | Validator.ensureNotNull(listener); |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | if (cancelRequestListeners != null) |
| | | { |
| | | cancelRequestListeners.remove(listener); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private <R extends ExtendedResult> void cancel( |
| | | final LocalizableMessage reason, |
| | | final ExtendedRequest<R> cancelRequest, |
| | | final ResultHandler<? super R> cancelResultHandler, |
| | | final boolean sendResult) |
| | | { |
| | | Validator.ensureNotNull(reason); |
| | | |
| | | if (!isCancelSupported) |
| | | { |
| | | if (cancelResultHandler != null) |
| | | { |
| | | final Result result = Responses |
| | | .newGenericExtendedResult(ResultCode.CANNOT_CANCEL); |
| | | cancelResultHandler |
| | | .handleErrorResult(newErrorResult(result)); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | List<CancelRequestListener> tmpListeners = null; |
| | | boolean invokeResultHandler = false; |
| | | boolean resultHandlerIsSuccess = false; |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | switch (state) |
| | | { |
| | | case PENDING: |
| | | // Switch to CANCEL_REQUESTED state. |
| | | cancelRequestReason = reason; |
| | | if (cancelResultHandler != null) |
| | | { |
| | | cancelResultHandlers = new LinkedList<ExtendedResultHandlerHolder<?>>(); |
| | | cancelResultHandlers |
| | | .add(new ExtendedResultHandlerHolder<R>( |
| | | cancelRequest, cancelResultHandler)); |
| | | } |
| | | tmpListeners = cancelRequestListeners; |
| | | cancelRequestListeners = null; |
| | | state = RequestState.CANCEL_REQUESTED; |
| | | this.sendResult &= sendResult; |
| | | break; |
| | | case CANCEL_REQUESTED: |
| | | // Cancel already request so listeners already invoked. |
| | | if (cancelResultHandler != null) |
| | | { |
| | | if (cancelResultHandlers == null) |
| | | { |
| | | cancelResultHandlers = new LinkedList<ExtendedResultHandlerHolder<?>>(); |
| | | } |
| | | cancelResultHandlers |
| | | .add(new ExtendedResultHandlerHolder<R>( |
| | | cancelRequest, cancelResultHandler)); |
| | | } |
| | | break; |
| | | case TOO_LATE: |
| | | case RESULT_SENT: |
| | | // Cannot cancel, so invoke result handler immediately outside of |
| | | // lock. |
| | | if (cancelResultHandler != null) |
| | | { |
| | | invokeResultHandler = true; |
| | | resultHandlerIsSuccess = false; |
| | | } |
| | | break; |
| | | case CANCELLED: |
| | | // Multiple cancellation attempts. Clients should not do this, but the |
| | | // cancel will effectively succeed immediately, so invoke result |
| | | // handler immediately outside of lock. |
| | | if (cancelResultHandler != null) |
| | | { |
| | | invokeResultHandler = true; |
| | | resultHandlerIsSuccess = true; |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // Invoke listeners outside of lock. |
| | | if (tmpListeners != null) |
| | | { |
| | | for (final CancelRequestListener listener : tmpListeners) |
| | | { |
| | | listener.handleCancelRequest(reason); |
| | | } |
| | | } |
| | | |
| | | if (invokeResultHandler) |
| | | { |
| | | if (resultHandlerIsSuccess) |
| | | { |
| | | final R result = cancelRequest.getResultDecoder() |
| | | .newExtendedErrorResult(ResultCode.SUCCESS, "", ""); |
| | | cancelResultHandler.handleResult(result); |
| | | } |
| | | else |
| | | { |
| | | final Result result = Responses |
| | | .newGenericExtendedResult(ResultCode.TOO_LATE); |
| | | cancelResultHandler.handleErrorResult(ErrorResultException |
| | | .newErrorResult(result)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Sets the result associated with this request context and updates the |
| | | * state accordingly. |
| | | * |
| | | * @param result |
| | | * The result. |
| | | */ |
| | | private boolean setResult(final Result result) |
| | | { |
| | | List<ExtendedResultHandlerHolder<?>> tmpHandlers = null; |
| | | boolean isCancelled = false; |
| | | boolean maySendResult; |
| | | |
| | | synchronized (stateLock) |
| | | { |
| | | maySendResult = sendResult; |
| | | |
| | | switch (state) |
| | | { |
| | | case PENDING: |
| | | case TOO_LATE: |
| | | // Switch to appropriate final state. |
| | | if (!result.getResultCode().equals(ResultCode.CANCELLED)) |
| | | { |
| | | state = RequestState.RESULT_SENT; |
| | | } |
| | | else |
| | | { |
| | | state = RequestState.CANCELLED; |
| | | } |
| | | break; |
| | | case CANCEL_REQUESTED: |
| | | // Switch to appropriate final state and invoke any cancel request |
| | | // handlers. |
| | | if (!result.getResultCode().equals(ResultCode.CANCELLED)) |
| | | { |
| | | state = RequestState.RESULT_SENT; |
| | | } |
| | | else |
| | | { |
| | | state = RequestState.CANCELLED; |
| | | } |
| | | |
| | | isCancelled = (state == RequestState.CANCELLED); |
| | | tmpHandlers = cancelResultHandlers; |
| | | cancelResultHandlers = null; |
| | | break; |
| | | case RESULT_SENT: |
| | | case CANCELLED: |
| | | // This should not happen - could throw an illegal state exception? |
| | | maySendResult = false; // Prevent sending multiple results. |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // Invoke handlers outside of lock. |
| | | if (tmpHandlers != null) |
| | | { |
| | | for (final ExtendedResultHandlerHolder<?> handler : tmpHandlers) |
| | | { |
| | | if (isCancelled) |
| | | { |
| | | handler.handleSuccess(); |
| | | } |
| | | else |
| | | { |
| | | handler.handleTooLate(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return maySendResult; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Search request context implementation. |
| | | */ |
| | | private final static class SearchRequestContextImpl extends |
| | | RequestContextImpl<Result, SearchResultHandler> implements |
| | | SearchResultHandler |
| | | { |
| | | |
| | | private SearchRequestContextImpl( |
| | | final ServerConnectionImpl<?> clientConnection, |
| | | final SearchResultHandler resultHandler, final int messageID, |
| | | final boolean isCancelSupported) |
| | | { |
| | | super(clientConnection, resultHandler, messageID, |
| | | isCancelSupported); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean handleEntry(final SearchResultEntry entry) |
| | | { |
| | | return resultHandler.handleEntry(entry); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean handleReference( |
| | | final SearchResultReference reference) |
| | | { |
| | | return resultHandler.handleReference(reference); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private static final class ServerConnectionImpl<C> implements |
| | | ServerConnection<Integer> |
| | | { |
| | | private final RequestHandler<RequestContext> requestHandler; |
| | | |
| | | private final AtomicBoolean isClosed = new AtomicBoolean(); |
| | | |
| | | private final ConcurrentHashMap<Integer, RequestContextImpl<?, ?>> pendingRequests = |
| | | new ConcurrentHashMap<Integer, RequestContextImpl<?, ?>>(); |
| | | |
| | | |
| | | |
| | | private ServerConnectionImpl( |
| | | final RequestHandler<RequestContext> requestHandler) |
| | | { |
| | | this.requestHandler = requestHandler; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAbandon(final Integer messageID, |
| | | final AbandonRequest request) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<?, ?> abandonedRequest = getPendingRequest(request |
| | | .getRequestID()); |
| | | if (abandonedRequest != null) |
| | | { |
| | | final LocalizableMessage abandonReason = INFO_CANCELED_BY_ABANDON_REQUEST |
| | | .get(messageID); |
| | | abandonedRequest.cancel(abandonReason, null, null, false); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleAdd(final Integer messageID, |
| | | final AddRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<Result, ResultHandler<? super Result>> requestContext = |
| | | new RequestContextImpl<Result, ResultHandler<? super Result>>( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleAdd(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleBind(final Integer messageID, |
| | | final int version, final BindRequest request, |
| | | final ResultHandler<? super BindResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<BindResult, ResultHandler<? super BindResult>> requestContext = |
| | | new RequestContextImpl<BindResult, ResultHandler<? super BindResult>>( |
| | | this, resultHandler, messageID, false); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleBind(requestContext, version, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleCompare(final Integer messageID, |
| | | final CompareRequest request, |
| | | final ResultHandler<? super CompareResult> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<CompareResult, ResultHandler<? super CompareResult>> requestContext = |
| | | new RequestContextImpl<CompareResult, ResultHandler<? super CompareResult>>( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleCompare(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionClosed(final Integer messageID, |
| | | final UnbindRequest request) |
| | | { |
| | | final LocalizableMessage cancelReason = INFO_CANCELED_BY_CLIENT_DISCONNECT |
| | | .get(); |
| | | doClose(cancelReason); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionDisconnected( |
| | | final ResultCode resultCode, final String message) |
| | | { |
| | | final LocalizableMessage cancelReason = INFO_CANCELED_BY_SERVER_DISCONNECT |
| | | .get(); |
| | | doClose(cancelReason); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleConnectionError(final Throwable error) |
| | | { |
| | | final LocalizableMessage cancelReason = INFO_CANCELED_BY_CLIENT_ERROR |
| | | .get(); |
| | | doClose(cancelReason); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleDelete(final Integer messageID, |
| | | final DeleteRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<Result, ResultHandler<? super Result>> requestContext = |
| | | new RequestContextImpl<Result, ResultHandler<? super Result>>( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleDelete(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public <R extends ExtendedResult> void handleExtendedRequest( |
| | | final Integer messageID, final ExtendedRequest<R> request, |
| | | final ResultHandler<? super R> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | if (request.getOID().equals(CancelExtendedRequest.OID)) |
| | | { |
| | | // Decode the request as a cancel request. |
| | | CancelExtendedRequest cancelRequest; |
| | | try |
| | | { |
| | | cancelRequest = CancelExtendedRequest.DECODER |
| | | .decodeExtendedRequest(request, new DecodeOptions()); |
| | | } |
| | | catch (final DecodeException e) |
| | | { |
| | | // Couldn't decode a cancel request. |
| | | resultHandler.handleErrorResult(newErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, e.getLocalizedMessage())); |
| | | return; |
| | | } |
| | | |
| | | // Register the request in the pending requests table. Even though |
| | | // this request cannot be cancelled, it is important to do this in |
| | | // order to monitor the number of pending operations. |
| | | final RequestContextImpl<R, ResultHandler<? super R>> requestContext = |
| | | new RequestContextImpl<R, ResultHandler<? super R>>( |
| | | this, resultHandler, messageID, false); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | // Find and cancel the request. |
| | | final RequestContextImpl<?, ?> cancelledRequest = getPendingRequest(cancelRequest |
| | | .getRequestID()); |
| | | if (cancelledRequest != null) |
| | | { |
| | | final LocalizableMessage cancelReason = INFO_CANCELED_BY_CANCEL_REQUEST |
| | | .get(messageID); |
| | | cancelledRequest.cancel(cancelReason, request, |
| | | requestContext, true); |
| | | } |
| | | else |
| | | { |
| | | // Couldn't find the request. Invoke on context in order to remove |
| | | // pending request. |
| | | requestContext |
| | | .handleErrorResult(newErrorResult(ResultCode.NO_SUCH_OPERATION)); |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | final RequestContextImpl<R, ResultHandler<? super R>> requestContext; |
| | | if (request.getOID().equals(StartTLSExtendedRequest.OID)) |
| | | { |
| | | // StartTLS requests cannot be cancelled. |
| | | requestContext = new RequestContextImpl<R, ResultHandler<? super R>>( |
| | | this, resultHandler, messageID, false); |
| | | } |
| | | else |
| | | { |
| | | requestContext = new RequestContextImpl<R, ResultHandler<? super R>>( |
| | | this, resultHandler, messageID, true); |
| | | } |
| | | |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleExtendedRequest(requestContext, |
| | | request, requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModify(final Integer messageID, |
| | | final ModifyRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<Result, ResultHandler<? super Result>> requestContext = |
| | | new RequestContextImpl<Result, ResultHandler<? super Result>>( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleModify(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleModifyDN(final Integer messageID, |
| | | final ModifyDNRequest request, |
| | | final ResultHandler<? super Result> resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final RequestContextImpl<Result, ResultHandler<? super Result>> requestContext = |
| | | new RequestContextImpl<Result, ResultHandler<? super Result>>( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleModifyDN(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void handleSearch(final Integer messageID, |
| | | final SearchRequest request, |
| | | final SearchResultHandler resultHandler, |
| | | final IntermediateResponseHandler intermediateResponseHandler) |
| | | throws UnsupportedOperationException |
| | | { |
| | | final SearchRequestContextImpl requestContext = new SearchRequestContextImpl( |
| | | this, resultHandler, messageID, true); |
| | | if (addPendingRequest(requestContext)) |
| | | { |
| | | requestHandler.handleSearch(requestContext, request, |
| | | requestContext, intermediateResponseHandler); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private boolean addPendingRequest( |
| | | final RequestContextImpl<?, ?> requestContext) |
| | | { |
| | | final Integer messageID = requestContext.getMessageID(); |
| | | |
| | | if (isClosed.get()) |
| | | { |
| | | final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING |
| | | .get(); |
| | | requestContext.handleErrorResult(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())); |
| | | return false; |
| | | } |
| | | else if (isClosed.get()) |
| | | { |
| | | // A concurrent close may have already removed the pending request but |
| | | // it will have only been notified for cancellation. |
| | | pendingRequests.remove(messageID); |
| | | |
| | | final LocalizableMessage message = INFO_CLIENT_CONNECTION_CLOSING |
| | | .get(); |
| | | requestContext.handleErrorResult(newErrorResult( |
| | | ResultCode.UNWILLING_TO_PERFORM, message.toString())); |
| | | return false; |
| | | } |
| | | else |
| | | { |
| | | // If the connection is closed now then we just have to pay the cost of |
| | | // invoking the request in the request handler. |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | private void doClose(final LocalizableMessage cancelReason) |
| | | { |
| | | if (!isClosed.getAndSet(true)) |
| | | { |
| | | // At this point if any pending requests are added then we may end up |
| | | // cancelling them, but this does not matter since addPendingRequest |
| | | // will fail the request immediately. |
| | | final Iterator<RequestContextImpl<?, ?>> iterator = pendingRequests |
| | | .values().iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | final RequestContextImpl<?, ?> pendingRequest = iterator |
| | | .next(); |
| | | pendingRequest.cancel(cancelReason, null, null, false); |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the pending request context having the specified message ID. |
| | | * |
| | | * @param messageID |
| | | * The message ID associated with the request context. |
| | | * @return The pending request context. |
| | | */ |
| | | private RequestContextImpl<?, ?> getPendingRequest( |
| | | final Integer messageID) |
| | | { |
| | | return pendingRequests.get(messageID); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Deregister a request context once it has completed. |
| | | * |
| | | * @param requestContext |
| | | * The request context. |
| | | * @return {@code true} if the request context was found and removed. |
| | | */ |
| | | private boolean removePendingRequest( |
| | | final RequestContextImpl<?, ?> requestContext) |
| | | { |
| | | return pendingRequests.remove(requestContext.getMessageID()) != null; |
| | | } |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | private final RequestHandlerFactory<C, RequestContext> factory; |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new server connection factory using the provided request handler |
| | | * factory. |
| | | * |
| | | * @param factory |
| | | * The request handler factory to be adapted into a server connection |
| | | * factory. |
| | | */ |
| | | RequestHandlerFactoryAdapter( |
| | | final RequestHandlerFactory<C, RequestContext> factory) |
| | | { |
| | | this.factory = factory; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public ServerConnection<Integer> handleAccept(final C clientContext) |
| | | throws ErrorResultException |
| | | { |
| | | final RequestHandler<RequestContext> requestHandler = factory |
| | | .handleAccept(clientContext); |
| | | return new ServerConnectionImpl<C>(requestHandler); |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import javax.security.auth.callback.NameCallback; |
| | | import javax.security.auth.callback.PasswordCallback; |
| | | import javax.security.auth.callback.UnsupportedCallbackException; |
| | |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e)); |
| | |
| | | import static com.forgerock.opendj.util.StaticUtils.getExceptionMessage; |
| | | import static com.forgerock.opendj.util.StaticUtils.joinCollection; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.ERR_SASL_PROTOCOL_ERROR; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.util.*; |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | "An error occurred during multi-stage authentication", e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_DECODING_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import javax.security.sasl.Sasl; |
| | | import javax.security.sasl.SaslClient; |
| | | import javax.security.sasl.SaslException; |
| | |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | | .setCause(e)); |
| | |
| | | import static com.forgerock.opendj.util.StaticUtils.getExceptionMessage; |
| | | import static com.forgerock.opendj.util.StaticUtils.joinCollection; |
| | | import static org.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.security.PrivilegedActionException; |
| | | import java.security.PrivilegedExceptionAction; |
| | |
| | | /** |
| | | * GSSAPI SASL bind request implementation. |
| | | */ |
| | | @SuppressWarnings("restriction") |
| | | final class GSSAPISASLBindRequestImpl extends |
| | | AbstractSASLBindRequest<GSSAPISASLBindRequest> implements |
| | | GSSAPISASLBindRequest |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "No authentication ID specified for GSSAPI SASL authentication")); |
| | | } |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setDiagnosticMessage( |
| | | "No password specified for GSSAPI SASL authentication")); |
| | | } |
| | |
| | | // FIXME: Is this the best result code? |
| | | final LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_LOCAL_AUTHENTICATION_FAILED |
| | | .get(StaticUtils.getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | throw ErrorResultException.newErrorResult(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(message.toString()).setCause(e)); |
| | | } |
| | |
| | | { |
| | | // FIXME: I18N need to have a better error message. |
| | | // FIXME: Is this the best result code? |
| | | throw ErrorResultException.wrap(Responses |
| | | throw ErrorResultException.newErrorResult(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage( |
| | | "An error occurred during multi-stage authentication") |
| | |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, e); |
| | | } |
| | | } |
| | | }); |
| | |
| | | else |
| | | { |
| | | // This should not happen. Must be a bug. |
| | | final LocalizableMessage msg = ERR_SASL_CONTEXT_CREATE_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | final LocalizableMessage msg = ERR_SASL_CONTEXT_CREATE_ERROR |
| | | .get(SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | } |
| | |
| | | // This should not happen. Must be a bug. |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_DECODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_DECODING_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | final LocalizableMessage msg = ERR_SASL_PROTOCOL_ERROR.get( |
| | | SASL_MECHANISM_NAME, getExceptionMessage(e)); |
| | | throw ErrorResultException.wrap(Responses |
| | | .newResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR) |
| | | .setDiagnosticMessage(msg.toString()).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_ENCODING_ERROR, |
| | | msg.toString(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import javax.security.auth.callback.NameCallback; |
| | | import javax.security.auth.callback.PasswordCallback; |
| | | import javax.security.auth.callback.UnsupportedCallbackException; |
| | |
| | | import org.forgerock.opendj.ldap.ErrorResultException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.responses.BindResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | import com.forgerock.opendj.util.Validator; |
| | | |
| | |
| | | } |
| | | catch (final SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_LOCAL_ERROR).setCause(e)); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_LOCAL_ERROR, e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.ExtendedRequest; |
| | | |
| | |
| | | .newExtendedErrorResult(result.getResultCode(), |
| | | result.getMatchedDN(), result.getDiagnosticMessage()); |
| | | adaptedResult.setCause(result.getCause()); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .wrap(adaptedResult)); |
| | | resultHandler.handleErrorResult(newErrorResult(adaptedResult)); |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | final R adaptedResult = request.getResultDecoder() |
| | | .adaptDecodeException(e); |
| | | resultHandler.handleErrorResult(ErrorResultException |
| | | .wrap(adaptedResult)); |
| | | resultHandler.handleErrorResult(newErrorResult(adaptedResult)); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.CoreMessages.*; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | |
| | | import org.forgerock.opendj.ldap.*; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | |
| | | import com.forgerock.opendj.util.FutureResultTransformer; |
| | |
| | | if (subentryAttr == null || subentryAttr.isEmpty()) |
| | | { |
| | | // Did not get the subschema sub-entry attribute. |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage( |
| | | ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString()).toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, |
| | | ERR_NO_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString()) |
| | | .toString()); |
| | | } |
| | | |
| | | final String dnString = subentryAttr.iterator().next().toString(); |
| | |
| | | } |
| | | catch (final LocalizedIllegalArgumentException e) |
| | | { |
| | | final Result result = Responses.newResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED).setDiagnosticMessage( |
| | | ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(), dnString, |
| | | e.getMessageObject()).toString()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_NO_RESULTS_RETURNED, |
| | | ERR_INVALID_SUBSCHEMA_SUBENTRY_ATTR.get(name.toString(), |
| | | dnString, e.getMessageObject()).toString()); |
| | | } |
| | | return subschemaDN; |
| | | } |
| | |
| | | |
| | | |
| | | |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.InterruptedIOException; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.concurrent.BlockingQueue; |
| | |
| | | return false; |
| | | } |
| | | |
| | | final ErrorResultException e = ErrorResultException.wrap(result); |
| | | throw new ErrorResultIOException(e); |
| | | throw new ErrorResultIOException(newErrorResult(result)); |
| | | } |
| | | |
| | | |
| | |
| | | contained the OID '%s', when '%s' was expected |
| | | ERR_VIRTUAL_ATTRS_ONLY_INVALID_CONTROL_VALUE=Cannot decode the provided \ |
| | | virtual attributes only control because it contains a value |
| | | WARN_CLIENT_DUPLICATE_MESSAGE_ID=The operation was rejected because there is \ |
| | | already another request on the same client connection with the same message \ |
| | | ID of %d |
| | | INFO_CANCELED_BY_ABANDON_REQUEST=The operation was canceled because the client \ |
| | | issued an abandon request (message ID %d) for this operation |
| | | INFO_CANCELED_BY_CANCEL_REQUEST=The operation was canceled because the client \ |
| | | issued a cancel request (message ID %d) for this operation |
| | | INFO_CANCELED_BY_CLIENT_DISCONNECT=The operation was canceled because the \ |
| | | client has disconnected from the server |
| | | INFO_CANCELED_BY_SERVER_DISCONNECT=The operation was canceled because the \ |
| | | server has disconnected from the client |
| | | INFO_CANCELED_BY_CLIENT_ERROR=The operation was canceled because the \ |
| | | client connection failed |
| | | INFO_CLIENT_CONNECTION_CLOSING=The operation was rejected because the \ |
| | | client connection is closing |
| | | |
| | | |
| | | |
| | | |
| | |
| | | throws UnsupportedOperationException |
| | | { |
| | | resultHandler |
| | | .handleErrorResult(ErrorResultException.wrap(request |
| | | .handleErrorResult(ErrorResultException.newErrorResult(request |
| | | .getResultDecoder().newExtendedErrorResult( |
| | | ResultCode.PROTOCOL_ERROR, "", |
| | | "Extended operation " + request.getOID() + " not supported"))); |
| | |
| | | { |
| | | // duplicate entry. |
| | | result = Responses.newResult(ResultCode.ENTRY_ALREADY_EXISTS); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | // doesn't matter if it was canceled. |
| | | requestsInProgress.remove(context); |
| | |
| | | if (abReq.isCanceled()) |
| | | { |
| | | result = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | |
| | | } |
| | | catch (SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.OPERATIONS_ERROR).setCause(e)); |
| | | } |
| | | } |
| | |
| | | } |
| | | catch (SaslException e) |
| | | { |
| | | throw ErrorResultException.wrap(Responses.newResult( |
| | | throw ErrorResultException.newErrorResult(Responses.newResult( |
| | | ResultCode.OPERATIONS_ERROR).setCause(e)); |
| | | } |
| | | } |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | resultHandler.handleErrorResult(ErrorResultException.wrap(Responses |
| | | resultHandler.handleErrorResult(ErrorResultException.newErrorResult(Responses |
| | | .newBindResult(ResultCode.OPERATIONS_ERROR).setCause(e) |
| | | .setDiagnosticMessage(e.toString()))); |
| | | } |
| | |
| | | { |
| | | // entry not found. |
| | | result = Responses.newCompareResult(ResultCode.NO_SUCH_ATTRIBUTE); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | resultHandler.handleErrorResult(ere); |
| | | // doesn't matter if it was canceled. |
| | | requestsInProgress.remove(context); |
| | |
| | | if (abReq.isCanceled()) |
| | | { |
| | | final Result r = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.wrap(r); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(r); |
| | | resultHandler.handleErrorResult(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | |
| | | { |
| | | // entry is not found. |
| | | result = Responses.newResult(ResultCode.NO_SUCH_OBJECT); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | // doesn't matter if it was canceled. |
| | | requestsInProgress.remove(context); |
| | |
| | | if (abReq.isCanceled()) |
| | | { |
| | | result = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | handler.handleErrorResult(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | |
| | | { |
| | | // Entry not found. |
| | | result = Responses.newResult(ResultCode.NO_SUCH_OBJECT); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | resultHandler.handleErrorResult(ere); |
| | | // Should searchResultHandler handle anything? |
| | | |
| | |
| | | if (abReq.isCanceled()) |
| | | { |
| | | result = Responses.newResult(ResultCode.CANCELLED); |
| | | final ErrorResultException ere = ErrorResultException.wrap(result); |
| | | final ErrorResultException ere = ErrorResultException.newErrorResult(result); |
| | | resultHandler.handleErrorResult(ere); |
| | | requestsInProgress.remove(context); |
| | | return; |
| | |
| | | import static com.forgerock.opendj.ldap.tools.ToolsMessages.*; |
| | | import static com.forgerock.opendj.ldap.tools.ToolConstants.*; |
| | | import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.*; |
| | | import java.util.ArrayList; |
| | |
| | | import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl; |
| | | import org.forgerock.opendj.ldap.requests.CompareRequest; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | |
| | | import com.forgerock.opendj.util.Base64; |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads to |
| | | // interrupt this one. |
| | | result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | |
| | | if (result.getResultCode() == ResultCode.COMPARE_FALSE) |
| | |
| | | import static com.forgerock.opendj.ldap.tools.ToolsMessages.*; |
| | | import static com.forgerock.opendj.ldap.tools.ToolConstants.*; |
| | | import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.FileInputStream; |
| | | import java.io.IOException; |
| | |
| | | import org.forgerock.opendj.ldap.requests.DeleteRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyDNRequest; |
| | | import org.forgerock.opendj.ldap.requests.ModifyRequest; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldif.*; |
| | | |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads |
| | | // to interrupt this one. |
| | | r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(r); |
| | | throw newErrorResult( |
| | | ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | printResult(opType, change.getName().toString(), r); |
| | | return r.getResultCode().intValue(); |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads |
| | | // to interrupt this one. |
| | | r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(r); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | printResult(opType, change.getName().toString(), r); |
| | | return r.getResultCode().intValue(); |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads |
| | | // to interrupt this one. |
| | | r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(r); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | printResult(opType, change.getName().toString(), r); |
| | | return r.getResultCode().intValue(); |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads |
| | | // to interrupt this one. |
| | | r = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(r); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | printResult(opType, change.getName().toString(), r); |
| | | return r.getResultCode().intValue(); |
| | |
| | | import static com.forgerock.opendj.ldap.tools.ToolsMessages.*; |
| | | import static com.forgerock.opendj.ldap.tools.ToolConstants.*; |
| | | import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.InputStream; |
| | | import java.io.OutputStream; |
| | |
| | | import org.forgerock.opendj.ldap.requests.PasswordModifyExtendedRequest; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.responses.PasswordModifyExtendedResult; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | |
| | | |
| | | |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads to |
| | | // interrupt this one. |
| | | result = Responses.newPasswordModifyExtendedResult( |
| | | ResultCode.CLIENT_SIDE_USER_CANCELLED).setCause(e) |
| | | .setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | } |
| | | catch (final ErrorResultException e) |
| | |
| | | import static com.forgerock.opendj.ldap.tools.ToolsMessages.*; |
| | | import static com.forgerock.opendj.ldap.tools.ToolConstants.*; |
| | | import static com.forgerock.opendj.ldap.tools.Utils.filterExitCode; |
| | | import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult; |
| | | |
| | | import java.io.*; |
| | | import java.util.*; |
| | |
| | | import org.forgerock.opendj.ldap.controls.*; |
| | | import org.forgerock.opendj.ldap.requests.Requests; |
| | | import org.forgerock.opendj.ldap.requests.SearchRequest; |
| | | import org.forgerock.opendj.ldap.responses.Responses; |
| | | import org.forgerock.opendj.ldap.responses.Result; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultEntry; |
| | | import org.forgerock.opendj.ldap.responses.SearchResultReference; |
| | |
| | | { |
| | | // This shouldn't happen because there are no other threads to |
| | | // interrupt this one. |
| | | result = Responses.newResult(ResultCode.CLIENT_SIDE_USER_CANCELLED) |
| | | .setCause(e).setDiagnosticMessage(e.getLocalizedMessage()); |
| | | throw ErrorResultException.wrap(result); |
| | | throw newErrorResult(ResultCode.CLIENT_SIDE_USER_CANCELLED, |
| | | e.getLocalizedMessage(), e); |
| | | } |
| | | |
| | | try |