// Copyright (c) 2008, NTT DATA Corporation.
//
// 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.

using System;
using System.Configuration;
using System.Reflection;
using TERASOLUNA.Fw.Common.Logging.TraceSourceLog;

namespace TERASOLUNA.Fw.Common.Logging
{
    /// <summary>
    /// <see cref="ILog"/> 実装クラスのインスタンスを生成するファクトリクラスです。
    /// </summary>
    public abstract class LogFactory
    {
        /// <summary>
        /// 利用する <see cref="LogFactory"/> クラスの型名をアプリケーション構成ファイルから
        /// 取得するためのキー文字列です。
        /// </summary>
        /// <remarks>
        /// <para>
        /// アプリケーション構成ファイルの appSettings 要素から、この文字列をキーとして、
        /// <see cref="LogFactory"/> クラスの完全修飾型名を取得します。
        /// </para>
        /// <para>
        /// この定数の値は "LogFactoryTypeName" です。
        /// </para>
        /// </remarks>
        protected static readonly string APP_KEY_FACTORY_PROPERTY = "LogFactoryTypeName";

        /// <summary>
        /// <see cref="LogFactory"/> 継承クラスのシングルトンインスタンスです。
        /// </summary>
        /// <remarks>
        /// デフォルトの値は、 null です。
        /// </remarks>
        private static volatile LogFactory _logFactory = null;

        /// <summary>
        /// ロック用のオブジェクトです。
        /// </summary>
        private static object _syncRoot = new Object();

        /// <summary>
        /// <see cref="LogFactory"/> 型のクラスのインスタンスを取得します。
        /// </summary>
        /// <remarks>
        /// 構成ファイルに <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとして型名が
        /// 記述されていた場合、その型のインスタンスを生成します。記述がない場合、
        /// <see cref="TraceSourceLogFactory"/> のインスタンスを生成します。
        /// </remarks>
        /// <value><see cref="LogFactory"/> 型のクラスのインスタンス。</value>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型は抽象クラスです。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型または、<see cref="TraceSourceLogFactory"/> のコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型または、<see cref="TraceSourceLogFactory"/> のコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// アプリケーション設定データを格納した NameValueCollection オブジェクトを取得できませんでした。
        /// </exception>
        protected static LogFactory Factory
        {
            get
            {
                if (_logFactory == null)
                {
                    lock (_syncRoot)
                    {
                        if (_logFactory == null)
                        {
                            _logFactory = CreateLogFactoryFromAppSettings(
                                APP_KEY_FACTORY_PROPERTY,
                                typeof(TraceSourceLogFactory));
                        }
                    }
                }
                return _logFactory;
            }
        }

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </summary>
        /// <param name="className">生成しようとする <see cref="ILog"/> 実装クラスの
        /// インスタンスを識別するための文字列。</param>
        /// <param name="args">
        /// 0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。
        /// 標準実装の <see cref="TraceSourceLogFactory"/> では、1 番目のオブジェクトのみ利用されます。
        /// </param>
        /// <returns><see cref="ILog"/> 実装クラスのインスタンス。</returns>
        /// <remarks>
        /// <list type="number">
        /// <item>
        /// 構成ファイルの設定に基づいて <see cref="LogFactory"/> 派生クラスのシングルトンインスタンスを生成します。
        /// インスタンスはキャッシュしており、キャッシュが存在しない場合は次のように生成します。
        /// 構成ファイルに <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとして型名が
        /// 記述されていた場合、その型のインスタンスを生成します。記述がない場合、
        /// 標準実装である <see cref="TraceSourceLogFactory"/> のインスタンスを生成します。
        /// </item>
        /// <item>
        /// 生成したインスタンスの <seealso cref="GetInstance(string, object[])"/> メソッドを呼び出して <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </item>
        /// </list>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="args"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="className"/> が空文字です。
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型は抽象クラスです。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが null 参照です。
        /// </item>
        /// </list>
        /// これに加えて、標準実装の <see cref="TraceSourceLogFactory"/> 使用時は、以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// 構成ファイルに記述した <see cref="System.Diagnostics.TraceSource"/> の設定項目が不正です。
        /// ログレベルの閾値には Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public static ILog GetLogger(string className, params object[] args)
        {
            // 入力チェック
            if (className == null)
            {
                throw new ArgumentNullException("className");
            }

            if (className.Length == 0)
            {
                throw new ArgumentException(string.Format(Properties.Resources.E_EMPTY_STRING, "className"));
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            // インスタンスの取得
            ILog result = Factory.GetInstance(className, args);
            if (result == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INSTANCE_CREATION_FAILED, typeof(ILog).FullName));
            }

