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

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

There is a newer version: 2024.11.18598.20241113T125352Z-241000
Show newest version
/*******************************************************************************
 * Copyright (c) Contributors to the Eclipse Foundation
 *
 * 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.
 *
 * SPDX-License-Identifier: Apache-2.0 
 *******************************************************************************/

package org.osgi.util.promise;

import static java.util.Objects.requireNonNull;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
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: 47302e4cee8df3450be43cd8850bc188e25b4828 $ */ 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); } /** * Marker interface for internal callbacks which do not call user code and * should be run on the current thread for an already resolved promise. Such * internal callbacks should be directly called to resolve a * DeferredPromiseImpl so that its {@link DeferredPromiseImpl#orDone()} * method can convert it to a resolved {@link PromiseImpl} type for * efficiency. * * @since 1.2 */ interface InlineCallback { // Internal callback that should be called inline for a resolved // promise. } /** * {@inheritDoc} */ @Override public Promise onResolve(Runnable callback) { requireNonNull(callback); if (isDone() && ((callback instanceof InlineCallback) || factory.allowCurrentThread())) { try { callback.run(); } catch (Throwable t) { uncaughtException(t); } } else { 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; (callback = callbacks.poll()) != null;) { execute(callback); } } /** * Execute a operation on the executor. * * @since 1.2 */ void execute(Runnable operation) { try { try { factory.executor().execute(operation); } catch (RejectedExecutionException e) { operation.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) { execute(operation); } } 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 } } /** * {@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, Result { private final Consumer< ? super T> success; OnSuccess(Consumer< ? super T> success) { this.success = requireNonNull(success); } @Override public void run() { result(this); } @Override public void accept(T v, Throwable f) { if (f == null) { try { success.accept(v); } 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, Result { private final Consumer< ? super Throwable> failure; OnFailure(Consumer< ? super Throwable> failure) { this.failure = requireNonNull(failure); } @Override public void run() { result(this); } @Override public void accept(T v, Throwable f) { if (f != null) { try { failure.accept(f); } catch (Throwable e) { uncaughtException(e); } } } } /** * {@inheritDoc} */ @Override public Promise then(Success success, Failure failure) { DeferredPromiseImpl chained = deferred(); onResolve(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(); onResolve(chained.new ThenAccept(this, consumer)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise filter(Predicate predicate) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new Filter(this, predicate)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise map(Function mapper) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new Map<>(this, mapper)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise flatMap(Function> mapper) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new FlatMap<>(this, mapper)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise recover(Function, ? extends T> recovery) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new Recover(this, recovery)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise recoverWith(Function, Promise> recovery) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new RecoverWith(this, recovery)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise fallbackTo(Promise fallback) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new FallbackTo(this, fallback)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise timeout(long millis) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new Timeout(this, millis)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public Promise delay(long millis) { DeferredPromiseImpl chained = deferred(); onResolve(chained.new Delay(this, millis)); return chained.orDone(); } /** * {@inheritDoc} */ @Override public CompletionStage toCompletionStage() { CompletableFuture completableFuture = new CompletableFuture<>(); onResolve(new ToCompletionStage(completableFuture)); return completableFuture; } /** * A callback used for the {@link #toCompletionStage()} method. * * @Immutable * @since 1.2 */ private final class ToCompletionStage implements Runnable, Result { private final CompletableFuture completableFuture; ToCompletionStage(CompletableFuture completableFuture) { this.completableFuture = requireNonNull(completableFuture); } @Override public void run() { result(this); } @Override public void accept(T v, Throwable f) { if (f == null) { completableFuture.complete(v); } else { completableFuture.completeExceptionally(f); } } } /** * A consumer of the result of a Promise. * * @since 1.2 */ interface Result { void accept(R value, Throwable fail); } /** * Accept the result of this PromiseImpl. * * @since 1.2 */ abstract void result(Result< ? super T> consumer); /** * Accept the result of the specified Promise. * * @since 1.2 */ static void result(Promise< ? extends R> promise, Result< ? super R> consumer) { if (promise instanceof PromiseImpl) { PromiseImpl< ? extends R> impl = (PromiseImpl< ? extends R>) promise; impl.result(consumer); return; } if (!promise.isDone()) { consumer.accept(null, new AssertionError("promise not resolved")); return; } R value; Throwable fail; final boolean interrupted = Thread.interrupted(); try { fail = promise.getFailure(); value = (fail == null) ? promise.getValue() : null; } catch (Throwable e) { fail = e; // propagate new exception value = null; } finally { if (interrupted) { // restore interrupt status Thread.currentThread().interrupt(); } } consumer.accept(value, fail); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy