/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.fukurou.process;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import org.opengion.fukurou.business.BizUtil;
import org.opengion.fukurou.queue.QueueInfo;
import org.opengion.fukurou.queue.QueueReceive;
import org.opengion.fukurou.queue.QueueReceiveFactory;
import org.opengion.fukurou.util.Argument;
import org.opengion.fukurou.util.LogWriter;

/**
 *Process_QueueReceiveは、MQ or SQSにメッセージキューを受信する、
 *FirstProcessインタフェースの実装クラスです。
 *
 *受信したメッセージを指定したbizlogicファイルで処理を行います。
 *bizlogicファイルでデータベース処理を行うため、
 *Process_DBParamを前処理として実行します。
 *
 *@og.formSample
 * 1)MQからメッセージを受信する場合
 *   java -DmqUserId=[mqﾕｰｻﾞid] -DmqPassword=[mqﾊﾟｽﾜｰﾄﾞ] -cp [ｸﾗｽﾊﾟｽ] org.opengion.fukurou.process.MainProcess org.opengion.fukurou.process.Process_Logger -logFile=System.out org.opengion.fukurou.process.Process_DBParam -infoUSER=[ﾕｰｻﾞｰID] -infoPGID=process -configFile=[DBConfigﾊﾟｽ] org.opengion.fukurou.process.Process_QueueReceive -accessKey=[ｱｸｾｽｷｰ] -secretKey=[ｼｰｸﾚｯﾄｷｰ] -webinfDir=[WEB-INFﾊﾟｽ] -bizsrcDir=[bizﾃﾞｨﾚｸﾄﾘﾊﾟｽ] -queueType=MQ -jmsServer=[mqｻｰﾊﾞのurl] -groupId=[ｸﾞﾙｰﾌﾟID] -systemId=[ｼｽﾃﾑID] -logicName=[bizlogicﾌｧｲﾙ名]
 * 2)SQSからメッセージを受信する場合
 *   java -cp [ｸﾗｽﾊﾟｽ] org.opengion.fukurou.process.MainProcess org.opengion.fukurou.process.Process_Logger -logFile=System.out org.opengion.fukurou.process.Process_DBParam -infoUSER=[ﾕｰｻﾞｰID] -infoPGID=process -configFile=[DBConfigﾊﾟｽ] org.opengion.fukurou.process.Process_QueueReceive -accessKey=[ｱｸｾｽｷｰ] -secretKey=[ｼｰｸﾚｯﾄｷｰ] -webinfDir=[WEB-INFﾊﾟｽ] -bizsrcDir=[bizﾃﾞｨﾚｸﾄﾘﾊﾟｽ] -queueType=SQS -jmsServer=[sqsｻｰﾊﾞのurl] -groupId=[ｸﾞﾙｰﾌﾟID] -systemId=[ｼｽﾃﾑID] -logicName=[bizlogicﾌｧｲﾙ名]
 *
 *※proxy環境から、外部のMQやSQSサーバにはﾌﾟﾛｷｼ情報を渡して、実行する必要があります。
 *-Dhttp.proxyHost=[proxyﾎｽﾄ] -Dhttp.proxyPort=[proxyﾎﾟｰﾄ] -Dhttps.proxyHost=[proxyﾎｽﾄ] -Dhttps.proxyPort=[proxyﾎﾟｰﾄ]
 *
 * -queueType=キュータイプ       :MQ or SQS
 * -jmsServer=キューサーバー     :キューサーバーのURLを指定
 * -groupId=グループID           :キュー格納先のグループID
 * -webinfDir=WEB-INFパス        :WEB-INFのディレクトリパス(bizlogic用)
 * -bizsrcDir=bizファイルパス    :bizファイルディレクトリパス(bizlogic用)
 * -systemId=システムID          :システムID(bizlogic用)
 * -logicName=ロジックファイル名 :bizLogicのファイル名(bizlogic用)
 * [-sccessKey=アクセスキー]     :SQSに接続用のアクセスキーです(aws上で取得)
 * [-secretKey=シークレットキー] :SQSに接続用のシークレットキーです(aws上で取得)
 * 
 * コマンド例
 * java -DmqUserId=admin -DmqPassword=admin -Dhttps.proxyHost=xxx-px^
 *  -Dhttps.proxyPort=8081 -cp H:\sample\* ^
 *  org.opengion.fukurou.process.MainProcess ^
 *  org.opengion.fukurou.process.Process_Logger -logFile=System.out org.opengion.fukurou.process.Process_DBParam ^
 *  -infoUSER=username -infoPGID=process -configFile=H:\sample\DBConfig.xml ^
 *  org.opengion.fukurou.process.Process_QueueReceive ^
 *  -webinfDir=H:\sample\gf\WEB-INF -bizsrcDir=H:\sample\gf\src\biz -queueType=MQ ^
 *  -jmsServer=tcp://localhost:61616 -groupId=sample002 -systemId=GF -logicName=gf.TEST03g.opengion.fukurou.process.Process_QueueReceive ^
 *  -webinfDir=H:\sample\gf\WEB-INF -bizsrcDir=H:\sample\gf\src\biz -queueType=MQ -jmsServer=tcp://localhost:61616 -groupId=sample002 ^
 *  -systemId=GF -logicName=gf.TEST03
 *
 * @og.rev 5.10.17.1 (2019/11/15) 新規追加
 *
 * @verion 5
 * @since JDK7
 */
public class Process_QueueReceive extends AbstractProcess implements FirstProcess{
	private static String name;
	private static Map<String, String> mustProperty;
	private static Map<String, String> usableProperty;

	QueueReceive queueReceive;

	private String queueType;
	private String jmsServer;
	private String groupId;
	private String systemId;
	private String logicName;
	private String receiveMessage;

	static {
		mustProperty = new HashMap<String, String>();
		mustProperty.put("queueType", "キュータイプ");
		mustProperty.put("jmsServer", "jms接続先");
		mustProperty.put("groupId", "グループID");
		mustProperty.put("webinfDir", "WEB-INFディレクトリ");
		mustProperty.put("bizsrcDir", "bizのソースファイルディレクトリ");
		mustProperty.put("systemId", "システムID");
		mustProperty.put("logicName", "ロジック名");

		usableProperty = new HashMap<String, String>();
		// SQS用
		usableProperty.put("accessKey", "アクセスキ");
		usableProperty.put("secretKey",  "シークレットキー");
	}

	/**
	 * コンストラクター
	 */
	public Process_QueueReceive() {
		super(name, mustProperty, usableProperty);
	}

	/**
	 * このクラスの使用方法を返します。
	 *
	 * @return	このクラスの使用方法
	 */
	@Override
	public String usage() {
		StringBuilder buf = new StringBuilder();

		buf.append("Process_QueueReceiveは、MQ or SQSにメッセージキューを受信する、").append(CR);
		buf.append("FirstProcessインタフェースの実装クラスです。").append(CR);
		buf.append(CR);
		buf.append("-queueType=キュータイプ       :MQ or SQS").append(CR);
		buf.append("-jmsServer=キューサーバー     :キューサーバーのURLを指定").append(CR);
		buf.append("-groupId=グループID           :キュー格納先のグループID").append(CR);
		buf.append("-webinfDir=WEB-INFパス        :WEB-INFのディレクトリパス(bizlogic用)").append(CR);
		buf.append("-bizsrcDir=bizファイルパス    :bizファイルディレクトリパス(bizlogic用)").append(CR);
		buf.append("-systemId=システムID          :システムID(bizlogic用)").append(CR);
		buf.append("-logicName=ロジックファイル名 :bizLogicのファイル名(bizlogic用)").append(CR);
		buf.append("[-sccessKey=アクセスキー]     :SQSに接続用のアクセスキーです(aws上で取得)").append(CR);
		buf.append("[-secretKey=シークレットキー] :SQSに接続用のシークレットキーです(aws上で取得)").append(CR);
		buf.append( CR ).append( CR );
		buf.append( getArgument().usage() ).append( CR );

		return null;
	}

	/**
	 * プロセスの初期化を行います。初めに一度だけ、呼び出されます。
	 * 初期処理(ファイルオープン、ＤＢオープン等)に使用します。
	 *
	 * @param   paramProcess データベースの接続先情報などを持っているオブジェクト
	 */
	@Override
	public void init(ParamProcess paramProcess) {
		Argument arg = getArgument();

		queueType = arg.getProparty("queueType");
		jmsServer = arg.getProparty("jmsServer");
		groupId = arg.getProparty("groupId");
		systemId = arg.getProparty("systemId");
		logicName = arg.getProparty("logicName");
		final String accessKey = arg.getProparty("accessKey");
		final String secretKey = arg.getProparty("secretKey");

		queueReceive = QueueReceiveFactory.newQueueReceive(queueType);

		queueReceive.setBatchFlg(true);

		queueReceive.connect(jmsServer, accessKey, secretKey);
	}

	/**
	 * プロセスの終了を行います。最後に一度だけ、呼び出されます。
	 * 終了処理(ファイルクローズ、ＤＢクローズ等)に使用します。
	 *
	 * @param   isOK トータルで、OKだったかどうか[true:成功/false:失敗]
	 */
	@Override
	public void end(boolean isOK) {
		queueType = "";
		jmsServer = "";
		groupId = "";
		systemId = "";
		logicName = "";
		receiveMessage = "";

		if(queueReceive != null) {
			queueReceive.close();
		}
	}

	/**
	 * このデータの処理において、次の処理が出来るかどうかを問い合わせます。
	 * この呼び出し１回毎に、次のデータを取得する準備を行います。
	 *
	 * @return 処理できる:true / 処理できない:false
	 **/
	@Override
	public boolean next() {

		QueueInfo queueInfo = queueReceive.receive(groupId);

		if(queueInfo != null) {
			receiveMessage = queueInfo.getMessage();

			try {
				// bizlogic処理
				callActBizLogic(systemId, logicName, receiveMessage);
			} catch (Throwable te) {
				String errMsg = "bizlogicの実行に失敗しました。" + te.getMessage();
				throw new RuntimeException(errMsg);
			}
		}else {
			String errMsg = "メッセージキューが登録されていません。";
			throw new RuntimeException(errMsg);
		}
		return false;
	}

	/**
	 * bizLogic処理の呼び出し
	 * 必要なパス情報をリソースから取得して、
	 * BizUtil.actBizLogicにパス情報を渡すことで、
	 * bizLogicの処理を行います。
	 *
	 * @param systemId  システムID
	 * @param logicName ロジックファイル名
	 * @param msgText   メッセージ
	 * @throws Throwable エラー情報
	 */
	private void callActBizLogic(String systemId, String logicName, String msgText) throws Throwable {
		Argument arg = getArgument();
		final String webinfDir = arg.getProparty("webinfDir");
		final String srcDir = arg.getProparty("bizsrcDir");

		// 対象 クラスパスの生成
		// HotDeploy機能を使用する場合に、Javaクラスをコンパイルするためのクラスパスを設定します。
		// 対象となるクラスパスは、WEB-INF/classes 及び WEB-INF/lib/*.jar です。
		// bizLogicTag.javaのコードを移植
		StringBuilder sb = new StringBuilder();
		sb.append('.').append(File.pathSeparatorChar);

		File lib = new File(webinfDir);
		File[] libFiles = lib.listFiles();
		for (int i = 0; i < libFiles.length; i++) {
			sb.append(libFiles[i].getAbsolutePath()).append(File.pathSeparatorChar);
		}
		final String classDir = webinfDir + File.pathSeparator + "classes";
		sb.append(classDir).append(File.pathSeparatorChar);
		String classPath = sb.toString();

		boolean isAutoCompile = true;
		boolean isHotDeploy = true;

		// bizLogicに渡すパラメータ
		String[] keys = new String[] { "message" };
		String[] vals = new String[] { msgText };

		// bizLogic処理の実行
		BizUtil.actBizLogic(srcDir, classDir, isAutoCompile, isHotDeploy, classPath, systemId, logicName, keys, vals);
	}

	/**
	 * 最初に、 行データである LineModel を作成します
	 * FirstProcess は、次々と処理をチェインしていく最初の行データを
	 * 作成して、後続の ChainProcess クラスに処理データを渡します。
	 *
	 * @param rowNo 処理中の行番号
	 *
	 * @return 処理変換後のLineModel
	 * */
	@Override
	public LineModel makeLineModel(int rowNo) {
		// 後続のChainProcessは実行しません。
		return null;
	}

	/**
	 * プロセスの処理結果のレポート表現を返します。
	 * 処理プログラム名、入力件数、出力件数などの情報です。
	 * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような
	 * 形式で出してください。
	 *
	 * @return   処理結果のレポート
	 */
	@Override
	public String report() {
		final String report = "[" + getClass().getName() + "]" + CR
				+ TAB + "queueType:" + queueType + CR
				+ TAB + "jmsServer:" + jmsServer + CR
				+ TAB + "gropuId:" + groupId + CR
				+ TAB + "systemId:" + systemId + CR
				+ TAB + "logicName" + logicName + CR
				+ TAB + "receiveMessage:" + receiveMessage + CR
				;
		return report;
	}

	/**
	 * このクラスは、main メソッドから実行できません。
	 *
	 * @param args コマンド引数配列
	 */
	public static void main(final String[] args) {
		LogWriter.log(new Process_QueueReceive().usage());
	}
}
