org.lib4j.dbcp.DataSources.java Source code

Java tutorial

Introduction

Here is the source code for org.lib4j.dbcp.DataSources.java

Source

/* Copyright (c) 2008 lib4j
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * You should have received a copy of The MIT License (MIT) along with this
 * program. If not, see <http://opensource.org/licenses/MIT/>.
 */

package org.lib4j.dbcp;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.commons.dbcp2.BasicDataSource;
import org.lib4j.dbcp_2_0_4.Dbcp;
import org.lib4j.logging.LoggerPrintWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import org.xml.sax.SAXException;

public final class DataSources {
    private static final String INDEFINITE = "INDEFINITE";
    private static Schema schema;

    /**
     * Create a <code>BasicDataSource</code> given a dbcp JAXB binding.
     * <code>ClassLoader.getSystemClassLoader()</code> is used as the <code>driverClassLoader</code> parameter.
     *
     * @param dbcpXml URL of dbcp xml resource.
     * @return the <code>BasicDataSource</code> instance.
     * @throws SAXException If a XML validation error occurs.
     * @throws SQLException If a database access error occurs.
     * @throws IOException If an IO exception occurs.
     */
    public static BasicDataSource createDataSource(final URL dbcpXml)
            throws IOException, SAXException, SQLException {
        return createDataSource(dbcpXml, ClassLoader.getSystemClassLoader());
    }

    /**
     * Create a <code>BasicDataSource</code> given a dbcp JAXB binding.
     *
     * @param dbcpXml URL of dbcp xml resource.
     * @param driverClassLoader Class loader to be used to load the JDBC driver.
     * @return the <code>BasicDataSource</code> instance.
     * @throws SAXException If a XML validation error occurs.
     * @throws SQLException If a database access error occurs.
     * @throws IOException If an IO exception occurs.
     */
    public static BasicDataSource createDataSource(final URL dbcpXml, final ClassLoader driverClassLoader)
            throws IOException, SAXException, SQLException {
        try {
            final Unmarshaller unmarshaller = JAXBContext.newInstance(Dbcp.class).createUnmarshaller();
            unmarshaller
                    .setSchema(
                            DataSources.schema == null
                                    ? DataSources.schema = SchemaFactory
                                            .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
                                            .newSchema(Thread.currentThread().getContextClassLoader()
                                                    .getResource("dbcp.xsd"))
                                    : DataSources.schema);

            try (final InputStream in = dbcpXml.openStream()) {
                final JAXBElement<Dbcp> element = unmarshaller
                        .unmarshal(XMLInputFactory.newInstance().createXMLStreamReader(in), Dbcp.class);
                return createDataSource(element.getValue(), driverClassLoader);
            }
        } catch (final FactoryConfigurationError e) {
            throw new UnsupportedOperationException(e);
        } catch (final JAXBException | XMLStreamException e) {
            throw new SAXException(e);
        }
    }

    /**
     * Create a <code>BasicDataSource</code> given a list of dbcp XSB bindings.
     * <code>ClassLoader.getSystemClassLoader()</code> is used as the <code>driverClassLoader</code> parameter.
     *
     * @param dbcp JAXB dbcp binding.
     * @param name The name of the pool to create. (The name is declared in the list of <code>dbcps</code>).
     * @return the <code>BasicDataSource</code> instance.
     * @throws SQLException If a database access error occurs.
     */
    public static BasicDataSource createDataSource(final List<Dbcp> dbcps, final String name) throws SQLException {
        return createDataSource(dbcps, name, ClassLoader.getSystemClassLoader());
    }

    /**
     * Create a <code>BasicDataSource</code> given a list of dbcp XSB bindings.
     *
     * @param dbcp JAXB dbcp binding.
     * @param name The name of the pool to create. (The name is declared in the list of <code>dbcps</code>).
     * @param driverClassLoader Class loader to be used to load the JDBC driver.
     * @return the <code>BasicDataSource</code> instance.
     * @throws SQLException If a database access error occurs.
     */
    public static BasicDataSource createDataSource(final List<Dbcp> dbcps, final String name,
            final ClassLoader driverClassLoader) throws SQLException {
        for (final Dbcp dbcp : dbcps)
            if (name.equals(dbcp.getName()))
                return createDataSource(dbcp, driverClassLoader);

        return null;
    }

