package org.apache.commons.dbcp.cpdsadapter;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and 
 *    "Apache Turbine" must not be used to endorse or promote products 
 *    derived from this software without prior written permission. For 
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache Turbine", nor may "Apache" appear in their name, without 
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
 

import java.util.Hashtable;
import  java.io.PrintWriter;
import  java.io.Serializable;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.sql.PooledConnection;
import javax.sql.ConnectionPoolDataSource;
import javax.naming.Name;
import javax.naming.Context;
import javax.naming.Referenceable;
import javax.naming.spi.ObjectFactory;
import javax.naming.Reference;
import javax.naming.RefAddr;
import javax.naming.StringRefAddr;
import javax.naming.NamingException;

import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;

/**
 * <p>
 * {@link javax.sql.ConnectionPoolDataSource} の実装は持っていないが
 * {@link java.sql.DriverManager} の実装は持っているJDBCドライバのためのアダプタです。
 * <code>ConnectionPoolDataSource</code> は、(まだ）一般的なアプリケーションでは使用されていません。
 * これらは {@link org.apache.commons.dbcp.jdbc2pool.Jdbc2PoolDataSource}
 * と同じように <code>Connection</code> をプールする <code>DataSource</code> の実装に使用されます。
 * J2EE コンテナは普通 <code>ConnectionPoolDataSource</code> を初期化するためのいくつかの方法を提供し、
 * 初期化の為の属性は bean のゲッタ/セッタにて参照され、JNDI を経てデプロイされます。
 * これはプールを行っている <code>DataSource</code>
 * が新たな接続を必要とした時のデータベースに対する物理的な接続の生成元として利用することができます。
 * {@primary An adapter for jdbc drivers that do not include an implementation
 * of {@link javax.sql.ConnectionPoolDataSource}, but still include a 
 * {@link java.sql.DriverManager} implementation.  
 * <code>ConnectionPoolDataSource</code>s are not used within general 
 * applications.  They are used by <code>DataSource</code> implementations
 * that pool <code>Connection</code>s, such as 
 * {@link org.apache.commons.dbcp.jdbc2pool.Jdbc2PoolDataSource}.  A J2EE
 * container will normally provide some method of initializing the
 * <code>ConnectionPoolDataSource</code> whose attributes are presented
 * as bean getters/setters and then deploying it via JNDI.  It is then
 * available as a source of physical connections to the database, when
 * the pooling <code>DataSource</code> needs to create a new 
 * physical connection.}
 * </p>
 *
 * <p>
 * 普通、 DriverAdapterCPDS は JNDI 環境で使用されますが、
 * DriverAdapterCPDS は他の bean と同じようにインスタンス化、初期化され、プールを行う
 * <code>DataSource</code> に直接アタッチされます。
 * <code>Jdbc2PoolDataSource</code> は JNDI を利用してもしなくても 
 * <code>ConnectionPoolDataSource</code> を使用することができます。
 * {@primary Although normally used within a JNDI environment, the DriverAdapterCPDS
 * can be instantiated and initialized as any bean and then attached
 * directly to a pooling <code>DataSource</code>. 
 * <code>Jdbc2PoolDataSource</code> can use the 
 * <code>ConnectionPoolDataSource</code> with or without the use of JNDI.}
 * </p>
 *
 * <p>
 * また DriverAdapterCPDS は JDBC2 の <code>ConnectionPoolDataSource</code> 
 * 実装では一般的に利用できないが JDBC3 の仕様には含まれる
 * <code>PreparedStatement</code> のプーリング機能を提供します。
 * DriverAdapterCPDS の <code>PreparedStatement</code> のプール(の実装)はいままで
 * dbcp パッケージに含まれていましたが、ここで扱われる設定での広範囲なテストを経ていませんでした。
 * この機能は実験的なものと考えるべきで、poolPreparedStatements 属性にて切り替えることができます。
 * {@primary The DriverAdapterCPDS also provides <code>PreparedStatement</code> pooling
 * which is not generally available in jbdc2 
 * <code>ConnectionPoolDataSource</code> implementation, but is 
 * addressed within the jdbc3 specification.  The <code>PreparedStatement</code>
 * pool in DriverAdapterCPDS has been in the dbcp package for some time, but
 * it has not undergone extensive testing in the configuration used here.
 * It should be considered experimental and can be toggled with the 
 * poolPreparedStatements attribute.}

 * </p>
 *
 * <p>
 * <a href="package-summary.html">パッケージドキュメント</a> には
 * catalina と JNDI を使用した例が含まれています。
 * <a href="../jdbc2pool/package-summary.html">jdbc2pool パッケージドキュメント</a>
 * には、JNDI を使用せずに <code>Jdbc2PoolDataSource</code> の接続取得元として
 * <code>DriverAdapterCPDS</code> を使用する方法が含まれています。
 * {@primary The <a href="package-summary.html">package documentation</a> contains an 
 * example using catalina and JNDI.  The <a 
 * href="../jdbc2pool/package-summary.html">jdbc2pool package documentation</a>
 * shows how to use <code>DriverAdapterCPDS</code> as a source for
 * <code>Jdbc2PoolDataSource</code> without the use of JNDI.}

 * </p>
 *
 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
 * @translator 日置 聡
 * @status firstdraft
 * @update 2003/09/11
 * @version $Id: DriverAdapterCPDS.java,v 1.1.1.1 2004/02/13 10:02:03 hioki Exp $
 */
