org.ops4j.pax.jdbc.pool.dbcp2.impl.ds.PooledDataSourceFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.ops4j.pax.jdbc.pool.dbcp2.impl.ds.PooledDataSourceFactory.java

Source

/*
 * 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 org.ops4j.pax.jdbc.pool.dbcp2.impl.ds;

import java.sql.Driver;
import java.sql.SQLException;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.XADataSource;

import org.apache.commons.dbcp2.DataSourceConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.osgi.framework.ServiceReference;
import org.osgi.service.jdbc.DataSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Creates pooled and optionally XA ready DataSources out of a non pooled DataSourceFactory. XA transaction
 * handling Besides pooling this also supports to provide a DataSource that wraps a XADataSource and handles
 * the XA Resources. This kind of DataSource can then for example be used in persistence.xml as
 * jta-data-source
 */
public class PooledDataSourceFactory implements DataSourceFactory {

    private static final String POOL_PREFIX = "pool.";
    private Logger LOG = LoggerFactory.getLogger(PooledDataSourceFactory.class);
    protected DataSourceFactory dsFactory;

    /**
     * Initialize non XA PoolingDataSourceFactory
     * 
     * @param dsFactory non pooled DataSourceFactory we delegate to
     */
    public PooledDataSourceFactory(DataSourceFactory dsFactory) {
        this.dsFactory = dsFactory;
    }

    @Override
    public DataSource createDataSource(Properties props) throws SQLException {
        try {
            Properties dsProps = getNonPoolProps(props);
            Map<String, String> poolProps = getPoolProps(props);
            return createDataSourceInternal(dsProps, poolProps);
        } catch (Throwable e) {
            LOG.error("Error creating pooled datasource" + e.getMessage(), e);
            if (e instanceof SQLException) {
                throw (SQLException) e;
            } else if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            } else {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    protected Map<String, String> getPoolProps(Properties props) {
        Map<String, String> poolProps = new HashMap<String, String>();
        for (Object keyO : props.keySet()) {
            String key = (String) keyO;
            if (key.startsWith(POOL_PREFIX)) {
                String strippedKey = key.substring(POOL_PREFIX.length());
                poolProps.put(strippedKey, (String) props.get(key));
            }
        }
        if (poolProps.get("jmxNameBase") == null) {
            poolProps.put("jmxNameBase", "org.ops4j.pax.jdbc.pool.dbcp2:type=GenericObjectPool,name=");
        }
        String dsName = (String) props.get(DataSourceFactory.JDBC_DATASOURCE_NAME);
        if (dsName != null) {
            poolProps.put("jmxNamePrefix", dsName);
        }
        return poolProps;
    }

    private Properties getNonPoolProps(Properties props) {
        Properties dsProps = new Properties();
        for (Object keyO : props.keySet()) {
            String key = (String) keyO;
            if (!key.startsWith(POOL_PREFIX)) {
                dsProps.put(key, props.get(key));
            }
        }
        dsProps.remove(DataSourceFactory.JDBC_DATASOURCE_NAME);
        return dsProps;
    }

    protected DataSource createDataSourceInternal(Properties props, Map<String, String> poolProps)
            throws SQLException {
        DataSource ds = dsFactory.createDataSource(props);
        DataSourceConnectionFactory connFactory = new DataSourceConnectionFactory(ds);
        PoolableConnectionFactory pcf = new PoolableConnectionFactory(connFactory, null);
        GenericObjectPoolConfig conf = new GenericObjectPoolConfig();
        BeanConfig.configure(conf, poolProps);
        GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>(pcf, conf);
        return new CloseablePoolingDataSource<PoolableConnection>(pool);
    }

    protected ObjectName getJmxName(String dsName) {
        if (dsName == null) {
            dsName = UUID.randomUUID().toString();
        }
        try {
            return new ObjectName("org.ops4j.pax.jdbc.pool", "dsName", dsName);
        } catch (MalformedObjectNameException e) {
            throw new IllegalArgumentException("Invalid object name for data source" + dsName, e);
        }
    }

    public Dictionary<String, Object> createPropsForPoolingDataSourceFactory(
            ServiceReference<DataSourceFactory> reference) {
        Dictionary<String, Object> props = new Hashtable<String, Object>();
        for (String key : reference.getPropertyKeys()) {
            if (!"service.id".equals(key)) {
                props.put(key, reference.getProperty(key));
            }
        }
        props.put("pooled", "true");
        props.put(DataSourceFactory.OSGI_JDBC_DRIVER_NAME, getPoolDriverName(reference));
        return props;
    }

    protected String getPoolDriverName(ServiceReference<DataSourceFactory> reference) {
        String origName = (String) reference.getProperty(DataSourceFactory.OSGI_JDBC_DRIVER_NAME);
        if (origName == null) {
            origName = (String) reference.getProperty(DataSourceFactory.OSGI_JDBC_DRIVER_CLASS);
        }
        return origName + "-pool";
    }

    @Override
    public ConnectionPoolDataSource createConnectionPoolDataSource(Properties props) throws SQLException {
        throw new SQLException("Not supported");
    }

    @Override
    public XADataSource createXADataSource(Properties props) throws SQLException {
        throw new SQLException("Not supported");
    }

    @Override
    public Driver createDriver(Properties props) throws SQLException {
        throw new SQLException("Not supported");
    }

}