/*
 * Copyright (c) 2011 NTT DATA Corporation
 */

package jp.terasoluna.batch.functionsample.b005;

import java.util.List;


import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * DAOの実行直前・実行直後に ログを出力するためのインタセプタ。
 * 
 * <p>
 * ログ出力の実処理は、OperationLoggerが行う。
 * </p>
 * 
 * <p>
 * このインタセプタの適用先を変更する場合は、 bean要素"daoLoggingAutoProxy"を編集すること。
 * </p>
 * 
 */
public class DAOLoggingInterceptor extends LoggingInterceptor {
    /**
     * Log。
     */
    private static Log logger = LogFactory.getLog(DAOLoggingInterceptor.class);

    /**
     * 処理対象メソッドリスト.
     */
    private List<String> methodNames = null;

    /**
     * 処理対象メソッドリスト.<br>
     * 未設定の場合は全メソッドが対象。
     * 
     * @param methodNames
     *            the methodNames to set
     */
    public void setMethodNames(List<String> methodNames) {
        this.methodNames = methodNames;
    }

    /**
     * ログクラスを取得し、ログ出力の判定を行う。
     * 
     * @param invocation
     *            本来呼び出されるメソッド
     * @return 本来呼び出されるメソッドの結果
     * @throws Throwable
     *             例外
     */
    public Object invoke(MethodInvocation invocation) throws Throwable {
        OperationLogger operationLogger = getOperationLogger();

        // methodNamesが設定されている場合は、処理対象かどうか検査。
        if (this.methodNames != null && this.methodNames.size() > 0) {
            String methodName = invocation.getMethod().getName();
            if (!this.methodNames.contains(methodName)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skip to logging:"
                            + getInvocationDescription(invocation));
                }
                return invocation.proceed();
            }
        }

        // 開始ログの出力
        if (logger.isTraceEnabled()) {
            logger.trace("Start:" + getInvocationDescription(invocation));
        }

        // 操作ログ(開始)の出力
        if (operationLogger != null) {
            try {
                operationLogger.logStartDAO(invocation.getThis().getClass(),
                        invocation.getMethod(), invocation.getArguments());
            } catch (Throwable logEx) {
                // 監査ログ書き出し失敗時に警告ログを出力する。
                logger.warn("Logging start DAO failed.", logEx);
            }
        }

        try {
            // 本来呼び出されるメソッドを呼び出す
            Object rval = invocation.proceed();

            // 終了ログの出力
            if (logger.isTraceEnabled()) {
                logger.trace("End:" + getInvocationDescription(invocation));
            }

            // 操作ログ(終了)の出力
            if (operationLogger != null) {
                try {
                    operationLogger.logEndDAO(invocation.getThis().getClass(),
                            invocation.getMethod(), invocation.getArguments(),
                            rval);
                } catch (Throwable logEx) {
                    // 監査ログ書き出し失敗時に警告ログを出力する。
                    logger.warn("Logging end DAO failed.", logEx);
                }
            }

            // 結果の返却
            return rval;

        } catch (Throwable ex) {
            // 例外が発生した際のログ出力
            if (logger.isTraceEnabled()) {
                logger.trace("Exception thrown in:"
                        + getInvocationDescription(invocation), ex);
            }

            // 操作ログ(例外)の出力
            if (operationLogger != null) {
                try {
                    operationLogger.logExceptionDAO(invocation.getThis()
                            .getClass(), invocation.getMethod(), invocation
                            .getArguments(), ex);
                } catch (Throwable logEx) {
                    // 監査ログ書き出し失敗時に警告ログを出力する。
                    logger.warn("Logging exception DAO failed.", logEx);
                }
            }

            throw ex;
        }
    }

}
