/*
 * $Header: /home/cvs/commons/dbcp-1.0/ja/src/org/apache/commons/dbcp/AbandonedTrace.java,v 1.1.1.1 2004/02/13 10:02:03 hioki Exp $
 * $Revision: 1.1.1.1 $
 * $Date: 2004/02/13 10:02:03 $ 
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-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 acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Commons", and "Apache Software
 *    Foundation" 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"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * 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/>.
 *
 */
package org.apache.commons.dbcp;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * データベースコネクションを回復するために追跡し、破棄されたデータベースコネクションの情報をレポートします。
 * (このパッケージの) JDBC Connection、Statement、ResultSet クラスはこのクラスを継承します。
 * {@primary Tracks db connection usage for recovering and reporting
 * abandoned db connections.
 *
 * The JDBC Connection, Statement, and ResultSet classes
 * extend this class.}
 * 
 * @author Glenn L. Nielsen
 * @translator 日置 聡
 * @status firstdraft
 * @update 2003/09/13
 * @version $Revision: 1.1.1.1 $ $Date: 2004/02/13 10:02:03 $
 */
public class AbandonedTrace {

    private static SimpleDateFormat format = new SimpleDateFormat
        ("'DBCP object created' yyyy-mm-dd HH:mm:ss " +
         "'by the following code was never closed:'");

    // DBCP AbandonedConfig
    private AbandonedConfig config = null;
    // Parent object
    private AbandonedTrace parent;
    // A stack trace of the code that created me (if in debug mode) **/
    private Exception createdBy;
    private Date createdDate;
    // A list of objects created by children of this object
    private List trace = new ArrayList();
    // Last time this connection was used
    private long lastUsed = 0;

    /**
     * 設定情報なしで、破棄された情報のトレースを行わない新たな AbandonedTrace を生成します。
     * {@primary Create a new AbandonedTrace without config and
     * without doing abandoned tracing.}
     */
    public AbandonedTrace() {
        init(parent);
    }

    /**
     * 親となるオブジェクトを持たない新たな AbandonedTrace を生成します。
     * {@primary Construct a new AbandonedTrace with no parent object.}
     *
     * @param config
     */
    public AbandonedTrace(AbandonedConfig config) {
        this.config = config;
        init(parent);
    }

    /**
     * 親となるオブジェクトを持つ新たな AbandonedTrace を生成します。
     * {@primary Construct a new AbandonedTrace with a parent object.}
     *
     * @param parent 親となるオブジェクト
     * {@primary parent object}
     */
    public AbandonedTrace(AbandonedTrace parent) {
        this.config = parent.getConfig();
        init(parent);
    }

    /**
     * このオブジェクトの破棄された情報のトレース処理を初期化します。
     * {@primary Initialize abandoned tracing for this object.}
     *
     * @param parent 親となるオブジェクト
     * {@primary parent object}
     */
    private void init(AbandonedTrace parent) {
        if (parent != null) {                  
            parent.addTrace(this);
        }

        if (config == null) {
            return;
        }
        if (config.getLogAbandoned()) {
            createdBy = new Exception();
            createdDate = new Date();
        }
    }

    /**
     * このオブジェクトの破棄された情報のトレース設定を取得します。
     * {@primary Get the abandoned config for this object.}
     *
     * @return このオブジェクトの AbandonedConfig。
     * {@primary AbandonedConfig for this object}
     */
    protected AbandonedConfig getConfig() {
        return config;
    }

    /**
     * このオブジェクトが最後に使用された時刻(ミリセカンド)を取得します。
     * {@primary Get the last time this object was used in ms.}
     *
     * @return 時刻(ミリセカンド)の long 値
     * {@primary long time in ms}
     */
    protected long getLastUsed() {
        if (parent != null) {     
           return parent.getLastUsed();  
        }
        return lastUsed;
    }

    /**
     * このオブジェクトが最後に使用された時刻(ミリセカンド)に現在の時刻を設定します。
     * {@primary Set the time this object was last used to the
     * current time in ms.}
     */
    protected void setLastUsed() {
        if (parent != null) {
           parent.setLastUsed();
        } else {
           lastUsed = new Date().getTime();
        }
    }

    /**
     * このオブジェクトが最後に使用された時刻(ミリセカンド)を設定します。
     * {@primary Set the time in ms this object was last used.}
     *
     * @param time 時刻(ミリセカンド)
     * {@primary time in ms}
     */
    protected void setLastUsed(long time) {
        if (parent != null) {
           parent.setLastUsed(time);
        } else {   
           lastUsed = time;
        }
    }

    /**
     * logAbandoned=true の場合、このオブジェクトのスタックトレースを生成し、このオブジェクトを親オブジェクトのトレースリストに追加します。
     * {@primary If logAbandoned=true generate a stack trace
     * for this object then add this object to the parent
     * object trace list.}
     */
    protected void setStackTrace() {
        if (config == null) {                 
            return;                           
        }                    
        if (config.getLogAbandoned()) {
            createdBy = new Exception();
            createdDate = new Date();
        }
        if (parent != null) {                  
            parent.addTrace(this);
        }
    }

    /**
     * トレースされるオブジェクトのリストにオブジェクトを追加します。
     * {@primary Add an object to the list of objects being
     * traced.}
     *
     * @param trace 追加するオブジェクト
     * {@primary object to add}
     */
    protected synchronized void addTrace(AbandonedTrace trace) {
        this.trace.add(trace);
        setLastUsed();
    }

    /**
     * このオブジェクトにトレースされるオブジェクトのリストをクリアします。
     * {@primary Clear the list of objects being traced by this
     * object.}
     */
    protected synchronized void clearTrace() {
        if (trace != null) {
            trace.clear();
        }
    }

    /**
     * このオブジェクトにトレースされるオブジェクトのリストを取得します。
     * {@primary Get a list of objects being traced by this object.}
     *
     * @return オブジェクトのリスト
     * {@primary List of objects}
     */
    protected List getTrace() {
        return trace;
    }

    /**
     * logAbandoned=true の場合、このオブジェクトの生成したコードのスタックトレースを出力します。
     * {@primary If logAbandoned=true, print a stack trace of the code that
     * created this object.}
     */
    public synchronized void printStackTrace() {
        if (createdBy != null) {
            System.out.println(format.format(createdDate));
            createdBy.printStackTrace();
        }
        Iterator it = trace.iterator();
        while (it.hasNext()) {
            AbandonedTrace at = (AbandonedTrace)it.next();
            at.printStackTrace();
        }
    }

    /**
     * このオブジェクトがトレースしている子オブジェクトを削除します。
     * {@primary Remove a child object this object is tracing.}
     *
     * @param trace 削除するオブジェクト
     * {@primary object to remvoe}
     */
    protected synchronized void removeTrace(AbandonedTrace trace) {
        if (this.trace != null) {
            this.trace.remove(trace);
        }
    }

}
