All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.plasma.sdo.jdbc.connect.RDBConnectionManager Maven / Gradle / Ivy

There is a newer version: 2.2.1
Show newest version
/**
 *         PlasmaSDO™ License
 * 
 * This is a community release of PlasmaSDO™, a dual-license 
 * Service Data Object (SDO) 2.1 implementation. 
 * This particular copy of the software is released under the 
 * version 2 of the GNU General Public License. PlasmaSDO™ was developed by 
 * TerraMeta Software, Inc.
 * 
 * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
 * 
 * General License information can be found below.
 * 
 * This distribution may include materials developed by third
 * parties. For license and attribution notices for these
 * materials, please refer to the documentation that accompanies
 * this distribution (see the "Licenses for Third-Party Components"
 * appendix) or view the online documentation at 
 * .
 *  
 */
package org.plasma.sdo.jdbc.connect;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

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.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.plasma.runtime.DataAccessProviderName;
import org.plasma.runtime.PlasmaRuntime;
import org.plasma.runtime.Property;
import org.plasma.sdo.jdbc.service.JDBCServiceException;

/**
 */
public class RDBConnectionManager {

  private static final Log log = LogFactory.getLog(RDBConnectionManager.class);

  /**
   * Default: true The default auto-commit state of connections created by this
   * pool.
   */
  public static final String DBCP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";

  /**
   * Default: driver default The default read-only state of connections created
   * by this pool. If not set then the setReadOnly method will not be called.
   * (Some drivers don't support read only mode, ex: Informix)
   */
  public static final String DBCP_DEFAULTREADONLY = "defaultReadOnly";

  /**
   * Default: driver default The default TransactionIsolation state of
   * connections created by this pool. One of the following: (see javadoc)
   */
  public static final String DBCP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";

  /**
   * Default: The default catalog of connections created by this pool.
   */
  public static final String DBCP_DEFAULTCATALOG = "defaultCatalog";

  /**
   * Default: 0 The initial number of connections that are created when the pool
   * is started. Since: 1.2
   */
  public static final String DBCP_INITIALSIZE = "initialSize";

  /**
   * Default: 8 The maximum number of active connections that can be allocated
   * from this pool at the same time, or negative for no limit.
   */
  public static final String DBCP_MAXACTIVE = "maxActive";

  /**
   * Default: 8 The maximum number of connections that can remain idle in the
   * pool, without extra ones being released, or negative for no limit.
   */
  public static final String DBCP_MAXIDLE = "maxIdle";

  /**
   * Default: 0 The minimum number of connections that can remain idle in the
   * pool, without extra ones being created, or zero to create none.
   * 
   */
  public static final String DBCP_MINIDLE = "minIdle";

  /**
   * 
   * Default: indefinitely The maximum number of milliseconds that the pool will
   * wait (when there are no available connections) for a connection to be
   * returned before throwing an exception, or -1 to wait indefinitely.
   */
  public static final String DBCP_MAXWAIT = "maxWait";

  /**
   * The SQL query that will be used to validate connections from this pool
   * before returning them to the caller. If specified, this query MUST be an
   * SQL SELECT statement that returns at least one row.
   * 
   */
  public static final String DBCP_VALIDATIONQUERY = "validationQuery";

  /**
   * Default: true The indication of whether objects will be validated before
   * being borrowed from the pool. If the object fails to validate, it will be
   * dropped from the pool, and we will attempt to borrow another. NOTE - for a
   * true value to have any effect, the validationQuery parameter must be set to
   * a non-null string.
   */
  public static final String DBCP_TESTONBORROW = "testOnBorrow";

  /**
   * Default: false The indication of whether objects will be validated before
   * being returned to the pool. NOTE - for a true value to have any effect, the
   * validationQuery parameter must be set to a non-null string.
   */
  public static final String DBCP_TESTONRETURN = "testOnReturn";

  /**
   * Default: false The indication of whether objects will be validated by the
   * idle object evictor (if any). If an object fails to validate, it will be
   * dropped from the pool. NOTE - for a true value to have any effect, the
   * validationQuery parameter must be set to a non-null string.
   */
  public static final String DBCP_TESTWHILEIDLE = "testWhileIdle";

  /**
   * Default: -1 The number of milliseconds to sleep between runs of the idle
   * object evictor thread. When non-positive, no idle object evictor thread
   * will be run.
   * 
   */
  public static final String DBCP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";

  /**
   * Default: 3 The number of objects to examine during each run of the idle
   * object evictor thread (if any).
   */
  public static final String DBCP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";

  /**
   * Default: 1000 * 60 * 30 The minimum amount of time an object may sit idle
   * in the pool before it is eligable for eviction by the idle object evictor
   * (if any).
   * 
   */
  public static final String DBCP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";

  /**
   * NOTE: Versions 1.3 and 1.4 of DBCP incorrectly use "initConnectionSqls" as
   * the name of this property for JNDI object factory configuration. Until
   * 1.3.1/1.4.1 are released, "initConnectionSqls" must be used as the name for
   * this property when using BasicDataSoureFactory to create BasicDataSource
   * instances via JNDI. null A Collection of SQL statements that will be used
   * to initialize physical connections when they are first created. These
   * statements are executed only once - when the configured connection factory
   * creates the connection.
   */
  public static final String DBCP_CONNECTIONINITSQLS = "connectionInitSqls";

  /**
   * Default: false Flag to remove abandoned connections if they exceed the
   * removeAbandonedTimout. If set to true a connection is considered abandoned
   * and eligible for removal if it has been idle longer than the
   * removeAbandonedTimeout. Setting this to true can recover db connections
   * from poorly written applications which fail to close a connection.
   */
  public static final String DBCP_REMOVEABANDONED = "removeAbandoned";

  /**
   * Default: 300 Timeout in seconds before an abandoned connection can be
   * removed.
   */
  public static final String DBCP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";

  /**
   * Default: false Flag to log stack traces for application code which
   * abandoned a Statement or Connection. Logging of abandoned Statements and
   * Connections adds overhead for every Connection open or new Statement
   * because a stack trace has to be generated.
   */
  public static final String DBCP_LOGABANDONED = "logAbandoned";

  private static RDBConnectionManager instance;
  private static DataSource DS = null;
  private static GenericObjectPool _pool = null;

  private RDBConnectionManager() {

    Map props = new HashMap();
    for (Property property : PlasmaRuntime.getInstance()
        .getDataAccessProvider(DataAccessProviderName.JDBC).getProperties())
      props.put(property.getName(), property.getValue());

    String driverName = props.get("org.plasma.sdo.access.provider.jdbc.ConnectionDriverName");
    String url = props.get("org.plasma.sdo.access.provider.jdbc.ConnectionURL");
    String user = props.get("org.plasma.sdo.access.provider.jdbc.ConnectionUserName");
    String password = props.get("org.plasma.sdo.access.provider.jdbc.ConnectionPassword");
    int poolMinSize = Integer.valueOf(props
        .get("org.plasma.sdo.access.provider.jdbc.ConnectionPoolMinSize"));
    int poolMaxSize = Integer.valueOf(props
        .get("org.plasma.sdo.access.provider.jdbc.ConnectionPoolMaxSize"));

    try {
      java.lang.Class.forName(driverName).newInstance();
    } catch (Exception e) {
      log.error("Error when attempting to obtain DB Driver: " + driverName, e);
    }

    if (log.isDebugEnabled())
      log.debug("trying to connect to database...");
    try {
      RDBConnectionManager.DS = setup(url, user, password, poolMinSize, poolMaxSize, props);

      log.debug("Connection attempt to database succeeded.");
    } catch (Exception e) {
      log.error("Error when attempting to connect to DB ", e);
    }
  }

  public static RDBConnectionManager instance() {
    if (instance == null)
      initInstance(); // double-checked locking pattern
    return instance;
  }

  private static synchronized void initInstance() {
    if (instance == null)
      instance = new RDBConnectionManager();
  }

  protected void finalize() {
    log.debug("Finalizing ConnectionManager");
    try {
      super.finalize();
    } catch (Throwable ex) {
      log.error("ConnectionManager finalize failed to disconnect: ", ex);
    }
  }

  public Connection getConnection() throws SQLException {
    try {
      printDriverStats();
    } catch (Exception e) {
      log.error(e.getMessage());
    }
    return DS.getConnection();
  }

