com.iodesystems.fn.thread.Async Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fn Show documentation
Show all versions of fn Show documentation
Fn is a lazy Java Library that helps utilize some rudimentary functional concepts with more nounular objects
package com.iodesystems.fn.thread;
import com.iodesystems.fn.data.Option;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class Async {
public static final Executor INLINE = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
protected final List> nexts = new ArrayList>();
final Executor executor;
protected Option result = null;
protected Exception exception = null;
protected int progress = -1;
Async(Executor executor) {
this.executor = executor;
}
public static Async async(Callable initial) {
return async(INLINE, initial);
}
public static Async async(final A value) {
return async(INLINE, new Callable() {
@Override
public A call() throws Exception {
return value;
}
});
}
public static Deferred defer() {
return defer(INLINE);
}
public static Deferred defer(Executor executor) {
return new Deferred(executor);
}
public static Async async(Executor executor, Callable initial) {
return new Initial(executor, initial);
}
public static Next, List> when(final Executor executor, final Async... asyncs) {
final List results = new ArrayList(asyncs.length);
final List> thens = new ArrayList>();
final AtomicInteger countdown = new AtomicInteger(asyncs.length);
final AtomicBoolean hasException = new AtomicBoolean(false);
int index = 0;
final Next, List> next = new Next, List>(executor, new Result>() {
// Ignore this
}, null) {
@Override
public void remove() {
for (Next then : thens) {
then.remove();
}
}
};
for (Async async : asyncs) {
final int asyncIndex = index++;
results.add(null);
thens.add(async.then(executor, new Result() {
@Override
public A onResult(A a) throws Exception {
results.set(asyncIndex, a);
if (countdown.decrementAndGet() == 0) {
next.onParentResult(executor, results);
}
return super.onResult(a);
}
@Override
public Option onException(Exception e) {
if (hasException.compareAndSet(false, true)) {
next.onParentException(executor, e);
}
return Option.empty();
}
}));
}
return next;
}
public static Async> when(Async... asyncs) {
return when(INLINE, asyncs);
}
synchronized void exceptionInternal(Executor executor, Exception exception) {
this.exception = exception;
for (Next next : nexts) {
next.onParentException(executor, exception);
}
}
protected synchronized Next then(Next next) {
if (progress >= 0) {
next.onParentProgress(executor, progress);
}
if (result != null) {
next.onParentResult(executor, result.orElse(null));
} else if (exception != null) {
next.onParentException(executor, exception);
}
nexts.add(next);
return next;
}
public Next then(OnResult onResult) {
return then(executor, onResult);
}
public Next then(OnResult onResult, final OnException onException) {
return then(executor, onResult, onException);
}
public Next then(OnResult onResult, final OnException onException, final OnProgress onProgress) {
return then(executor, onResult, onException, onProgress);
}
public Next then(Executor executor, OnResult onResult) {
return then(executor, onResult, null);
}
public Next then(Executor executor, OnResult onResult, final OnException onException) {
return then(executor, onResult, onException, null);
}
public Next then(Executor executor, final OnResult onResult, final OnException onException, final OnProgress onProgress) {
return then(new Next(executor, new From() {
@Override
public B onResult(A a) throws Exception {
return onResult.onResult(a);
}
@Override
public int onProgress(int progress) {
if (onProgress != null) {
return onProgress.onProgress(progress);
}
return super.onProgress(progress);
}
@Override
public Option onException(Exception e) {
if (onException != null) {
return onException.onException(e);
}
return super.onException(e);
}
}, this));
}
public Next then(Result from) {
return then(executor, from);
}
public Next then(From from) {
return then(executor, from);
}
public Next then(Executor executor, Result result) {
return then(new Next(executor, result, this));
}
public Next then(Executor executor, From from) {
return then(new Next(executor, from, this));
}
synchronized void progressInternal(Executor executor, int progress) {
this.progress = progress;
for (Next next : nexts) {
next.onParentProgress(executor, progress);
}
}
synchronized void resultInternal(Executor executor, A result) {
this.result = Option.of(result);
for (Next next : nexts) {
next.onParentResult(executor, result);
}
}
public Next onProgress(OnProgress onProgress) {
return then(executor, null, null, onProgress);
}
public Next onException(OnException onException) {
return then(executor, null, onException, null);
}
public Next onProgress(Executor executor, OnProgress onProgress) {
return then(executor, null, null, onProgress);
}
public Next onException(Executor executor, OnException onException) {
return then(executor, null, onException, null);
}
private synchronized void remove(Next next) {
nexts.remove(next);
}
public interface OnResult {
B onResult(A a) throws Exception;
}
public interface OnException {
Option onException(Exception e);
}
public interface OnProgress {
int onProgress(int progress);
}
public static class Deferred extends Async {
public Deferred(Executor executor) {
super(executor);
}
@Override
protected synchronized Next then(Next next) {
if (progress >= 0) {
next.onParentProgress(null, progress);
}
if (result != null) {
next.onParentResult(null, result.orElse(null));
} else if (exception != null) {
next.onParentException(null, exception);
}
nexts.add(next);
return next;
}
public void progress(int progress) {
if (progress > -1) {
progressInternal(null, progress);
}
}
public void result(A result) {
resultInternal(null, result);
}
public void exception(Exception exception) {
exceptionInternal(null, exception);
}
}
public static class Initial extends Async {
private Initial(final Executor executor, final Callable callable) {
super(executor);
if (executor == INLINE) {
try {
resultInternal(executor, callable.call());
} catch (Exception e) {
exceptionInternal(executor, e);
}
} else {
executor.execute(new Runnable() {
@Override
public void run() {
try {
resultInternal(executor, callable.call());
} catch (Exception e) {
exceptionInternal(executor, e);
}
}
});
}
}
}
public static class Next extends Async {
private final From from;
private final Async parent;
public Next(Executor executor, From from, Async parent) {
super(executor);
this.from = from;
this.parent = parent;
}
public void remove() {
parent.remove(this);
}
private void onParentProgressInternal(int progress) {
progressInternal(executor, from.onProgress(progress));
}
private void onParentResultInternal(final A result) {
try {
resultInternal(executor, from.onResult(result));
} catch (Exception e) {
exceptionInternal(executor, e);
}
}
void onParentProgress(Executor parentExecutor, final int progress) {
if (isCurrentExecutor(parentExecutor)) {
onParentProgressInternal(progress);
} else {
this.executor.execute(new Runnable() {
@Override
public void run() {
onParentProgressInternal(progress);
}
});
}
}
private boolean isCurrentExecutor(Executor executor) {
return this.executor == INLINE || executor == this.executor;
}
void onParentResult(Executor parentExecutor, final A result) {
if (isCurrentExecutor(parentExecutor)) {
onParentResultInternal(result);
} else {
this.executor.execute(new Runnable() {
@Override
public void run() {
onParentResultInternal(result);
}
});
}
}
void onParentException(Executor parentExecutor, final Exception exception) {
if (isCurrentExecutor(parentExecutor)) {
onParentExceptionInternal(exception);
} else {
this.executor.execute(new Runnable() {
@Override
public void run() {
onParentExceptionInternal(exception);
}
});
}
}
private void onParentExceptionInternal(Exception exception) {
try {
Option recovery = from.onException(exception);
if (recovery.isPresent()) {
resultInternal(executor, recovery.get());
} else {
exceptionInternal(executor, exception);
}
} catch (Exception e) {
exceptionInternal(executor, e);
}
}
}
public static abstract class Result extends From {
@Override
public A onResult(A a) throws Exception {
return a;
}
}
public static abstract class From implements OnResult, OnException, OnProgress {
@Override
public B onResult(A a) throws Exception {
return null;
}
@Override
public int onProgress(int progress) {
return progress;
}
@Override
public Option onException(Exception e) {
return Option.empty();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy