jeeves.resources.dbms.ApacheDBCPool.java Source code

Java tutorial

Introduction

Here is the source code for jeeves.resources.dbms.ApacheDBCPool.java

Source

//=============================================================================
//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
//=== and United Nations Environment Programme (UNEP)
//===
//===   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; either
//===   version 2.1 of the License, or (at your option) any later version.
//===
//===   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.
//===
//===   You should have received a copy of the GNU Lesser General Public
//===   License along with this library; if not, write to the Free Software
//===   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//===
//===   Contact: Jeroen Ticheler - GeoCat
//===   email: Jeroen.Ticheler@geocat.org
//==============================================================================

package jeeves.resources.dbms;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import jeeves.constants.Jeeves;

import jeeves.server.resources.Stats;
import org.apache.commons.dbcp.BasicDataSource;

import org.geotools.data.DataStore;

import org.geotools.data.postgis.PostgisNGDataStoreFactory;
import org.jdom.Element;

/**
 * @author sppigot
 * @author fxprunayre
 */

//=============================================================================

/**
 * A pool of database connections via Apache Commons DBC Pool.
 * Reads config params from web/geonetwork/WEB-INF/config.xml.
 */

public class ApacheDBCPool extends AbstractDbmsPool {

    private BasicDataSource basicDataSource;

    // --------------------------------------------------------------------------
    // ---
    // --- API
    // ---
    // --------------------------------------------------------------------------

    /**
     * Builds the pool using JNDI context or init parameters from jeeves config.
     */
    public void init(String name, Element config) throws Exception {

        parseJeevesDBConfig(config);

        setDataSource((DataSource) basicDataSource);
        setDataStore(createDataStore());
        debug(toString());
    }

