/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
 *
 *    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;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.geotools.jdbc;

import static org.junit.Assert.assertEquals;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.geotools.data.jdbc.datasource.DBCPDataSource;
import org.geotools.data.jdbc.datasource.ManageableDataSource;

/**
 * Sets up the test harness for a database.
 *
 * <p>The responsibilities of the test harness are the following:
 *
 * <ol>
 *   <li>Create and configure the {@link DataSource} used to connect to the underlying database
 *   <li>Provide the dialect used to communicate with the underlying database
 *   <li>Populate the underlying database with the data used by the tests.
 * </ol>
 *
 * @author Justin Deoliveira, The Open Planning Project
 */
public abstract class JDBCTestSetup {
    static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(JDBCTestSetup.class);
    protected Properties fixture = null;
    private DataSource dataSource = null;

    public void setFixture(Properties fixture) {
        this.fixture = fixture;
    }

    /** @see {@link OnlineTestCase#createOfflineFixture} */
    protected Properties createOfflineFixture() {
        return null;
    }

    /** @see {@link OnlineTestCase#createExampleFixture} */
    protected Properties createExampleFixture() {
        return null;
    }

    public DataSource getDataSource() throws IOException {
        if (dataSource == null) dataSource = createDataSource();
        return dataSource;
    }

    public void setUp() throws Exception {
        //
    }

    protected void initializeDatabase() throws Exception {}

    protected void setUpData() throws Exception {}

    protected void setUpDataStore(JDBCDataStore dataStore) {}

    public void tearDown() throws Exception {
        final String leakMessage =
                "Expected no active connection, either there is a connection leak "
                        + "or you forgot to close some object holding onto connections in the tests (e.g., a reader, an iterator)";
        if (dataSource instanceof BasicDataSource) {
            BasicDataSource bds = (BasicDataSource) dataSource;
            assertEquals(leakMessage, 0, bds.getNumActive());
        } else if (dataSource instanceof DBCPDataSource) {
            BasicDataSource bds = (BasicDataSource) ((DBCPDataSource) dataSource).getWrapped();
            assertEquals(leakMessage, 0, bds.getNumActive());
        }

        if (dataSource instanceof BasicDataSource) {
            BasicDataSource bds = (BasicDataSource) dataSource;
            bds.close();
        } else if (dataSource instanceof ManageableDataSource) {
            ((ManageableDataSource) dataSource).close();
        }
    }

    /**
     * Runs an sql string aginst the database.
     *
     * @param input The sql.
     */
    protected void run(String input) throws Exception {
        run(new ByteArrayInputStream(input.getBytes()));
    }

    /** Executes {@link #run(String)} ignoring any exceptions. */
    protected void runSafe(String input) {
        try {
            run(input);
        } catch (Exception ignore) {
            ignore.printStackTrace(System.out);
        }
    }

    /**
     * Runs an sql script against the database.
     *
     * @param script Input stream to the sql script to run.
     */
    protected void run(InputStream script) throws Exception {
        // load the script andconnect
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(script));
                Connection conn = getConnection();
                Statement st = conn.createStatement()) {
            String line = null;

            while ((line = reader.readLine()) != null) {
                LOGGER.fine(line);
                st.execute(line);
            }
        }
    }

    /** Returns a properly initialized connection. It's up to the calling code to close it */
    protected Connection getConnection() throws SQLException, IOException {
        Connection conn = getDataSource().getConnection();
        JDBCDataStore store = null;
        try {
            store = new JDBCDataStore();
            createDataStoreFactory().createSQLDialect(store).initializeConnection(conn);
        } finally {
            if (store != null) {
                store.dispose();
            }
        }

        return conn;
    }

    /**
     * This method is used whenever referencing the name of a feature type / table name.
     *
     * <p>Subclasses should override this is in case where databases can not respect case properly
     * and need to force either upper or lower case.
     */
    protected String typeName(String raw) {
        return raw;
    }

    /**
     * This method is used whenever referencing the name of an attribute / column name.
     *
     * <p>Subclasses should override this is in case where databases can not respect case properly
     * and need to force either upper or lower case.
     */
    protected String attributeName(String raw) {
        return raw;
    }

    /**
     * Creates a data source by reading properties from a file called 'db.properties', located
     * paralell to the test setup instance.
     */
    protected DataSource createDataSource() throws IOException {
        Properties db = fixture;

        BasicDataSource dataSource = new BasicDataSource();

        dataSource.setDriverClassName(db.getProperty("driver"));
        dataSource.setUrl(db.getProperty("url"));

        if (db.containsKey("user")) {
            dataSource.setUsername(db.getProperty("user"));
        } else if (db.containsKey("username")) {
            dataSource.setUsername(db.getProperty("username"));
        }
        if (db.containsKey("password")) {
            dataSource.setPassword(db.getProperty("password"));
        }

        dataSource.setPoolPreparedStatements(true);
        dataSource.setAccessToUnderlyingConnectionAllowed(true);
        dataSource.setMinIdle(1);
        dataSource.setMaxActive(4);
        // if we cannot get a connection within 5 seconds give up
        dataSource.setMaxWait(5000);

        initializeDataSource(dataSource, db);

        // return a closeable data source (DisposableDataSource interface)
        // so that the connection pool will be tore down on datastore dispose
        return new DBCPDataSource(dataSource);
    }

    protected void initializeDataSource(BasicDataSource ds, Properties db) {}

    protected abstract JDBCDataStoreFactory createDataStoreFactory();

    protected final SQLDialect createSQLDialect(JDBCDataStore dataStore) {
        return null;
    }

    /**
     * Called after a test case has determined that a connection to the data source can be obtained.
     *
     * <p>This method is used for subclasses to make additional checks that determine if the test
     * case should be run or not. This method is only called if a connection can successfully be
     * made to the database.
     */
    public boolean shouldRunTests(Connection cx) throws SQLException {
        return true;
    }

    /**
     * Returns true if making the test run without a target schema is safe (normally is, but for
     * Oracle Enterprise for example, it is not)
     */
    public boolean canResetSchema() {
        return true;
    }
}

@@ -4045,16 +4045,19 @@
         
+ //
  ignore.

Revert unintended change to JDBCTestSetup logging