eu.peppol.persistence.jdbc.OxalisDataSourceFactoryDbcpImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.peppol.persistence.jdbc.OxalisDataSourceFactoryDbcpImpl.java

Source

/*
 * Copyright (c) 2010 - 2015 Norwegian Agency for Pupblic Government and eGovernment (Difi)
 *
 * This file is part of Oxalis.
 *
 * Licensed under the EUPL, Version 1.1 or  as soon they will be approved by the European Commission
 * - subsequent versions of the EUPL (the "Licence"); You may not use this work except in compliance with the Licence.
 *
 * You may obtain a copy of the Licence at:
 *
 * https://joinup.ec.europa.eu/software/page/eupl5
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the Licence
 *  is distributed on an "AS IS" basis,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licence for the specific language governing permissions and limitations under the Licence.
 *
 */

package eu.peppol.persistence.jdbc;

import eu.peppol.jdbc.OxalisDataSourceFactory;
import eu.peppol.persistence.RepositoryConfiguration;
import org.apache.commons.dbcp2.*;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.sql.DataSource;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Driver;
import java.util.Properties;

/**
 * Thread safe and singleton. I.e. will always return the same DataSource.
 *
 * @author steinar
 *         Date: 18.04.13
 *         Time: 13:28
 */
public class OxalisDataSourceFactoryDbcpImpl implements OxalisDataSourceFactory {

    public static final Logger log = LoggerFactory.getLogger(OxalisDataSourceFactoryDbcpImpl.class);
    private final RepositoryConfiguration configuration;

    private volatile DataSource dataSource;

    @Inject
    public OxalisDataSourceFactoryDbcpImpl(RepositoryConfiguration configuration) {
        this.configuration = configuration;
        log.info("DataSource being connected to " + configuration.getJdbcConnectionUri().toString());

    }

    @Override
    public DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (this) {
                if (dataSource == null) {
                    dataSource = configureAndCreateDataSource(configuration);
                }
            }
        }
        return dataSource;
    }

    @Override
    public boolean isProvidedWithOxalisDistribution() {
        // This is the one and only supplied as default.
        return true;
    }

    /**
     * Creates a DataSource with connection pooling as provided by Apache DBCP
     *
     * @return a DataSource
     */
    DataSource configureAndCreateDataSource(RepositoryConfiguration configuration) {

        log.debug("Configuring DataSource wrapped in a Database Connection Pool, using custom loader");

        String jdbcDriverClassPath = configuration.getJdbcDriverClassPath();

        log.debug("Loading JDBC Driver with custom class path: " + jdbcDriverClassPath);
        // Creates a new class loader, which will be used for loading our JDBC driver
        URLClassLoader urlClassLoader = getOxalisClassLoaderForJdbc(jdbcDriverClassPath);

        String className = configuration.getJdbcDriverClassName();
        String connectURI = configuration.getJdbcConnectionUri().toString();
        String userName = configuration.getJdbcUsername();
        String password = configuration.getJdbcPassword();

        log.debug("className=" + className);
        log.debug("connectURI=" + connectURI);
        log.debug("userName=" + userName);
        log.debug("password=" + password);

        // Loads the JDBC Driver in a separate class loader
        Driver driver = getJdbcDriver(jdbcDriverClassPath, urlClassLoader, className);

        Properties properties = new Properties();
        properties.put("user", userName);
        properties.put("password", password);

        // DBCP factory which will produce JDBC Driver instances
        ConnectionFactory driverConnectionFactory = new DriverConnectionFactory(driver, connectURI, properties);

        // DBCP Factory holding the pooled connection, which are created by the driver connection factory and held in the supplied pool
        ObjectName dataSourceJmxName = null;
        try {
            dataSourceJmxName = new ObjectName("no.difi.oxalis", "connectionPool", "OxalisDB");
        } catch (MalformedObjectNameException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
        PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(driverConnectionFactory,
                dataSourceJmxName);

        String validationQuery = configuration.getValidationQuery();
        if (validationQuery != null) {
            poolableConnectionFactory.setValidationQuery(validationQuery);
        }
        // DBCP object pool holding our driver connections
        GenericObjectPool<PoolableConnection> genericObjectPool = new GenericObjectPool<PoolableConnection>(
                poolableConnectionFactory);
        poolableConnectionFactory.setPool(genericObjectPool);
        genericObjectPool.setMaxTotal(100);
        genericObjectPool.setMaxIdle(30);
        genericObjectPool.setMaxWaitMillis(10000);

        genericObjectPool.setTestOnBorrow(true); // Test the connection returned from the pool

        genericObjectPool.setTestWhileIdle(true); // Test idle instances visited by the pool maintenance thread and destroy any that fail validation
        genericObjectPool.setTimeBetweenEvictionRunsMillis(60 * 60 * 1000); // Test every hour

        // Creates the actual DataSource instance
        PoolingDataSource poolingDataSource = new PoolingDataSource(genericObjectPool);

        return poolingDataSource;

    }

    private static Driver getJdbcDriver(String jdbcDriverClassPath, URLClassLoader urlClassLoader,
            String className) {
        Class<?> aClass = null;
        try {
            aClass = Class.forName(className, true, urlClassLoader);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Unable to locate class " + className + " in " + jdbcDriverClassPath);
        }
        Driver driver = null;
        try {
            driver = (Driver) aClass.newInstance();
        } catch (InstantiationException e) {
            throw new IllegalStateException("Unable to instantiate driver from class " + className, e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unable to access driver class " + className + "; " + e, e);
        }
        return driver;
    }

    private static URLClassLoader getOxalisClassLoaderForJdbc(String jdbcDriverClassPath) {
        URLClassLoader urlClassLoader = null;

        try {
            urlClassLoader = new URLClassLoader(new URL[] { new URL(jdbcDriverClassPath) },
                    Thread.currentThread().getContextClassLoader());
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("Invalid jdbc driver class path: '" + jdbcDriverClassPath
                    + "', check property oxalis.jdbc.class.path. Cause: " + e.getMessage(), e);
        }
        return urlClassLoader;
    }

}