/* $Id: ActivityInternal.java,v 1.4 2007/12/06 07:47:15 nito Exp $
 *
 * Copyright (c)ARGO 21, Corporation. 2005, 2006.  All rights reserved.
 * 
 * This file is part of Nautica Workflow Core.
 * 
 *  Nautica Workflow Core is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2.1 of the License, or
 *  (at your option) any later version.
 * 
 *  Nautica Workflow Core is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Nautica Workflow Core; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 */
package jp.co.argo21.nautica.workflow.engine;

import java.sql.Timestamp;
import java.util.List;

import org.apache.log4j.Logger;

import jp.co.argo21.nautica.workflow.dataaccess.ActivityBean;
import jp.co.argo21.nautica.workflow.dataaccess.ActivityDAO;
import jp.co.argo21.nautica.workflow.dataaccess.ProcessBean;
import jp.co.argo21.nautica.workflow.dataaccess.VariableBean;
import jp.co.argo21.nautica.workflow.dataaccess.VariableDAO;
import jp.co.argo21.nautica.workflow.dataaccess.WorkItemBean;
import jp.co.argo21.nautica.workflow.dataaccess.WorkItemDAO;
import jp.co.argo21.nautica.workflow.dataaccess.WorkflowDAOFactory;
import jp.co.argo21.nautica.workflow.definition.ActivityDefinition;
import jp.co.argo21.nautica.workflow.definition.ProcessDefinition;
import jp.co.argo21.nautica.workflow.jms.WorkflowMessage;
import jp.co.argo21.nautica.workflow.omg.AlreadyRunningException;
import jp.co.argo21.nautica.workflow.omg.AlreadySuspendedException;
import jp.co.argo21.nautica.workflow.omg.CannotCompleteException;
import jp.co.argo21.nautica.workflow.omg.CannotResumeException;
import jp.co.argo21.nautica.workflow.omg.CannotStartException;
import jp.co.argo21.nautica.workflow.omg.CannotStopException;
import jp.co.argo21.nautica.workflow.omg.CannotSuspendException;
import jp.co.argo21.nautica.workflow.omg.HistoryNotAvailableException;
import jp.co.argo21.nautica.workflow.omg.InvalidDataException;
import jp.co.argo21.nautica.workflow.omg.InvalidPerformerException;
import jp.co.argo21.nautica.workflow.omg.InvalidStateException;
import jp.co.argo21.nautica.workflow.omg.NotRunningException;
import jp.co.argo21.nautica.workflow.omg.NotSuspendedException;
import jp.co.argo21.nautica.workflow.omg.ResultNotAvailableException;
import jp.co.argo21.nautica.workflow.omg.TransitionNotAllowedException;
import jp.co.argo21.nautica.workflow.omg.UpdateNotAllowedException;
import jp.co.argo21.nautica.workflow.omg.WfActivity;
import jp.co.argo21.nautica.workflow.omg.WfAssignment;
import jp.co.argo21.nautica.workflow.omg.WfEvent;
import jp.co.argo21.nautica.workflow.omg.WfNameValue;
import jp.co.argo21.nautica.workflow.omg.WfProcess;
import jp.co.argo21.nautica.workflow.omg.WfProcessManager;
import jp.co.argo21.nautica.workflow.omg.WfResource;
import jp.co.argo21.nautica.workflow.omg.WfState;
import jp.co.argo21.nautica.workflow.omg.WorkflowException;
import jp.co.argo21.nautica.workflow.security.OrganizationManager;
import jp.co.argo21.nautica.workflow.security.RoleManager;
import jp.co.argo21.nautica.workflow.security.UserManager;
import jp.co.argo21.nautica.workflow.util.StringManager;
import jp.co.argo21.nautica.workflow.util.UniqueKeyGenerator;
import jp.co.argo21.nautica.workflow.wfmc.Activity;
import jp.co.argo21.nautica.workflow.wfmc.ActivityState;
import jp.co.argo21.nautica.workflow.wfmc.Attribute;
import jp.co.argo21.nautica.workflow.wfmc.Filter;
import jp.co.argo21.nautica.workflow.wfmc.Participant;

/**
 * エンジン内部で使用されるアクティビティ情報を表す。
 *
 * @author  nito(Argo 21, Corp.)
 * @version $Revision: 1.4 $
 * @since   Nautica Workflow 1.0
 */
