/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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 General Public License for more details. * * Copyright 2005 - 2016 Pentaho Corporation. All rights reserved. * * @created Jul 07, 2008 * @author rmansoor */ package org.pentaho.reporting.engine.classic.extensions.modules.connections; import org.apache.commons.dbcp.ConnectionFactory; import org.apache.commons.dbcp.DriverConnectionFactory; import org.apache.commons.dbcp.PoolableConnectionFactory; import org.apache.commons.dbcp.PoolingDataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.pool.impl.GenericObjectPool; import org.pentaho.database.DatabaseDialectException; import org.pentaho.database.IDatabaseDialect; import org.pentaho.database.IDriverLocator; import org.pentaho.database.dialect.GenericDatabaseDialect; import org.pentaho.database.model.IDatabaseConnection; import org.pentaho.database.service.IDatabaseDialectService; import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot; import org.pentaho.reporting.engine.classic.core.modules.misc.connections.DataBaseConnectionAttributes; import org.pentaho.reporting.engine.classic.core.modules.misc.connections.DatasourceServiceException; import org.pentaho.reporting.libraries.base.config.Configuration; import org.pentaho.reporting.libraries.base.util.ObjectUtilities; import org.pentaho.reporting.libraries.base.util.StringUtils; import java.sql.Driver; import java.util.Map; import java.util.Properties; public class PooledDatasourceHelper { private static final Log logger = LogFactory.getLog( PooledDatasourceHelper.class ); public static final String GENERIC = "GENERIC"; private PooledDatasourceHelper() { } public static PoolingDataSource setupPooledDataSource( final IDatabaseConnection databaseConnection ) throws DatasourceServiceException { try { final DataSourceCacheManager cacheManager = ClassicEngineBoot.getInstance().getObjectFactory().get( DataSourceCacheManager.class ); final IDatabaseDialectService databaseDialectService = ClassicEngineBoot.getInstance().getObjectFactory().get( IDatabaseDialectService.class ); final IDatabaseDialect dialect = databaseDialectService.getDialect( databaseConnection ); final String driverClass; if ( GENERIC.equals( databaseConnection.getDatabaseType().getShortName() ) ) { //$NON-NLS-1$ driverClass = databaseConnection.getAttributes().get( GenericDatabaseDialect.ATTRIBUTE_CUSTOM_DRIVER_CLASS ); } else { driverClass = dialect.getNativeDriver(); } String url; try { url = dialect.getURLWithExtraOptions( databaseConnection ); } catch ( DatabaseDialectException e ) { url = null; } // Read default connection pooling parameter final String maxdleConn = getSystemSetting( "dbcp-defaults.max-idle-conn" ); //$NON-NLS-1$ final String minIdleConn = getSystemSetting( "dbcp-defaults.min-idle-conn" ); //$NON-NLS-1$ final String maxActConn = getSystemSetting( "dbcp-defaults.max-act-conn" ); //$NON-NLS-1$ String validQuery = null; final String whenExhaustedAction = getSystemSetting( "dbcp-defaults.when-exhausted-action" ); //$NON-NLS-1$ final String wait = getSystemSetting( "dbcp-defaults.wait" ); //$NON-NLS-1$ final String testWhileIdleValue = getSystemSetting( "dbcp-defaults.test-while-idle" ); //$NON-NLS-1$ final String testOnBorrowValue = getSystemSetting( "dbcp-defaults.test-on-borrow" ); //$NON-NLS-1$ final String testOnReturnValue = getSystemSetting( "dbcp-defaults.test-on-return" ); //$NON-NLS-1$ final boolean testWhileIdle = !StringUtils.isEmpty( testWhileIdleValue ) && Boolean.parseBoolean( testWhileIdleValue ); final boolean testOnBorrow = !StringUtils.isEmpty( testOnBorrowValue ) && Boolean.parseBoolean( testOnBorrowValue ); final boolean testOnReturn = !StringUtils.isEmpty( testOnReturnValue ) && Boolean.parseBoolean( testOnReturnValue ); int maxActiveConnection = -1; long waitTime = -1; byte whenExhaustedActionType = -1; final int minIdleConnection = !StringUtils.isEmpty( minIdleConn ) ? Integer.parseInt( minIdleConn ) : -1; final int maxIdleConnection = !StringUtils.isEmpty( maxdleConn ) ? Integer.parseInt( maxdleConn ) : -1; final Map<String, String> attributes = databaseConnection.getAttributes(); if ( attributes.containsKey( DataBaseConnectionAttributes.MAX_ACTIVE_KEY ) ) { maxActiveConnection = Integer.parseInt( attributes.get( DataBaseConnectionAttributes.MAX_ACTIVE_KEY ) ); } else { if ( !StringUtils.isEmpty( maxActConn ) ) { maxActiveConnection = Integer.parseInt( maxActConn ); } } if ( attributes.containsKey( DataBaseConnectionAttributes.MAX_WAIT_KEY ) ) { waitTime = Integer.parseInt( attributes.get( DataBaseConnectionAttributes.MAX_WAIT_KEY ) ); } else { if ( !StringUtils.isEmpty( wait ) ) { waitTime = Long.parseLong( wait ); } } if ( attributes.containsKey( DataBaseConnectionAttributes.QUERY_KEY ) ) { validQuery = attributes.get( DataBaseConnectionAttributes.QUERY_KEY ); } if ( !StringUtils.isEmpty( whenExhaustedAction ) ) { whenExhaustedActionType = Byte.parseByte( whenExhaustedAction ); } else { whenExhaustedActionType = GenericObjectPool.WHEN_EXHAUSTED_BLOCK; } final PoolingDataSource poolingDataSource = new PoolingDataSource(); // As the name says, this is a generic pool; it returns basic Object-class objects. final GenericObjectPool pool = new GenericObjectPool( null ); pool.setWhenExhaustedAction( whenExhaustedActionType ); // Tuning the connection pool pool.setMaxActive( maxActiveConnection ); pool.setMaxIdle( maxIdleConnection ); pool.setMaxWait( waitTime ); pool.setMinIdle( minIdleConnection ); pool.setTestWhileIdle( testWhileIdle ); pool.setTestOnReturn( testOnReturn ); pool.setTestOnBorrow( testOnBorrow ); pool.setTestWhileIdle( testWhileIdle ); /* * ConnectionFactory creates connections on behalf of the pool. Here, we use the DriverManagerConnectionFactory * because that essentially uses DriverManager as the source of connections. */ final Properties properties = new Properties(); properties.setProperty( "user", databaseConnection.getUsername() ); properties.setProperty( "password", databaseConnection.getPassword() ); final ConnectionFactory factory = new DriverConnectionFactory( getDriver( dialect, driverClass, url ), url, properties ); /* * Puts pool-specific wrappers on factory connections. For clarification: "[PoolableConnection]Factory," not * "Poolable[ConnectionFactory]." */ // This declaration is used implicitly. // noinspection UnusedDeclaration final PoolableConnectionFactory pcf = new PoolableConnectionFactory( factory, // ConnectionFactory pool, // ObjectPool null, // KeyedObjectPoolFactory validQuery, // String (validation query) false, // boolean (default to read-only?) true // boolean (default to auto-commit statements?) ); /* * initialize the pool to X connections */ logger.debug( "Pool defaults to " + maxActiveConnection + " max active/" + maxIdleConnection + "max idle" + "with " + waitTime + "wait time"//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + " idle connections." ); //$NON-NLS-1$ for ( int i = 0; i < maxIdleConnection; ++i ) { pool.addObject(); } logger.debug( "Pool now has " + pool.getNumActive() + " active/" + pool.getNumIdle() + " idle connections." ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ /* * All of this is wrapped in a DataSource, which client code should already know how to handle (since it's the * same class of object they'd fetch via the container's JNDI tree */ poolingDataSource.setPool( pool ); // store the pool, so we can get to it later cacheManager.getDataSourceCache().put( databaseConnection.getName(), poolingDataSource ); return ( poolingDataSource ); } catch ( Exception e ) { throw new DatasourceServiceException( e ); } } static Driver getDriver( IDatabaseDialect dialect, String driverClass, String url ) { if ( dialect instanceof IDriverLocator ) { return ( (IDriverLocator) dialect ).getDriver( url ); } else { return ObjectUtilities.loadAndInstantiate( driverClass, PooledDatasourceHelper.class, Driver.class ); } } private static String getSystemSetting( final String key ) { final Configuration config = ClassicEngineBoot.getInstance().getGlobalConfig(); return config.getConfigProperty( "org.pentaho.reporting.engine.classic.core." + key ); } }