edu.utah.further.core.data.service.ConfigurableBasicDataSource.java Source code

Java tutorial

Introduction

Here is the source code for edu.utah.further.core.data.service.ConfigurableBasicDataSource.java

Source

/**
 * Copyright (C) [2013] [The FURTHeR Project]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.utah.further.core.data.service;

import static edu.utah.further.core.api.message.Messages.unsupportedOperationMessage;
import static edu.utah.further.core.api.text.ToStringCustomStyles.SHORT_WITH_SPACES_STYLE;
import static edu.utah.further.core.util.io.ClasspathUtil.getThreadClassLoader;
import static org.slf4j.LoggerFactory.getLogger;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;

import edu.utah.further.core.api.context.Named;
import edu.utah.further.core.api.exception.ApplicationException;

/**
 * A wrapper around a {@link BasicDataSource} that allows easy configuration from a
 * properties file, whose format looks like that (properties' names should be exactly the
 * way they are below, values will change, of course, depending on your case):
 * <blockquote>
 * 
 * <pre>
 * datasource.url=jdbc:hsqldb:mem:cs
 * datasource.driver=org.hsqldb.jdbcDriver
 * datasource.user=sa
 * datasource.password=
 * # SQL implementation Hibernate dialect
 * hibernate.dialect=org.hibernate.dialect.HSQLDialect
 * </pre>
 * 
 * </blockquote>
 * <p>
 * -----------------------------------------------------------------------------------<br>
 * (c) 2008-2013 FURTHeR Project, Health Sciences IT, University of Utah<br>
 * Contact: {@code <further@utah.edu>}<br>
 * Biomedical Informatics, 26 South 2000 East<br>
 * Room 5775 HSEB, Salt Lake City, UT 84112<br>
 * Day Phone: 1-801-581-4080<br>
 * -----------------------------------------------------------------------------------
 * 
 * @author Oren E. Livne {@code <oren.livne@utah.edu>}
 * @version Oct 24, 2008
 */
// May need to unfinalize if will be using Spring DI or proxies on this class in the
// future
public final class ConfigurableBasicDataSource implements DataSource, Named {
    // ========================= CONSTANTS =================================

    /**
     * A logger that helps identify this class' printouts.
     */
    private static final Logger log = getLogger(ConfigurableBasicDataSource.class);

    /**
     * Default data source name.
     */
    private static final String DEFAULT_NAME = "Configurable Data Source";

    /**
     * Centralizes properties names used by this bean.
     */
    private static abstract class PROPERTIES {
        private static String PREFIX = "datasource.";
        static String URL = PREFIX + "url";
        static String DRIVER = PREFIX + "driver";
        static String USER = PREFIX + "user";
        static String PASSWORD = PREFIX + "password";
    }

    // ========================= FIELDS ====================================

    /**
     * The output set of annotated classes.
     */
    private final BasicDataSource dataSource;

    /**
     * An optional name of this data source.
     */
    private String name = DEFAULT_NAME;

    // ========================= CONSTRUCTORS ==============================

    /**
     * Construct a wrapped data source.
     * 
     * @param basicDataSource
     *            data source managed internally
     */
    public ConfigurableBasicDataSource(final BasicDataSource basicDataSource) {
        super();
        this.dataSource = basicDataSource;
    }

    // ========================= IMPLEMENTATION: Object ====================

    /**
     * @return
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return new ToStringBuilder(this, SHORT_WITH_SPACES_STYLE).append("name", getName()).append("url", getUrl())
                .append("driver", getDriverClassName()).append("username", getUsername()).toString();
    }

    // ========================= IMPLEMENTATION: Named =====================

    /**
     * @return
     * @see edu.utah.further.core.api.context.Named#getName()
     */
    @Override
    public String getName() {
        return name;
    }

    // ========================= IMPLEMENTATION: BasicDataSource ===========

    /**
     * @param propertyName
     * @param propertyValue
     * @see org.apache.commons.dbcp.BasicDataSource#addConnectionProperty(java.lang.String,
     *      java.lang.String)
     */
    public void addConnectionProperty(final String propertyName, final String propertyValue) {
        dataSource.addConnectionProperty(propertyName, propertyValue);
    }

    /**
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#close()
     */
    public void close() throws SQLException {
        dataSource.close();
    }

    /**
     * @return
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#getConnection()
     */
    @Override
    public Connection getConnection() throws SQLException {
        // Work around Oracle MBean initialization bug.
        // @see
        // http://www.robert-stupp.de/blog/2008/01/oracle_malicious_11g_data_source_implementation.html
        // -- we only implement an error-swallow instead, because it seems that the
        // returned connection from dataSource.getConnection() is fine.
        try {
            if (log.isWarnEnabled()) {
                log.trace(
                        "Note: if this is an oracle driver, it may throw and error after this line that can be ignored.");
            }
            return dataSource.getConnection();
        } catch (final Throwable e) {
            if (log.isInfoEnabled()) {
                log.info(
                        "Driver threw an error. If this is an oracle driver, it may be a bug in the oracle JDBC client that is ignored here as the connection is usually fine nevertheless.");
                final String loader = getThreadClassLoader().toString();
                log.info("Current thread class loader toString() returns: " + loader);
                log.info("Error message: " + e.getMessage());
            }
            return dataSource.getConnection();
        }
    }

