/* $Id: WorkflowMQ.java,v 1.5 2007/11/16 07:21:07 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.jms;

import java.io.Serializable;
import java.util.HashMap;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;

import org.apache.log4j.Logger;

import jp.co.argo21.nautica.workflow.engine.LogManager;
import jp.co.argo21.nautica.workflow.util.StringManager;

/**
 * ワークフロー用のメッセージキューを表す。
 *
 * @author  nito(Argo 21, Corp.)
 * @version $Revision: 1.5 $
 * @since   Nautica Workflow 1.0
 */
public class WorkflowMQ
{
	/** エンジンログ */
	private static Logger eLog = LogManager.getEngineLogger();
	
	/** トランザクショナルにメッセージを処理するかどうかのフラグ*/
	private static final boolean RECEIVE_TRANSACTION = false;
	
	/** 確認応答モード */
	private static final int RECEIVE_ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE;

	/** トランザクショナルにメッセージを処理するかどうかのフラグ*/
	private static final boolean SEND_TRANSACTION = false;
	
	/** 確認応答モード */
	private static final int SEND_ACKNOWLEDGE_MODE = Session.AUTO_ACKNOWLEDGE;

	/** キューコネクションファクトリ */
	private QueueConnectionFactory factory;

	/** 受信用キューコネクション */
	private QueueConnection receiveConnection;

	/** 受信用キューセッション */
	private QueueSession receiveSession;

	/** レシーバ */
	private QueueReceiver receiver;
	
	/** メッセージキュー */
	private Queue queue;

	/**
	 * 指定された名前でキューを作成し、指定されたアダプタを登録する。
	 *
	 * @param name キューの名前
	 * @param adapter 受信メッセージを処理するアダプタ
	 * @throws MessagingException 処理中に例外が発生した場合
	 */
	public WorkflowMQ(QueueConnectionFactory factory, String name, WorkflowMessageAdapter adapter)
	throws MessagingException
	{
		try {
			this.factory = factory;
			receiveConnection = factory.createQueueConnection();
			receiveConnection.setClientID(toString());
			receiveSession = receiveConnection.createQueueSession(RECEIVE_TRANSACTION, RECEIVE_ACKNOWLEDGE_MODE);
			queue = receiveSession.createQueue(name);
			receiver = receiveSession.createReceiver(queue);
			receiver.setMessageListener(adapter);
		} catch (JMSException ex) {
			if (receiver != null) {
				try { receiver.close(); } catch (JMSException ex2) { /* ignore */ }
			}
			if (receiveSession != null) {
				try { receiveSession.close(); } catch (JMSException ex2) { /* ignore */ }
			}
			if (receiveConnection != null) {
				try { receiveConnection.close(); } catch (JMSException ex2) { /* ignore */ }
			}
			// メッセージ処理用のアダプタの登録に失敗しました。
			String errMsg = StringManager.get("E0048");
			eLog.error(errMsg, ex);
			throw new MessagingException(errMsg, ex);
		}
	}
	
	/**
	 * 該当キューのキュー名を返す。
	 *
	 * @return キュー名
	 * @throws MessagingException 処理中に例外が発生した場合
	 */
	public String getQueueName() throws MessagingException
	{
		try {
			return queue.getQueueName();
		} catch (JMSException ex) {
			// メッセージキューの名前の取得に失敗しました、
			String errMsg = StringManager.get("E0041");
			eLog.error(errMsg, ex);
			throw new MessagingException(errMsg, ex);
		}
	}
	
	/**
	 * 該当キューを開始する。既に開始している場合は、単に無視される。
	 *
	 * @throws MessagingException 処理中に例外が発生した場合
	 */
	public void start() throws MessagingException
	{
		try {
			receiveConnection.start();
		} catch (JMSException ex) {
			// メッセージキューを開始できません。
			String errMsg = StringManager.get("E0046");
			eLog.error(errMsg, ex);
			throw new MessagingException(errMsg, ex);
		}
	}
	
	/**
	 * 該当キューを一時的に停止する。
	 * 再開する場合は、start()を呼ぶようにする。
	 *
	 * @throws MessagingException 処理中に例外が発生した場合
	 */
	public void stop() throws MessagingException
	{
		try {
			receiveConnection.stop();
		} catch (JMSException ex) {
			// メッセージキューを停止できません。
			String errMsg = StringManager.get("E0047");
			eLog.error(errMsg, ex);
			throw new MessagingException(errMsg, ex);
		}
	}
	
	/**
	 * 該当キューをシャットダウンする。
	 */
	public void shutdown()
	{
		if (receiver != null) {
			try {
				receiver.close();
			} catch (JMSException ex) {
				// 受信機構のクローズに失敗しました。
				String errMsg = StringManager.get("E0043");
				eLog.error(errMsg, ex);
			}
		}
		if (receiveSession != null) {
			try {
				receiveSession.close();
			} catch (JMSException ex) {
				// 受信セッションのクローズに失敗しました。
				String errMsg = StringManager.get("E0044");
				eLog.error(errMsg, ex);
			}
		}
		if (receiveConnection != null) {
			try {
				receiveConnection.close();
			} catch (JMSException ex) {
				// 受信接続のクローズに失敗しました。
				String errMsg = StringManager.get("E0045");
				eLog.error(errMsg, ex);
			}
		}
	}

	/**
	 * 指定されたワークフローメッセージをキューに対して送信する。
	 *
	 * @param message ワークフローメッセージ
	 * @throws MessagingException 処理中に例外が発生した場合
	 */
	public void send(WorkflowMessage message)
	throws MessagingException
	{
    	QueueConnection con = null;
    	QueueSession session = null;
    	QueueSender sender = null;
		try {
			con = factory.createQueueConnection();
			session = con.createQueueSession(SEND_TRANSACTION, SEND_ACKNOWLEDGE_MODE);
			sender = session.createSender(queue);
			sender.setDeliveryMode(DeliveryMode.PERSISTENT);			
			HashMap<String, Serializable> map = message.getMessageMap();
			ObjectMessage om = session.createObjectMessage(map);
			sender.send(om);
		} catch (JMSException ex) {
			// 送信処理中にエラーが起こりました。
			String errMsg = StringManager.get("E0042");
			eLog.error(errMsg, ex);
			throw new MessagingException(errMsg, ex);
		} finally {
			if (sender != null) {
				try { sender.close(); } catch (JMSException ex) { /* ignore */ }
			}
			if (session != null) {
				try { session.close(); } catch (JMSException ex) { /* ignore */ }
			}
			if (con != null) {
				try { con.close(); } catch (JMSException ex) { /* ignore */ }
			}
		}
	}
}
