/* $Id: InterWorkflowConnectorImpl.java,v 1.3 2007/11/26 08:51:40 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 javax.naming.NamingException;

import org.apache.log4j.Logger;

import jp.co.argo21.nautica.workflow.dataaccess.SourceActivityBean;
import jp.co.argo21.nautica.workflow.dataaccess.SourceActivityDAO;
import jp.co.argo21.nautica.workflow.dataaccess.TargetProcessBean;
import jp.co.argo21.nautica.workflow.dataaccess.TargetProcessDAO;
import jp.co.argo21.nautica.workflow.dataaccess.WorkflowDAOFactory;
import jp.co.argo21.nautica.workflow.omg.WfActivity;
import jp.co.argo21.nautica.workflow.omg.WfProcess;
import jp.co.argo21.nautica.workflow.omg.WfProcessManager;
import jp.co.argo21.nautica.workflow.omg.WfRequester;
import jp.co.argo21.nautica.workflow.omg.WorkflowException;
import jp.co.argo21.nautica.workflow.security.SessionManager;
import jp.co.argo21.nautica.workflow.security.User;
import jp.co.argo21.nautica.workflow.util.GeronimoUtils;
import jp.co.argo21.nautica.workflow.util.StateHelper;
import jp.co.argo21.nautica.workflow.util.StringManager;
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.InterWorkflowConnector;
import jp.co.argo21.nautica.workflow.wfmc.InvalidActivityInstanceException;
import jp.co.argo21.nautica.workflow.wfmc.InvalidProcessInstanceException;
import jp.co.argo21.nautica.workflow.wfmc.InvalidSessionException;
import jp.co.argo21.nautica.workflow.wfmc.Process;
import jp.co.argo21.nautica.workflow.wfmc.ProcessState;

/**
 * エンジン間接続のためInterWorkflowConnector実現クラスである。
 *
 * @author  nito(Argo 21, Corp.)
 * @version $Revision: 1.3 $
 * @since   Nautica Workflow 1.0
 */
public class InterWorkflowConnectorImpl implements InterWorkflowConnector
{
	/** エンジンログ */
	private static Logger eLog = LogManager.getEngineLogger();
	
	/** 監査ログ */
	private static Logger audit = LogManager.getAuditLogger();

	private static final String INTER_WORKFLOW_CONNECTOR_REMOTE_IF =
		"nautica-workflow/InterWorkflowConnectorBean/jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector";

	/** InterWorkflowConnectorImplのシングルトンインスタンス */
	private static InterWorkflowConnectorImpl connector;
	
	/** 外部エンジン設定 */
	private static InterWorkflowConfig config;
	
	/**
	 * InterWorkflowConnectorImplの生成と初期化を行う。
	 *
	 * @throws Exception 任意の例外
	 */
	static void create() throws Exception
	{
		config = new InterWorkflowConfig();
		connector = new InterWorkflowConnectorImpl();
		try {
			connector.init();
		} catch (Exception ex) {
			throw ex;
		}
	}

	/**
	 * InterWorkflowConnectorのインスタンスを返す。
	 *
	 * @return InterWorkflowConnector
	 */
	static InterWorkflowConnector getInstance()
	{
		return connector;
	}

	/**
	 * InterWorkflowConnectorのリモートインスタンスを返す。
	 *
	 * @param engineName エンジン名
	 * @return エンジン間接続リモートインタフェース
	 * @throws WorkflowException ワークフロー内で例外が起こった場合
	 * @throws NamingException 名前解決で例外が起こった場合
	 */
	static InterWorkflowConnector getRemoteInstance(String engineName)
	throws WorkflowException, NamingException
	{
		if (engineName == null || engineName.trim().equals("")) {
			// エンジン名が未設定です。
			String E0212 = StringManager.get("E0212");
			throw new WorkflowException(E0212);
		}

		InterWorkflowConfig.EngineInfo info = config.getEngineInfo(engineName);
		if (info == null) {
			// エンジン名に対応するエンジン情報がありません。
			String E0220 = StringManager.get("E0220");
			throw new WorkflowException(E0220);
		}
		String url = info.getURL();
		
		InterWorkflowConnector iwc =
			(InterWorkflowConnector)GeronimoUtils.getEJB(url, INTER_WORKFLOW_CONNECTOR_REMOTE_IF);
		return iwc;
	}
	
	/**
	 * リモートのエンジンに接続して、エンジン接続IDを返す。
	 *
	 * @param remote エンジンのリモートインタフェース
	 * @return エンジン接続ID
	 * @throws WorkflowException ワークフローレベルで例外が起こった場合
	 */
	static String connectToRemoteEngine(InterWorkflowConnector remote)
	throws WorkflowException
	{
		String id = config.getLocalEngineID();
		String pass = config.getPassword();
		
		String remoteEID = remote.connect(id, pass);
		
		// 監査ログ出力
		AuditDataRecord data = new AuditDataRecord(
		        new AuditPrefix("WMStartedConversation"),
		        new AuditSuffix(1, "4MIME"));
		data.setDataElement("SourceConverstaionID", id);
		data.setDataElement("TargetConversationID", remoteEID);
		audit.info(data);
		
		return remoteEID;
	}