    /**
     * Create a <code>BasicDataSource</code> given a dbcp JAXB binding.
     *
     * @param dbcp JAXB dbcp binding.
     * @return the <code>BasicDataSource</code> instance.
     * @throws SQLException If a database access error occurs.
     */
    public static BasicDataSource createDataSource(final Dbcp dbcp) throws SQLException {
        return createDataSource(dbcp, ClassLoader.getSystemClassLoader());
    }

    /**
     * Create a <code>BasicDataSource</code> given a dbcp JAXB binding.
     *
     * @param dbcp JAXB dbcp binding.
     * @param driverClassLoader Class loader to be used to load the JDBC driver.
     * @return the <code>BasicDataSource</code> instance.
     * @throws SQLException If a database access error occurs.
     */
    public static BasicDataSource createDataSource(final Dbcp dbcp, final ClassLoader driverClassLoader)
            throws SQLException {
        final BasicDataSource dataSource = new BasicDataSource();

        final Dbcp.Jdbc jdbc = dbcp.getJdbc();
        dataSource.setDriverClassName(jdbc.getDriverClassName());
        dataSource.setDriverClassLoader(driverClassLoader);

        dataSource.setUrl(jdbc.getUrl());

        dataSource.setUsername(jdbc.getUsername());
        dataSource.setPassword(jdbc.getPassword());

        final Dbcp.Default _default = dbcp.getDefault();
        if (_default != null && _default.getCatalog() != null)
            dataSource.setDefaultCatalog(_default.getCatalog());

        dataSource.setDefaultAutoCommit(
                _default == null || _default.getAutoCommit() == null || _default.getAutoCommit());
        dataSource.setDefaultReadOnly(_default != null && _default.getReadOnly() != null && _default.getReadOnly());
        if (_default != null && _default.getQueryTimeout() != null)
            dataSource.setDefaultQueryTimeout(_default.getQueryTimeout());

        if (_default != null && _default.getTransactionIsolation() != null) {
            if ("NONE".equals(_default.getTransactionIsolation()))
                dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_NONE);
            else if ("READ_COMMITTED".equals(_default.getTransactionIsolation()))
                dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
            else if ("READ_UNCOMMITTED".equals(_default.getTransactionIsolation()))
                dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
            else if ("REPEATABLE_READ".equals(_default.getTransactionIsolation()))
                dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            else if ("SERIALIZABLE".equals(_default.getTransactionIsolation()))
                dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
            else
                throw new UnsupportedOperationException(
                        "Unsupported transaction isolation: " + _default.getTransactionIsolation());
        }

        final Dbcp.Connection connection = dbcp.getConnection();
        if (connection != null) {
            if (connection.getProperties() != null)
                for (final Dbcp.Connection.Properties.Property property : connection.getProperties().getProperty())
                    if (property.getName() != null && property.getValue() != null)
                        dataSource.addConnectionProperty(property.getName(), property.getValue());

            if (connection.getInitSqls() != null) {
                final List<String> initSqls = new ArrayList<>();
                for (final String initSql : connection.getInitSqls().getInitSql())
                    initSqls.add(initSql);

                dataSource.setConnectionInitSqls(initSqls);
            }
        }

        final Dbcp.Size size = dbcp.getSize();
        dataSource.setInitialSize(size == null || size.getInitialSize() == null ? 0 : size.getInitialSize());
        dataSource.setMaxTotal(size == null || size.getMaxTotal() == null ? 8
                : INDEFINITE.equals(size.getMaxTotal()) ? -1 : Integer.parseInt(size.getMaxTotal()));
        dataSource.setMaxIdle(size == null || size.getMaxIdle() == null ? 8
                : INDEFINITE.equals(size.getMaxIdle()) ? -1 : Integer.parseInt(size.getMaxIdle()));
        dataSource.setMinIdle(size == null || size.getMinIdle() == null ? 9 : size.getMinIdle());
        if (size == null || size.getMaxOpenPreparedStatements() == null
                || INDEFINITE.equals(size.getMaxOpenPreparedStatements())) {
            dataSource.setPoolPreparedStatements(false);
        } else {
            dataSource.setPoolPreparedStatements(true);
            dataSource.setMaxOpenPreparedStatements(Integer.parseInt(size.getMaxOpenPreparedStatements()));
        }

        final Dbcp.Pool pool = dbcp.getPool();
        if (pool == null || pool.getQueue() == null || "lifo".equals(pool.getQueue()))
            dataSource.setLifo(true);
        else if ("fifo".equals(pool.getQueue()))
            dataSource.setLifo(false);
        else
            throw new UnsupportedOperationException("Unsupported queue spec: " + pool.getQueue());

