/* * Copyright 2013-2017 consulo.io * * 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 consulo.concurrency; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.ActionCallback; import com.intellij.openapi.util.AsyncResult; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.util.Consumer; import com.intellij.util.ThreeState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.concurrency.*; import java.util.Collection; /** * @author VISTALL * @since 30-Apr-17 * <p> * from kotlin intellij-community\platform\projectModel-api\src\org\jetbrains\concurrency\promise.kt */ public class Promises { private static final NotNullLazyValue<Promise> REJECTED = NotNullLazyValue.createValue(() -> Promise.REJECTED); private static final NotNullLazyValue<Promise> DONE = NotNullLazyValue.createValue(() -> Promise.DONE); private static final NotNullLazyValue<RuntimeException> OBSOLETE_ERROR = NotNullLazyValue.createValue(() -> Promise.createError("Obsolete")); private static final NotNullLazyValue<Promise> CANCELLED_PROMISE = NotNullLazyValue.createValue(() -> new RejectedPromise(OBSOLETE_ERROR.getValue())); public static boolean isFulfilled(@Nullable Promise<?> promise) { return promise != null && promise.getState() == Promise.State.FULFILLED; } public static boolean isRejected(@Nullable Promise<?> promise) { return promise != null && promise.getState() == Promise.State.REJECTED; } public static boolean isPending(@Nullable Promise<?> promise) { return promise != null && promise.getState() == Promise.State.PENDING; } @NotNull @SuppressWarnings("unchecked") public static <T> Promise<T> rejectedPromise() { return REJECTED.getValue(); } @NotNull @SuppressWarnings("unchecked") public static <T> Promise<T> resolvedPromise() { return DONE.getValue(); } @NotNull @SuppressWarnings("unchecked") public static <T> Promise<T> cancelledPromise() { return CANCELLED_PROMISE.getValue(); } @NotNull public static <T> Promise<T> rejectedPromise(@Nullable Throwable error) { if (error == null) { //noinspection unchecked return rejectedPromise(); } else { return new RejectedPromise<>(error); } } @NotNull public static <T> Promise<T> rejectedPromise(@NotNull String error) { return rejectedPromise(Promise.createError(error)); } @NotNull @Deprecated public static <T> Promise<T> reject(@Nullable Throwable error) { return rejectedPromise(error); } @NotNull @Deprecated public static <T> Promise<T> reject(@NotNull String error) { return rejectedPromise(error); } @NotNull public static Promise<Void> all(@NotNull Collection<Promise<?>> promises) { return all(promises, null); } @NotNull public static <T> Promise<T> all(@NotNull Collection<Promise<?>> promises, @Nullable T totalResult) { if (promises.isEmpty()) { //noinspection unchecked return (Promise<T>)DONE.getValue(); } final AsyncPromise<T> totalPromise = new AsyncPromise<>(); Consumer done = new CountDownConsumer<>(promises.size(), totalPromise, totalResult); Consumer<Throwable> rejected = error -> { if (totalPromise.getState() == AsyncPromise.State.PENDING) { totalPromise.setError(error); } }; for (Promise<?> promise : promises) { //noinspection unchecked promise.done(done); promise.rejected(rejected); } return totalPromise; } @NotNull public static Promise<Void> wrapAsVoid(@NotNull ActionCallback asyncResult) { final AsyncPromise<Void> promise = new AsyncPromise<>(); asyncResult.doWhenDone(() -> promise.setResult(null)) .doWhenRejected(error -> promise.setError(Promise.createError(error == null ? "Internal error" : error))); return promise; } @NotNull public static <T> Promise<T> wrap(@NotNull AsyncResult<T> asyncResult) { final AsyncPromise<T> promise = new AsyncPromise<>(); asyncResult.doWhenDone(promise::setResult).doWhenRejected(error -> promise.setError(Promise.createError(error))); return promise; } @NotNull public static <T> Promise<T> resolve(T result) { if (result == null) { //noinspection unchecked return (Promise<T>)Promise.DONE; } else { return new DonePromise<>(result); } } public static boolean errorIfNotMessage(Logger logger, Throwable e) { if (e instanceof Promise.MessageError) { ThreeState log = ((Promise.MessageError)e).getLog(); if (log == ThreeState.YES || (log == ThreeState.UNSURE && (ApplicationManager.getApplication().isUnitTestMode()))) { logger.error(e); return true; } } else if (!(e instanceof ProcessCanceledException)) { logger.error(e); return true; } return false; } }