	/**
	 * enginePasswordを返す。
	 *
	 * @return enginePassword
	 */
	static String getLocalEnginePassword()
	{
		return config.getPassword();
	}
	
	/**
	 * InterWorkflowConnectorImplを生成する。
	 */
	private InterWorkflowConnectorImpl()
	{
	}
	
	/**
	 * InterWorkflowConnectorImplを初期化する。
	 *
	 * @throws Exception 任意の例外
	 */
	private void init() throws Exception
	{
	}

	/**
	 * 自エンジンのIDを指定して、リモートエンジンアクセス用のIDを返す。
	 *
	 * @param seid 自エンジンのID
	 * @param password パスワード
	 * @return リモートのエンジンから返されるエンジン接続ID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#connect(java.lang.String, java.lang.String)
	 */
	public String connect(String seid, String password)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = connect,"
			 + "source engine id = [" + seid + "],"
			 + "password = [**SECURITY**])";
	
		try {
			InterWorkflowConfig.EngineInfo info = config.getEngineInfo(seid);
			if (info == null) {
				// エンジンIDに対応するエンジン情報がありません。
				String E0221 = StringManager.get("E0221");
				throw new WorkflowException(E0221);
			}

			//パスワードをチェックする。
			String pass = info.getPassword();
			if (pass == null) {
				if (password != null) {
					// 接続用パスワードが一致しません。
					String E0222 = StringManager.get("E0222");
					throw new WorkflowException(E0222);
				}
			} else {
				if (password == null) {
					// 接続用パスワードが一致しません。
					String E0222 = StringManager.get("E0222");
					throw new WorkflowException(E0222);
				} else if (password.equals(pass) == false) {
					// 接続用パスワードが一致しません。
					String E0222 = StringManager.get("E0222");
					throw new WorkflowException(E0222);
				}
			}
			
			//セッションの作成
			WorkflowEngine engine = WorkflowEngine.getInstance();
			
			String eid = engine.connect(seid, password);
			
			// 監査ログ出力
			AuditDataRecord data = new AuditDataRecord(
			        new AuditPrefix("WMStartedConversation"),
			        new AuditSuffix(1,"4MIME"));
			data.setDataElement("SourceConverstaionID", seid);
			data.setDataElement("TargetConversationID", eid);
			audit.info(data);
			
			return eid;
		} catch (WorkflowException ex) {
			String msg = ex.getMessage() + argInfo;
			eLog.error(msg, ex);
			throw ex;
		} catch (Exception ex) {
			// エンジン間接続に失敗しました。
			String E0207 = StringManager.get("E0207") + argInfo;
			eLog.error(E0207, ex);
			throw new WorkflowException(E0207, ex);
		}
	}

	/**
	 * リモートのエンジンとの接続を切断する。
	 *
	 * @param eid エンジンID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#disconnect(java.lang.String)
	 */
	public void disconnect(String eid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = disconnect,"
			 + "engine connection id = [" + eid + "])";
	
		try {
			//セッションの作成
			WorkflowEngine engine = WorkflowEngine.getInstance();

			engine.disconnect(eid);
			
			// 監査ログ出力
			AuditDataRecord data = new AuditDataRecord(
			        new AuditPrefix("WMStoppedConversation"),
			        new AuditSuffix(1,"4MIME"));
			data.setDataElement("TargetConversationID", eid);
			audit.info(data);
			
		} catch (WorkflowException ex) {
			String msg = ex.getMessage() + argInfo;
			eLog.error(msg, ex);
			throw ex;
		} catch (Exception ex) {
			// エンジン間接続の切断に失敗しました。
			String E0208 = StringManager.get("E0208") + argInfo;
			eLog.error(E0208, ex);
			throw new WorkflowException(E0208, ex);
		}
	}

	/**
	 * プロセスインスタンス状態の変更を要求する。
	 * 作成したプロセスを開始する場合も、このインタフェースを使用する。
	 *
	 * @param eid エンジンID
	 * @param pid プロセスインスタンスID
	 * @param state プロセスインスタンス状態
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#changeProcessState(java.lang.String, java.lang.String, jp.co.argo21.nautica.workflow.wfmc.ProcessState)
	 */
	public void changeProcessState(String eid, String pid, ProcessState state)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = changeProcessState,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "],"
			 + "state = [" + state.toString() + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedRequestChangeProcessInstanceState"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement("SourceRequestedState", state);
	    data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			if (state == null) {
				// プロセス状態が設定されていません。
				String E0218 = StringManager.get("E0218");
				throw new WorkflowException(E0218);
			}
	
			DataAccessManager.begin(false);
			
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			String remoteEngineID = validateEngineID(eid);
			
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(pid);

			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			WfProcessManager pm = pmf.getOwnerProcessManager(pid);
			WfProcess process = pm.getProcess(pid);
			process.changeState(state);
			
			DataAccessManager.commit();
			
			// 監査ログ出力
			data = new AuditDataRecord(
			        new AuditPrefix("WMChangeProcessInstanceState"),
			        new AuditSuffix(1, "4MIME"));
			data.setDataElement("NewProcessState", state);
			data.setDataElement("TargetConversationID", remoteEngineID);
			audit.info(data);

		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス状態の変更に失敗しました。
			String E0156 = StringManager.get("E0156") + argInfo;
			eLog.error(E0156, ex);
			throw new WorkflowException(E0156, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
			// 監査ログ出力
		    data = new AuditDataRecord(
		            new AuditPrefix("WMSentChangeProcessInstanceState"),
		            new AuditSuffix(1, "4MIME"));
		    data.setDataElement("TargetProcessInstanceID", pid);
		    data.setDataElement("TargetNodeID", SystemChecker.getProperty(WorkflowEngineConstants.NAUTICA_SCOPE));
		    data.setDataElement("TargetState", state);
		    data.setDataElement("TargetConversationID", eid);
			audit.info(data);
		}
	}

	/**
	 * プロセスインスタンスの生成を要求する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pdid プロセス定義ID
	 * @param flag 戻り値を返す必要があるかどうかを表すフラグ
	 * @param rootpid 要求元のプロセスインスタンスID
	 * @param aid 要求元のアクティビティインスタンスID
	 * @param userid ユーザID。主に記録用。
	 * @param roleid 権限ID。主に記録用。
	 * @return 生成されたプロセスインスタンスのID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#createProcess(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public String createProcess(String eid, String pdid, int flag,
			String rootpid, String aid, String userid, String roleid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = createProcess,"
			 + "engine connection id = [" + eid + "],"
			 + "pdid = [" + pdid + "],"
			 + "flag = [" + flag + "],"
			 + "rootpid = [" + rootpid + "],"
			 + "aid = [" + aid + "],"
			 + "userid = [" + userid + "],"
			 + "roleid = [" + roleid + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedRequestCreateProcessInstance"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement("SourceCurrentProcessInstanceID", rootpid);
	    data.setDataElement("SourceActivityInstanceID", aid);
	    data.setDataElement("SourceUserID", userid);
	    data.setDataElement("SourceRoleID", roleid);
	    data.setDataElement("SourceProcessDefinitionID", pdid);
		data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			if (pdid == null || pdid.trim().equals("")) {
				// プロセス定義IDが設定されていません。
				String E0219 = StringManager.get("E0219");
				throw new WorkflowException(E0219);
			}

			if (flag != NEED_RESULT && flag != NOT_NEED_RESULT) {
				// 戻り値フラグが有効な値ではありません。
				String E0224 = StringManager.get("E0224");
				throw new WorkflowException(E0224);
			}

			checkRootProcessID(rootpid);
			checkActivityID(aid);

			if (userid == null || userid.trim().equals("")) {
				// ユーザIDが未設定です。
				String E0166 = StringManager.get("E0166");
				throw new WorkflowException(E0166);
			}

			if (roleid == null || roleid.trim().equals("")) {
				// ロールIDが未設定です。
				String E0213 = StringManager.get("E0213");
				throw new WorkflowException(E0213);
			}

			DataAccessManager.begin(false);
			
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			String remoteEngineID = validateEngineID(eid);

			//プロセスの生成を行う。
			RequesterManager rqm = RequesterManager.getInstance();
			WfRequester requester = rqm.getRequesterBySession(eid);
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			WfProcessManager pm = pmf.getProcessManager(pdid);
			String name = "InterWorkflow process by " + remoteEngineID;
			WfProcess process = pm.createProcess(requester, name);
			String pid = process.getID();

			//要求を管理する必要がある場合、要求元情報を登録する。
			if (flag == NEED_RESULT) {
				WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
				SourceActivityDAO saDAO = daoFactory.getSourceActivityDAO();
				SourceActivityBean sabean = new SourceActivityBean();
				sabean.setEngineID(remoteEngineID);
				sabean.setRootProcID(rootpid);
				sabean.setRootActID(aid);
				sabean.setProcessID(pid);
				saDAO.insert(sabean);
			}
			
			DataAccessManager.commit();
			
			// 監査ログ出力
			data = new AuditDataRecord(
			        new AuditPrefix("WMCreatedProcessInstance"),
			        new AuditSuffix(1, "4MIME"));
			data.setDataElement("ProcessDefinitionID", pdid);
			data.setDataElement("TargetConversationID", eid);
			audit.info(data);

			return pid;
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセスの生成に失敗しました。
			String E0153 = StringManager.get("E0153") + argInfo;
			eLog.error(E0153, ex);
			throw new WorkflowException(E0153, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
			// 監査ログ出力
		    data = new AuditDataRecord(
		            new AuditPrefix("WMSentCreatedProcessInstance"),
		            new AuditSuffix(1, "4MIME"));
		    data.setDataElement("SourceCurrentProcessInstanceID", rootpid);
		    data.setDataElement("SourceActivityInstanceID", aid);
		    data.setDataElement("SourceUserID", userid);
		    data.setDataElement("SourceRoleID", roleid);
		    data.setDataElement("SourceProcessDefinitionID", pdid);
		    data.setDataElement("TargetConversationID", eid);
			audit.info(data);
		}
	}

	/**
	 * プロセスインスタンス属性の取得を要求する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @param rootpid 要求元のプロセスインスタンスID
	 * @param aid アクティビティインスタンスID
	 * @return 属性の配列を返す。
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#getProcessAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public Attribute[] getProcessAttributes(String eid, String pid,
			String rootpid, String aid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = getProcessAttributes,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "],"
			 + "rootpid = [" + rootpid + "],"
			 + "aid = [" + aid + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedRequestGetProcessInstanceAttribute"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement("SourceCurrentProcessInstanceID", rootpid);
	    data.setDataElement("SourceActivityInstanceID", aid);
	    data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			DataAccessManager.begin(false);
			
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
			
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(rootpid, aid, pid);

			//プロセス変数の取得
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			WfProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal process = (ProcessInternal)pm.getProcess(pid);
			Attribute[] attrs = (Attribute[])process.getContext();
			
			DataAccessManager.commit();

			return attrs;
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス変数の取得に失敗しました。
			String E0032 = StringManager.get("E0032") + argInfo;
			eLog.error(E0032, ex);
			throw new WorkflowException(E0032, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
			// 監査ログ出力
		    data = new AuditDataRecord(
		            new AuditPrefix("WMSentGetProcessInstanceAttribute"),
		            new AuditSuffix(1, "4MIME"));
		    data.setDataElement("TargetProcessInstanceID", pid);
		    data.setDataElement("TargetNodeID", SystemChecker.getProperty(WorkflowEngineConstants.NAUTICA_SCOPE));
		    data.setDataElement("TargetConversationID", eid);
			audit.info(data);
		}
	}

	/**
	 * プロセスインスタンス状態の取得を要求する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @return プロセスインスタンス状態
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#getProcessState(java.lang.String, java.lang.String)
	 */
	public ProcessState getProcessState(String eid, String pid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = getProcessState,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "])";
	
		try {
			DataAccessManager.begin(false);
				
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
				
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(pid);
	
			//プロセス状態の取得
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			WfProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal internal = (ProcessInternal)pm.getProcess(pid);
			Process proc = internal.getBean();
			ProcessState state = ProcessState.getState(proc.getProcessState());
				
			DataAccessManager.commit();
	
			return state;
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス状態の取得に失敗しました。
			String E0154 = StringManager.get("E0154") + argInfo;
			eLog.error(E0154, ex);
			throw new WorkflowException(E0154, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * プロセスインスタンス属性の変更を通知する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @param attrs 属性
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#processAttributesChanged(java.lang.String, java.lang.String, jp.co.argo21.nautica.workflow.wfmc.Attribute[])
	 */
	public void processAttributesChanged(String eid, String pid, Attribute[] attrs)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = processAttributesChanged,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "],"
			 + "attribute = [" + attrs + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedChangedProcessInstanceAttribute"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement(attrs);
	    data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			if (attrs == null) {
				// プロセス変数が未設定です。
				String E0131 = StringManager.get("E0131");
				throw new InvalidProcessInstanceException(E0131);
			}

			DataAccessManager.begin(false);
				
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			String remoteEngineID = validateEngineID(eid);
				
			//親プロセス側なので、セッションのチェックは行わない。
			//ただし、リモート情報のチェックを行う。
			@SuppressWarnings("unused")
			TargetProcessBean tpbean = checkTargetInfo(remoteEngineID, pid);
	
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			WfProcessManager pm = pmf.getOwnerProcessManager(pid);
			WfProcess process = pm.getProcess(pid);
	
			for (int i = 0; i < attrs.length; i++) {
				//プロセス変数の更新
				process.setContext(attrs[i]);
			}
				
			DataAccessManager.commit();

		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス変数の更新に失敗しました。
			String E0031 = StringManager.get("E0031") + argInfo;
			eLog.error(E0031, ex);
			throw new WorkflowException(E0031, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * プロセスインスタンス状態の変更を通知する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @param state プロセスインスタンス状態
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#processStateChanged(java.lang.String, java.lang.String, jp.co.argo21.nautica.workflow.wfmc.ProcessState)
	 */
	public void processStateChanged(String eid, String pid, ProcessState state)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = processStateChanged,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "],"
			 + "state = [" + state + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedChangedProcessInstanceState"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement("NewProcessState", state);
	    data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			if (state == null) {
				// プロセス状態が未設定です。
				String E0214 = StringManager.get("E0214");
				throw new InvalidProcessInstanceException(E0214);
			}

			DataAccessManager.begin(false);

			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			String remoteEngineID = validateEngineID(eid);
	
			//親プロセス側なので、セッションのチェックは行わない。
			//ただし、リモート情報のチェックを行う。
			TargetProcessBean tpbean = checkTargetInfo(remoteEngineID, pid);
				
			String rootpid = tpbean.getRootProcID();
			String rootaid = tpbean.getRootActID();
	
			//状態の変更
			//状態がCLOSEなら、リモートに関係の切り離しを通知する。
			if (ProcessState.CLOSED_COMPLETED.equals(state)
					|| ProcessState.CLOSED_TERMINATED.equals(state)
					|| ProcessState.CLOSED_ABORTED.equals(state)) {

				ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
				WfProcessManager pm = pmf.getOwnerProcessManager(rootpid);
				WfProcess process = pm.getProcess(rootpid);
				WfActivity activity = process.getStep(rootaid);
				ActivityState astate = StateHelper.convert(state);
				activity.changeState(astate);
					
				relinquishProcessLocal(remoteEngineID, pid);
			}
				
			DataAccessManager.commit();

		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス状態の変更に失敗しました。
			String E0156 = StringManager.get("E0156") + argInfo;
			eLog.error(E0156, ex);
			throw new WorkflowException(E0156, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * プロセスインスタンス属性の設定を要求する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param rootpid 要求元のプロセスインスタンスID
	 * @param aid 要求アクティビティインスタンスID
	 * @param pid プロセスインスタンスID
	 * @param attrs 属性
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#setProcessAttributes(java.lang.String, java.lang.String, java.lang.String, java.lang.String, jp.co.argo21.nautica.workflow.wfmc.Attribute[])
	 */
	public void setProcessAttributes(String eid, String rootpid,
			String aid, String pid, Attribute[] attrs)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = setProcessAttributes,"
			 + "engine connection id = [" + eid + "],"
			 + "rootpid = [" + rootpid + "],"
			 + "aid = [" + aid + "],"
			 + "pid = [" + pid + "],"
			 + "attrs = [" + attrs + "])";
	
		// 監査ログ出力
	    AuditDataRecord data = new AuditDataRecord(
	            new AuditPrefix("WMReceivedRequestChangeProcessInstanceAttribute"),
	            new AuditSuffix(1, "4MIME"));
	    data.setDataElement("SourceCurrentProcessInstanceID", rootpid);
	    data.setDataElement("SourceActivityInstanceID", aid);
	    data.setDataElement(attrs);
	    data.setDataElement("TargetConversationID", eid);
		audit.info(data);

		try {
			if (attrs == null) {
				// プロセス変数が未設定です。
				String E0131 = StringManager.get("E0131");
				throw new InvalidProcessInstanceException(E0131);
			}

			DataAccessManager.begin(false);
				
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
				
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(rootpid, aid, pid);
	
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal process = (ProcessInternal)pm.getProcess(pid);
			process.setContext(attrs);
				
			DataAccessManager.commit();
				
			// 監査ログ出力
			data = new AuditDataRecord(
			        new AuditPrefix("WMAssignedProcessInstanceAttribute"),
			        new AuditSuffix(1, "4MIME"));
			data.setDataElement(attrs);
			data.setDataElement("TargetConversationID", eid);
			audit.info(data);
	
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス変数の設定に失敗しました。
			String E0080 = StringManager.get("E0080") + argInfo;
			eLog.error(E0080, ex);
			throw new WorkflowException(E0080, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
			// 監査ログ出力
		    data = new AuditDataRecord(
		            new AuditPrefix("WMSentChangeProcessInstanceAttribute"),
		            new AuditSuffix(1, "4MIME"));
		    data.setDataElement("TargetProcessInstanceID", pid);
		    data.setDataElement("TargetNodeID", SystemChecker.getProperty(WorkflowEngineConstants.NAUTICA_SCOPE));
		    data.setDataElement(attrs);
		    data.setDataElement("TargetConversationID", eid);
			audit.info(data);
		}
	}

	/**
	 * トリガーとなるアクティビティを通知する。
	 * これは、起動したアクティビティとは別なアクティビティによって
	 * プロセスを制御する場合の通知として使用する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param rootpid 要求元のプロセスインスタンスID
	 * @param aid 要求アクティビティインスタンスID
	 * @param pid プロセスインスタンスID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#triggerActivity(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
	 */
	public void triggerActivity(String eid, String rootpid,
			String aid, String pid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = triggerActivity,"
			 + "engine connection id = [" + eid + "],"
			 + "rootpid = [" + rootpid + "],"
			 + "aid = [" + aid + "],"
			 + "pid = [" + pid + "])";
	
		try {
			DataAccessManager.begin(false);
				
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
				
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(rootpid, aid, pid);
	
			DataAccessManager.commit();
	
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// アクティビティの通知に失敗しました。
			String E0123 = StringManager.get("E0123") + argInfo;
			eLog.error(E0123, ex);
			throw new WorkflowException(E0123, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * このエンジンから要求されて動作中のプロセスインスタンスID一覧の
	 * 取得を要求する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param filter 検索用フィルター
	 * @return プロセスインスタンスID一覧
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#listProcesses(java.lang.String, jp.co.argo21.nautica.workflow.wfmc.Filter)
	 */
	public String[] listProcesses(String eid, Filter filter)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = listProcesses,"
			 + "engine connection id = [" + eid + "],"
			 + "filter = [" + filter + "])";

		try {
			DataAccessManager.begin(false);
			
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
			
			//自前でやる必要がある。
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			@SuppressWarnings("unused")
			Process[] procs = pmf.getProcesses(filter);
			
			DataAccessManager.commit();

			return null;
		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセス一覧の取得に失敗しました。
			String E0199 = StringManager.get("E0199") + argInfo;
			eLog.error(E0199, ex);
			throw new WorkflowException(E0199, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * プロセスインスタンスの制御の放棄を通知する。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 * @see jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector#relinquishProcess(java.lang.String, java.lang.String)
	 */
	public void relinquishProcess(String eid, String pid)
	throws WorkflowException
	{
		String argInfo = "(WfMC API = relinquishProcess,"
			 + "engine connection id = [" + eid + "],"
			 + "pid = [" + pid + "])";

		try {
			DataAccessManager.begin(false);
				
			//エンジン接続用のセッションから、実際のエンジンIDを取得する。
			@SuppressWarnings("unused")
			String remoteEngineID = validateEngineID(eid);
			
			//リモート情報のチェック
			@SuppressWarnings("unused")
			SourceActivityBean sabean = checkRemoteInfo(pid);
	
			//起動元アクティビティ情報から該当プロセスの削除を行う。
			WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
			SourceActivityDAO saDAO = daoFactory.getSourceActivityDAO();
			saDAO.delete(pid);
			
			DataAccessManager.commit();
	
 		} catch (WorkflowException ex) {
			rollbackAndLogging(ex, argInfo);
			throw ex;
		} catch (Exception ex) {
			try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
			// プロセスの制御の放棄に失敗しました。
			String E0209 = StringManager.get("E0209") + argInfo;
			eLog.error(E0209, ex);
			throw new WorkflowException(E0209, ex);
		} finally {
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}

	/**
	 * プロセスインスタンス属性の変更を通知する。
	 * このメソッドは、サブプロセス側で実行される。
	 *
	 * @param pid プロセスインスタンスID
	 * @param attrs 属性
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	void processAttributesChangedLocal(String pid, Attribute[] attrs)
	throws WorkflowException
	{
		try {
			//リモートのエンジンから呼ばれたプロセスかどうかをチェックする。
			//このエンジンのプロセスなので、キーはプロセスIDだけで特定可能。
			TargetProcessBean tpbean = checkTargetInfo(pid);
			
			//管理している起動元が存在する場合
			if (tpbean != null) {
				String engineName = tpbean.getEngineID();
				InterWorkflowConnector iwc = InterWorkflowConnectorImpl.getRemoteInstance(engineName);
				String eid = InterWorkflowConnectorImpl.connectToRemoteEngine(iwc);
				
				// 監査ログ出力
				AuditDataRecord data = new AuditDataRecord(
				        new AuditPrefix(pid, "WMSentChangedProcessInstanceAttribute"),
				        new AuditSuffix(1, "4MIME"));
				data.setDataElement("TargetProcessInstanceID", pid);
				data.setDataElement("TargetNodeID", SystemChecker.getProperty(WorkflowEngineConstants.NAUTICA_SCOPE));
				data.setDataElement(attrs);
				data.setDataElement("TargetConversationID", eid);
				audit.info(data);
				
				//変数が変更されたことを親プロセスに通知する。
				iwc.processAttributesChanged(eid, pid, attrs);

				iwc.disconnect(eid);
				
				// 監査ログ出力
				data = new AuditDataRecord(
				        new AuditPrefix(pid, "WMAssignedProcessInstanceAttribute"),
				        new AuditSuffix(1, "4MIME"));
				data.setDataElement(attrs);
				data.setDataElement("TargetConversationID", "eid");
				audit.info(data);
			}				
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセス変数の変更通知に失敗しました。
			String E0210 = StringManager.get("E0210");
			throw new WorkflowException(E0210, ex);
		}
	}

	/**
	 * プロセスインスタンス状態の変更を通知する。
	 * このメソッドは、サブプロセス側で実行される。
	 *
	 * @param pid プロセスインスタンスID
	 * @param state プロセスインスタンス状態
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	void processStateChangedLocal(String pid, ProcessState state)
	throws WorkflowException
	{  
		try {
			//リモートのエンジンから呼ばれたプロセスかどうかをチェックする。
			//このエンジンのプロセスなので、キーはプロセスIDだけで特定可能。
			SourceActivityBean sabean = checkSourceInfo(pid);
			
			//管理している起動元が存在する場合
			if (sabean != null) {
				String engineName = sabean.getEngineID();
				InterWorkflowConnector iwc = InterWorkflowConnectorImpl.getRemoteInstance(engineName);
				String eid = InterWorkflowConnectorImpl.connectToRemoteEngine(iwc);
				
				// 監査ログ出力
				AuditDataRecord data = new AuditDataRecord(
				        new AuditPrefix("WMSentChangedProcessInstanceState"),
				        new AuditSuffix(1, "4MIME"));
				data.setDataElement("TargetProcessInstanceID", pid);
				data.setDataElement("NewProcessState", state);
				data.setDataElement("TargetConversationID", eid);
				audit.info(data);
				
				//変数が変更されたことを親プロセスに通知する。
				iwc.processStateChanged(eid, pid, state);

				iwc.disconnect(eid);
				
				// 監査ログ出力
				data = new AuditDataRecord(
				        new AuditPrefix("WMChangedProcessInstanceState"),
				        new AuditSuffix(1, "4MIME"));
				data.setDataElement("NewProcessState", state);
				data.setDataElement("TargetConversationID", eid);	
				audit.info(data);					
			}			
		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセス状態の変更通知に失敗しました。
			String E0211 = StringManager.get("E0211");
			throw new WorkflowException(E0211, ex);
		}
	}

	/**
	 * プロセスインスタンスの制御の放棄を通知する。
	 * このメソッドは親側で呼ばれる。
	 *
	 * @param engineName リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @throws WorkflowException　ワークフロー関連で例外が発生した場合
	 */
	void relinquishProcessLocal(String engineName, String pid)
	throws WorkflowException
	{
		try {
			InterWorkflowConnector iwc = InterWorkflowConnectorImpl.getRemoteInstance(engineName);
			String eid = InterWorkflowConnectorImpl.connectToRemoteEngine(iwc);

			//リモートのサブプロセスに、関係の切り離しを通知する。
			iwc.relinquishProcess(eid, pid);

			iwc.disconnect(eid);

			//管理レコードを削除する。
			WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
			TargetProcessDAO tpDAO = daoFactory.getTargetProcessDAO();
			tpDAO.delete(engineName, pid);
 		} catch (WorkflowException ex) {
			throw ex;
		} catch (Exception ex) {
			// プロセスの制御の放棄に失敗しました。
			String E0209 = StringManager.get("E0209");
			throw new WorkflowException(E0209, ex);
		}
	}
	
	/**
	 * ロールバック処理とエラーログの出力を行う。
	 *
	 * @param ex 例外
	 * @param argInfo 引数情報
	 */
	private void rollbackAndLogging(Exception ex, String argInfo)
	{
		try { DataAccessManager.rollback(); } catch (Exception ex2) { /* Ignore */ }
		String msg = ex.getMessage() + argInfo;
		eLog.error(msg, ex);
	}

	/**
	 * 親プロセスIDを検証する。
	 *
	 * @param rootpid 親プロセスID
	 * @throws InvalidProcessInstanceException 無効なプロセスIDの場合
	 */
	private void checkRootProcessID(String rootpid)
	throws InvalidProcessInstanceException
	{
		if (rootpid == null || rootpid.trim().equals("")) {
			// 接続元エンジンのプロセスIDが未設定です。
			String E0215 = StringManager.get("E0215");
			throw new InvalidProcessInstanceException(E0215);
		}
	}

	/**
	 * アクティビティIDを検証する。
	 *
	 * @param aid アクティビティID
	 * @throws InvalidActivityInstanceException 無効なアクティビティIDの場合
	 */
	private void checkActivityID(String aid)
	throws InvalidActivityInstanceException
	{
		if (aid == null || aid.trim().equals("")) {
			// 接続元エンジンのアクティビティIDが未設定です。
			String E0216 = StringManager.get("E0216");
			throw new InvalidActivityInstanceException(E0216);
		}
	}
	
	/**
	 * エンジン接続IDを検証する。
	 *
	 * @param eid エンジン接続ID
	 * @return エンジンID
	 * @throws InvalidSessionException 指定されたセッションが無効の場合
	 * @throws WorkflowException 任意のワークフロー例外
	 */
	private String validateEngineID(String eid)
	throws InvalidSessionException, WorkflowException
	{
		if (eid == null || eid.trim().equals("")) {
			// エンジン接続IDが未設定です。
			String E0217 = StringManager.get("E0217");
			throw new InvalidSessionException(E0217);
		}

		SessionManagerFactory factory = SessionManagerFactory.getInstance();
		SessionManager manager = factory.getSessionManager();
		manager.validateSession(eid);

		//エンジン接続IDに対応したユーザ情報を取得する。
		String uid = null;
		try {
			User user = manager.getSessionUser(eid);
			uid = user.getID();
		} catch (Exception ex) {
			// 無効なユーザIDです。
			String E0225 = StringManager.get("E0225");
			throw new WorkflowException(E0225, ex);
		}

		//登録されているエンジンかどうかをチェックする。
		InterWorkflowConfig.EngineInfo info = config.getEngineInfo(uid);
		if (info == null) {
			// エンジンIDに対応するエンジン情報がありません。
			String E0221 = StringManager.get("E0221");
			throw new WorkflowException(E0221);
		}
		String remoteEngineID = info.getID();
		
		return remoteEngineID;
	}
	
	/**
	 * プロセスがリモートから作成されたものなら、起動元のアクティビティ情報を返す。
	 *
	 * @param pid プロセスID
	 * @return 起動元のアクティビティ情報
	 * @throws Exception 任意の例外
	 */
	private SourceActivityBean checkSourceInfo(String pid) throws Exception
	{
		WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
		SourceActivityDAO saDAO = daoFactory.getSourceActivityDAO();
		SourceActivityBean sabean = saDAO.findByPrimaryKey(pid);
		return sabean;
	}

	/**
	 * 起動先プロセス情報をチェックする。
	 *
	 * @param eid リモートエンジン接続ID
	 * @param pid プロセスインスタンスID
	 * @return 起動先プロセス情報
	 * @throws WorkflowException 任意のワークフロー例外
	 * @throws Exception 任意の例外
	 */
	private TargetProcessBean checkTargetInfo(String eid, String pid)
	throws WorkflowException, Exception
	{
		if (eid == null || eid.trim().equals("")) {
			// エンジンIDが未設定です。
			String E0162 = StringManager.get("E0162");
			throw new WorkflowException(E0162);
		}

		if (pid == null || pid.trim().equals("")) {
			// プロセスIDが未設定です。
			String E0189 = StringManager.get("E0189");
			throw new WorkflowException(E0189);
		}
		
		WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
		TargetProcessDAO tpDAO = daoFactory.getTargetProcessDAO();
		TargetProcessBean tpbean = tpDAO.findByPrimaryKey(eid, pid);

		//管理されているワークフロー接続がない
		if (tpbean == null) {
			// そのようなプロセスは存在しません。
			String E0226 = StringManager.get("E0226");
			throw new WorkflowException(E0226);
		}

		String teid = tpbean.getEngineID();

		if (teid == null || teid.equals(eid) == false) {
			// エンジンIDが一致しません。
			String E0223 = StringManager.get("E0223");
			throw new WorkflowException(E0223);
		}

		return tpbean;
	}

	/**
	 * 起動先プロセス情報をチェックする。
	 *
	 * @param pid プロセスインスタンスID
	 * @return 起動先プロセス情報
	 * @throws WorkflowException 任意のワークフロー例外
	 * @throws Exception 任意の例外
	 */
	private TargetProcessBean checkTargetInfo(String pid)
	throws WorkflowException, Exception
	{
		if (pid == null || pid.trim().equals("")) {
			// プロセスIDが未設定です。
			String E0189 = StringManager.get("E0189");
			throw new WorkflowException(E0189);
		}
		
		//リモートのエンジンから呼ばれたかどうかをチェックする。
		WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
		TargetProcessDAO tpDAO = daoFactory.getTargetProcessDAO();
		TargetProcessBean tpbean = tpDAO.findByProcessID(pid);

		return tpbean;
	}

	/**
	 * 起動元アクティビティ情報をチェックする。
	 *
	 * @param pid プロセスインスタンスID
	 * @return 起動元アクティビティ情報
	 * @throws WorkflowException 任意のワークフロー例外
	 * @throws Exception 任意の例外
	 */
	private SourceActivityBean checkRemoteInfo(String pid)
	throws WorkflowException, Exception
	{
		if (pid == null || pid.trim().equals("")) {
			// プロセスIDが未設定です。
			String E0189 = StringManager.get("E0189");
			throw new WorkflowException(E0189);
		}

		WorkflowDAOFactory daoFactory = DataAccessManager.getDAOFactory();
		SourceActivityDAO saDAO = daoFactory.getSourceActivityDAO();
		SourceActivityBean sabean = saDAO.findByPrimaryKey(pid);

		//管理されているワークフロー接続がない
		if (sabean == null) {
			// そのようなプロセスは存在しません。
			String E0226 = StringManager.get("E0226");
			throw new WorkflowException(E0226);
		}
		return sabean;
	}

	/**
	 * 起動元アクティビティ情報をチェックする。
	 *
	 * @param rootpid 要求元のプロセスインスタンスID
	 * @param rootaid 要求アクティビティインスタンスID
	 * @param pid プロセスインスタンスID
	 * @return 起動元アクティビティ情報
	 * @throws WorkflowException 任意のワークフロー例外
	 * @throws Exception 任意の例外
	 */
	private SourceActivityBean checkRemoteInfo(String rootpid, String rootaid, String pid)
	throws WorkflowException, Exception
	{
		SourceActivityBean sabean = checkRemoteInfo(pid);

		String rpid = sabean.getRootProcID();
		String raid = sabean.getRootActID();

		if (rootpid == null || rpid.equals(rootpid) == false) {
			// 接続元エンジンのプロセスIDが未設定です。
			String E0215 = StringManager.get("E0215");
			throw new WorkflowException(E0215);
		}

		if (rootaid == null || raid.equals(rootaid) == false) {
			// 接続元エンジンのアクティビティIDが未設定です。
			String E0216 = StringManager.get("E0216");
			throw new WorkflowException(E0216);
		}
		
		return sabean;
	}
}
