/** * Used the result of this promise to create a new one by passing the resulting value into the given mapper. * * @param mapper the mapper to transform the promised value of this promise. * @param <X> the resulting type of the mapper * @return a new promise which will be either contain the mapped value or which fails if either this promise fails * or if the mapper throws an exception. */ @Nonnull public <X> Promise<X> map(@Nonnull final Function<V, X> mapper) { final Promise<X> result = new Promise<>(); mapChain(result, mapper); return result; }
@Override public void onFailure(Throwable throwable) { promise.fail(throwable); } });
/** * Waits until the promise is completed. * * @param timeout the maximal time to wait for the completion of this promise. * @return <tt>true</tt> if the promise was completed within the given timeout, <tt>false</tt> otherwise */ public boolean await(Duration timeout) { if (!isCompleted()) { awaitBlocking(timeout); } return isCompleted(); }
/** * Updates the entity in the database asynchronous using a dedicated thread pool. * * @param entity the entity to be written into the DB * @param <E> the type of the entity to update * @return a {@link Promise} handling the update process */ public <E extends Entity> Promise<E> updateAsync(E entity) { Promise<E> promise = new Promise<>(); tasks.executor(ASYNC_UPDATER).start(() -> { try { update(entity); promise.success(entity); } catch (Exception e) { promise.fail(e); } }); return promise; }
/** * Adds a completion handler to this promise. * <p> * If the promise is already completed, the handler is immediately invoked. * * @param handler the handler to be notified once the promise is completed. A promise can notify more than one * handler. * @return <tt>this</tt> for fluent method chaining */ @Nonnull @SuppressWarnings("squid:S2589") @Explain("We really want to ensure that the given value is not null and not just rely on annotation.") public Promise<V> onComplete(@Nonnull CompletionHandler<V> handler) { if (handler != null) { if (isSuccessful()) { completeHandler(get(), handler); } else if (isFailed()) { failHandler(getFailure(), handler); } else { this.handlers.add(handler); logErrors = false; } } return this; }
/** * Transforms a collection of items into a promise for a list of results while invoking an async function for * each item. * * @param input the items to iterate over * @param toPromiseHandler the async function which returns a promise to indicate completion * @param <I> the input type * @param <O> the output type generated by the async function * @return a promise containing the invocation results of the async function for each item in the input */ public static <I, O> Promise<List<O>> sequence(Iterable<I> input, Function<I, Promise<O>> toPromiseHandler) { Promise<List<O>> result = new Promise<>(); List<O> buffer = new ArrayList<>(); processChain(input, toPromiseHandler, (ignored, output) -> buffer.add(output)).onSuccess(() -> result.success( buffer)).onFailure(result::fail); return result; }
/** * Uses to result of this promise to generate a new promise using the given mapper. * * @param mapper the mapper to transform the promised value of this promise. * @param <X> the resulting type of the mapper * @return a new promise which will be either contain the mapped value or which fails if either this promise fails * or if the mapper throws an exception. */ @Nonnull public <X> Promise<X> flatMap(@Nonnull final Function<V, Promise<X>> mapper) { final Promise<X> result = new Promise<>(); onComplete(new CompletionHandler<V>() { @Override public void onSuccess(V value) throws Exception { try { mapper.apply(value).chain(result); } catch (Exception throwable) { result.fail(throwable); } } @Override public void onFailure(Throwable throwable) { result.fail(throwable); } }); return result; }
@Override public void onSuccess(@Nullable V value) throws Exception { if (!result.isFailed()) { // onSuccess can be called from any thread -> sync on resultList... synchronized (resultList) { resultList.set(currentIndex, value); } // Keep track how many results we're waiting for and forward the result when we're finished. latch.countDown(); if (latch.getCount() <= 0) { result.success(resultList); } } }
/** * Creates an instantly successful promise containing the given value. * * @param successValue the value to fulfill the promise with */ public Promise(V successValue) { success(successValue); }
Condition completed = lock.newCondition(); onComplete(new CompletionHandler<V>() { @Override public void onSuccess(@Nullable Object value) throws Exception { if (!isCompleted()) { lock.lock(); try {
/** * Marks the promise as successful and completed with the given value. * * @param value the value to be used as promised result. * @return <tt>this</tt> for fluent method chaining */ public Promise<V> success(@Nullable final V value) { this.value = new ValueHolder<>(value); for (final CompletionHandler<V> handler : handlers) { completeHandler(value, handler); } return this; }
/** * Marks the promise as failed due to the given error. * * @param exception the error to be used as reason for failure. * @return <tt>this</tt> for fluent method chaining */ public Promise<V> fail(@Nonnull final Throwable exception) { this.failure = exception; if (logErrors) { Exceptions.handle(Tasks.LOG, exception); } else if (Tasks.LOG.isFINE() && !(exception instanceof HandledException)) { Tasks.LOG.FINE(Exceptions.createHandled().error(exception)); } for (final CompletionHandler<V> handler : handlers) { failHandler(exception, handler); } return this; }
/** * Forks the given computation and returns a {@link Promise} for the computed value. * <p> * Forks the computation, which means that the current <tt>CallContext</tt> is transferred to the new thread, * and returns the result of the computation as promise. * <p> * If the executor for the given category is saturated (all threads are active and the queue is full) this * will drop the computation and the promise will be sent a <tt>RejectedExecutionException</tt>. * * @param category the category which implies which executor to use. * @param computation the computation which eventually yields the resulting value * @param <V> the type of the resulting value * @return a promise which will either be eventually supplied with the result of the computation or with an error */ public <V> Promise<V> fork(String category, final Supplier<V> computation) { final Promise<V> result = new Promise<>(); executor(category).dropOnOverload(() -> result.fail(new RejectedExecutionException())).fork(() -> { try { result.success(computation.get()); } catch (Exception t) { result.fail(t); } }); return result; }
final Promise<List<V>> result = new Promise<>(); for (Promise<V> promise : list) { final int currentIndex = index; promise.onComplete(new CompletionHandler<V>() { @Override public void onSuccess(@Nullable V value) throws Exception {
@Override public void onSuccess(V value) throws Exception { promise.success(value); }
@Override public void onFailure(Throwable throwable) { promise.fail(throwable); } });
@Override public void onFailure(Throwable throwable) { result.fail(throwable); } });
@Override public void onFailure(Throwable throwable) { promise.fail(throwable); } });