Package org.pentaho.platform.engine.services.connection.datasource.dbcp

Source Code of org.pentaho.platform.engine.services.connection.datasource.dbcp.PooledDatasourceHelper

/*
* 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 2006 - 2013 Pentaho Corporation.  All rights reserved.
*/

package org.pentaho.platform.engine.services.connection.datasource.dbcp;

import java.util.Map;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.dbcp.AbandonedConfig;
import org.apache.commons.dbcp.AbandonedObjectPool;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.pentaho.database.DatabaseDialectException;
import org.pentaho.database.IDatabaseDialect;
import org.pentaho.database.dialect.GenericDatabaseDialect;
import org.pentaho.database.model.IDatabaseConnection;
import org.pentaho.database.service.IDatabaseDialectService;
import org.pentaho.platform.api.data.DBDatasourceServiceException;
import org.pentaho.platform.api.data.IDBDatasourceService;
import org.pentaho.platform.api.engine.ICacheManager;
import org.pentaho.platform.engine.core.system.PentahoSessionHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.messages.Messages;
import org.pentaho.platform.util.StringUtil;
import org.pentaho.platform.util.logging.Logger;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.Isolation;

public class PooledDatasourceHelper {

  public static PoolingDataSource setupPooledDataSource( IDatabaseConnection databaseConnection )
    throws DBDatasourceServiceException {
    PoolingDataSource poolingDataSource = null;
    String driverClass = null;
    String url = null;
    try {
      ICacheManager cacheManager = PentahoSystem.getCacheManager( null );
      IDatabaseDialectService databaseDialectService = PentahoSystem.get( IDatabaseDialectService.class );
      if ( databaseDialectService == null ) {
        throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
            "PooledDatasourceHelper.ERROR_0005_UNABLE_TO_POOL_DATASOURCE_NO_DIALECT_SERVICE",
            databaseConnection.getName() ) );
      }
      IDatabaseDialect dialect = databaseDialectService.getDialect( databaseConnection );
      if ( dialect == null || dialect.getDatabaseType() == null ) {
        throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
            "PooledDatasourceHelper.ERROR_0004_UNABLE_TO_POOL_DATASOURCE_NO_DIALECT", databaseConnection.getName() ) );
      }
      if ( databaseConnection.getDatabaseType().getShortName().equals( "GENERIC" ) ) { //$NON-NLS-1$
        driverClass = databaseConnection.getAttributes().get( GenericDatabaseDialect.ATTRIBUTE_CUSTOM_DRIVER_CLASS );
        if ( StringUtils.isEmpty( driverClass ) ) {
          throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
              "PooledDatasourceHelper.ERROR_0006_UNABLE_TO_POOL_DATASOURCE_NO_CLASSNAME", databaseConnection.getName() ) );
        }

      } else {
        driverClass = dialect.getNativeDriver();
        if ( StringUtils.isEmpty( driverClass ) ) {
          throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
              "PooledDatasourceHelper.ERROR_0007_UNABLE_TO_POOL_DATASOURCE_NO_DRIVER", databaseConnection.getName() ) );
        }
      }
      try {
        url = dialect.getURLWithExtraOptions( databaseConnection );
      } catch ( DatabaseDialectException e ) {
        url = null;
      }

      // Read default connection pooling parameter
      String maxdleConn = PentahoSystem.getSystemSetting( "dbcp-defaults/max-idle-conn", null ); //$NON-NLS-1$
      String minIdleConn = PentahoSystem.getSystemSetting( "dbcp-defaults/min-idle-conn", null ); //$NON-NLS-1$   
      String maxActConn = PentahoSystem.getSystemSetting( "dbcp-defaults/max-act-conn", null ); //$NON-NLS-1$
      String validQuery = null;
      String whenExhaustedAction = PentahoSystem.getSystemSetting( "dbcp-defaults/when-exhausted-action", null ); //$NON-NLS-1$
      String wait = PentahoSystem.getSystemSetting( "dbcp-defaults/wait", null ); //$NON-NLS-1$
      String testWhileIdleValue = PentahoSystem.getSystemSetting( "dbcp-defaults/test-while-idle", null ); //$NON-NLS-1$
      String testOnBorrowValue = PentahoSystem.getSystemSetting( "dbcp-defaults/test-on-borrow", null ); //$NON-NLS-1$
      String testOnReturnValue = PentahoSystem.getSystemSetting( "dbcp-defaults/test-on-return", null ); //$NON-NLS-1$

      // property initialization
      boolean testWhileIdle =
          !StringUtil.isEmpty( testWhileIdleValue ) ? Boolean.parseBoolean( testWhileIdleValue ) : false;
      boolean testOnBorrow =
          !StringUtil.isEmpty( testOnBorrowValue ) ? Boolean.parseBoolean( testOnBorrowValue ) : false;
      boolean testOnReturn =
          !StringUtil.isEmpty( testOnReturnValue ) ? Boolean.parseBoolean( testOnReturnValue ) : false;
      int maxActiveConnection = !StringUtil.isEmpty( maxActConn ) ? Integer.parseInt( maxActConn ) : -1;
      long waitTime = !StringUtil.isEmpty( wait ) ? Integer.parseInt( wait ) : -1;
      byte whenExhaustedActionType =
          !StringUtil.isEmpty( whenExhaustedAction ) ? Byte.parseByte( whenExhaustedAction )
              : GenericObjectPool.WHEN_EXHAUSTED_BLOCK;
      int minIdleConnection = !StringUtil.isEmpty( minIdleConn ) ? Integer.parseInt( minIdleConn ) : -1;
      int maxIdleConnection = !StringUtil.isEmpty( maxdleConn ) ? Integer.parseInt( maxdleConn ) : -1;

      // setting properties according to user specifications
      Map<String, String> attributes = databaseConnection.getConnectionPoolingProperties();

      if ( attributes.containsKey( IDBDatasourceService.MAX_ACTIVE_KEY )
          && NumberUtils.isNumber( attributes.get( IDBDatasourceService.MAX_ACTIVE_KEY ) ) ) {
        maxActiveConnection = Integer.parseInt( attributes.get( IDBDatasourceService.MAX_ACTIVE_KEY ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.MAX_WAIT_KEY )
          && NumberUtils.isNumber( attributes.get( IDBDatasourceService.MAX_WAIT_KEY ) ) ) {
        waitTime = Integer.parseInt( attributes.get( IDBDatasourceService.MAX_WAIT_KEY ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.MIN_IDLE_KEY )
          && NumberUtils.isNumber( attributes.get( IDBDatasourceService.MIN_IDLE_KEY ) ) ) {
        minIdleConnection = Integer.parseInt( attributes.get( IDBDatasourceService.MIN_IDLE_KEY ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.MAX_IDLE_KEY )
          && NumberUtils.isNumber( attributes.get( IDBDatasourceService.MAX_IDLE_KEY ) ) ) {
        maxIdleConnection = Integer.parseInt( attributes.get( IDBDatasourceService.MAX_IDLE_KEY ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.QUERY_KEY ) ) {
        validQuery = attributes.get( IDBDatasourceService.QUERY_KEY );
      }
      if ( attributes.containsKey( IDBDatasourceService.TEST_ON_BORROW ) ) {
        testOnBorrow = Boolean.parseBoolean( attributes.get( IDBDatasourceService.TEST_ON_BORROW ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.TEST_ON_RETURN ) ) {
        testOnReturn = Boolean.parseBoolean( attributes.get( IDBDatasourceService.TEST_ON_RETURN ) );
      }
      if ( attributes.containsKey( IDBDatasourceService.TEST_WHILE_IDLE ) ) {
        testWhileIdle = Boolean.parseBoolean( attributes.get( IDBDatasourceService.TEST_WHILE_IDLE ) );
      }

      poolingDataSource = new PoolingDataSource();
      Class.forName( driverClass );
      // As the name says, this is a generic pool; it returns basic Object-class objects.
      GenericObjectPool pool = new GenericObjectPool( null );

      // if removedAbandoned = true, then an AbandonedObjectPool object will take GenericObjectPool's place
      if ( attributes.containsKey( IDBDatasourceService.REMOVE_ABANDONED )
          && true == Boolean.parseBoolean( attributes.get( IDBDatasourceService.REMOVE_ABANDONED ) ) ) {

        AbandonedConfig config = new AbandonedConfig();
        config.setRemoveAbandoned( Boolean.parseBoolean( attributes.get( IDBDatasourceService.REMOVE_ABANDONED ) ) );

        if ( attributes.containsKey( IDBDatasourceService.LOG_ABANDONED ) ) {
          config.setLogAbandoned( Boolean.parseBoolean( attributes.get( IDBDatasourceService.LOG_ABANDONED ) ) );
        }

        if ( attributes.containsKey( IDBDatasourceService.REMOVE_ABANDONED_TIMEOUT )
            && NumberUtils.isNumber( attributes.get( IDBDatasourceService.REMOVE_ABANDONED_TIMEOUT ) ) ) {
          config.setRemoveAbandonedTimeout( Integer.parseInt( attributes
              .get( IDBDatasourceService.REMOVE_ABANDONED_TIMEOUT ) ) );
        }

        pool = new AbandonedObjectPool( null, config );
      }

      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 );

      if ( attributes.containsKey( IDBDatasourceService.TIME_BETWEEN_EVICTION_RUNS_MILLIS )
          && NumberUtils.isNumber( attributes.get( IDBDatasourceService.TIME_BETWEEN_EVICTION_RUNS_MILLIS ) ) ) {
        pool.setTimeBetweenEvictionRunsMillis( Long.parseLong( attributes
            .get( IDBDatasourceService.TIME_BETWEEN_EVICTION_RUNS_MILLIS ) ) );
      }

      /*
       * ConnectionFactory creates connections on behalf of the pool. Here, we use the DriverManagerConnectionFactory
       * because that essentially uses DriverManager as the source of connections.
       */
      ConnectionFactory factory =
          new DriverManagerConnectionFactory( url, databaseConnection.getUsername(), databaseConnection.getPassword() );

      boolean defaultReadOnly =
          attributes.containsKey( IDBDatasourceService.DEFAULT_READ_ONLY ) ? Boolean.parseBoolean( attributes
              .get( IDBDatasourceService.TEST_WHILE_IDLE ) ) : false; // default to false

      boolean defaultAutoCommit =
          attributes.containsKey( IDBDatasourceService.DEFAULT_AUTO_COMMIT ) ? Boolean.parseBoolean( attributes
              .get( IDBDatasourceService.DEFAULT_AUTO_COMMIT ) ) : true; // default to true

      KeyedObjectPoolFactory kopf = null;

      if ( attributes.containsKey( IDBDatasourceService.POOL_PREPARED_STATEMENTS )
          && true == Boolean.parseBoolean( attributes.get( IDBDatasourceService.POOL_PREPARED_STATEMENTS ) ) ) {

        int maxOpenPreparedStatements = -1; // unlimited

        if ( attributes.containsKey( IDBDatasourceService.MAX_OPEN_PREPARED_STATEMENTS )
            && NumberUtils.isNumber( attributes.get( IDBDatasourceService.MAX_OPEN_PREPARED_STATEMENTS ) ) ) {

          maxOpenPreparedStatements =
              Integer.parseInt( attributes.get( IDBDatasourceService.MAX_OPEN_PREPARED_STATEMENTS ) );
        }

        kopf =
            new GenericKeyedObjectPoolFactory( null, pool.getMaxActive(), pool.getWhenExhaustedAction(), pool
                .getMaxWait(), pool.getMaxIdle(), maxOpenPreparedStatements );
      }

      /*
       * Puts pool-specific wrappers on factory connections. For clarification: "[PoolableConnection]Factory," not
       * "Poolable[ConnectionFactory]."
       */
      PoolableConnectionFactory pcf = new PoolableConnectionFactory( factory, // ConnectionFactory
          pool, // ObjectPool
          kopf, // KeyedObjectPoolFactory
          validQuery, // String (validation query)
          defaultReadOnly, // boolean (default to read-only?)
          defaultAutoCommit // boolean (default to auto-commit statements?)
          );

      if ( attributes.containsKey( IDBDatasourceService.DEFAULT_TRANSACTION_ISOLATION )
          && !IDBDatasourceService.TRANSACTION_ISOLATION_NONE_VALUE.equalsIgnoreCase( attributes
              .get( IDBDatasourceService.DEFAULT_TRANSACTION_ISOLATION ) ) ) {
        Isolation isolationLevel =
            Isolation.valueOf( attributes.get( IDBDatasourceService.DEFAULT_TRANSACTION_ISOLATION ) );

        if ( isolationLevel != null ) {
          pcf.setDefaultTransactionIsolation( isolationLevel.value() );
        }
      }

      if ( attributes.containsKey( IDBDatasourceService.DEFAULT_CATALOG ) ) {
        pcf.setDefaultCatalog( attributes.get( IDBDatasourceService.DEFAULT_CATALOG ) );
      }

      /*
       * initialize the pool to X connections
       */
      Logger.debug( PooledDatasourceHelper.class, "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( PooledDatasourceHelper.class, "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 );

      if ( attributes.containsKey( IDBDatasourceService.ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED ) ) {
        poolingDataSource.setAccessToUnderlyingConnectionAllowed( Boolean.parseBoolean( attributes
            .get( IDBDatasourceService.ACCESS_TO_UNDERLYING_CONNECTION_ALLOWED ) ) );
      }

      // store the pool, so we can get to it later
      cacheManager.putInRegionCache( IDBDatasourceService.JDBC_POOL, databaseConnection.getName(), pool );
      return ( poolingDataSource );
    } catch ( Exception e ) {
      throw new DBDatasourceServiceException( e );
    }
  }

  public static DataSource convert( IDatabaseConnection databaseConnection ) throws DBDatasourceServiceException {
    DriverManagerDataSource basicDatasource = new DriverManagerDataSource(); // From Spring
    IDatabaseDialectService databaseDialectService =
        PentahoSystem.get( IDatabaseDialectService.class, PentahoSessionHolder.getSession() );
    IDatabaseDialect dialect = databaseDialectService.getDialect( databaseConnection );
    if ( databaseConnection.getDatabaseType() == null && dialect == null ) {
      // We do not have enough information to create a DataSource. Throwing exception
      throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
          "PooledDatasourceHelper.ERROR_0001_DATASOURCE_CREATE_ERROR_NO_DIALECT", databaseConnection.getName() ) );
    }

    if ( databaseConnection.getDatabaseType().getShortName().equals( "GENERIC" ) ) { //$NON-NLS-1$
      String driverClassName =
          databaseConnection.getAttributes().get( GenericDatabaseDialect.ATTRIBUTE_CUSTOM_DRIVER_CLASS );
      if ( !StringUtils.isEmpty( driverClassName ) ) {
        basicDatasource.setDriverClassName( driverClassName );
      } else {
        // We do not have enough information to create a DataSource. Throwing exception
        throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
            "PooledDatasourceHelper.ERROR_0002_DATASOURCE_CREATE_ERROR_NO_CLASSNAME", databaseConnection.getName() ) );
      }

    } else {
      if ( !StringUtils.isEmpty( dialect.getNativeDriver() ) ) {
        basicDatasource.setDriverClassName( dialect.getNativeDriver() );
      } else {
        // We do not have enough information to create a DataSource. Throwing exception
        throw new DBDatasourceServiceException( Messages.getInstance().getErrorString(
            "PooledDatasourceHelper.ERROR_0003_DATASOURCE_CREATE_ERROR_NO_DRIVER", databaseConnection.getName() ) );
      }

    }
    try {
      basicDatasource.setUrl( dialect.getURLWithExtraOptions( databaseConnection ) );
    } catch ( DatabaseDialectException e ) {
      basicDatasource.setUrl( null );
    }
    basicDatasource.setUsername( databaseConnection.getUsername() );
    basicDatasource.setPassword( databaseConnection.getPassword() );

    return basicDatasource;
  }

  public static DataSource getJndiDataSource( final String dsName ) throws DBDatasourceServiceException {

    try {
      InitialContext ctx = new InitialContext();
      Object lkup = null;
      DataSource rtn = null;
      NamingException firstNe = null;
      // First, try what they ask for...
      try {
        lkup = ctx.lookup( dsName );
        if ( lkup != null ) {
          rtn = (DataSource) lkup;
          return rtn;
        }
      } catch ( NamingException ignored ) {
        firstNe = ignored;
      }
      try {
        // Needed this for Jboss
        lkup = ctx.lookup( "java:" + dsName ); //$NON-NLS-1$
        if ( lkup != null ) {
          rtn = (DataSource) lkup;
          return rtn;
        }
      } catch ( NamingException ignored ) {
        // ignored
      }
      try {
        // Tomcat
        lkup = ctx.lookup( "java:comp/env/jdbc/" + dsName ); //$NON-NLS-1$
        if ( lkup != null ) {
          rtn = (DataSource) lkup;
          return rtn;
        }
      } catch ( NamingException ignored ) {
        // ignored
      }
      try {
        // Others?
        lkup = ctx.lookup( "jdbc/" + dsName ); //$NON-NLS-1$
        if ( lkup != null ) {
          rtn = (DataSource) lkup;
          return rtn;
        }
      } catch ( NamingException ignored ) {
        // ignored
      }
      if ( firstNe != null ) {
        throw new DBDatasourceServiceException( firstNe );
      }
      throw new DBDatasourceServiceException( dsName );
    } catch ( NamingException ne ) {
      throw new DBDatasourceServiceException( ne );
    }
  }

}
TOP

Related Classes of org.pentaho.platform.engine.services.connection.datasource.dbcp.PooledDatasourceHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.