/*
 * blanco Framework
 * Copyright (C) 2004-2007 IGA Tosiki
 * 
 * This library 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.
 */
package blanco.log.logging;

import java.util.logging.Handler;
import java.util.logging.LogRecord;

import blanco.log.resourcebundle.BlancoLogMessageResourceBundle;

/**
 * java.util.logging の出力を Apache log4j にリダイレクトするためのハンドラクラス。
 * 
 * <P>
 * blanco.log.logging.BlancoLogLog4jHandler クラスを利用すると、<A
 * href="http://java.sun.com/javase/ja/6/docs/ja/api/java/util/logging/package-summary.html">java.util.logging</A>
 * の出力を <A href="http://logging.apache.org/log4j/">Apache log4j</A>
 * にリダイレクトすることができます。これにより、標準 Java API のみを利用して Apache log4j
 * へのログ出力を実現することが出来るようになります。
 * </P>
 * <p>
 * 現在、多くの方々はロギングのインタフェースとして <A href="http://commons.apache.org/logging/">Apache
 * Commons Logging</A> を利用しているのものと思います。でも、Apache Commons Logging を利用すると、Java
 * ソースコードに org.apache.commons.logging.* の
 * import文が必要になってしまいます。「ロギングはしておきたいのだけれども、Javaの import文に 標準 Java
 * API以外のものが入るのは好ましくない」というジレンマを多くの方は感じていることでしょう。これを、blanco.log.logging.BlancoLogLog4jHandler
 * は矛盾無く解決することが出来ます。
 * </p>
 * <p>
 * blanco.log.logging.BlancoLogLog4jHandler
 * クラスの仕組みはとてもシンプルなものです。java.util.logging のログハンドラクラスである
 * java.util.logging.Handler を継承して、その出力を Apache log4j クラスへと引き渡しているだけです。<br>
 * 2007.11.23時点では およそ 105行のソースコードによって実現されています。
 * </p>
 * <p>
 * <font color="#ff00ff">利用方法</font>
 * </p>
 * <p>
 * 下記のような手順で利用することが出来ます。
 * </p>
 * <ul>
 * <li>クラスパス上に以下のファイルを配置します。<br>
 * ※Java実行環境の jre\lib\ext ディレクトリに配置するという方法もあります。
 * <ul>
 * <li>blancolog-?.?.?.jar: blancoLogのjarファイル
 * 
 * </li>
 * <li>log4j-1.2.??.jar : Apache log4jのjarファイル<br>
 * ※Apache log4j が既にクラスパス上にある場合には、新たに配置することは不要です。 </li>
 * </ul>
 * 
 * 
 * </li>
 * <li>java.util.logging の設定を変更します。<br>
 * ※最も単純な変更方法は、Java実行環境の jre\lib ディレクトリの logging.properties を変更する方法です。なお、変更する前に<STRONG>オリジナルのファイルをバックアップ</STRONG>することを推奨します。
 * <ul>
 * <li>Java実行環境の jre\lib ディレクトリ の logging.properties ファイルを、以下の２行だけに変更します。<br>
 * &lt;logging.properties&gt;<br>
 * <table border="1"> <tbody>
 * <tr>
 * <td>handlers=blanco.log.logging.BlancoLogLog4jHandler<br>
 * .level= ALL</td>
 * </tr>
 * </tbody> </table> </li>
 * <li>java.util.logging からは、これ以外にも幾つかの設定変更方法が提供されています。 </li>
 * </ul>
 * </li>
 * <li>Apache log4j のための設定ファイル &lt;log4j.properties&gt; を設定します。
 * <ul>
 * <li>クラスパス上の どこか利用者の都合の良いディレクトリに log4j.properties という名前のファイルを作成します。なお、状況によっては
 * このファイルは既に存在している場合もあります。 </li>
 * <li>&lt;log4j.properties&gt; の単純な記述内容例<br>
 * <table border="1"> <tbody>
 * <tr>
 * <td>log4j.rootLogger=DEBUG, A1<br>
 * log4j.appender.A1=org.apache.log4j.ConsoleAppender<br>
 * log4j.appender.A1.layout=org.apache.log4j.PatternLayout<br>
 * log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n</td>
 * </tr>
 * </tbody> </table>
 * 
 * 
 * </li>
 * </ul>
 * 
 * </li>
 * </ul>
 * <p>
 * <font color="#ff00ff">java.util.logging から Apache log4j へのログレベルマッピング</font>
 * </p>
 * <p>
 * java.util.logging と Apache log4j
 * とではログレベルが異なります。これを解決するために、下記のようなログレベルのマッピングを行っています。
 * </p>
 * <blockquote> <table border="1"> <tbody>
 * <tr>
 * <td bgcolor="#ffff00"><strong>java.util.logging のログレベル</strong></td>
 * <td bgcolor="#ffff00"><strong>Apache log4j のログレベル</strong></td>
 * <td bgcolor="#ffff00"><strong>備考</strong></td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.FINEST</td>
 * <td>org.apache.log4j.Level.TRACE</td>
 * <td>「詳細レベル(高)」。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.FINER</td>
 * <td>org.apache.log4j.Level.TRACE</td>
 * <td>「詳細レベル(中)」。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.FINE</td>
 * <td>org.apache.log4j.Level.DEBUG</td>
 * <td>「詳細レベル(低)」。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.CONFIG</td>
 * <td>org.apache.log4j.Level.DEBUG</td>
 * <td>「設定」。ログメッセージに 「config: 」プレフィクスを付与します。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.INFO</td>
 * <td>org.apache.log4j.Level.INFO</td>
 * <td>「情報」。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.WARNING</td>
 * <td>org.apache.log4j.Level.WARN</td>
 * <td>「警告」。</td>
 * </tr>
 * <tr>
 * <td>java.util.logging.Level.SEVERE</td>
 * <td>org.apache.log4j.Level.ERROR<br>
 * org.apache.log4j.Level.FATAL (*1)</td>
 * <td>「致命的」。<br>
 * (*1)メッセージがfatalから始まるもののみ FATAL にマップします。</td>
 * </tr>
 * </tbody> </table> </blockquote>
 * <P>
 * <FONT color="#ff00ff">java.util.logging の可能性</FONT>
 * </P>
 * <P>
 * 既に java.util.logging の利用を検討したことはあるのだけれども、java.util.logging
 * のログハンドラの非力さが原因で利用を断念した人は多いのではいでしょうか。ログハンドラ部分は Apache log4j
 * のほうが一日の長があり、また多機能であるのは確かなことです。そこで、java.util.logging を Apache Commons Logging
 * の代わりに利用して、ロギングは Apache log4j
 * を使ってしまうという、blanco.log.logging.BlancoLogLog4jHandler クラス の利用を提案します。是非 この機会に
 * blanco.log.logging.BlancoLogLog4jHandler クラス を活用して <A
 * href="http://java.sun.com/javase/ja/6/docs/ja/api/java/util/logging/package-summary.html">java.util.logging</A>の利用を検討されることをおすすめします。
 * </P>
 * 
 * @author IGA Tosiki
 */
