com.firefly.utils.concurrent.CountingCallback Maven / Gradle / Ivy
package com.firefly.utils.concurrent;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* A callback wrapper that succeeds the wrapped callback when the count is
* reached, or on first failure.
*
*
* This callback is particularly useful when an async operation is split into
* multiple parts, for example when an original byte buffer that needs to be
* written, along with a callback, is split into multiple byte buffers, since it
* allows the original callback to be wrapped and notified only when the last
* part has been processed.
*
*
* Example:
*
*
*
* public void process(EndPoint endPoint, ByteBuffer buffer, Callback callback) {
* ByteBuffer[] buffers = split(buffer);
* CountCallback countCallback = new CountCallback(callback, buffers.length);
* endPoint.write(countCallback, buffers);
* }
*
*/
public class CountingCallback extends Callback.Nested {
private final AtomicInteger count;
public CountingCallback(Callback callback, int count) {
super(callback);
this.count = new AtomicInteger(count);
}
@Override
public void succeeded() {
// Forward success on the last success.
while (true) {
int current = count.get();
// Already completed ?
if (current == 0)
return;
if (count.compareAndSet(current, current - 1)) {
if (current == 1)
super.succeeded();
return;
}
}
}
@Override
public void failed(Throwable failure) {
// Forward failure on the first failure.
while (true) {
int current = count.get();
// Already completed ?
if (current == 0)
return;
if (count.compareAndSet(current, 0)) {
super.failed(failure);
return;
}
}
}
@Override
public String toString() {
return String.format("%s@%x", getClass().getSimpleName(), hashCode());
}
}