return;
}
LOGGER.log(Level.FINE, "next state is {0} on {1} with stack {2}", new Object[] {next, thread, stack});
String priorID = heads.get(thread);
assert priorID != null;
FlowNode prior;
try {
prior = getNode(priorID);
} catch (IOException x) {
LOGGER.log(Level.WARNING, null, x);
return;
}
if (next.equals(END)) {
stack.pop();
if (stack.isEmpty()) {
LOGGER.log(Level.FINE, "finishing thread {0}", thread);
pcs.remove(thread);
heads.remove(thread);
try {
addingHead(new BlockEndNode<BlockStartNode>(this, newID(), /*TODO*/null, prior) {
@Override protected String getTypeDisplayName() {
return "Thread end";
}
});
// TODO keep a list of all thread end nodes to collect into finals list in finish()
if (heads.isEmpty()) {
finish(Result.SUCCESS);
}
} catch (Exception x) {
// What to do about it?
LOGGER.log(Level.WARNING, null, x);
}
} else {
Frame caller = stack.peek();
LOGGER.log(Level.FINE, "finishing subroutine from {0} on {1}", new Object[] {caller, thread});
State s = getStateMap().get(caller.state);
assert s instanceof BlockState : "found " + s + " rather than a BlockState on the stack for " + caller.state;
FutureCallback callback = caller.callback;
assert callback != null : "no callback defined for " + caller.state;
caller.callback = null;
callback.onSuccess(null); // TODO should there be a way of passing a return value from the block?
heads.put(thread, caller.id);
try {
addingHead(new BlockEndNode<BlockStartNode>(this, newID(), /*TODO*/null, /* TODO is this right? or should it be from caller.id? */prior) {
@Override protected String getTypeDisplayName() {
return "Block end";
}
});
} catch (IOException x) {
LOGGER.log(Level.WARNING, null, x);
}
}
} else {
State s = getStateMap().get(next);
if (s == null) {
LOGGER.log(Level.WARNING, "no such state {0}", next);
// How better to recover?
next(thread, END);
return;
}
String id = newID();
FlowNode n = s.run(new STMContext(owner, id, next, thread), id, this, prior);
stack.peek().state = next;
stack.peek().id = id;
heads.put(thread, id);
try {
addingHead(n);