/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. 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 Inc.
*
* 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.connection;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.util.ReflectHelper;
/**
* Instantiates a connection provider given either <tt>System</tt> properties or
* a <tt>java.util.Properties</tt> instance. The <tt>ConnectionProviderFactory</tt>
* first attempts to find a name of a <tt>ConnectionProvider</tt> subclass in the
* property <tt>hibernate.connection.provider_class</tt>. If missing, heuristics are used
* to choose either <tt>DriverManagerConnectionProvider</tt>,
* <tt>DatasourceConnectionProvider</tt>, <tt>C3P0ConnectionProvider</tt> or
* <tt>DBCPConnectionProvider</tt>.
*
* @author Gavin King
* @see ConnectionProvider
*/
public final class ConnectionProviderFactory {
private static final Logger log = LoggerFactory.getLogger( ConnectionProviderFactory.class );
/**
* Instantiate a <tt>ConnectionProvider</tt> using <tt>System</tt> properties.
*
* @return The created connection provider.
*
* @throws HibernateException
*/
public static ConnectionProvider newConnectionProvider() throws HibernateException {
return newConnectionProvider( Environment.getProperties() );
}
/**
* Instantiate a <tt>ConnectionProvider</tt> using given properties.
* Method newConnectionProvider.
*
* @param properties hibernate <tt>SessionFactory</tt> properties
*
* @return ConnectionProvider
*
* @throws HibernateException
*/
public static ConnectionProvider newConnectionProvider(Properties properties) throws HibernateException {
return newConnectionProvider( properties, null );
}
/**
* Create a connection provider based on the given information.
*
* @param properties Properties being used to build the {@link org.hibernate.SessionFactory}.
* @param connectionProviderInjectionData Something to be injected in the connection provided
*
* @return The created connection provider
*
* @throws HibernateException
*/
public static ConnectionProvider newConnectionProvider(Properties properties, Map connectionProviderInjectionData)
throws HibernateException {
ConnectionProvider connections;
String providerClass = properties.getProperty( Environment.CONNECTION_PROVIDER );
if ( providerClass != null ) {
connections = initializeConnectionProviderFromConfig( providerClass );
}
else if ( c3p0ConfigDefined( properties ) && c3p0ProviderPresent() ) {
connections = initializeConnectionProviderFromConfig("org.hibernate.connection.C3P0ConnectionProvider");
}
else if ( properties.getProperty( Environment.DATASOURCE ) != null ) {
connections = new DatasourceConnectionProvider();
}
else if ( properties.getProperty( Environment.URL ) != null ) {
connections = new DriverManagerConnectionProvider();
}
else {
connections = new UserSuppliedConnectionProvider();
}
if ( connectionProviderInjectionData != null && connectionProviderInjectionData.size() != 0 ) {
//inject the data
try {
BeanInfo info = Introspector.getBeanInfo( connections.getClass() );
PropertyDescriptor[] descritors = info.getPropertyDescriptors();
int size = descritors.length;
for ( int index = 0; index < size; index++ ) {
String propertyName = descritors[index].getName();
if ( connectionProviderInjectionData.containsKey( propertyName ) ) {
Method method = descritors[index].getWriteMethod();
method.invoke(
connections, new Object[] { connectionProviderInjectionData.get( propertyName ) }
);
}
}
}
catch ( IntrospectionException e ) {
throw new HibernateException( "Unable to inject objects into the connection provider", e );
}
catch ( IllegalAccessException e ) {
throw new HibernateException( "Unable to inject objects into the connection provider", e );
}
catch ( InvocationTargetException e ) {
throw new HibernateException( "Unable to inject objects into the connection provider", e );
}
}
connections.configure( properties );
return connections;
}
private static boolean c3p0ProviderPresent() {
try {
ReflectHelper.classForName( "org.hibernate.connection.C3P0ConnectionProvider" );
}
catch ( ClassNotFoundException e ) {
log.warn( "c3p0 properties is specificed, but could not find org.hibernate.connection.C3P0ConnectionProvider from the classpath, " +
"these properties are going to be ignored." );
return false;
}
return true;
}
private static boolean c3p0ConfigDefined(Properties properties) {
Iterator iter = properties.keySet().iterator();
while ( iter.hasNext() ) {
String property = (String) iter.next();
if ( property.startsWith( "hibernate.c3p0" ) ) {
return true;
}
}
return false;
}
private static ConnectionProvider initializeConnectionProviderFromConfig(String providerClass) {
ConnectionProvider connections;
try {
log.info( "Initializing connection provider: " + providerClass );
connections = (ConnectionProvider) ReflectHelper.classForName( providerClass ).newInstance();
}
catch ( Exception e ) {
log.error( "Could not instantiate connection provider", e );
throw new HibernateException( "Could not instantiate connection provider: " + providerClass );
}
return connections;
}
// cannot be instantiated
private ConnectionProviderFactory() {
throw new UnsupportedOperationException();
}
/**
* Transform JDBC connection properties.
*
* Passed in the form <tt>hibernate.connection.*</tt> to the
* format accepted by <tt>DriverManager</tt> by trimming the leading "<tt>hibernate.connection</tt>".
*/
public static Properties getConnectionProperties(Properties properties) {
Iterator iter = properties.keySet().iterator();
Properties result = new Properties();
while ( iter.hasNext() ) {
String prop = (String) iter.next();
if ( prop.startsWith( Environment.CONNECTION_PREFIX ) && !SPECIAL_PROPERTIES.contains( prop ) ) {
result.setProperty(
prop.substring( Environment.CONNECTION_PREFIX.length() + 1 ),
properties.getProperty( prop )
);
}
}
String userName = properties.getProperty( Environment.USER );
if ( userName != null ) {
result.setProperty( "user", userName );
}
return result;
}
private static final Set SPECIAL_PROPERTIES;
static {
SPECIAL_PROPERTIES = new HashSet();
SPECIAL_PROPERTIES.add( Environment.DATASOURCE );
SPECIAL_PROPERTIES.add( Environment.URL );
SPECIAL_PROPERTIES.add( Environment.CONNECTION_PROVIDER );
SPECIAL_PROPERTIES.add( Environment.POOL_SIZE );
SPECIAL_PROPERTIES.add( Environment.ISOLATION );
SPECIAL_PROPERTIES.add( Environment.DRIVER );
SPECIAL_PROPERTIES.add( Environment.USER );
}
}