/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.proxool.internal; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Map; import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.UnknownUnwrapTypeException; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Stoppable; 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, Configurable, Stoppable, ServiceRegistryAwareService { private 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; private ClassLoaderService classLoaderService; @Override public Connection getConnection() throws SQLException { // get a connection from the pool (thru DriverManager, cfr. Proxool doc) final Connection c = DriverManager.getConnection( proxoolAlias ); // set the Transaction Isolation if defined if ( isolation != null ) { c.setTransactionIsolation( isolation ); } // 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 ); } } @Override public void closeConnection(Connection conn) throws SQLException { conn.close(); } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); } @Override public void configure(Map props) { // Get the configurator files (if available) final String jaxpFile = (String) props.get( Environment.PROXOOL_XML ); final String propFile = (String) props.get( Environment.PROXOOL_PROPERTIES ); final String externalConfig = (String) props.get( Environment.PROXOOL_EXISTING_POOL ); // Default the Proxool alias setting proxoolAlias = (String) props.get( 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 ) ) { final 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 ) ) { final String msg = LOG.unableToConfigureProxoolProviderToUseJaxp( Environment.PROXOOL_POOL_ALIAS ); LOG.error( msg ); throw new HibernateException( msg ); } try { JAXPConfigurator.configure( getConfigStreamReader( jaxpFile ), false ); } catch (ProxoolException e) { final 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 ) ) { final String msg = LOG.unableToConfigureProxoolProviderToUsePropertiesFile( Environment.PROXOOL_POOL_ALIAS ); LOG.error( msg ); throw new HibernateException( msg ); } try { PropertyConfigurator.configure( getConfigProperties( propFile ) ); } catch (ProxoolException e) { final 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 = ConnectionProviderInitiator.extractIsolation( props ); LOG.jdbcIsolationLevel( ConnectionProviderInitiator.toIsolationNiceName( isolation ) ); autocommit = ConfigurationHelper.getBoolean( Environment.AUTOCOMMIT, props ); LOG.autoCommitMode( autocommit ); } private Reader getConfigStreamReader(String resource) { return new InputStreamReader( classLoaderService.locateResourceStream( resource ) ); } private Properties getConfigProperties(String resource) { try { Properties properties = new Properties(); properties.load( classLoaderService.locateResourceStream( resource ) ); return properties; } catch (IOException e) { throw new HibernateException( "Unable to load properties from specified config file: " + resource, e ); } } @Override public boolean supportsAggressiveRelease() { return false; } @Override public void stop() { // 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 final String msg = LOG.exceptionClosingProxoolPool(); LOG.warn( msg, e ); throw new HibernateException( msg, e ); } } /** * Release all resources held by this provider. * * @throws HibernateException Indicates a problem closing the underlying pool or releasing resources * * @deprecated Use {@link #stop} instead */ @Deprecated public void close() throws HibernateException { stop(); } }