blob: 2d0a4a834fe070fe810fde3e9a7e9bdfa1425f59 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* 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 com.intellij.openapi.util;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.PairConsumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
public class AsyncResult<T> extends ActionCallback {
private static final Logger LOG = Logger.getInstance(AsyncResult.class);
private static final AsyncResult REJECTED = new Rejected();
private static final AsyncResult DONE_LIST = new Done<Object>(Collections.EMPTY_LIST);
protected T myResult;
public AsyncResult() {
}
AsyncResult(int countToDone, @Nullable T result) {
super(countToDone);
myResult = result;
}
@NotNull
public AsyncResult<T> setDone(T result) {
myResult = result;
setDone();
return this;
}
@NotNull
public AsyncResult<T> setRejected(T result) {
myResult = result;
setRejected();
return this;
}
@NotNull
public <DependentResult> AsyncResult<DependentResult> subResult(@NotNull Function<T, DependentResult> doneHandler) {
return subResult(new AsyncResult<DependentResult>(), doneHandler);
}
@NotNull
public <SubResult, SubAsyncResult extends AsyncResult<SubResult>> SubAsyncResult subResult(@NotNull SubAsyncResult subResult,
@NotNull Function<T, SubResult> doneHandler) {
doWhenDone(new SubResultDoneCallback<T, SubResult, SubAsyncResult>(subResult, doneHandler)).notifyWhenRejected(subResult);
return subResult;
}
@NotNull
public ActionCallback subCallback(@NotNull Consumer<T> doneHandler) {
ActionCallback subCallback = new ActionCallback();
doWhenDone(new SubCallbackDoneCallback<T>(subCallback, doneHandler)).notifyWhenRejected(subCallback);
return subCallback;
}
@NotNull
@Deprecated
/**
* @deprecated Use {@link #doWhenDone(com.intellij.util.Consumer)} (to remove in IDEA 16)
*/
public AsyncResult<T> doWhenDone(@SuppressWarnings("deprecation") @NotNull final Handler<T> handler) {
doWhenDone(new Runnable() {
@Override
public void run() {
handler.run(myResult);
}
});
return this;
}
@NotNull
public AsyncResult<T> doWhenDone(@NotNull final Consumer<T> consumer) {
doWhenDone(new Runnable() {
@Override
public void run() {
consumer.consume(myResult);
}
});
return this;
}
@NotNull
@Deprecated
/**
* @deprecated Use {@link #doWhenRejected(com.intellij.util.Consumer)} (to remove in IDEA 16)
*/
public AsyncResult<T> doWhenRejected(@SuppressWarnings("deprecation") @NotNull final Handler<T> handler) {
doWhenRejected(new Runnable() {
@Override
public void run() {
handler.run(myResult);
}
});
return this;
}
@NotNull
public AsyncResult<T> doWhenRejected(@NotNull final PairConsumer<T, String> consumer) {
doWhenRejected(new Runnable() {
@Override
public void run() {
consumer.consume(myResult, myError);
}
});
return this;
}
@Override
@NotNull
public final AsyncResult<T> notify(@NotNull final ActionCallback child) {
super.notify(child);
return this;
}
public T getResult() {
return myResult;
}
public T getResultSync() {
return getResultSync(-1);
}
@Nullable
public T getResultSync(long msTimeout) {
waitFor(msTimeout);
return myResult;
}
@NotNull
public final ActionCallback doWhenProcessed(@NotNull final Consumer<T> consumer) {
doWhenDone(consumer);
doWhenRejected(new PairConsumer<T, String>() {
@Override
public void consume(T result, String error) {
consumer.consume(result);
}
});
return this;
}
@Deprecated
/**
* @deprecated Use {@link com.intellij.util.Consumer} (to remove in IDEA 16)
*/
public interface Handler<T> {
void run(T t);
}
public static class Done<T> extends AsyncResult<T> {
public Done(T value) {
setDone(value);
}
}
public static class Rejected<T> extends AsyncResult<T> {
public Rejected() {
setRejected();
}
public Rejected(T value) {
setRejected(value);
}
}
@NotNull
public static <R> AsyncResult<R> rejected() {
//noinspection unchecked
return REJECTED;
}
@NotNull
public static <R> AsyncResult<R> rejected(@NotNull String errorMessage) {
AsyncResult<R> result = new AsyncResult<R>();
result.reject(errorMessage);
return result;
}
@NotNull
public static <R> AsyncResult<R> done(@Nullable R result) {
return new AsyncResult<R>().setDone(result);
}
@NotNull
public static <R extends List> AsyncResult<R> doneList() {
//noinspection unchecked
return DONE_LIST;
}
// we don't use inner class, avoid memory leak, we don't want to hold this result while dependent is computing
private static class SubResultDoneCallback<Result, SubResult, AsyncSubResult extends AsyncResult<SubResult>> implements Consumer<Result> {
private final AsyncSubResult subResult;
private final Function<Result, SubResult> doneHandler;
public SubResultDoneCallback(AsyncSubResult subResult, Function<Result, SubResult> doneHandler) {
this.subResult = subResult;
this.doneHandler = doneHandler;
}
@Override
public void consume(Result result) {
SubResult v;
try {
v = doneHandler.fun(result);
}
catch (Throwable e) {
subResult.reject(e.getMessage());
LOG.error(e);
return;
}
subResult.setDone(v);
}
}
private static class SubCallbackDoneCallback<Result> implements Consumer<Result> {
private final ActionCallback subResult;
private final Consumer<Result> doneHandler;
public SubCallbackDoneCallback(ActionCallback subResult, Consumer<Result> doneHandler) {
this.subResult = subResult;
this.doneHandler = doneHandler;
}
@Override
public void consume(Result result) {
try {
doneHandler.consume(result);
}
catch (Throwable e) {
subResult.reject(e.getMessage());
LOG.error(e);
return;
}
subResult.setDone();
}
}
}