@Override protected void setHeads(@Nonnull Collection<FlowNode> heads) { Iterator<FlowNode> it = heads.iterator(); if (it.hasNext()) { this.myCurrent = jumpBlockScan(it.next(), myBlackList); this.myNext = this.myCurrent; if (it.hasNext()) { LOGGER.log(Level.WARNING, null, new IllegalArgumentException("Multiple heads not supported for linear scanners")); } } }
/** * Given a {@link FlowNode}, find the {@link FlowNode} most directly enclosing this one that comes from a {@link ThrottleStep}. * * @param inner The inner {@link FlowNode} * @return The most immediate enclosing {@link FlowNode} of the inner one that is associated with {@link ThrottleStep}. May be null. */ @CheckForNull private FlowNode firstThrottleStartNode(@CheckForNull FlowNode inner) { if (inner != null) { LinearBlockHoppingScanner scanner = new LinearBlockHoppingScanner(); scanner.setup(inner); for (FlowNode enclosing : scanner) { if (enclosing != null && enclosing instanceof BlockStartNode && enclosing instanceof StepNode && // There are two BlockStartNodes (aka StepStartNodes) for ThrottleStep, so make sure we get the // first one of those two, which will not have BodyInvocationAction.class on it. enclosing.getAction(BodyInvocationAction.class) == null) { // Check if this is a *different* throttling node. StepDescriptor desc = ((StepNode) enclosing).getDescriptor(); if (desc != null && desc.getClass().equals(ThrottleStep.DescriptorImpl.class)) { return enclosing; } } } } return null; }
@Override public void onSuccess(CpsThreadGroup g) { // Similar to getCurrentExecutions but we want the raw CpsThread, not a StepExecution; cf. CpsFlowExecution.interrupt Map<FlowHead, CpsThread> m = new LinkedHashMap<>(); for (CpsThread t : thread.group.threads.values()) { m.put(t.head, t); } for (CpsThread t : Iterators.reverse(ImmutableList.copyOf(m.values()))) { LinearBlockHoppingScanner scanner = new LinearBlockHoppingScanner(); scanner.setup(t.head.get()); for (FlowNode node : scanner) { if (node.getId().equals(startNodeId)) { t.stop(stopped); break; } } } }
@Override public void onSuccess(CpsThreadGroup g) { try { List<StepExecution> executions = new ArrayList<>(); // cf. trick in CpsFlowExecution.getCurrentExecutions(true) Map<FlowHead, CpsThread> m = new LinkedHashMap<>(); for (CpsThread t : g.threads.values()) { m.put(t.head, t); } for (CpsThread t : m.values()) { // TODO seems cumbersome to have to go through the flow graph to find out whether a head is a descendant of ours, yet FlowHead does not seem to retain a parent field LinearBlockHoppingScanner scanner = new LinearBlockHoppingScanner(); scanner.setup(t.head.get()); for (FlowNode node : scanner) { if (node.getId().equals(startNodeId)) { // this head is inside this body execution StepExecution execution = t.getStep(); if (execution != null) { executions.add(execution); } break; } } } result.set(executions); } catch (Exception x) { result.setException(x); } } @Override public void onFailure(Throwable t) {
@Override protected FlowNode next(@Nonnull FlowNode current, @Nonnull Collection<FlowNode> blackList) { if (current == null) { return null; } List<FlowNode> parents = current.getParents(); if (parents != null && parents.size() > 0) { for (FlowNode f : parents) { if (!blackList.contains(f)) { return (f instanceof BlockEndNode) ? jumpBlockScan(f, blackList) : f; } } } return null; } }
@Override public void run() { assert currentExecutions.isDone(); try { FlowNode outer = getContext().get(FlowNode.class); // timeout for (StepExecution exec : currentExecutions.get()) { FlowNode inner = exec.getContext().get(FlowNode.class); // some deadbeat step, perhaps LinearBlockHoppingScanner scanner = new LinearBlockHoppingScanner(); scanner.setup(inner); for (FlowNode enclosing : scanner) { if (enclosing.equals(outer)) { exec.getContext().onFailure(death); break; } } } } catch (IOException | InterruptedException | ExecutionException x) { LOGGER.log(Level.WARNING, null, x); } } }, MoreExecutors.sameThreadExecutor());