@Override
  public List<String> getNextTransitionNames(
      long companyId, long userId, long workflowTaskInstanceId) throws WorkflowException {

    try {
      KaleoTaskInstanceToken kaleoTaskInstanceToken =
          KaleoTaskInstanceTokenLocalServiceUtil.getKaleoTaskInstanceToken(workflowTaskInstanceId);

      if (kaleoTaskInstanceToken.isCompleted()) {
        return Collections.emptyList();
      }

      KaleoTask kaleoTask = kaleoTaskInstanceToken.getKaleoTask();
      KaleoNode kaleoNode = kaleoTask.getKaleoNode();

      List<KaleoTransition> kaleoTransitions = kaleoNode.getKaleoTransitions();

      List<String> transitionNames = new ArrayList<>(kaleoTransitions.size());

      for (KaleoTransition kaleoTransition : kaleoTransitions) {
        transitionNames.add(kaleoTransition.getName());
      }

      return transitionNames;
    } catch (Exception e) {
      throw new WorkflowException(e);
    }
  }
  @Override
  protected void doExecute(
      KaleoNode currentKaleoNode,
      ExecutionContext executionContext,
      List<PathElement> remainingPathElements)
      throws PortalException, SystemException {

    KaleoInstanceToken kaleoInstanceToken = executionContext.getKaleoInstanceToken();

    KaleoInstanceToken parentKaleoInstanceToken = kaleoInstanceToken.getParentKaleoInstanceToken();

    if (parentKaleoInstanceToken.hasIncompleteChildrenKaleoInstanceToken()) {

      return;
    }

    parentKaleoInstanceToken =
        kaleoInstanceTokenLocalService.updateKaleoInstanceToken(
            parentKaleoInstanceToken.getKaleoInstanceTokenId(), currentKaleoNode.getKaleoNodeId());

    KaleoTransition kaleoTransition = currentKaleoNode.getDefaultKaleoTransition();

    ExecutionContext newExecutionContext =
        new ExecutionContext(
            parentKaleoInstanceToken,
            executionContext.getWorkflowContext(),
            executionContext.getServiceContext());

    PathElement pathElement =
        new PathElement(
            currentKaleoNode, kaleoTransition.getTargetKaleoNode(), newExecutionContext);

    remainingPathElements.add(pathElement);
  }
  /**
   * Adds the kaleo node to the database. Also notifies the appropriate model listeners.
   *
   * @param kaleoNode the kaleo node
   * @return the kaleo node that was added
   * @throws SystemException if a system exception occurred
   */
  @Indexable(type = IndexableType.REINDEX)
  @Override
  public KaleoNode addKaleoNode(KaleoNode kaleoNode) throws SystemException {
    kaleoNode.setNew(true);

    return kaleoNodePersistence.update(kaleoNode);
  }
  @Override
  public Node buildNode(KaleoNode kaleoNode) throws PortalException, SystemException {

    Node node = createNode(kaleoNode);

    Set<Action> actions = buildActions(KaleoNode.class.getName(), kaleoNode.getKaleoNodeId());

    node.setActions(actions);

    node.setMetadata(kaleoNode.getMetadata());

    Set<Notification> notifications =
        buildNotifications(KaleoNode.class.getName(), kaleoNode.getKaleoNodeId());

    node.setNotifications(notifications);

    Set<Timer> timers = buildTimers(KaleoNode.class.getName(), kaleoNode.getKaleoNodeId());

    node.setTimers(timers);

    return node;
  }
  protected void doExecute(
      KaleoNode currentKaleoNode,
      ExecutionContext executionContext,
      List<PathElement> remainingPathElements)
      throws PortalException, SystemException {

    List<KaleoTransition> kaleoTransitions = currentKaleoNode.getKaleoTransitions();

    Map<String, KaleoInstanceToken> childKaleoInstanceTokens =
        new HashMap<String, KaleoInstanceToken>();

    for (KaleoTransition kaleoTransition : kaleoTransitions) {
      KaleoInstanceToken parentKaleoInstanceToken = executionContext.getKaleoInstanceToken();

      KaleoInstanceToken childKaleoInstanceToken =
          kaleoInstanceTokenLocalService.addKaleoInstanceToken(
              parentKaleoInstanceToken.getKaleoInstanceTokenId(),
              executionContext.getWorkflowContext(),
              executionContext.getServiceContext());

      childKaleoInstanceTokens.put(kaleoTransition.getName(), childKaleoInstanceToken);
    }

    for (KaleoTransition kaleoTransition : kaleoTransitions) {
      KaleoInstanceToken childKaleoInstanceToken =
          childKaleoInstanceTokens.get(kaleoTransition.getName());

      ExecutionContext forkedExecutionContext =
          new ExecutionContext(
              childKaleoInstanceToken,
              executionContext.getWorkflowContext(),
              executionContext.getServiceContext());

      PathElement pathElement =
          new PathElement(
              currentKaleoNode, kaleoTransition.getTargetKaleoNode(), forkedExecutionContext);

      remainingPathElements.add(pathElement);
    }
  }