public class ActivityInternal implements WfActivity
{
	/** シリアルバージョンUID */
	private static final long serialVersionUID = 20050000000000001L;

	/** エンジンログ */
	@SuppressWarnings("unused")
	private static Logger eLog = LogManager.getEngineLogger();
	
	private Activity activity;
	

	/**
	 * 内部用アクティビティ情報を生成する。
	 *
	 * @param act アクティビティ
	 */
	ActivityInternal(Activity act)
	{
		this.activity = act;
	}

	/**
	 * このアクティビティが所属しているWfProcessを返す。
	 *
	 * @return WfProcess
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#getContainer()
	 */
	public WfProcess getContainer() throws WorkflowException
	{
		String pid = activity.getProcessID();
		ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
		WfProcessManager pm = pmf.getOwnerProcessManager(pid);
		WfProcess process = pm.getProcess(pid);
		return process;
	}

	/**
	 * IDを返す。
	 *
	 * @return ID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getID()
	 */
	public String getID() throws WorkflowException
	{
		return activity.getActivityID();
	}

	/**
	 * 名称を返す。
	 *
	 * @return 名称
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getName()
	 */
	public String getName() throws WorkflowException
	{
		return activity.getName();
	}

	/**
	 * 名称を設定する。
	 *
	 * @param name 名称
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#setName(java.lang.String)
	 */
	public void setName(String name) throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 詳細情報を返す。
	 *
	 * @return 詳細情報
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getDescription()
	 */
	public String getDescription() throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 現在の状態を返す。
	 *
	 * @return 状態
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getState()
	 */
	public WfState getState() throws WorkflowException
	{
		return ActivityState.getState(activity.getActivityState());
	}

	/**
	 * 現在の状態から遷移可能な状態の一覧を返す。
	 *
	 * @return 遷移可能な状態の一覧
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getTransitableStates()
	 */
	public WfState[] getTransitableStates() throws WorkflowException
	{
		return ActivityState.getTransitableStates(activity.getActivityState());
	}

	/**
	 * 最後に状態が遷移した時間を返す。
	 *
	 * @return 最終状態変更時間
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getLastStateTime()
	 */
	public String getLastStateTime() throws WorkflowException
	{
		return activity.getUpdateDate().toString();
	}

	/**
	 * リクエスタに関連するリソースを返す。
	 *
	 * @return リクエスタの主体となったリソース
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#getReqesterResource()
	 */
	public WfResource getReqesterResource() throws WorkflowException
	{
		try {
			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			WorkItemDAO workitemDAO = daoFactory.getWorkItemDAO();
			
			WorkItemBean workitem = workitemDAO.findByProcessIDANDActivityID(activity.getProcessID(), activity.getActivityID());
			Participant part = null;
			if (workitem == null) {
				//対応する作業項目が存在しない
				part = ParticipantImpl.getSystemParticipant();
			} else {
				int ptype = workitem.getParticipantType();
				String pname = workitem.getParticipantName();
				ResourceManagerFactory rmf = ResourceManagerFactory.getInstance();
				if (ptype == Participant.HUMAN || ptype == Participant.SYSTEM) {
					UserManager um = rmf.getUserManager();
					part = um.getUser(pname);
				} else if (ptype == Participant.ORGANIZATIONAL_UNIT) {
					OrganizationManager om = rmf.getOrganizationManager();
					part = om.getOrganization(pname);
				} else if (ptype == Participant.ROLE) {
					RoleManager rm = rmf.getRoleManager();
					part = rm.getRole(pname);
				} else {
					// 認識されないリソース型です。
					String E0073 = StringManager.get("E0073");
					throw new WorkflowException(E0073);
				}
			}
			if (part == null) {
				// ワークフロー参加者情報が取得できませんでした。
				String E0074 = StringManager.get("E0074");
				throw new WorkflowException(E0074);
			}
			WfResource ret = new ResourceInternal(part);
			return ret;
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// 関連するリソースの取得に失敗しました。
			String E0075 = StringManager.get("E0075");
			throw new WorkflowException(E0075, ex);
		}
	}

