001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2014-2015 ForgeRock AS.
025 */
026package org.forgerock.opendj.ldap.spi;
027
028import org.forgerock.opendj.ldap.Connection;
029import org.forgerock.opendj.ldap.IntermediateResponseHandler;
030import org.forgerock.opendj.ldap.LdapException;
031import org.forgerock.opendj.ldap.LdapPromise;
032import org.forgerock.opendj.ldap.ResultCode;
033import org.forgerock.opendj.ldap.SearchResultHandler;
034import org.forgerock.opendj.ldap.requests.BindClient;
035import org.forgerock.opendj.ldap.requests.BindRequest;
036import org.forgerock.opendj.ldap.requests.CompareRequest;
037import org.forgerock.opendj.ldap.requests.ExtendedRequest;
038import org.forgerock.opendj.ldap.requests.Request;
039import org.forgerock.opendj.ldap.requests.SearchRequest;
040import org.forgerock.opendj.ldap.responses.CompareResult;
041import org.forgerock.opendj.ldap.responses.ExtendedResult;
042import org.forgerock.opendj.ldap.responses.Result;
043import org.forgerock.util.promise.Promise;
044import org.forgerock.util.promise.Promises;
045
046import static org.forgerock.opendj.ldap.responses.Responses.*;
047
048/**
049 * Utility methods for creating and composing {@link LdapPromise}s.
050 */
051public final class LdapPromises {
052    /**
053     * Returns a {@link LdapPromise} representing an asynchronous task which has
054     * already succeeded with the provided result. Attempts to get the result
055     * will immediately return the result.
056     *
057     * @param <R>
058     *            The type of the task's result, or {@link Void} if the task
059     *            does not return anything (i.e. it only has side-effects).
060     * @param result
061     *            The result of the asynchronous task.
062     * @return A {@link LdapPromise} representing an asynchronous task which has
063     *         already succeeded with the provided result.
064     */
065    public static <R> LdapPromise<R> newSuccessfulLdapPromise(final R result) {
066        return wrap(Promises.<R, LdapException> newResultPromise(result), -1);
067    }
068
069    /**
070     * Returns a {@link LdapPromise} representing an asynchronous task,
071     * identified by the provided requestID, which has already succeeded with
072     * the provided result. Attempts to get the result will immediately return
073     * the result.
074     *
075     * @param <R>
076     *            The type of the task's result, or {@link Void} if the task
077     *            does not return anything (i.e. it only has side-effects).
078     * @param result
079     *            The result of the asynchronous task.
080     * @param requestID
081     *            The request ID of the succeeded task.
082     * @return A {@link LdapPromise} representing an asynchronous task which has
083     *         already succeeded with the provided result.
084     */
085    public static <R> LdapPromise<R> newSuccessfulLdapPromise(final R result, int requestID) {
086        return wrap(Promises.<R, LdapException> newResultPromise(result), requestID);
087    }
088
089    /**
090     * Returns a {@link LdapPromise} representing an asynchronous task which has
091     * already failed with the provided error.
092     *
093     * @param <R>
094     *            The type of the task's result, or {@link Void} if the task
095     *            does not return anything (i.e. it only has side-effects).
096     * @param <E>
097     *            The type of the exception thrown by the task if it fails.
098     * @param error
099     *            The exception indicating why the asynchronous task has failed.
100     * @return A {@link LdapPromise} representing an asynchronous task which has
101     *         already failed with the provided error.
102     */
103    public static <R, E extends LdapException> LdapPromise<R> newFailedLdapPromise(final E error) {
104        return wrap(Promises.<R, LdapException> newExceptionPromise(error), -1);
105    }
106
107    /**
108     * Returns a {@link LdapPromise} representing an asynchronous task,
109     * identified by the provided requestID, which has already failed with the
110     * provided error.
111     *
112     * @param <R>
113     *            The type of the task's result, or {@link Void} if the task
114     *            does not return anything (i.e. it only has side-effects).
115     * @param <E>
116     *            The type of the exception thrown by the task if it fails.
117     * @param error
118     *            The exception indicating why the asynchronous task has failed.
119     * @param requestID
120     *            The request ID of the failed task.
121     * @return A {@link LdapPromise} representing an asynchronous task which has
122     *         already failed with the provided error.
123     */
124    public static <R, E extends LdapException> LdapPromise<R> newFailedLdapPromise(final E error, int requestID) {
125        return wrap(Promises.<R, LdapException> newExceptionPromise(error), requestID);
126    }
127
128    /**
129     * Creates a new {@link ResultLdapPromiseImpl} to handle  a standard request (add, delete, modify and modidyDN).
130     *
131     * @param <R>
132     *           The type of the task's request.
133     *
134     * @param requestID
135     *            Identifier of the request.
136     * @param request
137     *            The request sent to the server.
138     * @param intermediateResponseHandler
139     *            Handler that consumes intermediate responses from extended operations.
140     * @param connection
141     *            The connection to directory server.
142     *
143     * @return The new {@link ResultLdapPromiseImpl}.
144     */
145    public static <R extends Request> ResultLdapPromiseImpl<R, Result> newResultLdapPromise(final int requestID,
146            final R request, final IntermediateResponseHandler intermediateResponseHandler,
147            final Connection connection) {
148        return new ResultLdapPromiseImpl<R, Result>(requestID, request, intermediateResponseHandler, connection) {
149            @Override
150            protected Result newErrorResult(ResultCode resultCode, String diagnosticMessage, Throwable cause) {
151                return newResult(resultCode).setDiagnosticMessage(diagnosticMessage).setCause(cause);
152            }
153        };
154    }
155
156    /**
157     * Creates a new bind {@link BindResultLdapPromiseImpl}.
158     *
159     * @param requestID
160     *            Identifier of the request.
161     * @param request
162     *            The bind request sent to server.
163     * @param bindClient
164     *            Client that binds to the server.
165     * @param intermediateResponseHandler
166     *            Handler that consumes intermediate responses from extended operations.
167     * @param connection
168     *            The connection to directory server.
169     *
170     * @return The new {@link BindResultLdapPromiseImpl}.
171     */
172    public static BindResultLdapPromiseImpl newBindLdapPromise(final int requestID,
173            final BindRequest request, final BindClient bindClient,
174            final IntermediateResponseHandler intermediateResponseHandler, final Connection connection) {
175        return new BindResultLdapPromiseImpl(requestID, request, bindClient, intermediateResponseHandler, connection);
176    }
177
178    /**
179     * Creates a new compare {@link ResultLdapPromiseImpl}.
180     *
181     * @param requestID
182     *            Identifier of the request.
183     * @param request
184     *            The compare request sent to the server.
185     * @param intermediateResponseHandler
186     *            Handler that consumes intermediate responses from extended operations.
187     * @param connection
188     *            The connection to directory server.
189     *
190     * @return The new {@link ResultLdapPromiseImpl}.
191     */
192    public static ResultLdapPromiseImpl<CompareRequest, CompareResult> newCompareLdapPromise(final int requestID,
193            final CompareRequest request, final IntermediateResponseHandler intermediateResponseHandler,
194            final Connection connection) {
195        return new ResultLdapPromiseImpl<CompareRequest, CompareResult>(requestID, request, intermediateResponseHandler,
196                connection) {
197            @Override
198            protected CompareResult newErrorResult(ResultCode resultCode, String diagnosticMessage, Throwable cause) {
199                return newCompareResult(resultCode).setDiagnosticMessage(diagnosticMessage).setCause(cause);
200            }
201        };
202    }
203
204    /**
205     * Creates a new extended {@link ExtendedResultLdapPromiseImpl}.
206     *
207     * @param <S>
208     *            The type of result returned by this promise.
209     * @param requestID
210     *            Identifier of the request.
211     * @param request
212     *            The extended request sent to the server.
213     * @param intermediateResponseHandler
214     *            Handler that consumes intermediate responses from extended operations.
215     * @param connection
216     *            The connection to directory server.
217     *
218     * @return The new {@link ExtendedResultLdapPromiseImpl}.
219     */
220    public static <S extends ExtendedResult> ExtendedResultLdapPromiseImpl<S> newExtendedLdapPromise(
221            final int requestID, final ExtendedRequest<S> request,
222            final IntermediateResponseHandler intermediateResponseHandler, final Connection connection) {
223        return new ExtendedResultLdapPromiseImpl<>(requestID, request, intermediateResponseHandler, connection);
224    }
225
226    /**
227     * Creates a new search {@link SearchResultLdapPromiseImpl}.
228     *
229     * @param requestID
230     *            Identifier of the request.
231     * @param request
232     *            The search request sent to the server.
233     * @param resultHandler
234     *            Handler that consumes search result.
235     * @param intermediateResponseHandler
236     *            Handler that consumes intermediate responses from extended operations.
237     * @param connection
238     *            The connection to directory server.
239     *
240     * @return The new {@link SearchResultLdapPromiseImpl}.
241     */
242    public static SearchResultLdapPromiseImpl newSearchLdapPromise(final int requestID, final SearchRequest request,
243            final SearchResultHandler resultHandler, final IntermediateResponseHandler intermediateResponseHandler,
244            final Connection connection) {
245        return new SearchResultLdapPromiseImpl(requestID, request, resultHandler, intermediateResponseHandler,
246                connection);
247    }
248
249
250
251    /**
252     * Converts a {@link Promise} to a {@link LdapPromise}.
253     *
254     * @param <R>
255     *            The type of the task's result, or {@link Void} if the task
256     *            does not return anything (i.e. it only has side-effects).
257     * @param wrappedPromise
258     *            The {@link Promise} to wrap.
259     * @return A {@link LdapPromise} representing the same asynchronous task as
260     *         the {@link Promise} provided.
261     */
262    public static <R> LdapPromise<R> asPromise(Promise<R, LdapException> wrappedPromise) {
263        return wrap(wrappedPromise, -1);
264    }
265
266    static <R> LdapPromise<R> wrap(Promise<R, LdapException> wrappedPromise, int requestID) {
267        return new LdapPromiseWrapper<>(wrappedPromise, requestID);
268    }
269
270    private LdapPromises() {
271    }
272
273}