package io.datakernel.async;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.eventloop.ScheduledRunnable;
import io.datakernel.exception.AsyncTimeoutException;
import java.util.Arrays;
import java.util.List;
import static java.util.Arrays.asList;
public class AsyncCallables {
public static final AsyncTimeoutException CALLABLE_TIMEOUT_EXCEPTION = new AsyncTimeoutException("AsyncCallable timeout");
private AsyncCallables() {
}
public static <T> AsyncCallable<T> callWithTimeout(final Eventloop eventloop, final long timestamp, final AsyncCallable<T> callable) {
return new AsyncCallable<T>() {
@Override
public void call(final ResultCallback<T> callback) {
final ScheduledRunnable scheduledRunnable = eventloop.schedule(timestamp, new Runnable() {
@Override
public void run() {
callback.setException(CALLABLE_TIMEOUT_EXCEPTION);
if (callable instanceof AsyncCancellable) {
((AsyncCancellable) callable).cancel();
}
}
});
callable.call(new ResultCallback<T>() {
@Override
protected void onResult(T result) {
scheduledRunnable.cancel();
callback.setResult(result);
}
@Override
protected void onException(Exception e) {
scheduledRunnable.cancel();
callback.setException(e);
}
});
}
};
}
@SafeVarargs
public static <T> AsyncCallable<List<T>> callAll(final Eventloop eventloop, final AsyncCallable<T>... callables) {
return callAll(eventloop, asList(callables));
}
private static final class CallState {
int pending;
public CallState(int pending) {
this.pending = pending;
}
}
@SuppressWarnings("unchecked")
public static <T> AsyncCallable<List<T>> callAll(final Eventloop eventloop, final List<? extends AsyncCallable<T>> callables) {
return new AsyncCallable<List<T>>() {
@Override
public void call(final ResultCallback<List<T>> callback) {
final CallState state = new CallState(callables.size());
final T[] results = (T[]) new Object[callables.size()];
if (state.pending == 0) {
callback.postResult(eventloop, Arrays.asList(results));
return;
}
for (int i = 0; i < callables.size(); i++) {
AsyncCallable<T> callable = (AsyncCallable<T>) callables.get(i);
final int finalI = i;
callable.call(new ResultCallback<T>() {
@Override
protected void onResult(T result) {
results[finalI] = result;
if (--state.pending == 0) {
callback.setResult(Arrays.asList(results));
}
}
@Override
protected void onException(Exception e) {
if (state.pending > 0) {
state.pending = 0;
callback.setException(e);
}
}
});
}
}
};
}
@SafeVarargs
public static <T> AsyncCallable<List<T>> callAllWithTimeout(final Eventloop eventloop, final long timestamp, final AsyncCallable<T>... callables) {
return callAllWithTimeout(eventloop, timestamp, asList(callables));
}
public static <T> AsyncCallable<List<T>> callAllWithTimeout(final Eventloop eventloop, final long timestamp, final List<? extends AsyncCallable<T>> callables) {
return new AsyncCallable<List<T>>() {
@Override
public void call(final ResultCallback<List<T>> callback) {
final CallState state = new CallState(callables.size());
@SuppressWarnings("unchecked")
final T[] results = (T[]) new Object[callables.size()];
if (state.pending == 0) {
callback.postResult(eventloop, Arrays.asList(results));
return;
}
final ScheduledRunnable scheduledRunnable = eventloop.schedule(timestamp, new Runnable() {
@Override
public void run() {
state.pending = 0;
callback.setResult(Arrays.asList(results));
}
});
for (int i = 0; i < callables.size(); i++) {
final AsyncCallable<T> callable = (AsyncCallable<T>) callables.get(i);
final int finalI = i;
callable.call(new ResultCallback<T>() {
@Override
protected void onResult(T result) {
results[finalI] = result;
if (--state.pending == 0) {
scheduledRunnable.cancel();
callback.setResult(Arrays.asList(results));
}
}
@Override
protected void onException(Exception e) {
if (state.pending > 0) {
state.pending = 0;
scheduledRunnable.cancel();
callback.setException(e);
}
}
});
}
}
};
}
}