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

import jp.co.cybec.cb3.util.logging.LogMessageConstant;
import jp.co.cybec.cb3.util.logging.LogMessageFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * トレースログを出力するクラス。<br>
 * SpringのAspect機能を使用してトレースログを出力します。
 * Aspect機能の設定はトランザクションコンテキスト（transactionContext.xml）に記述されています。
 * @author Naoko Sugimoto
 */
public class LoggingAspect {

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

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

	/**
	 * トレース対象の実行前後にメッセージを出力します。<br>
	 * 一般的なクラス用のトレース処理です。
	 * @param pjp トレース対象のジョイントカットポイント
	 * @return トレース対象の戻り値
	 * @throws Throwable トレース対象から投げられた例外
	 */
	public Object around(ProceedingJoinPoint pjp) throws Throwable {

		// 実行クラス名を取得。
		String className = pjp.getTarget().getClass().getName();
		// メソッド名を取得。
		String methodName = pjp.getSignature().getName();
		// 開始ミリ秒を保存
		long beforeTime = System.currentTimeMillis();

		// 開始メッセージを出力。
		LOG.info(MESSAGE.getMessage(LogMessageConstant.CB3_ASPECT_001, className, methodName));
		// デバッグログに引数の中身を表示する。
		if (LOG.isDebugEnabled()) {
			// メソッド引数を取得。
			Object[] args = pjp.getArgs();
			LOG.debug(MESSAGE.getMessage(LogMessageConstant.CB3_ASPECT_005, formatArguments(args)));
		}

		// メソッドを実行。
		Object returnCode = pjp.proceed();

		// 終了ミリ秒を取得。
		long afterTime = System.currentTimeMillis();
		// 実行時間の取得
		long execTime = afterTime - beforeTime;

		// 終了メッセージを出力。
		LOG.info(MESSAGE.getMessage(LogMessageConstant.CB3_ASPECT_002, className, methodName, returnCode, execTime));

		return returnCode;
	}

	/**
	 * メソッドの引数をメッセージに表示できる形に変換します。
	 * @param args メソッドの引数
	 * @return メソッドの引数を文字列化したもの
	 */
	private String formatArguments(Object[] args) {
		if (args == null || args.length == 0) {
			return "";
		}

		// メソッドの引数をメッセージに表示できる形に変換する。
		StringBuilder argsMessage = new StringBuilder();
		for (Object arg: args) {
			argsMessage.append(arg.toString());	// パラメータを表示
			argsMessage.append(", ");
		}
		// 末尾の「,」を削除。
		if (argsMessage.length() > 0 && argsMessage.lastIndexOf(", ") == argsMessage.length() - 2) {
			argsMessage.delete(argsMessage.length() - 2, argsMessage.length());
		}
		return argsMessage.toString();
	}
}
