org.geotools.jdbc.JDBCTestSetup.java Source code

Java tutorial

Introduction

Here is the source code for org.geotools.jdbc.JDBCTestSetup.java

Source

/*
 *    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 junit.framework.Assert.*;

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;
import org.geotools.test.OnlineTestCase;

/**
 * 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>
 * </p>
 *
 * @author Justin Deoliveira, The Open Planning Project
 *
 *
 *
 *
 * @source $URL$
 */
public abstract class JDBCTestSetup {
    static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.jdbc");
    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
        BufferedReader reader = new BufferedReader(new InputStreamReader(script));

        //connect
        Connection conn = getConnection();

        try {
            Statement st = conn.createStatement();

            try {
                String line = null;

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

                reader.close();
            } finally {
                st.close();
            }
        } finally {
            conn.close();
        }
    }

    /**
     * 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();
        createDataStoreFactory().createSQLDialect(new JDBCDataStore()).initializeConnection(conn);
        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. 
     * </p>
     *
     */
    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. 
     * </p>
     */
    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.</p>
     */
    public boolean shouldRunTests(Connection cx) throws SQLException {
        return true;
    }
}