package io.datakernel.async;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.eventloop.ScheduledRunnable;
import io.datakernel.exception.AsyncTimeoutException;
import java.util.Collection;
import java.util.Iterator;
import static java.util.Arrays.asList;
public class AsyncRunnables {
public static final AsyncTimeoutException RUNNABLE_TIMEOUT_EXCEPTION =
new AsyncTimeoutException("AsyncRunnable timeout");
private AsyncRunnables() {
}
public static AsyncRunnable timeout(final Eventloop eventloop, final long timestamp, final AsyncRunnable runnable) {
return new AsyncRunnable() {
@Override
public void run(final CompletionCallback callback) {
final ScheduledRunnable scheduledRunnable = eventloop.schedule(timestamp, new Runnable() {
@Override
public void run() {
callback.setException(RUNNABLE_TIMEOUT_EXCEPTION);
if (runnable instanceof AsyncCancellable) {
((AsyncCancellable) runnable).cancel();
}
}
});
runnable.run(new CompletionCallback() {
@Override
protected void onComplete() {
scheduledRunnable.cancel();
callback.setComplete();
}
@Override
protected void onException(Exception e) {
scheduledRunnable.cancel();
callback.setException(e);
}
});
}
};
}
public static AsyncRunnable runInSequence(final Eventloop eventloop, final AsyncRunnable... runnables) {
return runInSequence(eventloop, asList(runnables));
}
public static AsyncRunnable runInSequence(final Eventloop eventloop, final Iterable<? extends AsyncRunnable> runnables) {
return new AsyncRunnable() {
@Override
public void run(CompletionCallback callback) {
next(runnables.iterator(), callback);
}
void next(final Iterator<? extends AsyncRunnable> iterator, final CompletionCallback callback) {
if (iterator.hasNext()) {
AsyncRunnable nextTask = iterator.next();
final long microTick = eventloop.getMicroTick();
nextTask.run(new ForwardingCompletionCallback(callback) {
@Override
protected void onComplete() {
if (eventloop.getMicroTick() != microTick)
next(iterator, callback);
else
eventloop.post(new Runnable() {
@Override
public void run() {
next(iterator, callback);
}
});
}
});
} else {
callback.setComplete();
}
}
};
}
public static AsyncRunnable runInParallel(final Eventloop eventloop, final AsyncRunnable... runnables) {
return runInParallel(eventloop, asList(runnables));
}
private static final class RunState {
int pending;
public RunState(int pending) {
this.pending = pending;
}
}
public static AsyncRunnable runInParallel(final Eventloop eventloop, final Collection<? extends AsyncRunnable> runnables) {
return new AsyncRunnable() {
@Override
public void run(final CompletionCallback callback) {
final RunState state = new RunState(runnables.size());
if (state.pending == 0) {
callback.postComplete(eventloop);
return;
}
for (AsyncRunnable runnable : runnables) {
runnable.run(new CompletionCallback() {
@Override
protected void onComplete() {
if (--state.pending == 0) {
callback.setComplete();
}
}
@Override
protected void onException(Exception e) {
if (state.pending > 0) {
state.pending = 0;
callback.setException(e);
}
}
});
}
}
};
}
}