/*                          
 * mBench: The Open Source Micro Benchmark Tool 
 *                                             
 * Distributable under GPL license. 
 * See terms of license at gnu.org.                 
 *
 * Copyright (C) 2005 Sumisho Computer Systems Corp.
 */
package jp.co.scs.mbench.jdbc;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.sql.DataSource;

import jp.co.scs.mbench.DocumentUtil;

/**
 *      JDBC 2.0 DataSource Implementation class
 * 
 *      @author Tetsuro Ikeda
 */
public class DataSourceImpl implements DataSource {

    private int loginTimeout = 0;
    
    private PrintWriter logWriter = null;
    
    private String dataSourceName = null;
    
    private DataSourceInfo info = null;
    
    private String url = null;
    
    public DataSourceImpl(String dataSourceName) {
        this.dataSourceName = dataSourceName;
    }
    
    public int getLoginTimeout() {
        return this.loginTimeout;
    }

    public void setLoginTimeout(int seconds) {
        this.loginTimeout = seconds;
    }

    public PrintWriter getLogWriter() {
        return this.logWriter;
    }

    public void setLogWriter(PrintWriter out) {
        this.logWriter = out;
    }

    public Connection getConnection() throws SQLException {
        return getConnection(this.info.getUser(), this.info.getPassword()); 
    }

    public Connection getConnection(final String username, final String password)
            throws SQLException {
        if (this.loginTimeout == 0) {
            return DriverManager.getConnection(this.url, username, password);
            
        } else {
            Connection con = null;
            class InnerClass extends Thread {
                private boolean isTimeout = false;
                private Connection con = null;
                private String url = null;
                public InnerClass(Connection con, String url) {
                    this.con = con;
                    this.url = url;
                }
                public void setIsTimeout(boolean isTimeout) {
                    this.isTimeout = isTimeout;
                }
                public void run() {
                    try {
                        this.con = DriverManager.
                            getConnection(this.url, username, password);
                        if (this.isTimeout) {
                            this.con.close();
                        }
                    } catch (SQLException ex) {
                        ex.printStackTrace();
                    }
                }
            };
            InnerClass innerClass = new InnerClass(con, this.url);
            innerClass.start();
            try {
                innerClass.join(this.loginTimeout * 1000);
            } catch (InterruptedException e) {
                // ignore
            }
            if (con == null) {
                innerClass.setIsTimeout(true);
                throw new SQLException(
                    "timeout : " + this.loginTimeout + " sec");
            } else {
                return con;
            }
        }
    }
    
    /**
     *  Initialize this data source.
     *  dataSourceName must be set before calling this method.
     */
    public void initialize() {
        try {
            this.info = DocumentUtil.getDataSourceInfo(this.dataSourceName);
            
            Class.forName(this.info.getDriver());
            if (this.info.getProtocol() == null) {
                throw new IllegalArgumentException("protocol is null");
            }
            if (this.info.getDriver() == null) {
                throw new IllegalArgumentException("JDBC Driver name is null");
            }
            if (this.info.getHost() == null) {
                throw new IllegalArgumentException("host is null");
            }
            if (this.info.getDB() == null) {
                throw new IllegalArgumentException("database instance name is null");
            }
            if (!this.info.getPort().equals("")) {
                info.setPort(":" + info.getPort());
            }
            String encoding = null;
            if (!this.info.getCharacterEncoding().equals("")) {
                encoding = "&characterEncoding=" + this.info.getCharacterEncoding();
            }
            
            this.url = "jdbc:" + info.getProtocol() + "://" + info.getHost()
                + info.getPort() + "/" + info.getDB() + "?" + info.getUseUnicode() + encoding; 
            
        } catch (ClassNotFoundException ex) {
            throw new IllegalArgumentException(
                "JDBC Driver name or CLASSPATH is wrong");
        } catch (RuntimeException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new RuntimeException(
                "exception caused by getting DataSourceInfo named :"
                + this.dataSourceName + " , dataSource setting might be wrong");
        }
    }
}
