/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.util.ConfigHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.UnknownUnwrapTypeException;
import org.jboss.logging.Logger;
import org.logicalcobwebs.proxool.ProxoolException;
import org.logicalcobwebs.proxool.ProxoolFacade;
import org.logicalcobwebs.proxool.configuration.JAXPConfigurator;
import org.logicalcobwebs.proxool.configuration.PropertyConfigurator;
/**
* A connection provider that uses a Proxool connection pool. Hibernate will use this by
* default if the <tt>hibernate.proxool.*</tt> properties are set.
* @see ConnectionProvider
*/
public class ProxoolConnectionProvider implements ConnectionProvider {
public static final ProxoolMessageLogger LOG = Logger.getMessageLogger(ProxoolMessageLogger.class, ProxoolConnectionProvider.class.getName());
private static final String PROXOOL_JDBC_STEM = "proxool.";
private String proxoolAlias;
// TRUE if the pool is borrowed from the outside, FALSE if we used to create it
private boolean existingPool;
// Not null if the Isolation level has been specified in the configuration file.
// Otherwise, it is left to the Driver's default value.
private Integer isolation;
private boolean autocommit;
/**
* Grab a connection
* @return a JDBC connection
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
// get a connection from the pool (thru DriverManager, cfr. Proxool doc)
Connection c = DriverManager.getConnection(proxoolAlias);
// set the Transaction Isolation if defined
if (isolation!=null) c.setTransactionIsolation( isolation.intValue() );
// toggle autoCommit to false if set
if ( c.getAutoCommit()!=autocommit ) c.setAutoCommit(autocommit);
// return the connection
return c;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) ||
ProxoolConnectionProvider.class.isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType ) ||
ProxoolConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
/**
* Dispose of a used connection.
* @param conn a JDBC connection
* @throws SQLException
*/
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
/**
* Initialize the connection provider from given properties.
* @param props <tt>SessionFactory</tt> properties
*/
public void configure(Properties props) throws HibernateException {
// Get the configurator files (if available)
String jaxpFile = props.getProperty(Environment.PROXOOL_XML);
String propFile = props.getProperty(Environment.PROXOOL_PROPERTIES);
String externalConfig = props.getProperty(Environment.PROXOOL_EXISTING_POOL);
// Default the Proxool alias setting
proxoolAlias = props.getProperty(Environment.PROXOOL_POOL_ALIAS);
// Configured outside of Hibernate (i.e. Servlet container, or Java Bean Container
// already has Proxool pools running, and this provider is to just borrow one of these
if ( "true".equals(externalConfig) ) {
// Validate that an alias name was provided to determine which pool to use
if ( !StringHelper.isNotEmpty( proxoolAlias ) ) {
String msg = LOG.unableToConfigureProxoolProviderToUseExistingInMemoryPool(Environment.PROXOOL_POOL_ALIAS);
LOG.error(msg);
throw new HibernateException( msg );
}
// Append the stem to the proxool pool alias
proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
// Set the existing pool flag to true
existingPool = true;
LOG.configuringProxoolProviderUsingExistingPool(proxoolAlias);
// Configured using the JAXP Configurator
}
else if ( StringHelper.isNotEmpty( jaxpFile ) ) {
LOG.configuringProxoolProviderUsingJaxpConfigurator(jaxpFile);
// Validate that an alias name was provided to determine which pool to use
if ( !StringHelper.isNotEmpty( proxoolAlias ) ) {
String msg = LOG.unableToConfigureProxoolProviderToUseJaxp(Environment.PROXOOL_POOL_ALIAS);
LOG.error(msg);
throw new HibernateException( msg );
}
try {
JAXPConfigurator.configure( ConfigHelper.getConfigStreamReader( jaxpFile ), false );
}
catch ( ProxoolException e ) {
String msg = LOG.unableToLoadJaxpConfiguratorFile(jaxpFile);
LOG.error(msg, e);
throw new HibernateException( msg, e );
}
// Append the stem to the proxool pool alias
proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
LOG.configuringProxoolProviderToUsePoolAlias(proxoolAlias);
// Configured using the Properties File Configurator
}
else if ( StringHelper.isNotEmpty( propFile ) ) {
LOG.configuringProxoolProviderUsingPropertiesFile(propFile);
// Validate that an alias name was provided to determine which pool to use
if ( !StringHelper.isNotEmpty( proxoolAlias ) ) {
String msg = LOG.unableToConfigureProxoolProviderToUsePropertiesFile(Environment.PROXOOL_POOL_ALIAS);
LOG.error(msg);
throw new HibernateException( msg );
}
try {
PropertyConfigurator.configure( ConfigHelper.getConfigProperties( propFile ) );
}
catch ( ProxoolException e ) {
String msg = LOG.unableToLoadPropertyConfiguratorFile(propFile);
LOG.error(msg, e);
throw new HibernateException( msg, e );
}
// Append the stem to the proxool pool alias
proxoolAlias = PROXOOL_JDBC_STEM + proxoolAlias;
LOG.configuringProxoolProviderToUsePoolAlias(proxoolAlias);
}
// Remember Isolation level
isolation = ConfigurationHelper.getInteger(Environment.ISOLATION, props);
if (isolation != null) LOG.jdbcIsolationLevel(Environment.isolationLevelToString(isolation.intValue()));
autocommit = ConfigurationHelper.getBoolean(Environment.AUTOCOMMIT, props);
LOG.autoCommmitMode(autocommit);
}
/**
* Release all resources held by this provider. JavaDoc requires a second sentence.
* @throws HibernateException
*/
public void close() throws HibernateException {
// If the provider was leeching off an existing pool don't close it
if (existingPool) {
return;
}
// We have created the pool ourselves, so shut it down
try {
if ( ProxoolFacade.getAliases().length == 1 ) {
ProxoolFacade.shutdown( 0 );
}
else {
ProxoolFacade.removeConnectionPool(proxoolAlias.substring(PROXOOL_JDBC_STEM.length()));
}
}
catch (Exception e) {
// If you're closing down the ConnectionProvider chances are an
// is not a real big deal, just warn
String msg = LOG.exceptionClosingProxoolPool();
LOG.warn(msg, e);
throw new HibernateException(msg, e);
}
}
/**
* @see ConnectionProvider#supportsAggressiveRelease()
*/
public boolean supportsAggressiveRelease() {
return false;
}
}