        dataSource.setCacheState(pool != null && pool.getCacheState() != null && pool.getCacheState());
        dataSource.setMaxWaitMillis(
                pool == null || pool.getMaxWait() != null || INDEFINITE.equals(pool.getMaxWait()) ? -1
                        : Long.parseLong(pool.getMaxWait()));
        dataSource.setMaxConnLifetimeMillis(pool == null || pool.getMaxConnectionLifetime() == null
                || INDEFINITE.equals(pool.getMaxConnectionLifetime()) ? 0
                        : Long.parseLong(pool.getMaxConnectionLifetime()));
        dataSource.setEnableAutoCommitOnReturn(_default == null || pool.getEnableAutoCommitOnReturn() == null
                || pool.getEnableAutoCommitOnReturn());
        dataSource.setRollbackOnReturn(
                pool == null || pool.getRollbackOnReturn() == null || pool.getRollbackOnReturn());
        if (pool != null && pool.getRemoveAbandoned() != null) {
            if ("borrow".equals(pool.getRemoveAbandoned().getOn()))
                dataSource.setRemoveAbandonedOnBorrow(true);
            else if ("maintenance".equals(pool.getRemoveAbandoned().getOn()))
                dataSource.setRemoveAbandonedOnMaintenance(true);
            else
                throw new UnsupportedOperationException(
                        "Unsupported remove abandoned spec: " + pool.getRemoveAbandoned().getOn());

            dataSource.setRemoveAbandonedTimeout(pool.getRemoveAbandoned().getTimeout());
        }

        dataSource.setAbandonedUsageTracking(
                pool != null && pool.getAbandonedUsageTracking() != null && pool.getAbandonedUsageTracking());
        dataSource.setAccessToUnderlyingConnectionAllowed(
                pool != null && pool.getAllowAccessToUnderlyingConnection() != null
                        && pool.getAllowAccessToUnderlyingConnection());

        final Dbcp.Pool.Eviction evictor = pool != null && pool.getEviction() != null ? pool.getEviction() : null;
        if (evictor != null) {
            dataSource.setTimeBetweenEvictionRunsMillis(evictor.getTimeBetweenRuns());
            dataSource.setNumTestsPerEvictionRun(evictor.getNumTestsPerRun());
            dataSource.setMinEvictableIdleTimeMillis(
                    evictor.getMinIdleTime() == null ? 1800000 : evictor.getMinIdleTime());
            dataSource.setSoftMinEvictableIdleTimeMillis(
                    evictor.getSoftMinIdleTime() == null || INDEFINITE.equals(evictor.getSoftMinIdleTime()) ? -1
                            : Long.parseLong(evictor.getSoftMinIdleTime()));
            if (evictor.getPolicyClassName() != null)
                dataSource.setEvictionPolicyClassName(evictor.getPolicyClassName());
        }

        final Dbcp.Validation validation = dbcp.getValidation();
        if (validation != null && validation.getQuery() != null)
            dataSource.setValidationQuery(validation.getQuery());

        dataSource.setTestOnBorrow(
                validation == null || validation.getTestOnBorrow() == null || validation.getTestOnBorrow());
        dataSource.setTestOnReturn(
                validation != null && validation.getTestOnReturn() != null && validation.getTestOnReturn());
        dataSource.setTestWhileIdle(
                validation != null && validation.getTestWhileIdle() != null && validation.getTestWhileIdle());
        if (validation != null && validation.getFastFail() != null) {
            dataSource.setFastFailValidation(true);
            if (validation.getFastFail().getDisconnectionSqlCodes() != null)
                dataSource.setDisconnectionSqlCodes(
                        Arrays.asList(validation.getFastFail().getDisconnectionSqlCodes().split(" ")));
        }

        final Dbcp.Logging logging = dbcp.getLogging();
        if (logging != null) {
            final Logger logger = LoggerFactory.getLogger(DataSources.class);
            final LoggerPrintWriter loggerPrintWriter = new LoggerPrintWriter(logger,
                    Level.valueOf(logging.getLevel().toString()));
            dataSource.setLogWriter(loggerPrintWriter);
            dataSource.setLogExpiredConnections(logging.isLogExpiredConnections());
            if (logging.isLogAbandoned()) {
                dataSource.setAbandonedLogWriter(loggerPrintWriter);
                dataSource.setLogAbandoned(true);
            }
        }

        return dataSource;
    }

    private DataSources() {
    }
}