/* $Id: EndProcessRequestWatcher.java,v 1.4 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.ActivityState;
import jp.co.argo21.nautica.workflow.wfmc.InterWorkflowConnector;
import jp.co.argo21.nautica.workflow.wfmc.ProcessState;

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

	@Override
	protected WorkflowMessage getMessage(HashMap<String, Serializable> map)
	{
		return new EndProcessRequestMessage(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 EndProcessRequestMessage == false) {
			//ログに出力して無視
			// 不正なメッセージ形式です。
			String E0099 = StringManager.get("E0099");
			eLog.error(E0099);
			return;
		}
		EndProcessRequestMessage msg = (EndProcessRequestMessage)message;
		String eid = msg.getEngineID();
		String spid = msg.getProcessID();
		ActivityState astate = msg.getActivityState();

		try {
			DataAccessManager.begin(false);
			endProcess(eid, spid, astate);
		} catch (Exception ex) {
			try {
				String E0101 = StringManager.get("E0101");
				eLog.error(E0101, ex);

				//たぶん無理だが、プロセス異常終了を試みる。
				endProcess(eid, spid, ActivityState.CLOSED_ABORTED);
			} 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 spid プロセスID
	 * @param astate アクティビティ終了状態
	 * @throws Exception 処理中の任意の例外
	 */
	private void endProcess(String eid, String spid, ActivityState astate)
	throws Exception
	{
		if (eid == null || eid.trim().equals("")) {
			ProcessManagerFactory pmf = ProcessManagerFactory.getInstance();
			ProcessManager pm = pmf.getOwnerProcessManager(spid);
			ProcessInternal proc = (ProcessInternal)pm.getProcess(spid);
			
			ProcessState pstate = null;
			if (astate == null || ActivityState.CLOSED_COMPLETED.equals(astate)) {
				proc.complete();
				pstate = ProcessState.CLOSED_COMPLETED;
			} else if (ActivityState.CLOSED_TERMINATED.equals(astate)) {
				proc.terminate(false);
				pstate = ProcessState.CLOSED_TERMINATED;
			} else if (ActivityState.CLOSED_ABORTED.equals(astate)) {
				proc.abort(true);
				pstate = ProcessState.CLOSED_ABORTED;
			}

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

			try {
				ProcessState pstate = null;
				if (astate == null || ActivityState.CLOSED_COMPLETED.equals(astate)) {
					pstate = ProcessState.CLOSED_COMPLETED;
				} else if (ActivityState.CLOSED_TERMINATED.equals(astate)) {
					pstate = ProcessState.CLOSED_TERMINATED;
				} else if (ActivityState.CLOSED_ABORTED.equals(astate)) {
					pstate = ProcessState.CLOSED_ABORTED;
				}

				//プロセス完了要求
				iwc.changeProcessState(session, spid, pstate);
			} finally {
				iwc.disconnect(session);
			}
		}
	}
}