public class BlancoLogLog4jHandler extends Handler {
    /**
     * メッセージクラス。
     * 
     * このインスタンスはロックオブジェクトの目的でも利用されます。
     */
    protected final BlancoLogMessageResourceBundle fMsg = new BlancoLogMessageResourceBundle();

    /**
     * 実際の処理を行うログハンドラクラス。
     * 
     * クラスロード失敗を検知できるようにするため、このクラスは Objectで記憶します。
     */
    protected Object fInternalHandler = null;

    /**
     * コンストラクタ。
     * 
     * このタイミングで Apache log4j の存在チェックを実施します。
     * 
     * @throws IllegalArgumentException
     *             Apache log4jクラスが見つからない場合。
     */
    public BlancoLogLog4jHandler() throws IllegalArgumentException {
        synchronized (fMsg) {
            try {
                fInternalHandler = new BlancoLogLog4jHandlerInternal();
                ((BlancoLogLog4jHandlerInternal) fInternalHandler).init();
            } catch (NoClassDefFoundError e) {
                throw new IllegalArgumentException(fMsg.getMblglg01(e
                        .toString()));
            }
        }
    }

    /**
     * 与えられたログレコードをロギングします。
     * 
     * @param argLogRecord
     *            ログレコード。
     */
    public void publish(final LogRecord argLogRecord) {
        synchronized (fMsg) {
            ((BlancoLogLog4jHandlerInternal) fInternalHandler)
                    .publish(argLogRecord);
        }
    }

    /**
     * ロガーをフラッシュします。
     */
    public void flush() {
        synchronized (fMsg) {
            ((BlancoLogLog4jHandlerInternal) fInternalHandler).flush();
        }
    }

    /**
     * ロガーをクローズします。
     * 
     * @throws SecurityException
     *             セキュリティ例外が発生した場合。
     */
    public void close() throws SecurityException {
        synchronized (fMsg) {
            ((BlancoLogLog4jHandlerInternal) fInternalHandler).close();
        }
    }
}