public class DriverAdapterCPDS
    implements ConnectionPoolDataSource, Referenceable, Serializable, 
               ObjectFactory
{
    private static final String GET_CONNECTION_CALLED = 
        "A PooledConnection was already requested from this source, " + 
        "further initialization is not allowed.";

    /**
     * Serialization のための引数のないデフォルトコンストラクタ。
     * {@primary Default no-arg constructor for Serialization}
     */
    public DriverAdapterCPDS() 
    {
    }

    /**
     * デフォルトのユーザ、パスワードを使用してデータベースへの接続の確立を試みます。
     * {@primary Attempt to establish a database connection using the default
     * user and password.}
     */
    public PooledConnection getPooledConnection() 
        throws SQLException
    {
        return getPooledConnection(getUser(), getPassword());
    }
                     
    /**
     * データベースへの接続の確立を試みます。
     * {@primary Attempt to establish a database connection.}
     */
    public PooledConnection getPooledConnection(String username, 
                                                String password)
        throws SQLException
    {
        getConnectionCalled = true;
        /*
        public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, 
        int maxActive, byte whenExhaustedAction, long maxWait, 
        int maxIdle, boolean testOnBorrow, boolean testOnReturn, 
        long timeBetweenEvictionRunsMillis, 
        int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, 
        boolean testWhileIdle) {
        */
        KeyedObjectPool stmtPool = null;
        if (isPoolPreparedStatements()) 
        {
            stmtPool = new GenericKeyedObjectPool(null,
                getMaxActive(), GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW, 0, 
                getMaxIdle(), false, false, getTimeBetweenEvictionRunsMillis(),
                getNumTestsPerEvictionRun(), 
                getMinEvictableIdleTimeMillis(), false);            
        }
        
        // Workaround for buggy WebLogic 5.1 classloader - ignore the
        // exception upon first invocation.
        try
        {
            return new PooledConnectionImpl(
                DriverManager.getConnection( getUrl(),
                                             username,
                                             password ), stmtPool );
        }
        catch( ClassCircularityError e )
        {
            return new PooledConnectionImpl(
                DriverManager.getConnection( getUrl(),
                                             username,
                                             password ), stmtPool );
        }
    }

    // ----------------------------------------------------------------------
    // Referenceable implementation 

    /**
     * <CODE>Referenceable</CODE> の実装です。
     * {@primary <CODE>Referenceable</CODE> implementation.}
     */
    public Reference getReference() 
        throws NamingException 
    {
        // this class implements its own factory
        String factory = getClass().getName();
        
        Reference ref = new Reference(getClass().getName(), factory, null);

        ref.add(new StringRefAddr("description", getDescription()));
        ref.add(new StringRefAddr("driver", getDriver()));
        ref.add(new StringRefAddr("loginTimeout", 
                                  String.valueOf(getLoginTimeout())));
        ref.add(new StringRefAddr("password", getPassword()));
        ref.add(new StringRefAddr("user", getUser()));
        ref.add(new StringRefAddr("url", getUrl()));

        ref.add(new StringRefAddr("poolPreparedStatements", 
                                  String.valueOf(isPoolPreparedStatements())));
        ref.add(new StringRefAddr("maxActive", 
                                  String.valueOf(getMaxActive())));
        ref.add(new StringRefAddr("maxIdle", 
                                  String.valueOf(getMaxIdle())));
        ref.add(new StringRefAddr("timeBetweenEvictionRunsMillis", 
            String.valueOf(getTimeBetweenEvictionRunsMillis())));
        ref.add(new StringRefAddr("numTestsPerEvictionRun", 
            String.valueOf(getNumTestsPerEvictionRun())));
        ref.add(new StringRefAddr("minEvictableIdleTimeMillis", 
            String.valueOf(getMinEvictableIdleTimeMillis())));

        return ref;
    }


    // ----------------------------------------------------------------------
    // ObjectFactory implementation 

    /**
     * このクラスのインスタンスを生成するための ObjectFactory の実装です。
     * {@primary implements ObjectFactory to create an instance of this class}
     */ 
    public Object getObjectInstance(Object refObj, Name name, 
                                    Context context, Hashtable env) 
        throws Exception 
    {
        // The spec says to return null if we can't create an instance 
        // of the reference
        DriverAdapterCPDS cpds = null;
        if (refObj instanceof Reference) 
        {
            Reference ref = (Reference)refObj;
            if (ref.getClassName().equals(getClass().getName())) 
            {
                RefAddr ra = ref.get("description");
                if (ra != null && ra.getContent() != null) 
                {
                    setDescription(ra.getContent().toString());
                }

                ra = ref.get("driver");
                if (ra != null && ra.getContent() != null) 
                {
                    setDriver(ra.getContent().toString());
                }
                ra = ref.get("url");
                if (ra != null && ra.getContent() != null) 
                {
                    setUrl(ra.getContent().toString());
                }
                ra = ref.get("user");
                if (ra != null && ra.getContent() != null) 
                {
                    setUser(ra.getContent().toString());
                }
                ra = ref.get("password");
                if (ra != null && ra.getContent() != null) 
                {
                    setPassword(ra.getContent().toString());
                }

                ra = ref.get("poolPreparedStatements");
                if (ra != null && ra.getContent() != null) 
                {
                    setPoolPreparedStatements(
                        Boolean.getBoolean(ra.getContent().toString()));
                }
                ra = ref.get("maxActive");
                if (ra != null && ra.getContent() != null) 
                {
                    setMaxActive(
                        Integer.parseInt(ra.getContent().toString()));
                }

                ra = ref.get("maxIdle");
                if (ra != null && ra.getContent() != null) 
                {
                    setMaxIdle(
                        Integer.parseInt(ra.getContent().toString()));
                }

                ra = ref.get("timeBetweenEvictionRunsMillis");
                if (ra != null && ra.getContent() != null) 
                {
                    setTimeBetweenEvictionRunsMillis(
                        Integer.parseInt(ra.getContent().toString()));
                }

                ra = ref.get("numTestsPerEvictionRun");
                if (ra != null && ra.getContent() != null) 
                {
                    setNumTestsPerEvictionRun(
                        Integer.parseInt(ra.getContent().toString()));
                }

                ra = ref.get("minEvictableIdleTimeMillis");
                if (ra != null && ra.getContent() != null) 
                {
                    setMinEvictableIdleTimeMillis(
                        Integer.parseInt(ra.getContent().toString()));
                }

                cpds = this;
            }
        }
            return cpds;
    }

    /**
     * PooledConnection が既にリクエストされていた場合、
     * IllegalStateException を投げます。
     * {@primary Throws an IllegalStateException, if a PooledConnection has already
     * been requested.}
     */
    private void assertInitializationAllowed()
        throws IllegalStateException 
    {
        if (getConnectionCalled) 
        {
            throw new IllegalStateException(GET_CONNECTION_CALLED);
        }
    }

    // ----------------------------------------------------------------------
    // Properties
    
    /**
     * 記述情報(Description)の値を取得します。
     * このプロパティはこのデータソースをデプロイする処理のために存在し、内部では使用されません。
     * {@primary Get the value of description.  This property is here for use by
     * the code which will deploy this datasource.  It is not used
     * internally.}
     *
     * @return 記述情報(Description)の値
     * {@primary value of description.}
     */
    public String getDescription() 
    {
        return description;
    }
    
    /**
     * 記述情報(Description)の値を設定します。
     * このプロパティはこのデータソースをデプロイする処理のために存在し、内部では使用されません。
     * {@primary Set the value of description.  This property is here for use by
     * the code which will deploy this datasource.  It is not used
     * internally.}
     *
     * @param v  記述情報(Description)に割り当てる値
     * {@primary Value to assign to description.}
     */
    public void setDescription(String  v) 
    {
        this.description = v;
    }

    /**
     * デフォルトユーザのパスワードの値を取得します。
     * {@primary Get the value of password for the default user.}
     * @return パスワードの値
     * {@primary value of password.}
     */
    public String getPassword() 
    {
        return password;
    }
    
    /**
     * デフォルトユーザのパスワードの値を設定します。
     * {@primary Set the value of password for the default user.}
     * @param v  パスワードに割り当てる値
     * {@primary Value to assign to password.}
     */
    public void setPassword(String  v) 
    {
        assertInitializationAllowed();
        this.password = v;
    }

    /**
     * このデータソースがデータベースの位置を認識するためのURLの値を取得します。
     * {@primary Get the value of url used to locate the database for this datasource.}
     * @return URLの値
     * {@primary value of url.}
     */
    public String getUrl() 
    {
        return url;
    }
    
    /**
     * このデータソースがデータベースの位置を認識するためのURLの値を設定します。
     * {@primary Set the value of url used to locate the database for this datasource.}
     * @param v  URLに割り当てる値
     * {@primary Value to assign to url.}
     */
    public void setUrl(String  v) 
    {
        assertInitializationAllowed();
        this.url = v;
    }

    /**
     * デフォルトユーザ(ログイン名 または ユーザ名)の値を取得します。
     * {@primary Get the value of default user (login or username).}
     * @return ユーザの値
     * {@primary value of user.}
     */
    public String getUser() 
    {
        return user;
    }
    
    /**
     * デフォルトユーザ(ログイン名 または ユーザ名)の値を設定します。
     * {@primary Set the value of default user (login or username).}
     * @param v  ユーザに割り当てる値
     * {@primary Value to assign to user.}
     */
    public void setUser(String  v) 
    {
        assertInitializationAllowed();
        this.user = v;
    }

    /**
     * ドライバのクラス名を取得します。
     * {@primary Get the driver classname.}
     * @return ドライバの値
     * {@primary value of driver.}
     */
    public String getDriver() 
    {
        return driver;
    }
    
    /**
     * ドライバのクラス名を設定します。
     * ドライバクラス名の設定は DriverManager に登録されたドライバに影響します。
     * {@primary Set the driver classname.  Setting the driver classname cause the 
     * driver to be registered with the DriverManager.}
     * @param v  ドライバに割り当てる値
     * {@primary Value to assign to driver.}
     */
    public void setDriver(String  v)
        throws ClassNotFoundException
    {
        assertInitializationAllowed();
        this.driver = v;
        // make sure driver is registered
        Class.forName(v);
    }
    
    /**
     * このデータソースがデータベースとの接続を試みる場合に待機する最長時間(秒)を取得します。
     * この実装では使用されません。
     * {@primary Gets the maximum time in seconds that this data source can wait 
     * while attempting to connect to a database. NOT USED.}
     */
    public int getLoginTimeout() 
    {
        return loginTimeout;
    }
                           
    /**
     * このデータソースのログライターを取得します。この実装では使用されません。
     * {@primary Get the log writer for this data source. NOT USED.}
     */
    public PrintWriter getLogWriter() 
    {
        return logWriter;
    }
                           
    /**
     * このデータソースがデータベースとの接続を試みる場合に待機する最長時間(秒)を設定します。
     * この実装では使用されません。
     * {@primary Sets the maximum time in seconds that this data source will wait 
     * while attempting to connect to a database. NOT USED.}
     */
    public void setLoginTimeout(int seconds)
    {
        loginTimeout = seconds;
    } 
                           
    /**
     * このデータソースのログライターを設定します。この実装では使用されません。
     * {@primary Set the log writer for this data source. NOT USED.}
     */
    public void setLogWriter(java.io.PrintWriter out)
    {
        logWriter = out;
    } 


    // ------------------------------------------------------------------
    // PreparedStatement pool properties

    
    /**
     * <code>PreparedStatement</code> のプーリング機能の切り替えフラグです。
     * {@primary Flag to toggle the pooling of <code>PreparedStatement</code>s}
     * @return poolPreparedStatements の値
     * {@primary value of poolPreparedStatements.}
     */
    public boolean isPoolPreparedStatements() 
    {
        return poolPreparedStatements;
    }
    
    /**
     * <code>PreparedStatement</code> のプーリング機能の切り替えフラグです。
     * {@primary Flag to toggle the pooling of <code>PreparedStatement</code>s}
     * @param v  true の場合、ステートメントをプールします。
     * {@primary true to pool statements.}
     */
    public void setPoolPreparedStatements(boolean  v) 
    {
        assertInitializationAllowed();
        this.poolPreparedStatements = v;
    }

    /**
     * このプールから1度に割り当てることのできるアクティブなステートメントの最大数です。
     * 0が設定された場合には制限を行いません。
     * {@primary The maximum number of active statements that can be allocated from
     * this pool at the same time, or zero for no limit.}
     */
    public int getMaxActive() {
        return (this.maxActive);
    }

    /**
     * このプールから1度に割り当てることのできるアクティブなステートメントの最大数です。
     * 0が設定された場合には制限を行いません。
     * {@primary The maximum number of active statements that can be allocated from
     * this pool at the same time, or zero for no limit.}
     */
    public void setMaxActive(int maxActive) {
        assertInitializationAllowed();
        this.maxActive = maxActive;
    }

    /**
     * 余分なものを開放せずにプール内にアイドル状態で保持できるステートメントの最大数です。
     * 0が設定された場合には制限を行いません。
     * {@primary The maximum number of statements that can remain idle in the
     * pool, without extra ones being released, or zero for no limit.}
     */
    public int getMaxIdle() {
        return (this.maxIdle);
    }

    /**
     * 余分なものを開放せずにプール内にアイドル状態で保持できるステートメントの最大数です。
     * 0が設定された場合には制限を行いません。
     * {@primary The maximum number of statements that can remain idle in the
     * pool, without extra ones being released, or zero for no limit.}
     */
    public void setMaxIdle(int maxIdle) {
        assertInitializationAllowed();
        this.maxIdle = maxIdle;
    }

    /**
     * アイドル状態のオブジェクトを排除するスレッドが次の動作までスリープする時間を示すミリセカンドの値を返します。
     * マイナスの値が設定されている場合、アイドル状態のオブジェクトを排除するスレッドは動作しません。
     * {@primary Returns the number of milliseconds to sleep between runs of the
     * idle object evictor thread.
     * When non-positive, no idle object evictor thread will be
     * run.}
     *
     * *see #setTimeBetweenEvictionRunsMillis
     */
    public int getTimeBetweenEvictionRunsMillis() {
        return _timeBetweenEvictionRunsMillis;
    }

    /**
     * アイドル状態のオブジェクトを排除するスレッドが次の動作までスリープする時間を示すミリセカンドの値を設定します。
     * マイナスの値が設定されている場合、アイドル状態のオブジェクトを排除するスレッドは動作しません。
     * {@primary Sets the number of milliseconds to sleep between runs of the
     * idle object evictor thread.
     * When non-positive, no idle object evictor thread will be
     * run.}
     *
     * *see #getTimeBetweenEvictionRunsMillis
     */
    public void 
        setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
        assertInitializationAllowed();
            _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
    }

    /**
     * アイドル状態のオブジェクトを排除するスレッドが1度の動作でチェックの対象とするステートメントの数を返します。
     * {@primary Returns the number of statements to examine during each run of the
     * idle object evictor thread (if any).}
     *
     * *see #setNumTestsPerEvictionRun
     * *see #setTimeBetweenEvictionRunsMillis
     */
    public int getNumTestsPerEvictionRun() {
        return _numTestsPerEvictionRun;
    }

    /**
     * アイドル状態のオブジェクトを排除するスレッドが1度の動作でチェックの対象とするステートメントの数を返します。
     * {@primary Sets the number of statements to examine during each run of the
     * idle object evictor thread (if any).}
     * <p>
     * マイナスの値が設定された場合、<tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt> の数のテストが実施されます。
     * 例えば値が <i>-n</i> の場合にはアイドル状態のステートメントのうち <i>1/n</i> が1度の動作でテストされます。
     * {@primary When a negative value is supplied, <tt>ceil({*link #numIdle})/abs({*link #getNumTestsPerEvictionRun})</tt>
     * tests will be run.  I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
     * idle objects will be tested per run.}
     *
     * *see #getNumTestsPerEvictionRun
     * *see #setTimeBetweenEvictionRunsMillis
     */
    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
        assertInitializationAllowed();
        _numTestsPerEvictionRun = numTestsPerEvictionRun;
    }

    /**
     * アイドル状態のオブジェクトがプール内に居られる最短時間を返します。
     * この時間を過ぎるとアイドル状態のオブジェクトを排除するスレッドのチェック対象となります。
     * {@primary Returns the minimum amount of time a statement may sit idle in the pool
     * before it is eligible for eviction by the idle object evictor
     * (if any).}
     *
     * *see #setMinEvictableIdleTimeMillis
     * *see #setTimeBetweenEvictionRunsMillis
     */
    public int getMinEvictableIdleTimeMillis() {
        return _minEvictableIdleTimeMillis;
    }

    /**
     * アイドル状態のオブジェクトがプール内に居られる最短時間を設定します。
     * この時間を過ぎるとアイドル状態のオブジェクトを排除するスレッドのチェック対象となります。
     * マイナスの値が設定された場合、アイドル状態で居た時間ではオブジェクトはプールから排除されません。
     * {@primary Sets the minimum amount of time a statement may sit idle in the pool
     * before it is eligable for eviction by the idle object evictor
     * (if any).
     * When non-positive, no objects will be evicted from the pool
     * due to idle time alone.}
     *
     * *see #getMinEvictableIdleTimeMillis
     * *see #setTimeBetweenEvictionRunsMillis
     */
    public void 
        setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
        assertInitializationAllowed();
        _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
    }

    /** Description */
    private String description;
    /** Password */
    private String password;
    /** Url name */
    private String url;
    /** User name */
    private String user;
    /** Driver class name */
    private String driver;

    /** Login TimeOut in seconds */
    private int loginTimeout;
    /** Log stream */
    private PrintWriter logWriter = null;

    // PreparedStatement pool properties
    private boolean poolPreparedStatements;
    private int maxActive = 10;
    private int maxIdle = 10;
    private int _timeBetweenEvictionRunsMillis = -1;
    private int _numTestsPerEvictionRun = -1;
    private int _minEvictableIdleTimeMillis = -1;

    private boolean getConnectionCalled = false;
}