    /**
     * Builds the pool using init parameters from jeeves config.
     */
    private void parseJeevesDBConfig(Element config) throws Exception {
        url = config.getChildText(Jeeves.Res.Pool.URL);

        String user = config.getChildText(Jeeves.Res.Pool.USER);
        String passwd = config.getChildText(Jeeves.Res.Pool.PASSWORD);
        String driver = config.getChildText(Jeeves.Res.Pool.DRIVER);
        String size = config.getChildText(Jeeves.Res.Pool.POOL_SIZE);
        String maxw = config.getChildText(Jeeves.Res.Pool.MAX_WAIT);
        String maxIdle = config.getChildText(Jeeves.Res.Pool.MAX_IDLE);
        String minIdle = config.getChildText(Jeeves.Res.Pool.MIN_IDLE);
        String maxActive = config.getChildText(Jeeves.Res.Pool.MAX_ACTIVE);
        String testWhileIdleStr = config.getChildText(Jeeves.Res.Pool.TEST_WHILE_IDLE);
        String timeBetweenEvictionRunsMillisStr = config
                .getChildText(Jeeves.Res.Pool.TIME_BETWEEN_EVICTION_RUNS_MILLIS);
        String minEvictableIdleTimeMillisStr = config.getChildText(Jeeves.Res.Pool.MIN_EVICTABLE_IDLE_TIME_MILLIS);
        String numTestsPerEvictionRunStr = config.getChildText(Jeeves.Res.Pool.NUM_TESTS_PER_EVICTION_RUN);
        String validationQuery = config.getChildText(Jeeves.Res.Pool.VALIDATION_QUERY);
        String transactionIsolation = config.getChildText(Jeeves.Res.Pool.TRANSACTION_ISOLATION);
        if (transactionIsolation == null) {
            // use READ_COMMITTED for everything by default except McKoi which 
            // only supports SERIALIZABLE 
            transactionIsolation = Jeeves.Res.Pool.TRANSACTION_ISOLATION_READ_COMMITTED;
            if (url.toUpperCase().contains("MCKOI"))
                transactionIsolation = Jeeves.Res.Pool.TRANSACTION_ISOLATION_SERIALIZABLE;
        } else {
            Set<String> isolations = new HashSet<String>();
            isolations.add(Jeeves.Res.Pool.TRANSACTION_ISOLATION_SERIALIZABLE);
            isolations.add(Jeeves.Res.Pool.TRANSACTION_ISOLATION_READ_COMMITTED);
            isolations.add(Jeeves.Res.Pool.TRANSACTION_ISOLATION_REPEATABLE_READ);

            if (!isolations.contains(transactionIsolation.toUpperCase())) {
                throw new IllegalArgumentException(
                        "Invalid " + Jeeves.Res.Pool.TRANSACTION_ISOLATION + " parameter value: "
                                + transactionIsolation + ". Should be one of " + isolations.toString());
            }
        }
        warning("Using transaction isolation setting " + transactionIsolation);

        this.name = url;

        int poolSize = (size == null) ? Jeeves.Res.Pool.DEF_POOL_SIZE : Integer.parseInt(size);
        int maxWait = (maxw == null) ? Jeeves.Res.Pool.DEF_MAX_WAIT : Integer.parseInt(maxw);

        // set maximum number of prepared statements in pool cache
        int iMaxOpen = getPreparedStatementCacheSize(config);

        boolean testWhileIdle = false;
        if (testWhileIdleStr != null) {
            testWhileIdle = testWhileIdleStr.equals("true");
        }

        long timeBetweenEvictionRunsMillis = -1;
        if (timeBetweenEvictionRunsMillisStr != null) {
            timeBetweenEvictionRunsMillis = Long.parseLong(timeBetweenEvictionRunsMillisStr);
        }

        long minEvictableIdleTimeMillis = 1000 * 60 * 30;
        if (minEvictableIdleTimeMillisStr != null) {
            minEvictableIdleTimeMillis = Long.parseLong(minEvictableIdleTimeMillisStr);
        }

        int numTestsPerEvictionRun = 3;
        if (numTestsPerEvictionRunStr != null) {
            numTestsPerEvictionRun = Integer.parseInt(numTestsPerEvictionRunStr);
        }

        // create the datasource 
        basicDataSource = new BasicDataSource();

        basicDataSource.setDriverClassName(driver);

        basicDataSource.setRemoveAbandoned(true);
        basicDataSource.setRemoveAbandonedTimeout(60 * 60);
        basicDataSource.setLogAbandoned(true);

        // configure the rest of the pool from params
        // http://commons.apache.org/dbcp/configuration.html
        if (maxActive != null) {
            basicDataSource.setMaxActive(Integer.parseInt(maxActive));
        } else {
            basicDataSource.setMaxActive(poolSize);
        }
        if (maxIdle != null) {
            basicDataSource.setMaxIdle(Integer.parseInt(maxIdle));
        } else {
            basicDataSource.setMaxIdle(poolSize);
        }
        if (minIdle != null) {
            basicDataSource.setMinIdle(Integer.parseInt(minIdle));
        } else {
            basicDataSource.setMinIdle(0);
        }
        basicDataSource.setMaxWait(maxWait);

        // always test connections when we get them from the pool    
        basicDataSource.setTestOnBorrow(true);

        // time between runs of idle evictor thread                  
        basicDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        // test idle connections                    
        basicDataSource.setTestWhileIdle(testWhileIdle);
        // let idle connections sit in there forever
        basicDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        // test all idle connections each run
        basicDataSource.setNumTestsPerEvictionRun(numTestsPerEvictionRun);

        // set maximum number of prepared statements in pool cache, if not set
        // then switch it off altogether
        if (iMaxOpen != -1) {
            basicDataSource.setPoolPreparedStatements(true);
            basicDataSource.setMaxOpenPreparedStatements(iMaxOpen);
        } else {
            basicDataSource.setPoolPreparedStatements(false);
            basicDataSource.setMaxOpenPreparedStatements(-1);
        }

        if (validationQuery != null && validationQuery.trim().length() > 0) {
            basicDataSource.setValidationQuery(validationQuery);
        }
        basicDataSource.setDefaultReadOnly(false);
        basicDataSource.setDefaultAutoCommit(false);

        basicDataSource.setUrl(url);
        basicDataSource.setUsername(user);
        basicDataSource.setPassword(passwd);

        basicDataSource.setInitialSize(poolSize);

    }

    // --------------------------------------------------------------------------

    public void end() {
        try {
            basicDataSource.close();
        } catch (java.sql.SQLException e) {
            error("Problem " + e);
            e.printStackTrace();
        }
    }

    // --------------------------------------------------------------------------

    public Map<String, String> getProps() {
        Map<String, String> result = new HashMap<String, String>();
        result.put("name", name);
        result.put("user", basicDataSource.getUsername());
        result.put("password", basicDataSource.getPassword());
        result.put("url", basicDataSource.getUrl());
        return result;
    }