  /**
   * 
   * @param connectURI
   *          - JDBC Connection URI
   * @param username
   *          - JDBC Connection username
   * @param password
   *          - JDBC Connection password
   * @param minIdle
   *          - Minimum number of idel connection in the connection pool
   * @param maxActive
   *          - Connection Pool Maximum Capacity (Size)
   * @throws Exception
   */
  private static DataSource setup(String connectURI, String username, String password, int minIdle,
      int maxActive, Map props) throws Exception {
    //
    // Create an ObjectPool that serves as the
    // actual pool of connections.
    //
    // Use a GenericObjectPool instance, although
    // any ObjectPool implementation will suffice.
    //
    GenericObjectPool.Config config = createGenericObjectPoolConfig(props);

    GenericObjectPool connectionPool = new GenericObjectPool(null, config);

    connectionPool.setMinIdle(minIdle);
    connectionPool.setMaxActive(maxActive);

    RDBConnectionManager._pool = connectionPool;
    // We keep it for two reasons
    // #1 We need it for statistics/debugging
    // #2 PoolingDataSource does not have getPool()
    // method, for some obscure, weird reason.

    //
    // Create a ConnectionFactory that the
    // pool will use to create Connections.
    // Use the DriverManagerConnectionFactory,
    // using the connect string from configuration
    //
    ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectURI, username,
        password);

    //
    // Create the PoolableConnectionFactory, which wraps
    // the "real" Connections created by the ConnectionFactory with
    // the classes that implement the pooling functionality.
    //
    PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(
        connectionFactory, connectionPool, null, null, false, true);

    String value = getValue(DBCP_VALIDATIONQUERY, props);
    if (value != null) {
      try {
        poolableConnectionFactory.setValidationQuery(value);
      } catch (Exception e) {
        throw new JDBCServiceException(e);
      }
    }

    PoolingDataSource dataSource = new PoolingDataSource(connectionPool);

    return dataSource;
  }

  public static void printDriverStats() throws Exception {
    ObjectPool connectionPool = RDBConnectionManager._pool;
    log.debug("NumActive: " + connectionPool.getNumActive());
    log.debug("NumIdle: " + connectionPool.getNumIdle());
  }

  /**
   * getNumLockedProcesses - gets the number of currently locked processes on
   * the MySQL db
   * 
   * @return Number of locked processes
   */
  public int getNumLockedProcesses() {
    int num_locked_connections = 0;
    Connection con = null;
    PreparedStatement p_stmt = null;
    ResultSet rs = null;
    try {
      con = RDBConnectionManager.DS.getConnection();
      p_stmt = con.prepareStatement("SHOW PROCESSLIST");
      rs = p_stmt.executeQuery();
      while (rs.next()) {
        if (rs.getString("State") != null && rs.getString("State").equals("Locked")) {
          num_locked_connections++;
        }
      }
    } catch (Exception e) {
      log.debug("Failed to get get Locked Connections - Exception: " + e.toString());
    } finally {
      try {
        rs.close();
        p_stmt.close();
        con.close();
      } catch (java.sql.SQLException ex) {
        log.error(ex.toString());
      }
    }
    return num_locked_connections;
  }

  private static GenericObjectPool.Config createGenericObjectPoolConfig(Map props) {
    GenericObjectPool.Config config = new GenericObjectPool.Config();

    String value = getValue(DBCP_TESTONBORROW, props);
    if (value != null) {
      try {
        config.testOnBorrow = Boolean.parseBoolean(value);
      } catch (Exception e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_TESTONRETURN, props);
    if (value != null) {
      try {
        config.testOnReturn = Boolean.parseBoolean(value);
      } catch (Exception e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_TESTWHILEIDLE, props);
    if (value != null) {
      try {
        config.testWhileIdle = Boolean.parseBoolean(value);
      } catch (Exception e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_TIMEBETWEENEVICTIONRUNSMILLIS, props);
    if (value != null) {
      try {
        config.timeBetweenEvictionRunsMillis = Long.parseLong(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_NUMTESTSPEREVICTIONRUN, props);
    if (value != null) {
      try {
        config.numTestsPerEvictionRun = Integer.parseInt(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_MINEVICTABLEIDLETIMEMILLIS, props);
    if (value != null) {
      try {
        config.minEvictableIdleTimeMillis = Long.parseLong(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_MAXIDLE, props);
    if (value != null) {
      try {
        config.maxIdle = Integer.parseInt(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_MINIDLE, props);
    if (value != null) {
      try {
        config.minIdle = Integer.parseInt(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_MAXACTIVE, props);
    if (value != null) {
      try {
        config.maxActive = Integer.parseInt(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    value = getValue(DBCP_MAXWAIT, props);
    if (value != null) {
      try {
        config.maxWait = Integer.parseInt(value);
      } catch (NumberFormatException e) {
        throw new JDBCServiceException(e);
      }
    }

    return config;
  }

  private static String getValue(String name, Map props) {
    String value = props.get(name);
    if (value == null)
      value = props.get("org.apache.commons.dbcp." + name);
    return value;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy