Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.outbrain.ob1k.concurrent.combiners.Combiner Maven / Gradle / Ivy
package com.outbrain.ob1k.concurrent.combiners;
import com.outbrain.ob1k.concurrent.*;
import com.outbrain.ob1k.concurrent.handlers.FutureSuccessHandler;
import com.outbrain.ob1k.concurrent.handlers.SuccessHandler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
import static com.outbrain.ob1k.concurrent.ComposableFutures.fromValue;
import static com.outbrain.ob1k.concurrent.ComposableFutures.schedule;
/**
* combines two or more futures into one.
*
* @author aronen on 9/2/14.
*/
public class Combiner {
public static ComposableFuture any(final Iterable> elements) {
return ComposableFutures.build(new Producer() {
@Override
public void produce(final Consumer consumer) {
final AtomicBoolean done = new AtomicBoolean();
for (final ComposableFuture future : elements) {
future.consume(new Consumer() {
@Override
public void consume(final Try result) {
if (done.compareAndSet(false, true)) {
consumer.consume(result);
}
}
});
}
}
});
}
public static ComposableFuture> all(final boolean failOnError, final Iterable> elements) {
final Map> elementsMap = new HashMap<>();
int index = 0;
for (final ComposableFuture element : elements) {
elementsMap.put(index++, element);
}
return all(failOnError, elementsMap).continueOnSuccess(new SuccessHandler, List>() {
@Override
public List handle(final Map result) {
return new ArrayList<>(result.values());
}
});
}
public static ComposableFuture> all(final boolean failOnError, final Map> elements) {
return first(elements, elements.size(), failOnError, null, null);
}
private static class Status {
final int total;
final int minSuccessful;
final int results;
final int successfulResults;
final boolean finished;
private Status(final int total, final int minSuccessful,
final int results, final int successfulResults,
final boolean finished) {
this.total = total;
this.minSuccessful = minSuccessful;
this.results = results;
this.successfulResults = successfulResults;
this.finished = finished;
}
boolean isDone() {
return finished || results == total || successfulResults >= minSuccessful;
}
}
private static class KeyValue {
final K key;
final V value;
private KeyValue(final K key, final V value) {
this.key = key;
this.value = value;
}
}
public static ComposableFuture> first(final Map> elements, final int numOfSuccess,
final boolean failOnError, final Long timeout, final TimeUnit timeUnit) {
if (elements.isEmpty()) {
final Map empty = new HashMap<>();
return fromValue(empty);
}
return ComposableFutures.build(new Producer>() {
@Override
public void produce(final Consumer> consumer) {
final AtomicReferenceArray> results = new AtomicReferenceArray<>(elements.size());
final AtomicReference status = new AtomicReference<>(new Status(elements.size(), numOfSuccess, 0, 0, false));
int counter = 0;
if (timeout != null) {
schedule(new Callable() {
@Override
public Object call() throws Exception {
while (true) {
final Status currentStatus = status.get();
if (currentStatus.isDone())
break;
final Status newStatus = new Status(currentStatus.total, currentStatus.minSuccessful,
currentStatus.results, currentStatus.successfulResults, true);
final boolean success = status.compareAndSet(currentStatus, newStatus);
if (success) {
consumer.consume(Try.fromValue(collectResults(results)));
break;
}
}
return null;
}
}, timeout, timeUnit);
}
for (final Map.Entry> element : elements.entrySet()) {
final ComposableFuture future = element.getValue();
final K key = element.getKey();
final int index = counter;
counter++;
future.consume(new Consumer() {
@Override
public void consume(final Try result) {
if (result.isSuccess()) {
final T element = result.getValue();
results.set(index, new KeyValue<>(key, element));
while (true) {
final Status currentStatus = status.get();
if (currentStatus.isDone())
break;
final Status newStatus = new Status(currentStatus.total, currentStatus.minSuccessful,
currentStatus.results + 1, currentStatus.successfulResults + 1, false);
final boolean success = status.compareAndSet(currentStatus, newStatus);
if (success) {
if (newStatus.isDone()) {
consumer.consume(Try.fromValue(collectResults(results)));
}
break;
}
}
} else {
final Throwable error = result.getError();
while (true) {
final Status currentStatus = status.get();
if (currentStatus.isDone())
break;
final Status newStatus = new Status(currentStatus.total, currentStatus.minSuccessful,
currentStatus.results + 1, currentStatus.successfulResults, failOnError);
final boolean success = status.compareAndSet(currentStatus, newStatus);
if (success) {
if (failOnError) {
consumer.consume(Try.>fromError(error));
} else {
if (newStatus.isDone()) {
consumer.consume(Try.fromValue(collectResults(results)));
}
}
break;
}
}
}
}
});
}
}
});
}
private static Map collectResults(final AtomicReferenceArray> elements) {
final Map result = new HashMap<>();
for (int i=0; i< elements.length(); i++) {
final KeyValue element = elements.get(i);
if (element != null && element.value != null) {
result.put(element.key, element.value);
}
}
return result;
}
public static ComposableFuture combine(final ComposableFuture left, final ComposableFuture right, final BiFunction combiner) {
final ComposableFuture> upliftLeft = left.continueOnSuccess(new SuccessHandler>() {
@Override
public BiContainer handle(final T1 result) {
return new BiContainer<>(result, null);
}
});
final ComposableFuture> upliftRight = right.continueOnSuccess(new SuccessHandler>() {
@Override
public BiContainer handle(final T2 result) {
return new BiContainer<>(null, result);
}
});
final HashMap>> elements = new HashMap<>();
final String leftKey = "left";
final String rightKey = "right";
elements.put(leftKey, upliftLeft);
elements.put(rightKey, upliftRight);
return all(true, elements).continueOnSuccess(new SuccessHandler>, R>() {
@Override
public R handle(final Map> result) throws ExecutionException {
final BiContainer leftContainer = result.get(leftKey);
final BiContainer rightContainer = result.get(rightKey);
return combiner.apply(leftContainer.left, rightContainer.right);
}
});
}
public static ComposableFuture combine(final ComposableFuture left, final ComposableFuture right, final FutureBiFunction combiner) {
final ComposableFuture> upliftLeft = left.continueOnSuccess(new SuccessHandler>() {
@Override
public BiContainer handle(final T1 result) {
return new BiContainer<>(result, null);
}
});
final ComposableFuture> upliftRight = right.continueOnSuccess(new SuccessHandler>() {
@Override
public BiContainer handle(final T2 result) {
return new BiContainer<>(null, result);
}
});
final HashMap>> elements = new HashMap<>();
final String leftKey = "left";
final String rightKey = "right";
elements.put(leftKey, upliftLeft);
elements.put(rightKey, upliftRight);
return all(true, elements).continueOnSuccess(new FutureSuccessHandler>, R>() {
@Override
public ComposableFuture handle(final Map> result) {
final BiContainer leftContainer = result.get(leftKey);
final BiContainer rightContainer = result.get(rightKey);
return combiner.apply(leftContainer.left, rightContainer.right);
}
});
}
public static ComposableFuture combine(final ComposableFuture first,
final ComposableFuture second,
final ComposableFuture third,
final TriFunction combiner) {
final ComposableFuture> upliftFirst = first.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T1 result) {
return new TriContainer<>(result, null, null);
}
});
final ComposableFuture> upliftSecond = second.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T2 result) {
return new TriContainer<>(null, result, null);
}
});
final ComposableFuture> upliftThird = third.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T3 result) {
return new TriContainer<>(null, null, result);
}
});
final HashMap>> elements = new HashMap<>();
final String firstKey = "first";
final String secondKey = "second";
final String thirdKey = "third";
elements.put(firstKey, upliftFirst);
elements.put(secondKey, upliftSecond);
elements.put(thirdKey, upliftThird);
return all(true, elements).continueOnSuccess(new SuccessHandler>, R>() {
@Override
public R handle(final Map> result) throws ExecutionException {
final TriContainer firstContainer = result.get(firstKey);
final TriContainer secondContainer = result.get(secondKey);
final TriContainer thirdContainer = result.get(thirdKey);
return combiner.apply(firstContainer.first, secondContainer.second, thirdContainer.third);
}
});
}
public static ComposableFuture combine(final ComposableFuture first,
final ComposableFuture second,
final ComposableFuture third,
final FutureTriFunction combiner) {
final ComposableFuture> upliftFirst = first.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T1 result) {
return new TriContainer<>(result, null, null);
}
});
final ComposableFuture> upliftSecond = second.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T2 result) {
return new TriContainer<>(null, result, null);
}
});
final ComposableFuture> upliftThird = third.continueOnSuccess(new SuccessHandler>() {
@Override
public TriContainer handle(final T3 result) {
return new TriContainer<>(null, null, result);
}
});
final HashMap>> elements = new HashMap<>();
final String firstKey = "first";
final String secondKey = "second";
final String thirdKey = "third";
elements.put(firstKey, upliftFirst);
elements.put(secondKey, upliftSecond);
elements.put(thirdKey, upliftThird);
return all(true, elements).continueOnSuccess(new FutureSuccessHandler>, R>() {
@Override
public ComposableFuture handle(final Map> result) {
final TriContainer firstContainer = result.get(firstKey);
final TriContainer secondContainer = result.get(secondKey);
final TriContainer thirdContainer = result.get(thirdKey);
return combiner.apply(firstContainer.first, secondContainer.second, thirdContainer.third);
}
});
}
}