Skip to content

Commit

Permalink
Inactionware#99 Add code to verify action inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
minjing committed Jan 9, 2019
1 parent 7ad2171 commit 7dfe316
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 60 deletions.
58 changes: 58 additions & 0 deletions uapi.behavior/src/main/java/uapi/behavior/BehaviorErrors.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public class BehaviorErrors extends FileBasedExceptionErrors<BehaviorException>
public static final int GENERATE_ACTION_LABEL_OVER_MAX = 28;
public static final int INVALID_ACTION_INPUT_REF = 29;
public static final int REF_ACTION_NOT_EXIST_IN_BEHAVIOR = 30;
public static final int DUPLICATED_ACTION_OUTPUT = 31;
public static final int NO_OUTPUT_IN_ACTION = 32;

private static final Map<Integer, String> keyCodeMapping;

Expand Down Expand Up @@ -87,6 +89,8 @@ public class BehaviorErrors extends FileBasedExceptionErrors<BehaviorException>
keyCodeMapping.put(GENERATE_ACTION_LABEL_OVER_MAX, GenerateActionLabelOverMax.KEY);
keyCodeMapping.put(INVALID_ACTION_INPUT_REF, InvalidActionInputRef.KEY);
keyCodeMapping.put(REF_ACTION_NOT_EXIST_IN_BEHAVIOR, RefActionNotExistInBehavior.KEY);
keyCodeMapping.put(DUPLICATED_ACTION_OUTPUT, DuplicatedActionOutput.KEY);
keyCodeMapping.put(NO_OUTPUT_IN_ACTION, NoOutputInAction.KEY);
}

public BehaviorErrors() {
Expand Down Expand Up @@ -856,4 +860,58 @@ public Object[] get() {
return new Object[] { this._actionLabel, this._behaviorId.toString() };
}
}

/**
* Error string template:
* The output [{}] of action [{}] is duplicated
*/
public static final class DuplicatedActionOutput extends IndexedParameters<DuplicatedActionOutput> {

public static final String KEY = "DuplicatedActionOutput";

private String _outputName;
private ActionIdentify _actionId;

public DuplicatedActionOutput outputName(final String name) {
this._outputName = name;
return this;
}

public DuplicatedActionOutput actionId(final ActionIdentify actionId) {
this._actionId = actionId;
return this;
}

@Override
public Object[] get() {
return new Object[] { this._outputName, this._actionId.toString() };
}
}