	/**
	 * 実行オブジェクトにかかわる属性一覧を返す。
	 *
	 * @return 属性一覧
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getContext()
	 */
	public WfNameValue[] getContext() throws WorkflowException
	{
		try {
			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			VariableDAO variableDAO = daoFactory.getVariableDAO();
			
			VariableBean[] beans = variableDAO.findByProcessID(activity.getProcessID());
			
			return beans;
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// 関連するプロセス変数の取得に失敗しました。
			String E0076 = StringManager.get("E0076");
			throw new WorkflowException(E0076, ex);
		}
	}

	/**
	 * 実行オブジェクトにかかわる属性を返す。
	 *
	 * @param name 属性名
	 * @return 属性
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getContext()
	 */
	public WfNameValue getContext(String name) throws WorkflowException
	{
		try {
			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			VariableDAO variableDAO = daoFactory.getVariableDAO();
			
			VariableBean beans = variableDAO.findByName(activity.getProcessID(), name);
		
			return beans;
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// 関連するプロセス変数の取得に失敗しました。
			String E0076 = StringManager.get("E0076") + "(" + name + ")";
			throw new WorkflowException(E0076, ex);
		}
	}

	/**
	 * WfActivityによって表される作業の実行によって生成される結果を返す。
	 * 結果データがまだ利用可能でない場合は、例外が発生する。
	 *
	 * @return　実行結果を返す
	 * @throws ResultNotAvailableException 結果がない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#getResult()
	 */
	public WfNameValue[] getResult()
	throws ResultNotAvailableException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 割り当てられているすべてのアサインメントを返す。
	 *
	 * @return WfAssignment
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#getAllAssignment()
	 */
	public WfAssignment[] getAllAssignment() throws WorkflowException
	{
		try {
			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			WorkItemDAO workitemDAO = daoFactory.getWorkItemDAO();
			
			WorkItemBean workitem = workitemDAO.findByProcessIDANDActivityID(activity.getProcessID(), activity.getActivityID());
			WorkItemInternal[] ret = null;
			if (workitem == null) {
				ret = new WorkItemInternal[0];
			} else {
				ret = new WorkItemInternal[1];
				ret[0] = new WorkItemInternal(workitem);
			}
			return ret;
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// 関連する作業項目の取得に失敗しました。
			String E0077 = StringManager.get("E0077");
			throw new WorkflowException(E0077, ex);
		}
	}

