teichmann@5844: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5844: * Software engineering by Intevation GmbH teichmann@5844: * teichmann@5992: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5844: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5992: * documentation coming with Dive4Elements River for details. teichmann@5844: */ teichmann@5844: sascha@168: /* sascha@168: * Copyright 2004 The Apache Software Foundation. sascha@168: * sascha@168: * Licensed under the Apache License, Version 2.0 (the "License"); sascha@168: * you may not use this file except in compliance with the License. sascha@168: * You may obtain a copy of the License at sascha@168: * sascha@168: * http://www.apache.org/licenses/LICENSE-2.0 sascha@168: * sascha@168: * Unless required by applicable law or agreed to in writing, software sascha@168: * distributed under the License is distributed on an "AS IS" BASIS, sascha@168: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. sascha@168: * See the License for the specific language governing permissions and sascha@168: * limitations under the License. sascha@168: */ teichmann@8187: package org.dive4elements.river.backend.utils; sascha@168: sascha@168: import java.sql.Connection; sascha@168: import java.sql.SQLException; sascha@168: sascha@168: import java.util.Iterator; sascha@168: import java.util.Properties; sascha@168: import java.util.Map; tom@8763: import java.util.Arrays; sascha@168: tom@8763: import org.apache.commons.dbcp2.BasicDataSource; tom@8763: import org.apache.commons.dbcp2.BasicDataSourceFactory; sascha@168: sascha@168: import org.apache.log4j.Logger; sascha@168: sascha@168: import org.hibernate.HibernateException; sascha@168: sascha@168: import org.hibernate.connection.ConnectionProviderFactory; sascha@168: import org.hibernate.connection.ConnectionProvider; sascha@168: sascha@168: import org.hibernate.cfg.Environment; sascha@168: sascha@168: /** sascha@168: *

A connection provider that uses an Apache commons DBCP connection pool.

sascha@168: * sascha@168: *

To use this connection provider set:
sascha@168: * hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider

sascha@168: * sascha@168: *
Supported Hibernate properties:
sascha@168:  *   hibernate.connection.driver_class
sascha@168:  *   hibernate.connection.url
sascha@168:  *   hibernate.connection.username
sascha@168:  *   hibernate.connection.password
sascha@168:  *   hibernate.connection.isolation
sascha@168:  *   hibernate.connection.autocommit
sascha@168:  *   hibernate.connection.pool_size
sascha@168:  *   hibernate.connection (JDBC driver properties)
sascha@168: *
sascha@168: * All DBCP properties are also supported by using the hibernate.dbcp prefix. sascha@168: * A complete list can be found on the DBCP configuration page: sascha@168: * http://jakarta.apache.org/commons/dbcp/configuration.html. sascha@168: *
sascha@168: *
Example:
sascha@168:  *   hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider
sascha@168:  *   hibernate.connection.driver_class org.hsqldb.jdbcDriver
sascha@168:  *   hibernate.connection.username sa
sascha@168:  *   hibernate.connection.password
sascha@168:  *   hibernate.connection.url jdbc:hsqldb:test
sascha@168:  *   hibernate.connection.pool_size 20
sascha@168:  *   hibernate.dbcp.initialSize 10
sascha@168:  *   hibernate.dbcp.maxWait 3000
sascha@168:  *   hibernate.dbcp.validationQuery select 1 from dual
sascha@168: * sascha@168: *

More information about configuring/using DBCP can be found on the sascha@168: * DBCP website. sascha@168: * There you will also find the DBCP wiki, mailing lists, issue tracking sascha@168: * and other support facilities

sascha@168: * sascha@168: * @see org.hibernate.connection.ConnectionProvider sascha@168: * @author Dirk Verbeeck sascha@168: */ sascha@168: public class DBCPConnectionProvider sascha@168: implements ConnectionProvider sascha@168: { sascha@168: private static Logger log = Logger.getLogger(DBCPConnectionProvider.class); sascha@168: sascha@168: private static final String PREFIX = "hibernate.dbcp."; sascha@168: sascha@168: private BasicDataSource ds; sascha@168: sascha@464: // Old Environment property for backward-compatibility sascha@168: // (property removed in Hibernate3) sascha@168: private static final String DBCP_PS_MAXACTIVE = sascha@168: "hibernate.dbcp.ps.maxActive"; sascha@168: sascha@168: // Property doesn't exists in Hibernate2 sascha@168: private static final String AUTOCOMMIT = sascha@168: "hibernate.connection.autocommit"; sascha@168: sascha@168: public void configure(Properties props) throws HibernateException { sascha@168: try { sascha@168: log.debug("Configure DBCPConnectionProvider"); sascha@168: sascha@168: // DBCP properties used to create the BasicDataSource sascha@168: Properties dbcpProperties = new Properties(); sascha@168: sascha@168: // DriverClass & url sascha@168: String jdbcDriverClass = props.getProperty(Environment.DRIVER); sascha@168: String jdbcUrl = props.getProperty(Environment.URL); sascha@168: dbcpProperties.put("driverClassName", jdbcDriverClass); sascha@168: dbcpProperties.put("url", jdbcUrl); sascha@168: sascha@168: // Username / password sascha@168: String username = props.getProperty(Environment.USER); sascha@168: String password = props.getProperty(Environment.PASS); sascha@168: dbcpProperties.put("username", username); sascha@168: dbcpProperties.put("password", password); sascha@168: sascha@168: // Isolation level sascha@168: String isolationLevel = props.getProperty(Environment.ISOLATION); sascha@168: if (isolationLevel != null sascha@168: && (isolationLevel = isolationLevel.trim()).length() > 0) { sascha@168: dbcpProperties.put("defaultTransactionIsolation", isolationLevel); sascha@168: } sascha@168: sascha@168: // Turn off autocommit (unless autocommit property is set) sascha@168: String autocommit = props.getProperty(AUTOCOMMIT); sascha@168: if (autocommit != null sascha@168: && (autocommit = autocommit.trim()).length() > 0) { sascha@168: dbcpProperties.put("defaultAutoCommit", autocommit); sascha@168: } else { sascha@168: dbcpProperties.put("defaultAutoCommit", String.valueOf(Boolean.FALSE)); sascha@168: } sascha@168: sascha@168: // Pool size sascha@168: String poolSize = props.getProperty(Environment.POOL_SIZE); sascha@168: if (poolSize != null sascha@168: && (poolSize = poolSize.trim()).length() > 0 sascha@168: && Integer.parseInt(poolSize) > 0) { sascha@168: dbcpProperties.put("maxActive", poolSize); sascha@168: } sascha@168: sascha@168: // Copy all "driver" properties into "connectionProperties" sascha@168: Properties driverProps = sascha@168: ConnectionProviderFactory.getConnectionProperties(props); sascha@168: sascha@168: if (driverProps.size() > 0) { sascha@168: StringBuilder connectionProperties = new StringBuilder(); sascha@464: for (Iterator iter = driverProps.entrySet().iterator(); sascha@168: iter.hasNext(); sascha@168: ) { sascha@168: Map.Entry entry = (Map.Entry)iter.next(); sascha@168: String key = (String)entry.getKey(); sascha@168: String value = (String)entry.getValue(); sascha@168: connectionProperties sascha@168: .append(key) sascha@168: .append('=') sascha@168: .append(value); sascha@168: if (iter.hasNext()) { sascha@168: connectionProperties.append(';'); sascha@168: } sascha@168: } sascha@168: dbcpProperties.put( sascha@168: "connectionProperties", connectionProperties.toString()); sascha@168: } sascha@168: sascha@168: // Copy all DBCP properties removing the prefix sascha@168: for (Iterator iter = props.entrySet().iterator() ; iter.hasNext() ;) { sascha@168: Map.Entry entry = (Map.Entry)iter.next(); sascha@168: String key = (String)entry.getKey(); sascha@168: if (key.startsWith(PREFIX)) { sascha@168: String property = key.substring(PREFIX.length()); sascha@168: String value = (String)entry.getValue(); sascha@168: dbcpProperties.put(property, value); sascha@168: } sascha@168: } sascha@168: sascha@168: // Backward-compatibility sascha@168: if (props.getProperty(DBCP_PS_MAXACTIVE) != null) { sascha@168: dbcpProperties.put( sascha@168: "poolPreparedStatements", sascha@168: String.valueOf(Boolean.TRUE)); sascha@168: dbcpProperties.put( sascha@168: "maxOpenPreparedStatements", sascha@168: props.getProperty(DBCP_PS_MAXACTIVE)); sascha@168: } sascha@168: sascha@168: // Some debug info sascha@181: /* // commented out, because it leaks the password sascha@168: if (log.isDebugEnabled()) { sascha@168: log.debug("Creating a DBCP BasicDataSource" + sascha@168: " with the following DBCP factory properties:"); sascha@168: StringWriter sw = new StringWriter(); sascha@168: dbcpProperties.list(new PrintWriter(sw, true)); sascha@168: log.debug(sw.toString()); sascha@168: } sascha@181: */ sascha@168: sascha@168: // Let the factory create the pool sascha@168: ds = (BasicDataSource)BasicDataSourceFactory sascha@168: .createDataSource(dbcpProperties); sascha@168: aheinecke@5200: // This needs to be done manually as it is somehow ignored aheinecke@5200: // by the BasicDataSourceFactory if you set it as a dbcpProperty aheinecke@5200: String connectionInitSqls = props.getProperty("connectionInitSqls"); aheinecke@5200: if (connectionInitSqls != null) { tom@8763: String[] statements = connectionInitSqls.split(";"); tom@8763: ds.setConnectionInitSqls(Arrays.asList(statements)); aheinecke@5200: } teichmann@8470: teichmann@8470: String validationQuery = props.getProperty("validationQuery"); teichmann@8470: if (validationQuery != null) { teichmann@8470: ds.setValidationQuery(validationQuery); teichmann@8470: } tom@8484: tom@8485: String maxWait = props.getProperty("maxWait"); tom@8485: if (maxWait != null) { tom@8485: try { tom@8763: ds.setMaxWaitMillis(Integer.parseInt(maxWait)); tom@8485: } tom@8485: catch (NumberFormatException nfe) { tom@8485: log.error( tom@8485: "Property maxWait could not be parsed as integer." tom@8485: ); tom@8485: } tom@8485: } tom@8484: sascha@168: // The BasicDataSource has lazy initialization sascha@168: // borrowing a connection will start the DataSource sascha@168: // and make sure it is configured correctly. sascha@168: sascha@168: // Connection conn = ds.getConnection(); sascha@168: // conn.close(); sascha@168: } sascha@168: catch (Exception e) { sascha@168: String message = "Could not create a DBCP pool"; sascha@168: log.fatal(message, e); sascha@168: if (ds != null) { sascha@168: BasicDataSource x = ds; ds = null; sascha@168: try { sascha@168: x.close(); sascha@168: } sascha@168: catch (SQLException sqle) { sascha@168: } sascha@168: } sascha@168: throw new HibernateException(message, e); sascha@168: } sascha@168: log.debug("Configure DBCPConnectionProvider complete"); sascha@168: } sascha@168: sascha@168: public Connection getConnection() throws SQLException { andre@8708: log.trace("Connection pool parameters:"); andre@8708: log.trace("_ active connections: " + ds.getNumActive()); andre@8708: log.trace("_ idle connections: " + ds.getNumIdle()); tom@8763: log.trace("_ max active: " + ds.getMaxTotal()); tom@8763: if (ds.getNumActive() == ds.getMaxTotal()) { tom@8481: log.warn("Maximum number of database connections in pool in use!"); tom@8481: } tom@8481: Connection conn = ds.getConnection(); andre@8708: log.trace("Return connection with hash: " + conn.hashCode()); tom@8481: return conn; sascha@168: } sascha@168: sascha@168: public void closeConnection(Connection conn) throws SQLException { andre@8708: log.trace("Close connection with hash: " + conn.hashCode()); sascha@168: conn.close(); sascha@168: } sascha@168: sascha@168: public void close() throws HibernateException { sascha@168: try { sascha@168: if (ds != null) { sascha@168: BasicDataSource x = ds; ds = null; sascha@168: x.close(); sascha@168: } sascha@168: } sascha@168: catch (SQLException sqle) { sascha@168: throw new HibernateException("Could not close DBCP pool", sqle); sascha@168: } sascha@168: } sascha@168: sascha@168: public boolean supportsAggressiveRelease() { sascha@168: return false; sascha@168: } sascha@168: } sascha@168: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :