package org.infinispan.remoting.inboundhandler.action;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.commons.util.InfinispanCollections;
/**
* A list of {@link Action} to be executed to check when it is ready.
* <p/>
* If an {@link Action} is canceled, then the remaining {@link Action} are not invoked.
*
* @author Pedro Ruivo
* @since 8.0
*/
public class DefaultReadyAction implements ReadyAction, ActionListener {
private final ActionState state;
private final Action[] actions;
private final AtomicInteger currentAction;
private final CompletableFuture<Void> notifier;
public DefaultReadyAction(ActionState state, Action... actions) {
this.state = Objects.requireNonNull(state, "Action state must be non null.");
this.actions = Objects.requireNonNull(actions, "Actions must be non null.");
notifier = new CompletableFuture<>();
currentAction = new AtomicInteger(0);
}
public void registerListener() {
InfinispanCollections.forEach(actions, action -> action.addListener(this));
}
@Override
public boolean isReady() {
int current = currentAction.get();
if (current >= actions.length) {
return true;
}
Action action = actions[current];
switch (action.check(state)) {
case READY:
//check the next action. If currentAction has changed, some thread already advanced.
return currentAction.compareAndSet(current, current + 1) && isReady();
case NOT_READY:
return false;
case CANCELED:
currentAction.set(actions.length);
return true;
}
return false;
}
@Override
public void addListener(ActionListener listener) {
notifier.thenRun(listener::onComplete);
}
@Override
public void onException() {
InfinispanCollections.forEach(actions, action -> action.onException(state));
}
@Override
public void onComplete() {
if (isReady()) {
notifier.complete(null);
}
}
@Override
public void onFinally() {
InfinispanCollections.forEach(actions, action -> action.onFinally(state));
}
}