All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nablarch.integration.workflow.definition.Task Maven / Gradle / Ivy

package nablarch.integration.workflow.definition;

import static nablarch.integration.workflow.util.WorkflowUtil.createInstance;
import static nablarch.integration.workflow.util.WorkflowUtil.find;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import nablarch.integration.workflow.condition.CompletionCondition;
import nablarch.integration.workflow.condition.SingleTaskCompletionCondition;
import nablarch.integration.workflow.dao.ActiveGroupTaskEntity;
import nablarch.integration.workflow.dao.ActiveUserTaskEntity;
import nablarch.integration.workflow.dao.TaskAssignedGroupEntity;
import nablarch.integration.workflow.dao.TaskAssignedUserEntity;
import nablarch.integration.workflow.dao.WorkflowInstanceDao;
import nablarch.integration.workflow.util.WorkflowUtil.ListFilter;

/**
 * タスク定義を表すクラス。
 *
 * @author hisaaki sioiri
 * @since 1.4.2
 */
public class Task extends FlowNode {

    /** 非マルチインスタンス用完了条件 */
    private static final SingleTaskCompletionCondition SINGLE_TASK_COMPLETION_CONDITION = new SingleTaskCompletionCondition();

    /**
     * マルチインスタンスタイプを表す列挙型。
     */
    public enum MultiInstanceType {
        /** 非マルチインスタンス */
        NONE,
        /** 順次実行型マルチインインスタンス */
        SEQUENTIAL,
        /** 並行実行型マルチインスタンス */
        PARALLEL
    }

    /** マルチインスタンスタイプ */
    private final MultiInstanceType multiInstanceType;

    /** 完了条件 */
    private final CompletionCondition completionCondition;

    /**
     * タスク定義を生成する。
     *
     * @param flowNodeId フローノードID
     * @param flowNodeName フローノード名
     * @param laneId レーンID
     * @param multiInstanceType マルチインスタンスタイプ
     * @param completionCondition 終了条件の型名
     * @param sequenceFlows 自身をソースとするシーケンスフロー
     */
    public Task(
            String flowNodeId,
            String flowNodeName,
            String laneId,
            String multiInstanceType,
            String completionCondition, List sequenceFlows) {
        super(flowNodeId, flowNodeName, laneId, sequenceFlows);
        this.multiInstanceType = MultiInstanceType.valueOf(multiInstanceType);
        this.completionCondition = createInstance(completionCondition);
        validate();
    }

