All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.osgi.util.promise.PromiseImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) OSGi Alliance (2014, 2017). All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osgi.util.promise;

import static java.util.Objects.requireNonNull;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.osgi.util.function.Consumer;
import org.osgi.util.function.Function;
import org.osgi.util.function.Predicate;

/**
 * Abstract Promise implementation.
 * 

* This class is not used directly by clients. Clients should use * {@link PromiseFactory} to create a {@link Promise}. * * @param The result type associated with the Promise. * @ThreadSafe * @author $Id: d78ae3b66022562df2d4fbd7cca23038b30057d5 $ */ abstract class PromiseImpl implements Promise { /** * The factory to use for callbacks and scheduled operations. */ private final PromiseFactory factory; /** * A ConcurrentLinkedQueue to hold the callbacks for this Promise, so no * additional synchronization is required to write to or read from the * queue. */ private final ConcurrentLinkedQueue callbacks; /** * Initialize this Promise. * * @param factory The factory to use for callbacks and scheduled * operations. */ PromiseImpl(PromiseFactory factory) { this.factory = requireNonNull(factory); callbacks = new ConcurrentLinkedQueue<>(); } /** * Return a new {@link DeferredPromiseImpl} using the {@link PromiseFactory} * of this PromiseImpl. * * @return A new DeferredPromiseImpl. * @since 1.1 */ DeferredPromiseImpl deferred() { return new DeferredPromiseImpl<>(factory); } /** * Return a new {@link ResolvedPromiseImpl} using the {@link PromiseFactory} * of this PromiseImpl. * * @param v Value for the ResolvedPromiseImpl. * @return A new ResolvedPromiseImpl. * @since 1.1 */ ResolvedPromiseImpl resolved(V v) { return new ResolvedPromiseImpl<>(v, factory); } /** * Return a new {@link FailedPromiseImpl} using the {@link PromiseFactory} * of this PromiseImpl. * * @param f Failure for the FailedPromiseImpl. * @return A new FailedPromiseImpl. * @since 1.1 */ FailedPromiseImpl failed(Throwable f) { return new FailedPromiseImpl<>(f, factory); } /** * {@inheritDoc} */ @Override public Promise onResolve(Runnable callback) { callbacks.offer(callback); notifyCallbacks(); // call any registered callbacks return this; } /** * Call any registered callbacks if this Promise is resolved. */ void notifyCallbacks() { if (!isDone()) { return; // return if not resolved } /* * Note: multiple threads can be in this method removing callbacks from * the queue and executing them, so the order in which callbacks are * executed cannot be specified. */ for (Runnable callback = callbacks.poll(); callback != null; callback = callbacks.poll()) { try { try { factory.executor().execute(callback); } catch (RejectedExecutionException e) { callback.run(); } } catch (Throwable t) { uncaughtException(t); } } } /** * Schedule a operation on the scheduled executor. * * @since 1.1 */ ScheduledFuture< ? > schedule(Runnable operation, long delay, TimeUnit unit) { try { try { return factory.scheduledExecutor().schedule(operation, delay, unit); } catch (RejectedExecutionException e) { operation.run(); } } catch (Throwable t) { uncaughtException(t); } return null; } /** * Handle an uncaught exception from a Runnable. * * @param t The uncaught exception. * @since 1.1 */ static void uncaughtException(Throwable t) { try { Thread thread = Thread.currentThread(); thread.getUncaughtExceptionHandler().uncaughtException(thread, t); } catch (Throwable ignored) { // we ignore this } } /** * Run the specified chain when the specified promise is resolved. * * @param promise The promise associated with the chain. * @param chain The chain to run when the promise is resolved. */ static void chain(Promise promise, Runnable chain) { if (promise.isDone()) { try { chain.run(); } catch (Throwable t) { uncaughtException(t); } } else { promise.onResolve(chain); } } /** * {@inheritDoc} */ @Override public Promise onSuccess(Consumer< ? super T> success) { return onResolve(new OnSuccess(success)); } /** * A callback used for the {@link #onSuccess(Consumer)} method. * * @Immutable * @since 1.1 */ private final class OnSuccess implements Runnable { private final Consumer< ? super T> success; OnSuccess(Consumer< ? super T> success) { this.success = requireNonNull(success); } @Override public void run() { Result result = collect(); if (result.fail == null) { try { success.accept(result.value); } catch (Throwable e) { uncaughtException(e); } } } } /** * {@inheritDoc} */ @Override public Promise onFailure(Consumer< ? super Throwable> failure) { return onResolve(new OnFailure(failure)); } /** * A callback used for the {@link #onFailure(Consumer)} method. * * @Immutable * @since 1.1 */ private final class OnFailure implements Runnable { private final Consumer< ? super Throwable> failure; OnFailure(Consumer< ? super Throwable> failure) { this.failure = requireNonNull(failure); } @Override public void run() { Result result = collect(); if (result.fail != null) { try { failure.accept(result.fail); } catch (Throwable e) { uncaughtException(e); } } } } /** * {@inheritDoc} */ @Override public Promise then(Success success, Failure failure) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Then<>(this, success, failure)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise then(Success success) { return then(success, null); } /** * {@inheritDoc} */ @Override public Promise thenAccept(Consumer< ? super T> consumer) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new ThenAccept(this, consumer)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise filter(Predicate predicate) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Filter(this, predicate)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise map(Function mapper) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Map<>(this, mapper)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise flatMap(Function> mapper) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new FlatMap<>(this, mapper)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise recover(Function, ? extends T> recovery) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Recover(this, recovery)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise recoverWith(Function, Promise> recovery) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new RecoverWith(this, recovery)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise fallbackTo(Promise fallback) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new FallbackTo(this, fallback)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise timeout(long millis) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Timeout(this, millis)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise delay(long millis) { DeferredPromiseImpl chained = deferred(); chain(this, chained.new Delay(this, millis)); return chained.orDone(); } /** * A holder of the result of a Promise. * * @NotThreadSafe * @since 1.1 */ static final class Result

{ P value; Throwable fail; Result(P value) { this.value = value; this.fail = null; } Result(Throwable fail) { this.value = null; this.fail = fail; } } /** * Return a holder of the result of this PromiseImpl. * * @since 1.1 */ abstract Result collect(); /** * Return a holder of the result of the specified Promise. * * @since 1.1 */ static Result collect(Promise< ? extends R> promise) { if (promise instanceof PromiseImpl) { @SuppressWarnings("unchecked") PromiseImpl impl = (PromiseImpl) promise; return impl.collect(); } if (!promise.isDone()) { return new Result(new AssertionError("promise not resolved")); } final boolean interrupted = Thread.interrupted(); try { Throwable fail = promise.getFailure(); if (fail == null) { return new Result(promise.getValue()); } return new Result(fail); } catch (Throwable e) { return new Result(e); // propagate new exception } finally { if (interrupted) { // restore interrupt status Thread.currentThread().interrupt(); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy