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 = Runnable::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, () -> 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);
}
@SafeVarargs
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;
}
@SafeVarargs
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 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(
() -> {
try {
Initial.this.resultInternal(executor, callable.call());
} catch (Exception e) {
Initial.this.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() {
//noinspection unchecked
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(() -> Next.this.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(() -> Next.this.onParentResultInternal(result));
}
}
void onParentException(Executor parentExecutor, final Exception exception) {
if (isCurrentExecutor(parentExecutor)) {
onParentExceptionInternal(exception);
} else {
this.executor.execute(() -> Next.this.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 abstract static class Result extends From {
@Override
public A onResult(A a) throws Exception {
return a;
}
}
public abstract static 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