	/**
	 * インデクスで指定されたアサインメントを返す。
	 *
	 * @param index インデクス
	 * @return WfAssignment
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#getAssignment(int)
	 */
	public WfAssignment getAssignment(int index) throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 割り当てられているアサインメントの個数を返す。
	 *
	 * @return WfAssignmentの個数
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#getAssignmentCount()
	 */
	public int getAssignmentCount() throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 管理下のすべてのプロセスを返す。
	 *
	 * @return プロセス
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#getAllPerformers()
	 */
	public WfProcess[] getAllPerformers() throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * インデクスで指定されたプロセスを返す。
	 *
	 * @param index インデクス
	 * @return プロセス
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#getPerformer(int)
	 */
	public WfProcess getPerformer(int index) throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 管理しているプロセスの個数を返す。
	 *
	 * @return プロセスの個数
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#getPerformerCount()
	 */
	public int getPerformerCount() throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * この実行オブジェクトに関わる変更履歴を取得する。
	 *
	 * @return 変更履歴
	 * @throws HistoryNotAvailableException 変更履歴が取得可能でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getAllHistories()
	 */
	public WfEvent[] getAllHistories()
	throws HistoryNotAvailableException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * インデクスを指定して、履歴を取得する。
	 *
	 * @param index インデクス
	 * @return 変更履歴
	 * @throws HistoryNotAvailableException 変更履歴が取得可能でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getHistory(int)
	 */
	public WfEvent getHistory(int index)
	throws HistoryNotAvailableException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 変更履歴の数を返す。
	 *
	 * @return 変更履歴の数
	 * @throws HistoryNotAvailableException 変更履歴が取得可能でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#getHistoryCount()
	 */
	public int getHistoryCount()
	throws HistoryNotAvailableException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 指定されたアサインメントが、このアクティビティに割り当てられたものかどうかを返す。
	 *
	 * @param ass WfAssignment
	 * @return このアクティビティに割り当てられたものである場合はtrue
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#isMemberOfAssignment(jp.co.argo21.nautica.workflow.omg.WfAssignment)
	 */
	public boolean isMemberOfAssignment(WfAssignment ass)
	throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 引数で指定されたプロセスが、管理下にあるかどうかを返す。
	 *
	 * @param proc プロセス
	 * @return 管理下にある場合はtrue
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#isMemberOfPerformer(jp.co.argo21.nautica.workflow.omg.WfProcess)
	 */
	public boolean isMemberOfPerformer(WfProcess proc) throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 詳細情報を設定する。
	 *
	 * @param desc 詳細情報
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#setDescription(java.lang.String)
	 */
	public void setDescription(String desc)
	throws WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * WfActivityによって表される作業の実行によって生成される結果を設定する。
	 *
	 * @param result 実行結果を設定する。
	 * @throws InvalidDataException 無効なデータの場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfActivity#setResult(jp.co.argo21.nautica.workflow.omg.WfNameValue[])
	 */
	public void setResult(WfNameValue[] result)
	throws InvalidDataException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * 実行オブジェクトにかかわる属性一覧を設定する。
	 *
	 * @param context 属性一覧
	 * @throws InvalidDataException 無効な属性の場合 
	 * @throws UpdateNotAllowedException 更新ができない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#setContext(jp.co.argo21.nautica.workflow.omg.WfNameValue[])
	 */
	public void setContext(WfNameValue[] context)
	throws InvalidDataException, UpdateNotAllowedException, WorkflowException
	{
		try {
			if (context == null) {
				// プロセス変数がnullです。
				String E0079 = StringManager.get("E0079");
				throw new InvalidDataException(E0079);
			}
			
			String aid = activity.getActivityID();

			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			VariableDAO variableDAO = daoFactory.getVariableDAO();
			Timestamp ts = DataAccessManager.getAccessTime();
			
			for (int i = 0; i < context.length; i++) {
				if (context[i] instanceof Attribute == false) {
					// プロセス変数ではありません。
					String E0078 = StringManager.get("E0078");
					throw new InvalidDataException(E0078);
				}
				Attribute attr = (Attribute)context[i];
				VariableBean bean = new VariableBean();
				bean.setName(attr.getName());
				bean.setType(attr.getType());
				bean.setValue(attr.getValue());
				VariableBean check = variableDAO.findByPrimaryKey(
						bean.getProcessID(), bean.getID());
				if (check == null) {
					bean.setProcessID(activity.getProcessID());
					bean.setUpdateDate(ts);
					bean.setID(UniqueKeyGenerator.generate(VariableBean.ID_PREFIX));
					variableDAO.insert(bean, aid);
				} else {
					variableDAO.update(check, bean.getValue(), aid, ts);
				}
			}
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセス変数の設定に失敗しました。
			String E0080 = StringManager.get("E0080");
			throw new WorkflowException(E0080, ex);
		}
	}

	/**
	 * 実行オブジェクトにかかわる属性を設定する。
	 *
	 * @param context 属性
	 * @throws InvalidDataException 無効な属性の場合 
	 * @throws UpdateNotAllowedException 更新ができない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#setContext(jp.co.argo21.nautica.workflow.omg.WfNameValue[])
	 */
	public void setContext(WfNameValue context)
	throws InvalidDataException, UpdateNotAllowedException, WorkflowException
	{
		try {
			if (context == null) {
				// プロセス変数がnullです。
				String E0079 = StringManager.get("E0079");
				throw new InvalidDataException(E0079);
			}
			
			String aid = activity.getActivityID();

			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			VariableDAO variableDAO = daoFactory.getVariableDAO();
			Timestamp ts = DataAccessManager.getAccessTime();
			
			if (context instanceof Attribute == false) {
				// プロセス変数ではありません。
				String E0078 = StringManager.get("E0078");
				throw new InvalidDataException(E0078);
			}
			Attribute attr = (Attribute)context;
			VariableBean bean = new VariableBean();
			bean.setName(attr.getName());
			bean.setType(attr.getType());
			bean.setValue(attr.getValue());
			VariableBean check = variableDAO.findByName(
					activity.getProcessID(), bean.getName());
			if (check == null) {
				bean.setProcessID(activity.getProcessID());
				bean.setUpdateDate(ts);
				bean.setID(UniqueKeyGenerator.generate(VariableBean.ID_PREFIX));
				variableDAO.insert(bean, aid);
			} else {
				variableDAO.update(check, bean.getValue(), aid, ts);
			}
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセス変数の設定に失敗しました。
			String E0080 = StringManager.get("E0080");
			throw new WorkflowException(E0080, ex);
		}
	}