    /**
     * @param username
     * @param password
     * @return
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#getConnection(java.lang.String,
     *      java.lang.String)
     */
    @Override
    public Connection getConnection(final String username, final String password) throws SQLException {
        return dataSource.getConnection(username, password);
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getDefaultAutoCommit()
     */
    public boolean getDefaultAutoCommit() {
        return dataSource.getDefaultAutoCommit();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getDefaultReadOnly()
     */
    public boolean getDefaultReadOnly() {
        return dataSource.getDefaultReadOnly();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getDefaultTransactionIsolation()
     */
    public int getDefaultTransactionIsolation() {
        return dataSource.getDefaultTransactionIsolation();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getDriverClassName()
     */
    public String getDriverClassName() {
        return dataSource.getDriverClassName();
    }

    /**
     * @return
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#getLoginTimeout()
     */
    @Override
    public int getLoginTimeout() throws SQLException {
        return dataSource.getLoginTimeout();
    }

    /**
     * @return
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#getLogWriter()
     */
    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return dataSource.getLogWriter();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getMaxActive()
     */
    public int getMaxActive() {
        return dataSource.getMaxActive();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getMaxIdle()
     */
    public int getMaxIdle() {
        return dataSource.getMaxIdle();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getMaxWait()
     */
    public long getMaxWait() {
        return dataSource.getMaxWait();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getMinEvictableIdleTimeMillis()
     */
    public long getMinEvictableIdleTimeMillis() {
        return dataSource.getMinEvictableIdleTimeMillis();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getMinIdle()
     */
    public int getMinIdle() {
        return dataSource.getMinIdle();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getNumActive()
     */
    public int getNumActive() {
        return dataSource.getNumActive();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getNumIdle()
     */
    public int getNumIdle() {
        return dataSource.getNumIdle();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getNumTestsPerEvictionRun()
     */
    public int getNumTestsPerEvictionRun() {
        return dataSource.getNumTestsPerEvictionRun();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getPassword()
     */
    public String getPassword() {
        return dataSource.getPassword();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getTestOnBorrow()
     */
    public boolean getTestOnBorrow() {
        return dataSource.getTestOnBorrow();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getTestOnReturn()
     */
    public boolean getTestOnReturn() {
        return dataSource.getTestOnReturn();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getTestWhileIdle()
     */
    public boolean getTestWhileIdle() {
        return dataSource.getTestWhileIdle();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getTimeBetweenEvictionRunsMillis()
     */
    public long getTimeBetweenEvictionRunsMillis() {
        return dataSource.getTimeBetweenEvictionRunsMillis();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getUrl()
     */
    public String getUrl() {
        return dataSource.getUrl();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getUsername()
     */
    public String getUsername() {
        return dataSource.getUsername();
    }

    /**
     * @return
     * @see org.apache.commons.dbcp.BasicDataSource#getValidationQuery()
     */
    public String getValidationQuery() {
        return dataSource.getValidationQuery();
    }

    /**
     * @param iface
     * @return
     * @throws SQLException
     * @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
     */
    @Override
    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
        // return dataSource.isWrapperFor(iface);
        return false;
    }

    /**
     * @param defaultAutoCommit
     * @see org.apache.commons.dbcp.BasicDataSource#setDefaultAutoCommit(boolean)
     */
    public void setDefaultAutoCommit(final boolean defaultAutoCommit) {
        dataSource.setDefaultAutoCommit(defaultAutoCommit);
    }

    /**
     * @param defaultReadOnly
     * @see org.apache.commons.dbcp.BasicDataSource#setDefaultReadOnly(boolean)
     */
    public void setDefaultReadOnly(final boolean defaultReadOnly) {
        dataSource.setDefaultReadOnly(defaultReadOnly);
    }

    /**
     * @param defaultTransactionIsolation
     * @see org.apache.commons.dbcp.BasicDataSource#setDefaultTransactionIsolation(int)
     */
    public void setDefaultTransactionIsolation(final int defaultTransactionIsolation) {
        dataSource.setDefaultTransactionIsolation(defaultTransactionIsolation);
    }

    /**
     * @param driverClassName
     * @see org.apache.commons.dbcp.BasicDataSource#setDriverClassName(java.lang.String)
     */
    public void setDriverClassName(final String driverClassName) {
        dataSource.setDriverClassName(driverClassName);
    }

    /**
     * @param loginTimeout
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#setLoginTimeout(int)
     */
    @Override
    public void setLoginTimeout(final int loginTimeout) throws SQLException {
        dataSource.setLoginTimeout(loginTimeout);
    }

    /**
     * @param logWriter
     * @throws SQLException
     * @see org.apache.commons.dbcp.BasicDataSource#setLogWriter(java.io.PrintWriter)
     */
    @Override
    public void setLogWriter(final PrintWriter logWriter) throws SQLException {
        dataSource.setLogWriter(logWriter);
    }

    /**
     * @param maxActive
     * @see org.apache.commons.dbcp.BasicDataSource#setMaxActive(int)
     */
    public void setMaxActive(final int maxActive) {
        dataSource.setMaxActive(maxActive);
    }

    /**
     * @param maxIdle
     * @see org.apache.commons.dbcp.BasicDataSource#setMaxIdle(int)
     */
    public void setMaxIdle(final int maxIdle) {
        dataSource.setMaxIdle(maxIdle);
    }

    /**
     * @param maxWait
     * @see org.apache.commons.dbcp.BasicDataSource#setMaxWait(long)
     */
    public void setMaxWait(final long maxWait) {
        dataSource.setMaxWait(maxWait);
    }

    /**
     * @param minEvictableIdleTimeMillis
     * @see org.apache.commons.dbcp.BasicDataSource#setMinEvictableIdleTimeMillis(long)
     */
    public void setMinEvictableIdleTimeMillis(final long minEvictableIdleTimeMillis) {
        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
    }

    /**
     * @param minIdle
     * @see org.apache.commons.dbcp.BasicDataSource#setMinIdle(int)
     */
    public void setMinIdle(final int minIdle) {
        dataSource.setMinIdle(minIdle);
    }

    /**
     * @param numTestsPerEvictionRun
     * @see org.apache.commons.dbcp.BasicDataSource#setNumTestsPerEvictionRun(int)
     */
    public void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
        dataSource.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
    }

    /**
     * @param password
     * @see org.apache.commons.dbcp.BasicDataSource#setPassword(java.lang.String)
     */
    public void setPassword(final String password) {
        dataSource.setPassword(password);
    }

    /**
     * @param testOnBorrow
     * @see org.apache.commons.dbcp.BasicDataSource#setTestOnBorrow(boolean)
     */
    public void setTestOnBorrow(final boolean testOnBorrow) {
        dataSource.setTestOnBorrow(testOnBorrow);
    }

    /**
     * @param testOnReturn
     * @see org.apache.commons.dbcp.BasicDataSource#setTestOnReturn(boolean)
     */
    public void setTestOnReturn(final boolean testOnReturn) {
        dataSource.setTestOnReturn(testOnReturn);
    }

    /**
     * @param testWhileIdle
     * @see org.apache.commons.dbcp.BasicDataSource#setTestWhileIdle(boolean)
     */
    public void setTestWhileIdle(final boolean testWhileIdle) {
        dataSource.setTestWhileIdle(testWhileIdle);
    }

    /**
     * @param timeBetweenEvictionRunsMillis
     * @see org.apache.commons.dbcp.BasicDataSource#setTimeBetweenEvictionRunsMillis(long)
     */
    public void setTimeBetweenEvictionRunsMillis(final long timeBetweenEvictionRunsMillis) {
        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
    }

    /**
     * @param url
     * @see org.apache.commons.dbcp.BasicDataSource#setUrl(java.lang.String)
     */
    public void setUrl(final String url) {
        dataSource.setUrl(url);
    }

    /**
     * @param username
     * @see org.apache.commons.dbcp.BasicDataSource#setUsername(java.lang.String)
     */
    public void setUsername(final String username) {
        dataSource.setUsername(username);
    }

    /**
     * @param validationQuery
     * @see org.apache.commons.dbcp.BasicDataSource#setValidationQuery(java.lang.String)
     */
    public void setValidationQuery(final String validationQuery) {
        dataSource.setValidationQuery(validationQuery);
    }

    /*
     * (non-Javadoc)
     * 
     * @see javax.sql.CommonDataSource#getParentLogger()
     */
    @Override
    public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return java.util.logging.Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME);
    }

    /**
     * @param <T>
     * @param iface
     * @return
     * @throws SQLException
     * @see java.sql.Wrapper#unwrap(java.lang.Class)
     */
    @Override
    public <T> T unwrap(final Class<T> iface) throws SQLException {
        throw new ApplicationException(unsupportedOperationMessage("unwrap()"));
    }

    // ========================= DEPENDENCY INJECTION ======================

    /**
     * Set a new value for the properties property.
     * 
     * @param properties
     *            the properties to set
     */
    public void setProperties(final Properties properties) {
        // Set the data sources' properties according the properties object;
        // basically, we are following the Adapter Pattern.
        dataSource.setUrl((String) properties.get(PROPERTIES.URL));
        dataSource.setDriverClassName((String) properties.get(PROPERTIES.DRIVER));
        dataSource.setUsername((String) properties.get(PROPERTIES.USER));
        dataSource.setPassword((String) properties.get(PROPERTIES.PASSWORD));
    }

    /**
     * Set a new value for the name property.
     * 
     * @param name
     *            the name to set
     */
    public void setName(final String name) {
        this.name = name;
    }
}