All Downloads are FREE. Search and download functionalities are using the official Maven repository.

delight.async.AsyncCommon Maven / Gradle / Ivy

Go to download

Asynchronous utilities for Java and GWT applications. Includes a simple promise implementation for Java.

There is a newer version: 0.1.5
Show newest version
package delight.async;

import delight.async.callbacks.ListCallback;
import delight.async.callbacks.SimpleCallback;
import delight.async.callbacks.ValueCallback;
import delight.async.flow.CallbackAggregator;
import delight.async.flow.CallbackMap;
import delight.async.helper.Aggregator;
import delight.functional.Closure;
import delight.functional.Closure2;
import delight.functional.Success;
import delight.functional.SuccessFail;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 

* Asynchronous operations which can be applied in a Java and JavaScript * environment. * * @author Max Rohde * */ public class AsyncCommon { /** *

* Tries to resolve a {@link Operation} immediately without waiting for the * asynchronous operation. *

* This is useful for operations which actually resolve in a synchronous * fashion (which might be added for legacy logic). * * @param deferred * @return */ public static final ResultType getDirty(final Operation deferred) { final Value resolved = new Value(false); final Value value = new Value(null); final Value exception = new Value(null); deferred.apply(new ValueCallback() { @Override public void onFailure(final Throwable t) { exception.set(t); } @Override public void onSuccess(final ResultType result) { value.set(result); resolved.set(true); } }); if (exception.get() != null) { throw new RuntimeException(exception.get()); } if (!resolved.get()) { throw new RuntimeException("Asynchronous get could not be resolved for " + deferred); } return value.get(); } /** *

* Will apply the asynchronous operation operation to all inputs and * call the callback once all operations are completed. *

* Callback is also called upon the first operation which fails. *

* ValueCallback must be called in closure. * * @param inputs * @param operation * @param callback */ public static void map(final List inputs, final AsyncFunction operation, final ListCallback callback) { final CallbackMap callbackMap = new CallbackMap(inputs, callback); for (final InputType input : inputs) { operation.apply(input, callbackMap.createCallback(input)); } } public final static SimpleCallback asSimpleCallbackAndReturnSuccess(final ValueCallback callback) { return new SimpleCallback() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess() { callback.onSuccess(Success.INSTANCE); } }; } public final static SimpleCallback asSimpleCallback(final ValueCallback callback) { return new SimpleCallback() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess() { callback.onSuccess((T) Success.INSTANCE); } }; } public static final ValueCallback> asListCallback(final ValueCallback callback) { return new ValueCallback>() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess(final List value) { callback.onSuccess(Success.INSTANCE); } }; } public static final ValueCallback asValueCallback(final SimpleCallback callback) { return new ValueCallback() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess(final T value) { callback.onSuccess(); } }; } public static final Closure wrapAsClosure(final ValueCallback callback) { return new Closure() { @Override public void apply(final SuccessFail o) { if (o.isFail()) { callback.onFailure(o.getException()); return; } callback.onSuccess(Success.INSTANCE); } }; } public final static SimpleCallback doNothing() { return new SimpleCallback() { @Override public void onFailure(final Throwable t) { throw new RuntimeException(t); } @Override public void onSuccess() { } }; } public final static SimpleCallback onSuccess(final Closure closure) { return new SimpleCallback() { @Override public void onFailure(final Throwable t) { throw new RuntimeException(t); } @Override public void onSuccess() { closure.apply(Success.INSTANCE); } }; } /** *

* Creates a factory for callbacks. When these callbacks are called, their * results are aggregated in the order in which the callbacks have been * created. *

* If the factory has not been called the same number of times as results * are expected, the defined callback will be called when the created * callbacks have been called the number of expected times. * * @param results * @param callWhenCollected * @return */ public final static Aggregator collect(final int results, final ValueCallback> callWhenCollected) { return new CallbackAggregator(results, callWhenCollected); } @SuppressWarnings("rawtypes") public static void parallelAr(final OP[] operations, final ValueCallback> callback) { parallel(Arrays.asList(operations), callback); } public static > void parallel(final List operations, final ValueCallback> callback) { parallel(operations, Integer.MAX_VALUE, callback); } public final static > void parallel(final List operations, final int maxParallelOps, final ValueCallback> callback) { if (operations.size() == 0) { callback.onSuccess(new ArrayList(0)); return; } if (operations.size() <= maxParallelOps) { final Aggregator aggregator = collect(operations.size(), callback); for (final Operation op : operations) { op.apply(aggregator.createCallback()); } return; } final List toRun = operations.subList(0, maxParallelOps); final List remaining = operations.subList(maxParallelOps, operations.size()); assert operations.size() == toRun.size() + remaining.size() : "Invalid list split: " + operations.size() + " into (" + toRun.size() + " and " + remaining.size() + ")"; parallel(toRun, maxParallelOps, AsyncCommon.embed(callback, new Closure>() { @Override public void apply(final List head) { parallel(remaining, maxParallelOps, embed(callback, new Closure>() { @Override public void apply(final List tail) { final List all = new ArrayList(head.size() + tail.size()); all.addAll(head); all.addAll(tail); callback.onSuccess(all); } })); } })); } public static void parallelUnsafe(final List operations, final ValueCallback> callback) { parallel((List>) operations, callback); } /** * Perform the listed operations sequentially. * * @param operations * @param callback */ public static void sequential(final List> operations, final ValueCallback> callback) { sequentialInt(operations, 0, new ArrayList(operations.size()), callback); } private static void sequentialInt(final List> operations, final int idx, final List results, final ValueCallback> callback) { if (idx >= operations.size()) { callback.onSuccess(results); return; } operations.get(idx).apply(new ValueCallback() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess(final R value) { results.add(value); sequentialInt(operations, idx + 1, results, callback); } }); } /** *

* Performs the provided operation on all elements of the provided list and * calls a callback with all results when completed. *

* Does not wait for the asynchronous result of one operation to proceed * with the other. Thus if operations are implemented asynchronously, the * operations will run in parallel. * * @param elements * @param operation * @param callback */ public final static void forEach(final List elements, final Closure2> operation, final ValueCallback> callback) { final Aggregator agg = collect(elements.size(), callback); for (final E element : elements) { final ValueCallback itmcb = agg.createCallback(); operation.apply(element, itmcb); } } /** *

* Embeds the closure within the provided callback. *

* Useful for cascading callbacks while avoiding to define onFailure method * declarations. * * @param toCallback * @param onSuccess * @return */ public final static ValueCallback embed(final ValueCallback toCallback, final Closure onSuccess) { return new ValueCallback() { @Override public void onFailure(final Throwable t) { toCallback.onFailure(t); } @Override public void onSuccess(final V value) { onSuccess.apply(value); } }; } public static final SimpleCallback embed(final SimpleCallback toCallback, final Runnable onSuccess) { return new SimpleCallback() { @Override public void onFailure(final Throwable t) { toCallback.onFailure(t); } @Override public void onSuccess() { onSuccess.run(); } }; } public static ValueCallback> asValueCallback(final ListCallback callback) { return new ValueCallback>() { @Override public void onFailure(final Throwable t) { callback.onFailure(t); } @Override public void onSuccess(final List value) { callback.onSuccess(value); } }; } public static ValueCallback asValueCallback(final ValueCallback callback) { return AsyncCommon.embed(callback, new Closure() { @Override public void apply(final V o) { callback.onSuccess(Success.INSTANCE); } }); } }