	/**
	 * 指定された状態に遷移を試みる。
	 *
	 * @param state 状態
	 * @throws InvalidStateException 無効な状態の場合
	 * @throws TransitionNotAllowedException 指定された状態に遷移できない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#changeState(jp.co.argo21.nautica.workflow.omg.WfState)
	 */
	public void changeState(WfState state)
	throws InvalidStateException, TransitionNotAllowedException, WorkflowException
	{
		if (state instanceof ActivityState == false) {
			// アクティビティ状態ではありません。
			String E0081 = StringManager.get("E0081");
			throw new InvalidStateException(E0081);
		}

		if (ActivityState.OPEN_NOT_RUNNING_NOT_STARTED.equals(state)) {
			// そのアクティビティ状態には遷移できません。
			String E0082 = StringManager.get("E0082") + "(" + state.toString() + ")";
			throw new TransitionNotAllowedException(E0082);
		} else if (ActivityState.OPEN_NOT_RUNNING_SUSPENDED.equals(state)) {
			suspend();
		} else if (ActivityState.OPEN_RUNNING.equals(state)) {
			if (ActivityState.OPEN_NOT_RUNNING_NOT_STARTED.equals(getState())) {
				start();
			} else {
				resume();
			}
		} else if (ActivityState.CLOSED_COMPLETED.equals(state)) {
			complete();
		} else if (ActivityState.CLOSED_TERMINATED.equals(state)) {
			terminate();
		} else if (ActivityState.CLOSED_ABORTED.equals(state)) {
			abort();
		}
	}

	/**
	 * アクティビティの開始処理を行う。
	 *
	 * @throws CannotStartException 開始できない場合
	 * @throws AlreadyRunningException すでに開始されている場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	public void start()
	throws CannotStartException, AlreadyRunningException, WorkflowException
	{
		try {
			ActivityState state = (ActivityState)getState();
			boolean closedAlready = false;
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				closedAlready = true;
			} else if (ActivityState.OPEN_NOT_RUNNING_NOT_STARTED.equals(state) == false) {
				//下で型によって区別する
				//throw new AlreadyRunningException("");
			}

			String pid = activity.getProcessID();
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);
			
			ProcessBean pbean = proc.getBean();
			String pdid = pbean.getProcDefinitionID();
			
			String adid = activity.getActivityDefinitionID();

			//対応するプロセス定義の取得
			WorkflowEngine engine = WorkflowEngine.getInstance();
			DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
			ProcessDefinition pd = rep.getProcessDefinition(pdid);
			
			//アクティビティ定義の探索
			ActivityDefinition ad = findActivity(pd, adid);
			String type = ad.getType();
			
			if (closedAlready) {
				//同期終了のみ例外を返さず、処理を終了する。
				if (type.equals(ActivityDefinition.CONCUR_END) == false) {
					// アクティビティはすでに実行を終了しています。
					String E0085 = StringManager.get("E0085");
					throw new NotRunningException(E0085);
				} else {
					return;
				}
			} else if (ActivityState.OPEN_NOT_RUNNING_NOT_STARTED.equals(state) == false) {
				//同期終了のみ例外を返さず、処理を終了する。
				if (type.equals(ActivityDefinition.CONCUR_END) == false) {
					// アクティビティはすでに開始されています。
					String E0083 = StringManager.get("E0083");
					throw new AlreadyRunningException(E0083);
				}
			}
			
			//アクティビティの種類に応じた個別の処理を実行
			ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
			ActivityBehavior behavior = abf.getActivityBehavior(ad.getType());
			BehaviorExecutor.start(behavior, pd, ad, proc, this);
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを開始できませんでした。
			String E0087 = StringManager.get("E0087");
			throw new WorkflowException(E0087, ex);
		}
	}

	/**
	 * 保留中の実行オブジェクトの再開を要求する。
	 * 要求が受け入れられた場合、状態は、open.not_running.suspendedから、
	 * open.runningに設定される。
	 *
	 * @throws CannotResumeException 再開できない場合 
	 * @throws NotRunningException 走行中でない場合
	 * @throws NotSuspendedException 保留されていない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#resume()
	 */
	public void resume()
	throws CannotResumeException, NotRunningException,
		NotSuspendedException, WorkflowException
	{
		try {
			ActivityState state = (ActivityState)getState();
			
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				// アクティビティはすでに実行を終了しています。
				String E0085 = StringManager.get("E0085");
				throw new NotRunningException(E0085);
			} else if (ActivityState.OPEN_NOT_RUNNING_SUSPENDED.equals(state) == false) {
				// アクティビティは保留されていません。
				String E0086 = StringManager.get("E0086");
				throw new NotSuspendedException(E0086);
			}

			String pid = activity.getProcessID();
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);
			