    // --------------------------------------------------------------------------

    public Stats getStats() {
        return new Stats(basicDataSource.getNumActive(), basicDataSource.getNumIdle(),
                basicDataSource.getMaxActive());
    }

    //---------------------------------------------------------------------------

    public String toString() {
        StringBuffer sb = new StringBuffer();

        sb.append("------------------------------------------------------------------------------");
        sb.append('\n');
        sb.append("Created connection pool (" + this.name + ")");
        sb.append('\n');
        sb.append("MaxActive connections                 : " + basicDataSource.getMaxActive());
        sb.append('\n');
        sb.append("MaxIdle connections                   : " + basicDataSource.getMaxIdle());
        sb.append('\n');
        sb.append("MinIdle connections                   : " + basicDataSource.getMinIdle());
        sb.append('\n');
        sb.append("Maximum wait time connection (maxWait): " + basicDataSource.getMaxWait());
        sb.append('\n');
        sb.append("Test While Idle        (testWhileIdle): " + basicDataSource.getTestWhileIdle());
        sb.append('\n');
        sb.append("Time Between Eviction Runs (timeBetweenEvictionRunsMillis): "
                + basicDataSource.getTimeBetweenEvictionRunsMillis());
        sb.append('\n');
        sb.append("Minimum Evictable Idle Time (minEvictableIdleTimeMillis)  : "
                + basicDataSource.getMinEvictableIdleTimeMillis());
        sb.append('\n');
        sb.append("Number Connections Tested Per Eviction Run (numTestsPerEvictionRun) : "
                + basicDataSource.getNumTestsPerEvictionRun());
        sb.append('\n');
        sb.append("------------------------------------------------------------------------------");
        sb.append('\n');

        return sb.toString();
    }

    // --------------------------------------------------------------------------

    private DataStore createDataStore() throws Exception {
        Map<String, String> props = getProps();
        String url = props.get("url");
        String user = props.get("user");
        String passwd = props.get("password");
        String name = props.get("name");

        DataStore newDataStore = null;
        try {
            if (url.contains("postGIS")) {
                newDataStore = createPostgisDatastore(name, user, passwd, url);
            }
        } catch (Exception e) {
            error("Failed to create datastore for " + url + ". Will use shapefile instead.");
            error(e.getMessage());
            e.printStackTrace();
        }

        return newDataStore;
    }

    //---------------------------------------------------------------------------

    private DataStore createPostgisDatastore(String name, String user, String passwd, String url) throws Exception {

        String[] values = url.split("/");

        DataStore newDataStore = null;

        Map<String, Object> params = new HashMap<String, Object>();
        params.put(PostgisNGDataStoreFactory.DBTYPE.key, PostgisNGDataStoreFactory.DBTYPE.sample);
        params.put(PostgisNGDataStoreFactory.DATABASE.key, getDatabase(url, values));
        params.put(PostgisNGDataStoreFactory.USER.key, user);
        params.put(PostgisNGDataStoreFactory.PASSWD.key, passwd);
        params.put(PostgisNGDataStoreFactory.HOST.key, getHost(url, values));
        params.put(PostgisNGDataStoreFactory.PORT.key, getPort(url, values));
        params.put(PostgisNGDataStoreFactory.EXPOSE_PK.key, false);

        PostgisNGDataStoreFactory factory = new PostgisNGDataStoreFactory();
        newDataStore = factory.createDataStore(params);
        if (newDataStore != null)
            info("NOTE: Using POSTGIS for spatial index");

        return newDataStore;
    }

    //---------------------------------------------------------------------------

    private String getDatabase(String url, String[] values) throws Exception {
        if (url.contains("postGIS")) {
            return values[3];
        } else {
            throw new Exception("Unknown database in url " + url);
        }
    }

    //---------------------------------------------------------------------------

    private String getHost(String url, String[] values) throws Exception {
        if (url.contains("postGIS")) {
            String value = values[2];
            return value.substring(0, value.indexOf(':'));
        } else {
            throw new Exception("Unknown database in url " + url);
        }
    }

    //---------------------------------------------------------------------------

    private String getPort(String url, String values[]) throws Exception {
        if (url.contains("postGIS")) {
            String value = values[2];
            return value.substring(value.indexOf(':') + 1);
        } else {
            throw new Exception("Unknown database in url " + url);
        }
    }

}

// =============================================================================