            return result;
        }

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </summary>
        /// <param name="classType">生成しようとする　<see cref="ILog"/> 実装クラスの
        /// インスタンスを識別するためのクラスの型。</param>
        /// <param name="args">
        /// 0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。
        /// 標準実装の <see cref="TraceSourceLogFactory"/> では、1 番目のオブジェクトのみ利用されます。
        /// </param>
        /// <returns><see cref="ILog"/> 実装クラスのインスタンス。</returns>
        /// <remarks>
        /// <list type="number">
        /// <item>
        /// 構成ファイルの設定に基づいて <see cref="LogFactory"/> 派生クラスのシングルトンインスタンスを生成します。
        /// インスタンスはキャッシュしており、キャッシュが存在しない場合は次のように生成します。
        /// 構成ファイルに <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとして型名が
        /// 記述されていた場合、その型のインスタンスを生成します。記述がない場合、
        /// 標準実装である <see cref="TraceSourceLogFactory"/> のインスタンスを生成します。
        /// </item>
        /// <item>
        /// 生成したインスタンスの <seealso cref="GetInstance(string, object[])"/> メソッドを呼び出して <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </item>
        /// </list>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="args"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型は抽象クラスです。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが null 参照です。
        /// </item>
        /// </list>
        /// これに加えて、標準実装の <see cref="TraceSourceLogFactory"/> 使用時は、以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// 構成ファイルに記述した <see cref="System.Diagnostics.TraceSource"/> の設定項目が不正です。
        /// ログレベルの閾値には Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public static ILog GetLogger(Type classType, params object[] args)
        {
            // 入力チェック
            if (classType == null)
            {
                throw new ArgumentNullException("classType");
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            // インスタンスの取得
            ILog result = Factory.GetInstance(classType, args);
            if (result == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INSTANCE_CREATION_FAILED, typeof(ILog).FullName));
            }

