private void checkForCompletion(final GraphProcess process) {
   if (!process.hasActiveTokens() && process.isArcTokenQueueEmpty() && asyncQueue.isEmpty()) {
     process.setState(ProcessState.PendingCompletion);
     fireEvent(ProcessEvent.newCompletedEvent(this, process));
     finalizeComplete(process);
   }
 }
  @Override
  public void finalizeComplete(GraphProcess process) {
    process.setState(ProcessState.Completed);

    NodeToken parentToken = process.getParentToken();
    if (parentToken != null) {
      Engine engine = getParentEngine() == null ? newEngine(false) : getParentEngine();
      engine.complete(parentToken, Arc.DEFAULT_ARC);
    }
  }
  @Override
  public void startProcess(GraphProcess process) {
    process.setState(ProcessState.Executing);
    fireEvent(ProcessEvent.newStartedEvent(this, process));

    arcExecutionStarted = true;

    try {
      for (Node startNode : process.getGraph().getStartNodes()) {
        NodeToken startToken =
            getFactory().newNodeToken(process, startNode, new ArrayList<ArcToken>(0));
        process.addNodeToken(startToken);
        executeNode(process, startToken);
      }
      executeQueuedArcTokens(process);
    } finally {
      arcExecutionStarted = false;
      drainAsyncQueue(process);
    }

    if (process.isExecuting()) {
      checkForCompletion(process);
    }
  }
 @Override
 public void finalizeCancel(GraphProcess process) {
   process.setState(ProcessState.Canceled);
 }
 @Override
 public void cancelProcess(GraphProcess process) {
   process.setState(ProcessState.PendingCancel);
   fireEvent(ProcessEvent.newCanceledEvent(this, process));
   finalizeCancel(process);
 }