io.vlingo.common.BasicCompletes Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vlingo-common Show documentation
Show all versions of vlingo-common Show documentation
These are just a few common tools shared across various vlingo projects.
// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.
package io.vlingo.common;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;
public class BasicCompletes implements Completes {
protected final ActiveState state;
public BasicCompletes(final Scheduler scheduler) {
this(new BasicActiveState(scheduler));
}
public BasicCompletes(final Scheduler scheduler, ActiveState parent) {
this(new BasicActiveState(scheduler, parent));
}
public BasicCompletes(final T outcome, final boolean succeeded) {
this(new BasicActiveState(), outcome, succeeded);
}
public BasicCompletes(final T outcome) {
this(new BasicActiveState(), outcome);
}
protected BasicCompletes(final ActiveState state) {
this.state = state;
}
protected BasicCompletes(final ActiveState state, final T outcome, final boolean succeeded) {
this.state = state;
if (succeeded) {
this.state.completedWith(outcome);
} else {
this.state.failedValue(outcome);
this.state.failed();
}
}
protected BasicCompletes(final ActiveState state, final T outcome) {
this.state = state;
this.state.outcome(outcome);
}
@Override
@SuppressWarnings("unchecked")
public Completes andThen(final long timeout, final O failedOutcomeValue, final Function function) {
state.failedValue(failedOutcomeValue);
state.registerWithExecution(Action.with(function), timeout, state);
return (Completes) this;
}
@Override
public Completes andThen(final O failedOutcomeValue, final Function function) {
return andThen(-1L, failedOutcomeValue, function);
}
@Override
public Completes andThen(final long timeout, final Function function) {
return andThen(timeout, null, function);
}
@Override
public Completes andThen(final Function function) {
return andThen(-1L, null, function);
}
@Override
public Completes andThenConsume(final long timeout, final T failedOutcomeValue, final Consumer consumer) {
state.failedValue(failedOutcomeValue);
state.registerWithExecution(Action.with(consumer), timeout, state);
return this;
}
@Override
public Completes andThenConsume(final long timeout, final Consumer consumer) {
return andThenConsume(timeout, null, consumer);
}
@Override
public Completes andThenConsume(final T failedOutcomeValue, final Consumer consumer) {
return andThenConsume(-1, failedOutcomeValue, consumer);
}
@Override
public Completes andThenConsume(final Consumer consumer) {
return andThenConsume(-1, null, consumer);
}
@Override
@SuppressWarnings("unchecked")
public O andThenTo(final long timeout, final F failedOutcomeValue, final Function function) {
final BasicCompletes nestedCompletes = new BasicCompletes<>(state.scheduler(), (ActiveState) state);
nestedCompletes.state.failedValue(failedOutcomeValue);
nestedCompletes.state.failureAction((Action) state.failureActionFunction());
state.registerWithExecution((Action) Action.with(function, nestedCompletes), timeout, state);
return (O) nestedCompletes;
}
@Override
public O andThenTo(final F failedOutcomeValue, final Function function) {
return andThenTo(-1, failedOutcomeValue, function);
}
@Override
@SuppressWarnings("unchecked")
public O andThenTo(final long timeout, final Function function) {
return andThenTo(timeout, (O) BasicActiveState.UnfailedValue, function);
}
@Override
@SuppressWarnings("unchecked")
public O andThenTo(final Function function) {
return andThenTo(-1, (O) BasicActiveState.UnfailedValue, function);
}
@Override
public Completes otherwise(final Function function) {
state.failureAction(Action.with(function));
return this;
}
@Override
public Completes otherwiseConsume(final Consumer consumer) {
state.failureAction(Action.with(consumer));
return this;
}
@Override
public Completes recoverFrom(final Function function) {
state.exceptionAction(function);
return this;
}
@Override
@SuppressWarnings("unchecked")
public O await() {
state.await();
return (O) outcome();
}
@Override
@SuppressWarnings("unchecked")
public O await(final long timeout) {
if (state.await(timeout)) {
return (O) outcome();
}
return null;
}
@Override
public boolean isCompleted() {
return state.isOutcomeKnown();
}
@Override
public boolean hasFailed() {
return state.hasFailed();
}
@Override
public void failed() {
with(state.failedValue());
}
@Override
public boolean hasOutcome() {
return state.hasOutcome();
}
@Override
public T outcome() {
return state.outcome();
}
@Override
public Completes repeat() {
throw new UnsupportedOperationException();
}
@Override
@SuppressWarnings("unchecked")
public Completes with(final O outcome) {
if (!state.handleFailure((T) outcome)) {
state.completedWith((T) outcome);
}
return (Completes) this;
}
@Override
@SuppressWarnings("unchecked")
public Completes andFinally() {
return andFinally(value -> (O) value);
}
@Override
public Completes andFinally(final Function function) {
return andThen(function);
}
@Override
public void andFinallyConsume(final Consumer consumer) {
andThenConsume(consumer);
}
private BasicCompletes(final BasicActiveState parent) {
this.state = new BasicActiveState(parent.scheduler(), parent);
}
protected static class Action {
private final T defaultValue;
private final boolean hasDefaultValue;
private final Object function;
private final Completes nestedCompletes;
static Action with(final Object function) {
return new Action(function);
}
static Action with(final Object function, Completes nestedCompletes) {
return new Action(function, nestedCompletes);
}
static Action with(final Object function, final T defaultValue, Completes nestedCompletes) {
return new Action(function, defaultValue, nestedCompletes);
}
Action(final Object function) {
this.function = function;
this.defaultValue = null;
this.hasDefaultValue = false;
this.nestedCompletes = null;
}
Action(final Object function, final T defaultValue) {
this.function = function;
this.defaultValue = defaultValue;
this.hasDefaultValue = true;
this.nestedCompletes = null;
}
Action(final Object function, Completes nestedCompletes) {
this.function = function;
this.defaultValue = null;
this.hasDefaultValue = false;
this.nestedCompletes = nestedCompletes;
}
Action(final Object function, final T defaultValue, Completes nestedCompletes) {
this.function = function;
this.defaultValue = defaultValue;
this.hasDefaultValue = true;
this.nestedCompletes = nestedCompletes;
}
@SuppressWarnings("unchecked")
F function() {
return (F) function;
}
@SuppressWarnings("unchecked")
Consumer asConsumer() {
return (Consumer) function;
}
boolean isConsumer() {
return (function instanceof Consumer);
}
@SuppressWarnings("unchecked")
Function asFunction() {
return (Function) function;
}
boolean isFunction() {
return (function instanceof Function);
}
boolean hasNestedCompletes() {
return nestedCompletes != null;
}
Completes nestedCompletes() {
return nestedCompletes;
}
}
protected static interface ActiveState {
void await();
boolean await(final long timeout);
void backUp(final Action action);
void cancelTimer();
void completedWith(final T outcome);
boolean executeFailureAction();
boolean hasFailed();
void failed();
void failedValue(final F failedOutcomeValue);
T failedValue();
void failureAction(final Action action);
Action failureActionFunction();
boolean handleFailure(final T outcome);
void exceptionAction(final Function function);
void handleException();
void handleException(final Exception e);
boolean hasException();
boolean hasOutcome();
void outcome(final T outcome);
O outcome();
boolean isOutcomeKnown();
void outcomeKnown(final boolean flag);
boolean outcomeMustDefault();
void registerWithExecution(final Action action, final long timeout, final ActiveState state);
boolean isRepeatable();
void repeat();
void restore();
void restore(final Action action);
Scheduler scheduler();
void startTimer(final long timeout);
}
private static class Executables {
private AtomicBoolean accessible;
private Queue> actions;
private AtomicBoolean readyToExecute;
Executables() {
this.accessible = new AtomicBoolean(false);
this.actions = new ConcurrentLinkedQueue<>();
this.readyToExecute = new AtomicBoolean(false);
}
int count() {
return actions.size();
}
void execute(final ActiveState state) {
while (true) {
if (accessible.compareAndSet(false, true)) {
readyToExecute.set(true);
executeActions(state);
accessible.set(false);
break;
}
}
}
boolean isReadyToExecute() {
return readyToExecute.get();
}
void registerWithExecution(final Action action, final long timeout, final ActiveState state) {
while (true) {
if (accessible.compareAndSet(false, true)) {
actions.add(action);
if (isReadyToExecute()) {
executeActions(state);
} else {
state.startTimer(timeout);
}
accessible.set(false);
break;
}
}
}
void reset() {
readyToExecute.set(false);
actions.clear();
}
void restore(final Action action) {
actions.add(action);
}
private boolean hasAction() {
return !actions.isEmpty();
}
@SuppressWarnings("unchecked")
private void executeActions(final ActiveState state) {
while (hasAction()) {
if (state.hasOutcome() && state.hasFailed()) {
state.executeFailureAction();
return;
} else if (state.hasException()) {
state.handleException();
return;
}
final Action action = actions.poll();
state.backUp(action);
if (action.hasDefaultValue && state.outcomeMustDefault()) {
state.outcome(action.defaultValue);
} else {
try {
if (action.isConsumer()) {
action.asConsumer().accept((T) state.outcome());
} else if (action.isFunction()) {
if (action.hasNestedCompletes()) {
((Completes) action.asFunction().apply((T) state.outcome()))
.andThenConsume(value -> action.nestedCompletes().with(value));
} else {
state.outcome(action.asFunction().apply(state.outcome()));
}
}
} catch (Exception e) {
state.handleException(e);
break;
}
}
}
}
}
protected static class BasicActiveState implements ActiveState, Scheduled