            return result;
        }

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </summary>
        /// <typeparam name="T"> 生成したインスタンスを受ける型。</typeparam>
        /// <param name="className">生成しようとする <see cref="ILog"/> 実装クラスの
        /// インスタンスを識別するための文字列。</param>
        /// <param name="args">
        /// 0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。
        /// 標準実装の <see cref="TraceSourceLogFactory"/> では、1 番目のオブジェクトのみ利用されます。
        /// </param>
        /// <returns><see cref="ILog"/> 実装クラスのインスタンス。</returns>
        /// <remarks>
        /// <list type="number">
        /// <item>
        /// 構成ファイルの設定に基づいて <see cref="LogFactory"/> 派生クラスのシングルトンインスタンスを生成します。
        /// インスタンスはキャッシュしており、キャッシュが存在しない場合は次のように生成します。
        /// 構成ファイルに <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとして型名が
        /// 記述されていた場合、その型のインスタンスを生成します。記述がない場合、
        /// 標準実装である <see cref="TraceSourceLogFactory"/> のインスタンスを生成します。
        /// </item>
        /// <item>
        /// 生成したインスタンスの <seealso cref="GetInstance(string, object[])"/> メソッドを呼び出して <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </item>
        /// </list>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="args"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="className"/> が空文字です。
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型は抽象クラスです。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが null 参照です。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが <typeparamref name="T"/> にキャストできません。
        /// </item>
        /// </list>
        /// これに加えて、標準実装の <see cref="TraceSourceLogFactory"/> 使用時は、以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// 構成ファイルに記述した <see cref="System.Diagnostics.TraceSource"/> の設定項目が不正です。
        /// ログレベルの閾値には Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public static T GetLogger<T>(string className, params object[] args) where T : class, ILog
        {
            // 入力チェック
            if (className == null)
            {
                throw new ArgumentNullException("className");
            }

            if (className.Length == 0)
            {
                throw new ArgumentException(string.Format(Properties.Resources.E_EMPTY_STRING, "className"));
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            // インスタンスの取得
            ILog logger = Factory.GetInstance(className, args);
            if (logger == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INSTANCE_CREATION_FAILED, typeof(ILog).FullName));
            }

            T result = logger as T;
            if (result == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INVALID_CAST, logger.GetType().FullName, typeof(T).FullName));
            }

            return result;
        }

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </summary>
        /// <typeparam name="T"> 生成したインスタンスを受ける型。</typeparam>
        /// <param name="classType">生成しようとする <see cref="ILog"/> 実装クラスの
        /// インスタンスを識別するためのクラスの型。</param>
        /// <param name="args">
        /// 0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。
        /// 標準実装の <see cref="TraceSourceLogFactory"/> では、1 番目のオブジェクトのみ利用されます。
        /// </param>
        /// <returns><see cref="ILog"/> 実装クラスのインスタンス。</returns>
        /// <remarks>
        /// <list type="number">
        /// <item>
        /// 構成ファイルの設定に基づいて <see cref="LogFactory"/> 派生クラスのシングルトンインスタンスを生成します。
        /// インスタンスはキャッシュしており、キャッシュが存在しない場合は次のように生成します。
        /// 構成ファイルに <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとして型名が
        /// 記述されていた場合、その型のインスタンスを生成します。記述がない場合、
        /// 標準実装である <see cref="TraceSourceLogFactory"/> のインスタンスを生成します。
        /// </item>
        /// <item>
        /// 生成したインスタンスの <seealso cref="GetInstance(string, object[])"/> メソッドを呼び出して <see cref="ILog"/> 実装クラスのインスタンスを取得します。
        /// </item>
        /// </list>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="className"/> が null 参照です。
        /// </item>
        /// <item>
        /// <paramref name="args"/> が null 参照です。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型は抽象クラスです。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のデフォルトコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <seealso cref="APP_KEY_FACTORY_PROPERTY"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが null 参照です。
        /// </item>
        /// <item>
        /// 取得した <see cref="ILog"/> 実装クラスのインスタンスが <typeparamref name="T"/> にキャストできません。
        /// </item>
        /// </list>
        /// これに加えて、標準実装の <see cref="TraceSourceLogFactory"/> 使用時は、以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// 構成ファイルに記述した <see cref="System.Diagnostics.TraceSource"/> の設定項目が不正です。
        /// ログレベルの閾値には Off, Critical, Error, Warning, Information, Verbose, All のいずれかを設定してください。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// 構成ファイルの設定が不正です。
        /// </exception>
        public static T GetLogger<T>(Type classType, params object[] args) where T : class, ILog
        {
            // 入力チェック
            if (classType == null)
            {
                throw new ArgumentNullException("classType");
            }

            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            // インスタンスの取得
            ILog logger = Factory.GetInstance(classType, args);
            if (logger == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INSTANCE_CREATION_FAILED, typeof(ILog).FullName));
            }

            T result = logger as T;
            if (result == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INVALID_CAST, logger.GetType().FullName, typeof(T).FullName));
            }

            return result;
        }

        /// <summary>
        /// アプリケーション構成ファイルから、キーを指定して型名を取得し、リフレクションを用いて
        /// インスタンスを生成します。型名を取得できない場合、<paramref name="defaultType"/> で指定
        /// された<see cref="Type"/>のインスタンスを生成します。
        /// </summary>
        /// <param name="appSettingsKey">アプリケーション構成ファイルから型名を取得するために用いるキー
        /// 文字列。</param>
        /// <param name="defaultType">アプリケーション構成ファイルから型名が取得できなかった場合、
        /// 利用される型。</param>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 型を解決することができません。
        /// </item>
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が抽象クラスです。
        /// </item>
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>      
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型のコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <paramref name="appSettingsKey"/> をキーとする構成ファイルの appSettings 要素の、 value 属性値から
        /// 生成した型が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// </list>
        /// </exception>
        /// <exception cref="ConfigurationErrorsException">
        /// アプリケーション設定データを格納した NameValueCollection オブジェクトを取得できませんでした。
        /// </exception>
        /// <returns>生成されたインスタンス。</returns>
        protected static LogFactory CreateLogFactoryFromAppSettings(
            string appSettingsKey, Type defaultType)
        {
            // 型名をアプリケーション構成ファイルから取得する。
            string typeName = ConfigurationManager.AppSettings[appSettingsKey];

            LogFactory logFactory = null;

            // 型名からインスタンスを取得する。
            // 型名がnullまたは空文字の場合、defaultTypeを型として利用する。
            Type type = null;
            if (!string.IsNullOrEmpty(typeName))
            {
                try
                {
                    type = Type.GetType(typeName, true);
                }
                catch (Exception e)
                {
                    throw new TerasolunaException(string.Format(
                        Properties.Resources.E_TYPE_LOAD_FAILED, typeName), e);
                }
            }
            else
            {
                type = defaultType;
            }

            logFactory = CreateLogFactoryByType(type);
            return logFactory;
        }

        /// <summary>
        /// 型を指定し、リフレクションを用いてインスタンスを生成します。
        /// </summary>
        /// <param name="targetType">生成するインスタンスの型。</param>
        /// <returns>生成されたインスタンス。</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="targetType"/> が null 参照です。
        /// </exception>
        /// <exception cref="TerasolunaException">
        /// 以下のような場合に例外をスローします。
        /// <list type="bullet">
        /// <item>
        /// <paramref name="targetType"/> が抽象クラスです。
        /// </item>
        /// <item>
        /// <paramref name="targetType"/> はジェネリック型のクラスですが、型パラメータが設定されていません。
        /// </item>
        /// <item>
        /// <paramref name="targetType"/> のコンストラクタ呼び出しに失敗しました。
        /// </item>
        /// <item>
        /// <paramref name="targetType"/> のコンストラクタで例外が発生しました。
        /// </item>
        /// <item>
        /// <paramref name="targetType"/> が <see cref="LogFactory"/> にキャストできません。
        /// </item>
        /// </list>
        /// </exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
        protected static LogFactory CreateLogFactoryByType(Type targetType)
        {
            // 入力チェック
            if (targetType.IsAbstract)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_PARAM_ABSTRACT_TYPE,
                    "targetType",
                    targetType.AssemblyQualifiedName));
            }

            // ジェネリック型で型パラメータが設定されていない場合。
            if (targetType.ContainsGenericParameters)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_PARAM_GENERIC_TYPE,
                    "targetType",
                    targetType.AssemblyQualifiedName));
            }

            // 型targetTypeのインスタンスを生成する。
            // publicで引数を取らないコンストラクタが存在する必要がある。
            LogFactory result = null;

            try
            {
                result = Activator.CreateInstance(targetType) as LogFactory;
            }
            catch (MemberAccessException e)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_MEMBER_ACCESS_EXCEPTION,
                    targetType.FullName), e);
            }
            catch (TargetInvocationException e)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_TARGET_INVOCATION_EXCEPTION,
                    targetType.FullName), e);
            }

            if (result == null)
            {
                throw new TerasolunaException(string.Format(
                    Properties.Resources.E_INVALID_CAST,
                    targetType.FullName, typeof(LogFactory).FullName));
            }

            return result;
        }

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得するメソッドの抽象メソッドです。
        /// </summary>
        /// <param name="className">生成するインスタンスの型の文字列。</param>
        /// <param name="args">0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。</param>
        /// <returns><see cref="ILog"/> 実装クラスのインスタンスです。</returns>
        protected abstract ILog GetInstance(string className, params object[] args);

        /// <summary>
        /// <see cref="ILog"/> 実装クラスのインスタンスを取得するメソッドの抽象メソッドです。
        /// </summary>
        /// <param name="classType">生成するインスタンスの型。</param>
        /// <param name="args">0 個以上のログインスタンスを生成するために必要な対象オブジェクトを含んだ object 型の可変長引数。</param>
        /// <returns><see cref="ILog"/>実装クラスのインスタンスです。</returns>
        protected abstract ILog GetInstance(Type classType, params object[] args);
    }
}