			ProcessBean pbean = proc.getBean();
			String pdid = pbean.getProcDefinitionID();
			
			String adid = activity.getActivityDefinitionID();

			//対応するプロセス定義の取得
			WorkflowEngine engine = WorkflowEngine.getInstance();
			DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
			ProcessDefinition pd = rep.getProcessDefinition(pdid);
			
			//アクティビティ定義の探索
			ActivityDefinition ad = findActivity(pd, adid);
			
			//アクティビティの種類に応じた動作を実行する。
			String type = ad.getType();
			ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
			ActivityBehavior behavior = abf.getActivityBehavior(type);
			BehaviorExecutor.resume(behavior, pd, ad, proc, this);
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを再開できませんでした。
			String E0088 = StringManager.get("E0088");
			throw new WorkflowException(E0088, ex);
		}
	}

	/**
	 * 実行中の実行オブジェクトの停止を要求する。
	 * 要求が受け入れられた場合、状態はclosed.terminatedに設定される。
	 *
	 * @throws CannotStopException 停止できない場合
	 * @throws NotRunningException 走行中でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#suspend()
	 */
	public void suspend()
	throws CannotSuspendException, NotRunningException,
		AlreadySuspendedException, WorkflowException
	{
		try {
			ActivityState state = (ActivityState)getState();
			
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				// アクティビティはすでに実行を終了しています。
				String E0085 = StringManager.get("E0085");
				throw new NotRunningException(E0085);
			} else if (ActivityState.OPEN_NOT_RUNNING_SUSPENDED.equals(state)) {
				// アクティビティはすでに保留されています。
				String E0084 = StringManager.get("E0084");
				throw new AlreadySuspendedException(E0084);
			}
			String pid = activity.getProcessID();
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);
			
			ProcessBean pbean = proc.getBean();
			String pdid = pbean.getProcDefinitionID();
			
			String adid = activity.getActivityDefinitionID();

			//対応するプロセス定義の取得
			WorkflowEngine engine = WorkflowEngine.getInstance();
			DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
			ProcessDefinition pd = rep.getProcessDefinition(pdid);
			
			//アクティビティ定義の探索
			ActivityDefinition ad = findActivity(pd, adid);
			
			//アクティビティの種類に応じた動作を実行する。
			String type = ad.getType();
			ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
			ActivityBehavior behavior = abf.getActivityBehavior(type);
			BehaviorExecutor.suspend(behavior, pd, ad, proc, this);
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを保留できませんでした。
			String E0089 = StringManager.get("E0089");
			throw new WorkflowException(E0089, ex);
		}
	}

	/**
	 * WfActivityの完了を要求するために、アプリケーションによって使用される。
	 * これは、setResult()と共に、アクティビティの結果をプロセスに返すために使用される。
	 *
	 * @throws CannotCompleteException 完了できない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	public void complete()
	throws CannotStopException, NotRunningException, WorkflowException
	{
		try {
			boolean closedAlready = false;
			ActivityState state = (ActivityState)getState();
			
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				closedAlready = true;
			}
			
			//該当アクティビティを完了させる。
			WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
			ActivityDAO actDAO = daoFactory.getActivityDAO();
			Timestamp ts = DataAccessManager.getAccessTime();
			if (closedAlready) {
				//すでにほかの要求により完了しているため、
				//完了状態は変更せずに日付のみを更新する。
				actDAO.updateDate(getBean(), ts);
			} else {
				//所属プロセスの取得
				String pid = activity.getProcessID();
				ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
				ProcessManager pm = pmf.getOwnerProcessManager(pid);
				ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);

				ProcessBean pbean = proc.getBean();
				String pdid = pbean.getProcDefinitionID();
				String adid = activity.getActivityDefinitionID();

				//対応するプロセス定義の取得
				WorkflowEngine engine = WorkflowEngine.getInstance();
				DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
				ProcessDefinition pd = rep.getProcessDefinition(pdid);
				
				//アクティビティ定義の探索
				ActivityDefinition ad = findActivity(pd, adid);
				
				//アクティビティの種類に応じた動作を実行する。
				String type = ad.getType();
				ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
				ActivityBehavior behavior = abf.getActivityBehavior(type);
				BehaviorExecutor.complete(behavior, pd, ad, proc, this);
			}
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを完了できませんでした。
			String E0090 = StringManager.get("E0090");
			throw new WorkflowException(E0090, ex);
		}
	}

	/**
	 * 実行中の実行オブジェクトの停止を要求する。
	 * 要求が受け入れられた場合、状態はclosed.terminatedに設定される。
	 *
	 * @throws CannotStopException 停止できない場合
	 * @throws NotRunningException 走行中でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#terminate()
	 */
	public void terminate()
	throws CannotStopException, NotRunningException, WorkflowException
	{
		terminate(true);
	}

	/**
	 * 保留された実行オブジェクトの中断を要求する。
	 * 要求が受け入れられた場合、状態はclosed.abortedに設定される。
	 *
	 * @throws CannotStopException 停止できない場合
	 * @throws NotRunningException 走行中でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfExecutionObject#abort()
	 */
	public void abort()
	throws CannotStopException, NotRunningException, WorkflowException
	{
		abort(true);
	}

	/**
	 * WfProcessがそのリクエスタにワークフローイベントを通知するために
	 * 使用されるリスナーインタフェース。このインタフェースを通して、
	 * WfProcessは、完了(complete)、停止(terminate)、中断(abort)のイベントや、
	 * クローズド(closed)状態への遷移をリクエスタに通知するものとする。
	 *
	 * @param event イベント
	 * @throws InvalidPerformerException 無効なプロセスの場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.omg.WfRequester#receiveEvent(jp.co.argo21.nautica.workflow.omg.WfEvent)
	 */
	public void receiveEvent(WfEvent event)
	throws InvalidPerformerException, WorkflowException
	{
		String E0900 = StringManager.get("E0900");
		throw new UnsupportedOperationException(E0900);
	}

	/**
	 * フィルターで特定されたプロセス変数を返す。
	 *
	 * @param filter フィルター
	 * @return プロセス変数
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	WfNameValue[] getContext(Filter filter) throws WorkflowException
	{
		try {
			WorkflowDAOFactory daoFactory
				= DataAccessManager.getDAOFactory();
			VariableDAO variableDAO = daoFactory.getVariableDAO();
			
			VariableBean[] beans = variableDAO.findByFilter(filter, activity.getProcessID());
			
			return beans;
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセス変数の取得に失敗しました。
			String E0032 = StringManager.get("E0032");
			throw new WorkflowException(E0032, ex);
		}
	}

	/**
	 * 内部に保持しているアクティビティを返す。
	 *
	 * @return アクティビティ
	 */
	ActivityBean getBean()
	{
		return (ActivityBean)activity;
	}

	/**
	 * 停止処理を行う。引数がfalseの場合は、サブプロセスをチェックしない。
	 *
	 * @param checkChild サブプロセスをチェックするかどうかを示すフラグ
	 * @throws CannotStopException 停止できない場合
	 * @throws NotRunningException 走行中でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	void terminate(boolean checkChild)
	throws CannotStopException, NotRunningException, WorkflowException
	{
		try {
			boolean closedAlready = false;
			ActivityState state = (ActivityState)getState();
			
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				closedAlready = true;
			}
			
			//該当アクティビティを中止させる。
			WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
			ActivityDAO actDAO = daoFactory.getActivityDAO();
			Timestamp ts = DataAccessManager.getAccessTime();
			if (closedAlready) {
				//すでにほかの要求により完了しているため、
				//完了状態は変更せずに日付のみを更新する。
				actDAO.updateDate(getBean(), ts);
			} else {
				//所属プロセスの取得
				String pid = activity.getProcessID();
				ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
				ProcessManager pm = pmf.getOwnerProcessManager(pid);
				ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);

				ProcessBean pbean = proc.getBean();
				String pdid = pbean.getProcDefinitionID();
				String adid = activity.getActivityDefinitionID();

				//対応するプロセス定義の取得
				WorkflowEngine engine = WorkflowEngine.getInstance();
				DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
				ProcessDefinition pd = rep.getProcessDefinition(pdid);
				
				//アクティビティ定義の探索
				ActivityDefinition ad = findActivity(pd, adid);
				
				//アクティビティの種類に応じた動作を実行する。
				String type = ad.getType();
				ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
				ActivityBehavior behavior = abf.getActivityBehavior(type);
				BehaviorExecutor.terminate(behavior, pd, ad, proc, this, checkChild);
			}
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを停止できませんでした。
			String E0091 = StringManager.get("E0091");
			throw new WorkflowException(E0091, ex);
		}
	}

	/**
	 * 中止処理を行う。引数がfalseの場合は、サブプロセスをチェックしない。
	 *
	 * @param checkChild サブプロセスをチェックするかどうかを示すフラグ
	 * @throws CannotStopException 停止できない場合
	 * @throws NotRunningException 走行中でない場合
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	void abort(boolean checkChild)
	throws CannotStopException, NotRunningException, WorkflowException
	{
		try {
			boolean closedAlready = false;
			ActivityState state = (ActivityState)getState();
			
			if (ActivityState.CLOSED_COMPLETED.equals(state)
					|| ActivityState.CLOSED_TERMINATED.equals(state)
					|| ActivityState.CLOSED_ABORTED.equals(state)) {
				closedAlready = true;
			}
			
			//該当アクティビティを中止させる。
			WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
			ActivityDAO actDAO = daoFactory.getActivityDAO();
			Timestamp ts = DataAccessManager.getAccessTime();
			//所属プロセスの取得
			String pid = activity.getProcessID();
			if (closedAlready) {
				//すでにほかの要求により完了しているため、
				//完了状態は変更せずに日付のみを更新する。
				actDAO.updateDate(getBean(), ts);
			} else {
				ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
				ProcessManager pm = pmf.getOwnerProcessManager(pid);
				ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);

				ProcessBean pbean = proc.getBean();
				String pdid = pbean.getProcDefinitionID();
				String adid = activity.getActivityDefinitionID();

				//対応するプロセス定義の取得
				WorkflowEngine engine = WorkflowEngine.getInstance();
				DefinitionRepositoryImpl rep = engine.getDefinitionRepository();
				ProcessDefinition pd = rep.getProcessDefinition(pdid);
				
				//アクティビティ定義の探索
				ActivityDefinition ad = findActivity(pd, adid);
				
				//アクティビティの種類に応じた動作を実行する。
				String type = ad.getType();
				ActivityBehaviorFactory abf = ActivityBehaviorFactory.getInstance();
				ActivityBehavior behavior = abf.getActivityBehavior(type);
				BehaviorExecutor.abort(behavior, pd, ad, proc, this, checkChild);
			}

			//メッセージキューにプロセス完了要求登録
			WorkflowMessage eprmsg = new EndProcessRequestMessage(pid, ActivityState.CLOSED_ABORTED);
			SystemMessageTransporter mt = new SystemMessageTransporter(EndProcessRequestWatcher.NAME);
			mt.sendMessage(eprmsg);
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// アクティビティを中止できませんでした。
			String E0092 = StringManager.get("E0092");
			throw new WorkflowException(E0092, ex);
		}
	}
	
	/**
	 * 引数情報から特定されるアクティビティ定義を返す。
	 *
	 * @param pd プロセス定義
	 * @param adid アクティビティ定義ID
	 * @return アクティビティ定義
	 * @throws Exception 任意の例外
	 */
	private ActivityDefinition findActivity(ProcessDefinition pd, String adid)
	throws Exception
	{
		List<ActivityDefinition> acts = pd.getActivities();
		ActivityDefinition ad = null;
		for (ActivityDefinition def :acts) {
			if (def.getID().equals(adid)) {
				ad = def;
				break;
			}
		}
		
		if (ad == null) {
			// 対応するアクティビティ定義が存在しません。
			String E0093 = StringManager.get("E0093") + "(" + adid + ")";
			throw new WorkflowException(E0093);
		}
		return ad;
	}
}