/**
* Error string template:
* No output named [{}] is defined in Action [{}]
*/
public static class NoOutputInAction extends IndexedParameters<NoOutputInAction> {

public static final String KEY = "NoOutputInAction";

private String _outputName;
private ActionIdentify _actionId;

public NoOutputInAction outputName(final String name) {
this._outputName = name;
return this;
}

public NoOutputInAction actionId(final ActionIdentify actionId) {
this._actionId = actionId;
return this;
}

@Override
public Object[] get() {
return new Object[] { this._outputName, this._actionId.toString() };
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package uapi.behavior.internal;

import uapi.behavior.BehaviorErrors;
import uapi.behavior.BehaviorException;
import uapi.behavior.IAction;
import uapi.common.ArgumentChecker;
import uapi.common.Functionals;
import uapi.common.IAttributed;
import uapi.common.StringHelper;
import uapi.behavior.*;
import uapi.common.*;
import uapi.rx.Looper;

import java.util.LinkedList;
Expand All @@ -20,37 +15,50 @@ class ActionHolder {
private static final Functionals.Evaluator ALWAYS_MATCHED = attributed -> true;

private final Functionals.Evaluator _evaluator;
private final Behavior _behavior;
private final IAction _action;
private final String _label;
private final List<ActionHolder> _nextActions;

private ActionHolder _previousAction;

ActionHolder(
final IAction action
final IAction action,
final Behavior behavior
) {
this(action, null, null);
this(action, null, behavior, null);
}

ActionHolder(
final IAction action,
final String label,
final Behavior behavior,
final Functionals.Evaluator evaluator
) {
ArgumentChecker.required(action, "action");
ArgumentChecker.required(action.getId(), "action.id");
ArgumentChecker.required(action.inputMetas(), "action.inputMetas");
ArgumentChecker.required(action.outputMetas(), "action.outputMetas");
ArgumentChecker.required(behavior, "behavior");
if (evaluator == null) {
this._evaluator = ALWAYS_MATCHED;
} else {
this._evaluator = evaluator;
}
this._behavior = behavior;
this._action = action;
this._label = label;
this._nextActions = new LinkedList<>();
}

ActionOutputMeta[] outputMetas() {
return this._action.outputMetas();
}

ActionInputMeta[] inputMetas() {
return this._action.inputMetas();
}

/**
* Return previously action
*
Expand Down Expand Up @@ -142,4 +150,40 @@ ActionHolder findNext(final Object data) throws BehaviorException {
.build();
}
}

void verifyOutput(final String[] inputs) {
Looper.on(inputs).foreach(input -> {
ArgumentChecker.required(input, "input");
Pair<String, String> inputRef = ActionInputMeta.parse(input);
String refLabel = inputRef.getLeftValue();
String refName = inputRef.getRightValue();

boolean foundPrevious = false;
ActionHolder previous = this;
while (previous != null) {
if (refLabel.equals(previous.label())) {
foundPrevious = true;
break;
}
previous = previous.previous();
}
if (! foundPrevious) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.REF_ACTION_NOT_EXIST_IN_BEHAVIOR)
.variables(new BehaviorErrors.RefActionNotExistInBehavior()
.actionLabel(refLabel)
.behaviorId(this._behavior.getId()))
.build();
}
boolean found = Looper.on(previous._action.outputMetas()).filter(meta -> meta.name().equals(refName)).first() != null;
if (! found) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.NO_OUTPUT_IN_ACTION)
.variables(new BehaviorErrors.NoOutputInAction()
.outputName(refName)
.actionId(previous._action.getId()))
.build();
}
});
}
}
74 changes: 26 additions & 48 deletions uapi.behavior/src/main/java/uapi/behavior/internal/Behavior.java
Original file line number Diff line number Diff line change
Expand Up @@ -566,59 +566,37 @@ private void newNextAction(
}
}
// Check inputs
Looper.on(inputs).foreach(input -> {
ArgumentChecker.required(input, "input");
Pair<String, String> inputRef = ActionInputMeta.parse(input);
String refLabel = inputRef.getLeftValue();
String refName = inputRef.getRightValue();
if (! this._labeledActions.containsKey(refLabel)) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.REF_ACTION_NOT_EXIST_IN_BEHAVIOR)
.variables(new BehaviorErrors.RefActionNotExistInBehavior()
.actionLabel(refLabel)
.behaviorId(Behavior.this._actionId))
.build();
}
boolean isPrevious = false;
ActionHolder previous = this._current;
while (previous != null) {
if (actionLabel.equals(previous.label())) {
isPrevious = true;
break;
}
previous = previous.previous();
}
});
this._current.verifyOutput(inputs);
ActionHolder newAction = new ActionHolder(action, actionLabel, Behavior.this, evaluator);

ActionHolder newAction = new ActionHolder(action, actionLabel, evaluator);

// Check new action input is matched to current action output
// The check only on non-anonymous action
if (! this._current.action().isAnonymous() && ! action.isAnonymous()) {
if (! action.inputType().isAssignableFrom(this._current.action().outputType())) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.ACTION_IO_MISMATCH)
.variables(new BehaviorErrors.ActionIOMismatch()
.outputAction(this._current.action().getId())
.outputType(this._current.action().outputType())
.inputAction(action.getId())
.inputType(action.inputType()))
.build();
}
}
// if (! this._current.action().isAnonymous() && ! action.isAnonymous()) {
// if (! action.inputType().isAssignableFrom(this._current.action().outputType())) {
// throw BehaviorException.builder()
// .errorCode(BehaviorErrors.ACTION_IO_MISMATCH)
// .variables(new BehaviorErrors.ActionIOMismatch()
// .outputAction(this._current.action().getId())
// .outputType(this._current.action().outputType())
// .inputAction(action.getId())
// .inputType(action.inputType()))
// .build();
// }
// }
// Check action label
if (! ArgumentChecker.isEmpty(label)) {
ActionHolder existingAction = this._labeledActions.get(label);
if (existingAction != null) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.ACTION_LABEL_IS_BIND)
.variables(new BehaviorErrors.ActionLabelIsBind()
.label(label)
.actionId(existingAction.action().getId()))
.build();
}
this._labeledActions.put(label, newAction);
}
// if (! ArgumentChecker.isEmpty(label)) {
// ActionHolder existingAction = this._labeledActions.get(label);
// if (existingAction != null) {
// throw BehaviorException.builder()
// .errorCode(BehaviorErrors.ACTION_LABEL_IS_BIND)
// .variables(new BehaviorErrors.ActionLabelIsBind()
// .label(label)
// .actionId(existingAction.action().getId()))
// .build();
// }
// this._labeledActions.put(label, newAction);
// }

this._current.next(newAction);
this._current = newAction;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import uapi.common.Repository;
import uapi.event.IEventBus;
import uapi.log.ILogger;
import uapi.rx.Looper;
import uapi.service.IServiceLifecycle;
import uapi.service.annotation.*;

Expand All @@ -38,7 +39,7 @@ public class ResponsibleRegistry implements IResponsibleRegistry, IServiceLifecy
@Inject
protected IEventBus _eventBus;

private final Repository<ActionIdentify, IAction<?, ?>> _actionRepo;
private final Repository<ActionIdentify, IAction> _actionRepo;

private final Lock _lock;

Expand All @@ -52,7 +53,7 @@ public ResponsibleRegistry() {

@Inject
@Optional
public void addAction(IAction<?, ?> action) {
public void addAction(IAction action) {
ArgumentChecker.required(action, "action");
if (action instanceof IInterceptor && action instanceof IInterceptive) {
throw BehaviorException.builder()
Expand All @@ -61,7 +62,22 @@ public void addAction(IAction<?, ?> action) {
.interceptorId(action.getId()))
.build();
}
IAction<?, ?> existing = this._actionRepo.put(action);
// Check duplicated Action output
ActionOutputMeta[] metas = action.outputMetas();
for (int i = 0; i < metas.length; i++) {
for (int j = i + 1; j < metas.length; j++) {
if (metas[i].name().equals(metas[j].name())) {
throw BehaviorException.builder()
.errorCode(BehaviorErrors.DUPLICATED_ACTION_OUTPUT)
.variables(new BehaviorErrors.DuplicatedActionOutput()
.outputName(metas[i].name())
.actionId(action.getId()))
.build();
}
}
}

IAction existing = this._actionRepo.put(action);
if (existing != null) {
this._logger.warn("The existing action {} was overridden by new action {}", existing, action);
}
Expand Down
2 changes: 2 additions & 0 deletions uapi.behavior/src/main/resources/behaviorErrors.properties
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ DuplicatedActionLabel = The Action label [{}] is duplicated in Beh
GenerateActionLabelOverMax = Try generate label for action [{}] count over max count [{}]
InvalidActionInputRef = The action input reference is invalid - {}
RefActionNotExistInBehavior = The referenced action [{}] does not exist in behavior [{}]
DuplicatedActionOutput = The output [{}] of action [{}] is duplicated
NoOutputInAction = No output named [{}] is defined in Action [{}]

0 comments on commit 7dfe316

Please sign in to comment.