/* $Id: StartProcessRequestWatcher.java,v 1.5 2007/11/28 07:09:06 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.io.Serializable;
import java.util.HashMap;

import org.apache.log4j.Logger;

import jp.co.argo21.nautica.workflow.jms.WorkflowMessage;
import jp.co.argo21.nautica.workflow.jms.WorkflowMessageAdapter;
import jp.co.argo21.nautica.workflow.util.StringManager;
import jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector;
import jp.co.argo21.nautica.workflow.wfmc.ProcessState;

/**
 * プロセス開始要求キューを監視する。
 *
 * @author  nito(Argo 21, Corp.)
 * @version $Revision: 1.5 $
 * @since   Nautica Workflow 1.0
 */
class StartProcessRequestWatcher extends WorkflowMessageAdapter
{
	/** エンジンログ */
	private static Logger eLog = LogManager.getEngineLogger();
	/** メッセージキュー名 */
	public static final String NAME = "START_PROCESS_REQUEST";
	
	/**
	 * プロセス開始要求キュー監視を生成する。
	 */
	StartProcessRequestWatcher()
	{
	}

	@Override
	protected WorkflowMessage getMessage(HashMap<String, Serializable> map)
	{
		return new StartProcessRequestMessage(map);
	}

	/**
	 * プロセス開始要求を処理する。
	 *
	 * @param mid メッセージID
	 * @param message メッセージ
	 * @param isRedelivered 再配信フラグ
	 * @see jp.co.argo21.nautica.workflow.jms.WorkflowMessageAdapter#onMessage(java.lang.String, jp.co.argo21.nautica.workflow.jms.WorkflowMessage, boolean)
	 */
	public void onMessage(String mid, WorkflowMessage message, boolean isRedelivered)
	{
		if (message instanceof StartProcessRequestMessage == false) {
			//ログに出力して無視
			// 不正なメッセージ形式です。
			String E0099 = StringManager.get("E0099");
			eLog.error(E0099);
			return;
		}
		StartProcessRequestMessage msg = (StartProcessRequestMessage)message;
		String eid = msg.getEngineID();
		String pid = msg.getProcessID();

		try {
			DataAccessManager.begin(false);
			
			if (eid == null || eid.trim().equals("")) {
				ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
				ProcessManager pm = pmf.getOwnerProcessManager(pid);
				ProcessInternal process = (ProcessInternal)pm.getProcess(pid);
				process.start();
			} else {
				//リモートのエンジンにプロセス開始要求を行う。
				InterWorkflowConnector iwc = InterWorkflowConnectorImpl.getRemoteInstance(eid);
				String session = InterWorkflowConnectorImpl.connectToRemoteEngine(iwc);

				synchronized (this) {
					//プロセス開始要求
					iwc.changeProcessState(session, pid, ProcessState.OPEN_RUNNING);
				}
				
				iwc.disconnect(session);
				
			}
		} catch (Exception ex) {
			try {
				String E0100 = StringManager.get("E0100");
				eLog.error(E0100, ex);

				//たぶん無理だが、プロセス異常終了を試みる。
				abortProcess(eid, pid);
			} catch (Exception ex2) {
				String F0101 = StringManager.get("F0101");
				eLog.fatal(F0101, ex);
			}
		} finally {
			try { DataAccessManager.commit(); } catch (Exception ex) { /* Ignore */ }
			try { DataAccessManager.close(); } catch (Exception ex) { /* Ignore */ }
		}
	}
	
	/**
	 * ローカルまたはリモートのプロセス異常終了処理を行う。
	 *
	 * @param eid エンジンID
	 * @param pid プロセスID
	 * @throws Exception 処理中の任意の例外
	 */
	private void abortProcess(String eid, String pid)
	throws Exception
	{
		if (eid == null || eid.trim().equals("")) {
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(pid);
			ProcessInternal proc = (ProcessInternal)pm.getProcess(pid);
			
			proc.abort(true);

			//リモートにプロセス完了を通知する必要があれば通知する。
			InterWorkflowConnectorImpl iwc = (InterWorkflowConnectorImpl)InterWorkflowConnectorImpl.getInstance();
			iwc.processStateChangedLocal(pid, ProcessState.CLOSED_ABORTED);
		} else {
			//リモートのエンジンにプロセス完了要求を行う。
			InterWorkflowConnector iwc = InterWorkflowConnectorImpl.getRemoteInstance(eid);
			String session = InterWorkflowConnectorImpl.connectToRemoteEngine(iwc);

			try {
				//プロセス完了要求
				iwc.changeProcessState(session, pid, ProcessState.CLOSED_ABORTED);
			} finally {
				iwc.disconnect(session);
			}
		}
	}
}