    /**
     * タスク定義の状態チェックを行う。
     * 

* 精査内容:
*

    *
  • シングルタスク(非マルチインスタンスタスク)の場合、終了条件は設定されていないこと
  • *
*/ private void validate() { if (!isMultiInstanceType() && (completionCondition != null)) { throw new IllegalArgumentException(String.format( "Single Task must be CompletionCondition is empty.flow_node_id = [%s], flow_node_name = [%s]", getFlowNodeId(), getFlowNodeName())); } } /** * マルチインスタンスタイプを取得する。 * * @return マルチインスタンスタイプ */ public MultiInstanceType getMultiInstanceType() { return multiInstanceType; } /** * 終了条件を取得する。 * * @return 終了条件 */ private CompletionCondition getCompletionCondition() { if (isMultiInstanceType()) { return completionCondition; } else { return SINGLE_TASK_COMPLETION_CONDITION; } } /** * マルチインスタンスタスクか否か。 * * @return マルチインスタンスタスクの場合はtrue */ public boolean isMultiInstanceType() { return multiInstanceType != MultiInstanceType.NONE; } /** * マルチインスタンスタスクでシーケンシャルタイプか否か * * @return マルチインスタンスタスクで、シーケンシャルタイプの場合はtrue */ public boolean isSequentialType() { return multiInstanceType == MultiInstanceType.SEQUENTIAL; } /** * {@inheritDoc} *

* このタスクをアクティブフローノードに登録し、タスク担当ユーザ/グループから、アクティブユーザタスク/アクティブグループタスクを作成する。 * マルチインスタンスタスクで、シーケンシャルタイプの場合は、タスク担当ユーザ/グループのうち実行順が先頭のユーザ/グループのアクティブタスクを作成し、 * それ以外の場合は、すべてのユーザ/グループのアクティブタスクを作成する。 * * @param instanceId アクティブ化処理を行う対象のワークフローインスタンスID * @param parameter アクティブ化時に使用するパラメータ */ @Override public void activate(String instanceId, Map parameter) { super.activate(instanceId, parameter); // このノードをアクティブフローノードに登録する。 getWorkflowInstanceDao().saveActiveFlowNode(instanceId, this); // アクティブタスクを更新する。 // ユーザかタスクのいずれかしかアサインされていないはずなので、ユーザがアサインされている場合はグループ側の処理は実行しない。 List users = getAssignedUsers(instanceId); if (!users.isEmpty()) { refreshActiveUserTasks(instanceId, users); } else { List groups = getAssignedGroups(instanceId); if (!groups.isEmpty()) { refreshActiveGroupTasks(instanceId, groups); } } } /** * {@inheritDoc} *

* {@code executor} に指定されたユーザのアクティブタスクを完了させ、シーケンシャルタイプの場合は、実行順が次のユーザのアクティブタスクを作成する。 * その後、 {@link CompletionCondition#isCompletedUserTask(Map, String, Task)} を評価してその結果を返却する。 * * @param instanceId 対象のワークフローインスタンスID * @param parameter ワークフローの進行時に使用するパラメータ * @param executor このノードでの処理を実行しているユーザ * @return 次のフローノードにワークフローを進行させて良い場合は {@code true} * @throws IllegalStateException 指定された実行ユーザのアクティブタスクが存在しない場合 */ @Override public boolean processNodeByUser(String instanceId, Map parameter, String executor) throws IllegalStateException { super.processNodeByUser(instanceId, parameter, executor); String taskId = getFlowNodeId(); WorkflowInstanceDao dao = getWorkflowInstanceDao(); ActiveUserTaskEntity activeUserTask = dao.findActiveUserTaskByPk(executor, taskId, instanceId); if (activeUserTask == null) { throw new IllegalStateException( "Active task is not found for user = [" + executor + "]. instance id = [" + instanceId + "], task id = [" + taskId + "]."); } dao.deleteActiveUserTaskByUserId(instanceId, taskId, executor); // シーケンシャルの場合のみ、実行順が次になっている担当ユーザのアクティブユーザタスクを作成しておく。 if (isSequentialType()) { activateNextUserTask(instanceId, activeUserTask.getExecutionOrder()); } return getCompletionCondition().isCompletedUserTask(parameter, instanceId, this); } /** * {@inheritDoc} *

* {@code executor} に指定されたグループのアクティブタスクを完了させ、シーケンシャルタイプの場合は、実行順が次のグループのアクティブタスクを作成する。 * その後、 {@link CompletionCondition#isCompletedGroupTask(Map, String, Task)} を評価してその結果を返却する。 * * @param instanceId 対象のワークフローインスタンスID * @param parameter ワークフローの進行時に使用するパラメータ * @param executor このノードでの処理を実行しているグループ * @return 次のフローノードにワークフローを進行させて良い場合は {@code true} * @throws IllegalStateException 指定された実行グループのアクティブタスクが存在しない場合 */ @Override public boolean processNodeByGroup(String instanceId, Map parameter, String executor) throws IllegalStateException { super.processNodeByGroup(instanceId, parameter, executor); String taskId = getFlowNodeId(); WorkflowInstanceDao dao = getWorkflowInstanceDao(); ActiveGroupTaskEntity activeGroupTask = dao.findActiveGroupTaskByPk(instanceId, taskId, executor); if (activeGroupTask == null) { throw new IllegalStateException( "Active task is not found for group = [" + executor + "]. instance id = [" + instanceId + "], task id = [" + taskId + "]."); } dao.deleteActiveGroupTaskByGroupId(instanceId, taskId, executor); // シーケンシャルの場合のみ、実行順が次になっている担当ユーザのアクティブユーザタスクを作成しておく。 if (isSequentialType()) { activateNextGroupTask(instanceId, activeGroupTask.getExecutionOrder()); } return getCompletionCondition().isCompletedGroupTask(parameter, instanceId, this); } /** * タスクに担当ユーザを割り当てる。マルチインスタンスでないタスクに対しては、複数ユーザを割り当てることは出来ない。 *

* マルチインスタンスタスクで、シーケンシャルタイプの場合は、指定された担当ユーザの順序がタスクの実行順となる。 * すでにタスクに担当ユーザや担当グループが割り当てられている場合、それらの情報はクリアされ、今回設定した担当ユーザのみが有効となる。 * * @param instanceId ワークフローインスタンスID * @param users 担当ユーザリスト * @throws IllegalArgumentException 指定されたタスクが存在しない場合、もしくはマルチインスタンスでないタスクに複数ユーザを割り当てようとした場合。 */ public void assignUsers(String instanceId, List users) throws IllegalArgumentException { String flowNodeId = getFlowNodeId(); if (!isMultiInstanceType() && (users.size() > 1)) { throw new IllegalArgumentException("Multiple users cannot be assigned to NOT Multi-Instance Tasks." + " instance id = [" + instanceId + "], task id = [" + flowNodeId + "], users = [" + users + "]."); } WorkflowInstanceDao dao = getWorkflowInstanceDao(); if (isSequentialType()) { dao.saveAssignedSequentialUser(instanceId, flowNodeId, users); } else { dao.saveAssignedUser(instanceId, flowNodeId, users); } } /** * アクティブタスクを、現在このタスクに割り当てられている担当ユーザのタスクに置き換える。 *

* マルチインスタンスタスクで、シーケンシャルタイプの場合は、割り当てられている担当ユーザのうち実行順が先頭の担当ユーザの * アクティブタスクが作成される。それ以外の場合は、割り当てられているすべての担当ユーザのアクティブタスクが作成される。 * * @param instanceId ワークフローインスタンスID * @param users 担当ユーザリスト */ public void refreshActiveUserTasks(String instanceId, List users) { WorkflowInstanceDao dao = getWorkflowInstanceDao(); if (isSequentialType() && !users.isEmpty()) { // 順次タスクの場合は、実行順が先頭の担当ユーザだけを最初のアクティブユーザタスクとして登録する。 // ただし、担当ユーザが空の場合は、アクティブユーザタスクを削除したいので、リストをそのままdaoに渡す。 dao.saveActiveUserTask(instanceId, getFlowNodeId(), users.get(0), 1); } else { dao.saveActiveUserTask(instanceId, getFlowNodeId(), users); } } /** * タスクに担当グループを割り当てる。マルチインスタンスでないタスクに対しては、複数グループを割り当てることは出来ない。 *

* マルチインスタンスタスクで、シーケンシャルタイプの場合は、指定された担当グループの順序がタスクの実行順となる。 * すでにタスクに担当ユーザや担当グループが割り当てられている場合、それらの情報はクリアされ、今回設定した担当グループのみが有効となる。 * * @param instanceId ワークフローインスタンスID * @param groups 担当グループリスト * @throws IllegalArgumentException 指定されたタスクが存在しない場合、もしくはマルチインスタンスでないタスクに複数グループを割り当てようとした場合。 */ public void assignGroups(String instanceId, List groups) throws IllegalArgumentException { String flowNodeId = getFlowNodeId(); if (!isMultiInstanceType() && (groups.size() > 1)) { throw new IllegalArgumentException("Multiple groups cannot be assigned to NOT Multi-Instance Tasks." + " instance id = [" + instanceId + "], task id = [" + flowNodeId + "], groups = [" + groups + "]."); } WorkflowInstanceDao dao = getWorkflowInstanceDao(); if (isSequentialType()) { dao.saveAssignedSequentialGroup(instanceId, flowNodeId, groups); } else { dao.saveAssignedGroup(instanceId, flowNodeId, groups); } } /** * アクティブタスクを、指定された担当グループのタスクに置き換える。 *

* マルチインスタンスタスクで、シーケンシャルタイプの場合は、割り当てられている担当グループのうち実行順が先頭の担当グループの * アクティブタスクが作成される。それ以外の場合は、割り当てられているすべての担当グループのアクティブタスクが作成される。 * * @param instanceId ワークフローインスタンスID * @param groups 担当グループリスト */ public void refreshActiveGroupTasks(String instanceId, List groups) { WorkflowInstanceDao dao = getWorkflowInstanceDao(); if (isSequentialType() && !groups.isEmpty()) { // 順次タスクの場合は、実行順が先頭の担当グループだけを最初のアクティブグループタスクとして登録する。 // ただし、担当グループが空の場合は、アクティブグループタスクを削除したいので、リストをそのままdaoに渡す。 dao.saveActiveGroupTask(instanceId, getFlowNodeId(), groups.get(0), 1); } else { dao.saveActiveGroupTask(instanceId, getFlowNodeId(), groups); } } /** * タスクに現在アサインされている担当ユーザを、別の担当ユーザに振り替える。 * * @param instanceId 対象のワークフローのインスタンスID * @param oldUser 振替元の担当ユーザ * @param newUser 振替先の担当ユーザ * @throws IllegalStateException 指定されたタスクに、振替元の担当ユーザがアサインされていない場合 */ public void changeAssignedUser(String instanceId, String oldUser, String newUser) throws IllegalStateException { String taskId = getFlowNodeId(); List assigned = getAssignedUsers(instanceId); if (!assigned.contains(oldUser)) { throw new IllegalStateException("User is not assigned to task." + " instance id = [" + instanceId + "], task id = [" + taskId + "], " + "old user = [" + oldUser + "], assigned user = [" + assigned + "]."); } getWorkflowInstanceDao().changeAssignedUser(instanceId, taskId, oldUser, newUser); } /** * 現在のアクティブユーザタスクのうち、 {@code oldUser} に指定されたユーザのタスクを、 {@code newUser} のタスクに更新する。 *

* {@code oldUser} のアクティブユーザタスクが見つからない場合には、何も処理を行わない。 * * @param instanceId 対象のワークフローのインスタンスID * @param oldUser 振替元の担当ユーザ * @param newUser 振替先の担当ユーザ */ public void changeActiveUserTask(String instanceId, String oldUser, String newUser) { getWorkflowInstanceDao().changeActiveUser(instanceId, getFlowNodeId(), oldUser, newUser); } /** * タスクに現在アサインされている担当グループを、別の担当グループに振り替える。 * * @param instanceId 対象のワークフローのインスタンスID * @param oldGroup 振替元の担当グループ * @param newGroup 振替先の担当グループ * @throws IllegalStateException 指定されたタスクに、振替元の担当グループがアサインされていない場合 */ public void changeAssignedGroup(String instanceId, String oldGroup, String newGroup) throws IllegalStateException { String taskId = getFlowNodeId(); List assigned = getAssignedGroups(instanceId); if (!assigned.contains(oldGroup)) { throw new IllegalStateException("Group is not assigned to task." + " instance id = [" + instanceId + "], task id = [" + taskId + "], " + "old group = [" + oldGroup + "], assigned group = [" + assigned + "]."); } getWorkflowInstanceDao().changeAssignedGroup(instanceId, taskId, oldGroup, newGroup); } /** * 現在のアクティブグループタスクのうち、 {@code oldGroup} に指定されたグループのタスクを、 {@code newGroup} のタスクに更新する。 *

* {@code oldGroup} のアクティブグループタスクが見つからない場合には、何も処理を行わない。 * * @param instanceId 対象のワークフローのインスタンスID * @param oldGroup 振替元の担当グループ * @param newGroup 振替先の担当グループ */ public void changeActiveGroupTask(String instanceId, String oldGroup, String newGroup) { getWorkflowInstanceDao().changeActiveGroup(instanceId, getFlowNodeId(), oldGroup, newGroup); } /** * タスクに割り当てられた担当ユーザを取得する。 *

* 担当ユーザは、実行順でソートされて返却される。 * * @param instanceId 対象のワークフローのインスタンスID * @return 担当ユーザ */ public List getAssignedUsers(String instanceId) { List users = getWorkflowInstanceDao().findTaskAssignedUser(instanceId, getFlowNodeId()); List result = new ArrayList(users.size()); for (TaskAssignedUserEntity user : users) { result.add(user.getUserId()); } return result; } /** * タスクに割り当てられた担当グループを取得する。 *

* 担当グループは、実行順でソートされて返却される。 * * @param instanceId 対象のワークフローのインスタンスID * @return 担当グループ */ public List getAssignedGroups(String instanceId) { List groups = getWorkflowInstanceDao().findTaskAssignedGroup(instanceId, getFlowNodeId()); List result = new ArrayList(); for (TaskAssignedGroupEntity group : groups) { result.add(group.getAssignedGroupId()); } return result; } /** * 順次タスクであるアクティブユーザタスクで、実行順が次になっている担当ユーザのアクティブユーザタスクを作成する。 * * @param instanceId 対象のワークフローインスタンスID * @param currentOrder 現在のタスクの実行順 */ private void activateNextUserTask(String instanceId, int currentOrder) { WorkflowInstanceDao dao = getWorkflowInstanceDao(); // 実行順が次になっている担当ユーザのタスクを取得して、アクティブユーザタスクとして登録する。 TaskAssignedUserEntity candidate = find(dao.findTaskAssignedUser(instanceId, getFlowNodeId()), new UserExecutionOrderFilter(currentOrder)); if (candidate != null) { dao.saveActiveUserTask(instanceId, getFlowNodeId(), candidate.getUserId(), candidate.getExecutionOrder()); } } /** * 順次タスクであるアクティブグループタスクで、実行順が次になっている担当グループのアクティブグループタスクを作成する。 * * @param instanceId 対象のワークフローインスタンスID * @param currentOrder 現在のタスクの実行順 */ private void activateNextGroupTask(String instanceId, int currentOrder) { WorkflowInstanceDao dao = getWorkflowInstanceDao(); // 実行順が次になっている担当グループのタスクを取得して、アクティブグループタスクとして登録する。 TaskAssignedGroupEntity candidate = find(dao.findTaskAssignedGroup(instanceId, getFlowNodeId()), new GroupExecutionOrderFilter(currentOrder)); if (candidate != null) { dao.saveActiveGroupTask(instanceId, getFlowNodeId(), candidate.getAssignedGroupId(), candidate.getExecutionOrder()); } } /** * {@link TaskAssignedUserEntity#getExecutionOrder()} でフィルタを行う {@link ListFilter} 実装クラス。 *

* 指定された実行順より大きい実行順を持つ {@link TaskAssignedUserEntity} を返却する。 */ private static class UserExecutionOrderFilter implements ListFilter { /** フィルタ対象の実行順 */ private final int order; /** * フィルタ対象の実行順を指定してインスタンスを生成する。 * * @param order フィルタ対象の実行順 */ public UserExecutionOrderFilter(int order) { this.order = order; } /** * {@inheritDoc} *

* 比較対象の {@link TaskAssignedUserEntity#getExecutionOrder()} がフィルタ対象の実行順より大きい値を返す場合 {@code true} * * @param other 比較対象 * @return フィルタ対象よりも比較対象の実行順が大きい場合 {@code true} */ @Override public boolean isMatch(TaskAssignedUserEntity other) { return order < other.getExecutionOrder(); } } /** * {@link TaskAssignedGroupEntity#getExecutionOrder()} でフィルタを行う {@link ListFilter} 実装クラス。 *

* 指定された実行順より大きい実行順を持つ {@link TaskAssignedGroupEntity} を返却する。 */ private static class GroupExecutionOrderFilter implements ListFilter { /** フィルタ対象の実行順 */ private final int order; /** * フィルタ対象の実行順を指定してインスタンスを生成する。 * * @param order フィルタ対象の実行順 */ public GroupExecutionOrderFilter(int order) { this.order = order; } /** * {@inheritDoc} *

* 比較対象の {@link TaskAssignedGroupEntity#getExecutionOrder()} がフィルタ対象の実行順より大きい値を返す場合 {@code true} * * @param other 比較対象 * @return フィルタ対象よりも比較対象の実行順が大きい場合 {@code true} */ @Override public boolean isMatch(TaskAssignedGroupEntity other) { return order < other.getExecutionOrder(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy