/*
 * ServiceProviderImpl.java
 * Copyright (C) 2008 Cyber Beans Corporation. All rights reserved.
 */
package jp.co.cybec.cb3.container.provider;

import java.text.SimpleDateFormat;
import java.util.Date;

import jp.co.cybec.cb3.container.service.Service;
import jp.co.cybec.cb3.exception.RuntimeArgumentsAnalyzeException;
import jp.co.cybec.cb3.session.RuntimeArgumentsAnalyzer;
import jp.co.cybec.cb3.session.RuntimeParameters;
import jp.co.cybec.cb3.session.ServiceParameters;
import jp.co.cybec.cb3.util.ApplicationExiterDelegater;
import jp.co.cybec.cb3.util.ExitCodeConstant;
import jp.co.cybec.cb3.util.logging.ErrorCodeConstant;
import jp.co.cybec.cb3.util.logging.LogMessageConstant;
import jp.co.cybec.cb3.util.logging.LogMessageFactory;
import jp.co.cybec.cb3.util.logging.LogMessageIdentifier;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * サービスプロバイダの実装クラス。
 * @author Naoko Sugimoto
 */
public class ServiceProviderImpl implements ServiceProvider {

	/** ログ */
	private static final Log LOG = LogFactory.getLog(ServiceProviderImpl.class);

	/** 起動パラメータに指定するサービス名のキー */
	private static final String SERVICE_KEY = "-ServiceName";

	/** サービス */
	private Service service = null;

	/** メッセージ */
	private static final LogMessageFactory MESSAGE = new LogMessageFactory(
			LogMessageConstant.CB3_MESSAGE_FILENAME);

	/**
	 * サービスを単体で実行する場合に使用する、起動メソッドです。<br>
	 * main起動時の引数に、serviceContext.xmlで定義したサービスプロバイダのbean idを
	 * 指定する必要があります。<br>
	 * 指定方法： -ServiceName [bean id]<br>
	 * <pre>
	 * 例：コンソール>java (略) xxx.ServiceProviderImpl -ServiceName sample
	 * </pre>
	 * また、サービスに任意のパラメータを渡すことができます。<br>
	 * 指定方法： -AppParams key1=value1 key2=value2 key3=value3 ...<br>
	 * <pre>
	 * 例：コンソール>java (略) xxx.ServiceProviderImpl -ServiceName sample -AppParams key1=value1 key2=value2 ...
	 * </pre>
	 * 「-AppParams」以降に指定されたパラメータ(key1=value1 key2=value2 ...)は{@link RuntimeParameters}に格納され、
	 * サービスに引き渡されます。<br>
	 * ※「-AppParams」は、「-ServiceName」より後に記述する必要があります。
	 * @param args 起動パラメータ
	 */
	public static void main(String[] args) {

		try {
			// 引数を解析し、パラメータを取得する。
			RuntimeArgumentsAnalyzer analyzer = analyzeArguments(args);

			// サービスのbeanIdを取得する。
			String beanId = analyzer.getReservedParameter(SERVICE_KEY);

			// ログメッセージ識別子を設定する。
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
			LogMessageIdentifier.setJobProcessId(beanId + sdf.format(new Date()));
			LogMessageIdentifier.setServiceId(beanId);

			// サービス定義ファイルを読み込み、DIを使用してサービスプロバイダを生成する。
			ServiceProvider provider = (ServiceProvider)ServiceProviderFactory.getInstance().getServiceProvider(beanId);

			// サービスを実行する。
			int resultCode = provider.callService(new ServiceParameters(), analyzer.getRuntimeParameters());

			ApplicationExiterDelegater.getInstance().exit(resultCode);
		} catch (Throwable t) {
			// 引数エラーの場合、引数のヘルプを表示する。
			if (t instanceof RuntimeArgumentsAnalyzeException) {
				String helpMessage = "ServiceProviderImpl [-ServiceName サービスプロバイダのbeanid] [-AppParam キー=値 キー=値 ...]";
				LOG.error(MESSAGE.getErrorMessage(ErrorCodeConstant.CONTAINER_PROVIDER_002,
						LogMessageConstant.CB3_CONTAINER_PROVIDER_003, helpMessage));
			}

			// エラーレベルでログを出力。
			LOG.error(t.getMessage(), t);
			// 異常終了。
			ApplicationExiterDelegater.getInstance().exit(ExitCodeConstant.ERROR);
		}
	}

	/**
	 * main起動時の引数を解析し、パラメータを取得します。
	 * @param args main起動時の引数
	 * @return 解析結果を保持するアナライザ
	 */
	private static RuntimeArgumentsAnalyzer analyzeArguments(String[] args) {

		// 引数を解析し、パラメータを取得する。
		RuntimeArgumentsAnalyzer analyzer = new RuntimeArgumentsAnalyzer(args, SERVICE_KEY);

		// 引数に実行先サービスが指定されていることをチェックする。
		if (analyzer.getReservedParameter(SERVICE_KEY) == null) {
			throw new RuntimeArgumentsAnalyzeException(MESSAGE.getErrorMessage(
					ErrorCodeConstant.CONTAINER_PROVIDER_003,
					LogMessageConstant.CB3_CONTAINER_PROVIDER_001, SERVICE_KEY));
		}

		return analyzer;
	}

	/**
	 * サービスをセットします。
	 * @param service サービス。
	 */
	public void setService(Service service) {
		this.service = service;
	}

	/**
	 * サービスを実行します。
	 * @param serviceParameters サービスパラメータ。
	 * @param runtimeParameters 起動パラメータ。
	 * @return 実行結果。
	 */
	public int callService(
			ServiceParameters serviceParameters, RuntimeParameters runtimeParameters) {

		// 業務処理を実行する。
		return service.callService(serviceParameters, runtimeParameters);
	}

}
