HHH-5943 - Make ServiceRegistry mutable

This commit is contained in:
Steve Ebersole 2011-02-21 17:31:40 -06:00 committed by JPAV
parent 02cf95da33
commit 11d32ba69c
25 changed files with 878 additions and 143 deletions

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
@ -31,6 +32,7 @@ import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.util.ReflectHelper;
import org.jboss.logging.Logger;
import com.mchange.v2.c3p0.DataSources;
@ -87,9 +89,22 @@ public class C3P0ConnectionProvider implements ConnectionProvider {
conn.close();
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else if ( DataSource.class.isAssignableFrom( unwrapType ) ) {
return (T) ds;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
/**
* @param props
* @throws HibernateException
* {@inheritDoc}
*/
public void configure(Properties props) throws HibernateException {
String jdbcDriverClass = props.getProperty( Environment.DRIVER );

View File

@ -22,19 +22,10 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.cfg.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.service.classloading.internal.ClassLoaderServiceInitiator;
import org.hibernate.service.internal.ServiceRegistryImpl;
import org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.service.jdbc.dialect.internal.DialectFactoryInitiator;
import org.hibernate.service.jdbc.dialect.internal.DialectResolverInitiator;
import org.hibernate.service.jmx.internal.JmxServiceInitiator;
import org.hibernate.service.jndi.internal.JndiServiceInitiator;
import org.hibernate.service.jta.platform.internal.JtaPlatformInitiator;
import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.StandardServiceInitiators;
/**
* The standard bootstrap process for Hibernate services
@ -42,25 +33,7 @@ import org.hibernate.service.spi.ServiceInitiator;
* @author Steve Ebersole
*/
public class ServicesRegistryBootstrap {
private List<ServiceInitiator> serviceInitiators = new ArrayList<ServiceInitiator>();
public ServicesRegistryBootstrap() {
serviceInitiators.add( ClassLoaderServiceInitiator.INSTANCE );
serviceInitiators.add( JndiServiceInitiator.INSTANCE );
serviceInitiators.add( JmxServiceInitiator.INSTANCE );
serviceInitiators.add( ConnectionProviderInitiator.INSTANCE );
serviceInitiators.add( DialectResolverInitiator.INSTANCE );
serviceInitiators.add( DialectFactoryInitiator.INSTANCE );
serviceInitiators.add( JdbcServicesInitiator.INSTANCE );
serviceInitiators.add( JtaPlatformInitiator.INSTANCE );
//serviceInitiators.add( TransactionFactoryInitiator.INSTANCE );
}
public ServiceRegistryImpl initiateServicesRegistry(Map configurationValues) {
final ServiceRegistryImpl servicesRegistry = new ServiceRegistryImpl( serviceInitiators );
servicesRegistry.initialize( configurationValues );
return servicesRegistry;
return new ServiceRegistryImpl( StandardServiceInitiators.LIST, configurationValues );
}
}

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.internal;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
@ -44,15 +45,15 @@ import org.jboss.logging.Logger;
*
* @author Steve Ebersole
*/
public class ServicesInitializer {
public class ServiceInitializer {
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, ServicesInitializer.class.getName());
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, ServiceInitializer.class.getName());
private final ServiceRegistryImpl servicesRegistry;
private final Map<Class,ServiceInitiator> serviceInitiatorMap;
private final Map configurationValues;
public ServicesInitializer(
public ServiceInitializer(
ServiceRegistryImpl servicesRegistry,
List<ServiceInitiator> serviceInitiators,
Map configurationValues) {
@ -64,11 +65,12 @@ public class ServicesInitializer {
/**
* We convert the incoming list of initiators to a map for 2 reasons:<ul>
* <li>to make it easier to look up the initiator we need for a given service role</li>
* <li>to make sure there is only one initator for a given service role (last wins)</li>
* <li>to make sure there is only one initiator for a given service role (last wins)</li>
* </ul>
*
* @param serviceInitiators
* @return
* @param serviceInitiators The list of individual initiators
*
* @return The map of initiators keyed by the service rle they initiate.
*/
private static Map<Class, ServiceInitiator> toMap(List<ServiceInitiator> serviceInitiators) {
final Map<Class, ServiceInitiator> result = new HashMap<Class, ServiceInitiator>();
@ -78,6 +80,13 @@ public class ServicesInitializer {
return result;
}
void registerServiceInitiator(ServiceInitiator serviceInitiator) {
final Object previous = serviceInitiatorMap.put( serviceInitiator.getServiceInitiated(), serviceInitiator );
final boolean overwritten = previous != null;
if (overwritten) LOG.debugf("Over-wrote existing service initiator [role=%s]",
serviceInitiator.getServiceInitiated().getName());
}
/**
* The main function of this delegate. Used to initialize the service of a given role.
*
@ -158,7 +167,9 @@ public class ServicesInitializer {
dependentServiceRole = injectionMethod.getParameterTypes()[0];
}
final Service dependantService = servicesRegistry.internalGetService( dependentServiceRole );
// todo : because of the use of proxies, this is no longer returning null here...
final Service dependantService = servicesRegistry.getService( dependentServiceRole );
if ( dependantService == null ) {
if ( injectService.required() ) {
throw new ServiceDependencyException(

View File

@ -0,0 +1,41 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.internal;
import org.hibernate.service.spi.Service;
/**
* Marker interface for a service proxy which allows mixed-in ability to unproxy.
*
* @author Steve Ebersole
*/
public interface ServiceProxy extends Service {
/**
* Get the target service instance represented by this proxy.
*
* @param <T>
* @return
*/
public <T extends Service> T getTargetInstance();
}

View File

@ -0,0 +1,41 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.internal;
import org.hibernate.HibernateException;
/**
* Indicates a problem generating a service proxy
*
* @author Steve Ebersole
*/
public class ServiceProxyGenerationException extends HibernateException {
public ServiceProxyGenerationException(String string, Throwable root) {
super( string, root );
}
public ServiceProxyGenerationException(Throwable root) {
super( root );
}
}

View File

@ -22,44 +22,53 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.service.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.internal.proxy.javassist.ServiceProxyFactoryFactoryImpl;
import org.hibernate.service.spi.Service;
import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.ServiceRegistry;
import org.hibernate.service.spi.StandardServiceInitiators;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownServiceException;
import org.hibernate.service.spi.proxy.ServiceProxyFactory;
import org.hibernate.service.spi.proxy.ServiceProxyTargetSource;
import org.hibernate.util.CollectionHelper;
import org.jboss.logging.Logger;
/**
* Basic Hibernate implementation of the service registry.
* Standard Hibernate implementation of the service registry.
*
* @author Steve Ebersole
*/
public class ServiceRegistryImpl implements ServiceRegistry {
public class ServiceRegistryImpl implements ServiceProxyTargetSource {
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, ServiceRegistryImpl.class.getName());
private final List<ServiceInitiator> serviceInitiators;
private ServicesInitializer initializer;
private final ServiceInitializer initializer;
// for now just hardcode the javassist factory
private ServiceProxyFactory serviceProxyFactory = new ServiceProxyFactoryFactoryImpl().makeServiceProxyFactory( this );
private HashMap<Class,Service> serviceMap = new HashMap<Class, Service>();
private ConcurrentHashMap<Class,ServiceBinding> serviceBindingMap;
// IMPL NOTE : the list used for ordered destruction. Cannot used ordered map above because we need to
// iterate it in reverse order which is only available through ListIterator
private List<Service> serviceList = new ArrayList<Service>();
public ServiceRegistryImpl(List<ServiceInitiator> serviceInitiators) {
this.serviceInitiators = Collections.unmodifiableList( serviceInitiators );
public ServiceRegistryImpl(Map configurationValues) {
this( StandardServiceInitiators.LIST, configurationValues );
}
public void initialize(Map configurationValues) {
this.initializer = new ServicesInitializer( this, serviceInitiators, ConfigurationHelper.clone( configurationValues ) );
public ServiceRegistryImpl(List<ServiceInitiator> serviceInitiators, Map configurationValues) {
this.initializer = new ServiceInitializer( this, serviceInitiators, ConfigurationHelper.clone( configurationValues ) );
final int anticipatedSize = serviceInitiators.size() + 5; // allow some growth
serviceBindingMap = CollectionHelper.concurrentMap( anticipatedSize );
serviceList = CollectionHelper.arrayList( anticipatedSize );
}
public void destroy() {
@ -77,35 +86,84 @@ public class ServiceRegistryImpl implements ServiceRegistry {
}
serviceList.clear();
serviceList = null;
serviceMap.clear();
serviceMap = null;
serviceBindingMap.clear();
serviceBindingMap = null;
}
@Override
@SuppressWarnings({ "unchecked" })
public <T extends Service> T getService(Class<T> serviceRole) {
T service = internalGetService( serviceRole );
return locateOrCreateServiceBinding( serviceRole ).getProxy();
}
@SuppressWarnings({ "unchecked" })
private <T extends Service> ServiceBinding<T> locateOrCreateServiceBinding(Class<T> serviceRole) {
ServiceBinding<T> serviceBinding = serviceBindingMap.get( serviceRole );
if ( serviceBinding == null ) {
T proxy = serviceProxyFactory.makeProxy( serviceRole );
serviceBinding = new ServiceBinding<T>( proxy );
serviceBindingMap.put( serviceRole, serviceBinding );
}
return serviceBinding;
}
@Override
@SuppressWarnings( {"unchecked"})
public <T extends Service> T getServiceInternal(Class<T> serviceRole) {
ServiceBinding<T> serviceBinding = serviceBindingMap.get( serviceRole );
if ( serviceBinding == null ) {
throw new HibernateException( "Only proxies should invoke #getServiceInternal" );
}
T service = serviceBinding.getTarget();
if ( service == null ) {
service = initializer.initializeService( serviceRole );
serviceBinding.setTarget( service );
}
if ( service == null ) {
throw new UnknownServiceException( serviceRole );
}
return service;
}
@SuppressWarnings({ "unchecked" })
private <T extends Service> T locateService(Class<T> serviceRole) {
return (T) serviceMap.get( serviceRole );
@Override
public <T extends Service> void registerService(Class<T> serviceRole, T service) {
ServiceBinding<T> serviceBinding = locateOrCreateServiceBinding( serviceRole );
T priorServiceInstance = serviceBinding.getTarget();
serviceBinding.setTarget( service );
if ( priorServiceInstance != null ) {
serviceList.remove( priorServiceInstance );
}
<T extends Service> T internalGetService(Class<T> serviceRole) {
T service = locateService( serviceRole );
if ( service == null ) {
service = initializer.initializeService( serviceRole );
}
return service;
}
<T extends Service> void registerService(Class<T> serviceRole, T service) {
serviceList.add( service );
serviceMap.put( serviceRole, service );
}
@Override
@SuppressWarnings( {"unchecked"})
public void registerServiceInitiator(ServiceInitiator initiator) {
ServiceBinding serviceBinding = serviceBindingMap.get( initiator.getServiceInitiated() );
if ( serviceBinding != null ) {
serviceBinding.setTarget( null );
}
initializer.registerServiceInitiator( initiator );
}
private static final class ServiceBinding<T> {
private final T proxy;
private T target;
private ServiceBinding(T proxy) {
this.proxy = proxy;
}
public T getProxy() {
return proxy;
}
public T getTarget() {
return target;
}
public void setTarget(T target) {
this.target = target;
}
}
}

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.internal.proxy.javassist;
import org.hibernate.service.spi.proxy.ServiceProxyFactory;
import org.hibernate.service.spi.proxy.ServiceProxyFactoryFactory;
import org.hibernate.service.spi.proxy.ServiceProxyTargetSource;
/**
* @author Steve Ebersole
*/
public class ServiceProxyFactoryFactoryImpl implements ServiceProxyFactoryFactory {
@Override
public ServiceProxyFactory makeServiceProxyFactory(ServiceProxyTargetSource registry) {
return new ServiceProxyFactoryImpl( registry );
}
}

View File

@ -0,0 +1,122 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.internal.proxy.javassist;
import javassist.util.proxy.MethodFilter;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import org.hibernate.service.internal.ServiceProxy;
import org.hibernate.service.internal.ServiceProxyGenerationException;
import org.hibernate.service.spi.Service;
import org.hibernate.service.spi.proxy.ServiceProxyFactory;
import org.hibernate.service.spi.proxy.ServiceProxyTargetSource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Steve Ebersole
*/
public class ServiceProxyFactoryImpl implements ServiceProxyFactory {
private final ServiceProxyTargetSource serviceRegistry;
public ServiceProxyFactoryImpl(ServiceProxyTargetSource serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
private static final MethodFilter FINALIZE_FILTER = new MethodFilter() {
public boolean isHandled(Method m) {
// skip finalize methods
return !( m.getParameterTypes().length == 0 && m.getName().equals( "finalize" ) );
}
};
@Override
@SuppressWarnings( {"unchecked"})
public <T extends Service> T makeProxy(Class<T> serviceRole) {
try {
ProxyFactory factory = new ProxyFactory();
factory.setFilter( FINALIZE_FILTER );
Class[] interfaces = new Class[2];
interfaces[0] = serviceRole;
interfaces[1] = ServiceProxy.class;
factory.setInterfaces( interfaces );
Class proxyClass = factory.createClass();
ProxyObject proxyObject = (ProxyObject) proxyClass.newInstance();
proxyObject.setHandler( new ServiceProxyMethodInterceptor<T>( (T)proxyObject, serviceRole, serviceRegistry ) );
return (T) proxyObject;
}
catch (Exception e) {
throw new ServiceProxyGenerationException( "Unable to make service proxy", e );
}
}
private static class ServiceProxyMethodInterceptor<T extends Service> implements MethodHandler {
private final T proxy;
private final Class<T> serviceRole;
private final ServiceProxyTargetSource serviceRegistry;
private ServiceProxyMethodInterceptor(T proxy, Class<T> serviceRole, ServiceProxyTargetSource serviceRegistry) {
this.proxy = proxy;
this.serviceRole = serviceRole;
this.serviceRegistry = serviceRegistry;
}
@Override
@SuppressWarnings( {"UnnecessaryBoxing"} )
public Object invoke(
Object object,
Method method,
Method method1,
Object[] args) throws Exception {
String name = method.getName();
if ( "toString".equals( name ) ) {
return serviceRole.getName() + "_$$_Proxy@" + System.identityHashCode( object );
}
else if ( "equals".equals( name ) ) {
return proxy == object ? Boolean.TRUE : Boolean.FALSE;
}
else if ( "hashCode".equals( name ) ) {
return Integer.valueOf( System.identityHashCode( object ) );
}
else if ( "getTargetInstance".equals( name ) && ServiceProxy.class.equals( method.getDeclaringClass() ) ) {
return serviceRegistry.getServiceInternal( serviceRole );
}
else {
try {
T target = serviceRegistry.getServiceInternal( serviceRole );
return method.invoke( target, args );
}
catch (InvocationTargetException e) {
throw (Exception) e.getTargetException();
}
}
}
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.service.jndi.spi.JndiService;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.InjectService;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
/**
* A {@link ConnectionProvider} that manages connections from an underlying {@link DataSource}.
@ -69,6 +70,28 @@ public class DatasourceConnectionProviderImpl implements ConnectionProvider, Con
this.jndiService = jndiService;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) ||
DatasourceConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ||
DataSource.class.isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType ) ||
DatasourceConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else if ( DataSource.class.isAssignableFrom( unwrapType ) ) {
return (T) getDataSource();
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
/**
* {@inheritDoc}
*/

View File

@ -35,6 +35,7 @@ import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.util.ReflectHelper;
import org.jboss.logging.Logger;
@ -61,6 +62,24 @@ public class DriverManagerConnectionProviderImpl implements ConnectionProvider,
private final ArrayList<Connection> pool = new ArrayList<Connection>();
private int checkedOut = 0;
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) ||
DriverManagerConnectionProviderImpl.class.isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType ) ||
DriverManagerConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
public void configure(Map configurationValues) {
LOG.usingHibernateBuiltInConnectionPool();

View File

@ -25,6 +25,7 @@ package org.hibernate.service.jdbc.connections.internal;
import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
/**
* An implementation of the {@link ConnectionProvider} interface that simply throws an exception when a connection
@ -35,6 +36,24 @@ import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
* @author Steve Ebersole
*/
public class UserSuppliedConnectionProviderImpl implements ConnectionProvider {
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProvider.class.equals( unwrapType ) ||
UserSuppliedConnectionProviderImpl.class.isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProvider.class.equals( unwrapType ) ||
UserSuppliedConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
/**
* {@inheritDoc}
*/

View File

@ -26,6 +26,7 @@ import java.sql.Connection;
import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.service.spi.Service;
import org.hibernate.service.spi.Wrapped;
/**
* A contract for obtaining JDBC connections.
@ -37,7 +38,7 @@ import org.hibernate.service.spi.Service;
* @author Gavin King
* @author Steve Ebersole
*/
public interface ConnectionProvider extends Service {
public interface ConnectionProvider extends Service, Wrapped {
/**
* Obtains a connection for Hibernate use according to the underlying strategy of this provider.
*
@ -62,7 +63,7 @@ public interface ConnectionProvider extends Service {
* Does this connection provider support aggressive release of JDBC
* connections and re-acquistion of those connections (if need be) later?
* <p/>
* This is used in conjunction with {@link org.hibernate.cfg.Environment.RELEASE_CONNECTIONS}
* This is used in conjunction with {@link org.hibernate.cfg.Environment#RELEASE_CONNECTIONS}
* to aggressively release JDBC connections. However, the configured ConnectionProvider
* must support re-acquisition of the same underlying connection for that semantic to work.
* <p/>

View File

@ -31,14 +31,30 @@ package org.hibernate.service.spi;
*/
public interface ServiceRegistry {
/**
* Retrieve a service by role.
* Retrieve a service by role. If service is not found, but a {@link ServiceInitiator} is registered for
* this service role, the service will be initialized and returned.
*
* @param type The service role
* @param serviceRole The service role
* @param <T> The type of the service
*
* @return The requested service.
*
* @throws UnknownServiceException Indicates the service was not known.
*/
public <T extends Service> T getService(Class<T> type);
public <T extends Service> T getService(Class<T> serviceRole);
/**
* Register a service into the registry.
*
* @param serviceRole The service role.
* @param service The service to register
*/
public <T extends Service> void registerService(Class<T> serviceRole, T service);
/**
* Register a service initiator.
*
* @param initiator The initiator of a service
*/
public void registerServiceInitiator(ServiceInitiator initiator);
}

View File

@ -0,0 +1,61 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi;
import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.service.classloading.internal.ClassLoaderServiceInitiator;
import org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.service.jdbc.dialect.internal.DialectFactoryInitiator;
import org.hibernate.service.jdbc.dialect.internal.DialectResolverInitiator;
import org.hibernate.service.jmx.internal.JmxServiceInitiator;
import org.hibernate.service.jndi.internal.JndiServiceInitiator;
import org.hibernate.service.jta.platform.internal.JtaPlatformInitiator;
import java.util.ArrayList;
import java.util.List;
/**
* @author Steve Ebersole
*/
public class StandardServiceInitiators {
public static List<ServiceInitiator> LIST = buildStandardServiceInitiatorList();
private static List<ServiceInitiator> buildStandardServiceInitiatorList() {
final List<ServiceInitiator> serviceInitiators = new ArrayList<ServiceInitiator>();
serviceInitiators.add( ClassLoaderServiceInitiator.INSTANCE );
serviceInitiators.add( JndiServiceInitiator.INSTANCE );
serviceInitiators.add( JmxServiceInitiator.INSTANCE );
serviceInitiators.add( ConnectionProviderInitiator.INSTANCE );
serviceInitiators.add( DialectResolverInitiator.INSTANCE );
serviceInitiators.add( DialectFactoryInitiator.INSTANCE );
serviceInitiators.add( JdbcServicesInitiator.INSTANCE );
serviceInitiators.add( JtaPlatformInitiator.INSTANCE );
//serviceInitiators.add( TransactionFactoryInitiator.INSTANCE );
return serviceInitiators;
}
}

View File

@ -0,0 +1,40 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi;
import org.hibernate.HibernateException;
/**
* @author Steve Ebersole
*/
public class UnknownUnwrapTypeException extends HibernateException {
public UnknownUnwrapTypeException(Class unwrapType) {
super( "Cannot unwrap to requested type [" + unwrapType.getName() + "]" );
}
public UnknownUnwrapTypeException(Class unwrapType, Throwable root) {
this( unwrapType );
super.initCause( root );
}
}

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi;
/**
* @author Steve Ebersole
*/
public interface Wrapped {
/**
* Can this wrapped service be unwrapped as the indicated type?
*
* @param unwrapType The type to check.
*
* @return True/false.
*/
public boolean isUnwrappableAs(Class unwrapType);
/**
* Unproxy the service proxy
*
* @param unwrapType The java type as which to unwrap this instance.
*
* @return The unwrapped reference
*/
public <T> T unwrap(Class<T> unwrapType);
}

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi.proxy;
import org.hibernate.service.spi.Service;
/**
* @author Steve Ebersole
*/
public interface ServiceProxyFactory {
public <T extends Service> T makeProxy(Class<T> serviceRole);
}

View File

@ -0,0 +1,31 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi.proxy;
/**
* @author Steve Ebersole
*/
public interface ServiceProxyFactoryFactory {
public ServiceProxyFactory makeServiceProxyFactory(ServiceProxyTargetSource registry);
}

View File

@ -0,0 +1,47 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.service.spi.proxy;
import org.hibernate.service.spi.Service;
import org.hibernate.service.spi.ServiceRegistry;
/**
* Additional contract for service proxies. This allows the proxies access to their actual service instances.
*
* @author Steve Ebersole
*/
public interface ServiceProxyTargetSource extends ServiceRegistry {
/**
* Retrieve a service by role. Unlike {@link org.hibernate.service.spi.ServiceRegistry#getService}, this version
* will never return a proxy.
*
* @param serviceRole The service role
* @param <T> The type of the service
*
* @return The requested service.
*
* @throws org.hibernate.service.spi.UnknownServiceException Indicates the service was not known.
*/
public <T extends Service> T getServiceInternal(Class<T> serviceRole);
}

View File

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* Various help for handling collections.
@ -92,4 +93,37 @@ public final class CollectionHelper {
int actual = ( (int) (numberOfElements / LOAD_FACTOR) ) + 1;
return Math.max( actual, MINIMUM_INITIAL_CAPACITY );
}
/**
* Create a properly sized {@link ConcurrentHashMap} based on the given expected number of elements.
*
* @param expectedNumberOfElements The expected number of elements for the created map
* @param <K> The map key type
* @param <V> The map value type
*
* @return The created map.
*/
public static <K,V> ConcurrentHashMap<K,V> concurrentMap(int expectedNumberOfElements) {
return concurrentMap( expectedNumberOfElements, LOAD_FACTOR );
}
/**
* Create a properly sized {@link ConcurrentHashMap} based on the given expected number of elements and an
* explicit load factor
*
* @param expectedNumberOfElements The expected number of elements for the created map
* @param loadFactor The collection load factor
* @param <K> The map key type
* @param <V> The map value type
*
* @return The created map.
*/
public static <K,V> ConcurrentHashMap<K,V> concurrentMap(int expectedNumberOfElements, float loadFactor) {
final int size = expectedNumberOfElements + 1 + (int) ( expectedNumberOfElements * loadFactor );
return new ConcurrentHashMap<K, V>( size, loadFactor );
}
public static <T> List<T> arrayList(int anticipatedSize) {
return new ArrayList<T>( anticipatedSize );
}
}

View File

@ -22,20 +22,13 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.cfg.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.classloading.internal.ClassLoaderServiceInitiator;
import org.hibernate.service.internal.ServiceRegistryImpl;
import org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.service.jdbc.dialect.internal.DialectFactoryInitiator;
import org.hibernate.service.jdbc.dialect.internal.DialectResolverInitiator;
import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.test.common.ConnectionProviderBuilder;
import org.hibernate.testing.junit.UnitTestCase;
@ -45,47 +38,32 @@ import org.hibernate.testing.junit.UnitTestCase;
* @author Steve Ebersole
*/
public class ServiceBootstrappingTest extends UnitTestCase {
private ServiceRegistryImpl servicesRegistry;
public ServiceBootstrappingTest(String string) {
super( string );
}
@Override
protected void setUp() {
List<ServiceInitiator> serviceInitiators = new ArrayList<ServiceInitiator>();
serviceInitiators.add( ClassLoaderServiceInitiator.INSTANCE );
serviceInitiators.add( ConnectionProviderInitiator.INSTANCE );
serviceInitiators.add( DialectResolverInitiator.INSTANCE );
serviceInitiators.add( DialectFactoryInitiator.INSTANCE );
serviceInitiators.add( JdbcServicesInitiator.INSTANCE );
servicesRegistry = new ServiceRegistryImpl( serviceInitiators );
}
@Override
protected void tearDown() {
servicesRegistry.destroy();
}
public void testBasicBuild() {
servicesRegistry.initialize( ConnectionProviderBuilder.getConnectionProviderProperties() );
JdbcServices jdbcServices = servicesRegistry.getService( JdbcServices.class );
ServiceRegistryImpl serviceRegistry = new ServiceRegistryImpl( ConnectionProviderBuilder.getConnectionProviderProperties() );
JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
assertTrue( jdbcServices.getDialect() instanceof H2Dialect );
assertTrue( jdbcServices.getConnectionProvider() instanceof DriverManagerConnectionProviderImpl );
assertTrue( jdbcServices.getConnectionProvider().isUnwrappableAs( DriverManagerConnectionProviderImpl.class ) );
assertFalse( jdbcServices.getSqlStatementLogger().isLogToStdout() );
serviceRegistry.destroy();
}
public void testBuildWithLogging() {
Properties props = ConnectionProviderBuilder.getConnectionProviderProperties();
props.put( Environment.SHOW_SQL, "true" );
servicesRegistry.initialize( props );
JdbcServices jdbcServices = servicesRegistry.getService( JdbcServices.class );
ServiceRegistryImpl serviceRegistry = new ServiceRegistryImpl( props );
JdbcServices jdbcServices = serviceRegistry.getService( JdbcServices.class );
assertTrue( jdbcServices.getDialect() instanceof H2Dialect );
assertTrue( jdbcServices.getConnectionProvider() instanceof DriverManagerConnectionProviderImpl );
assertTrue( jdbcServices.getConnectionProvider().isUnwrappableAs( DriverManagerConnectionProviderImpl.class ) );
assertTrue( jdbcServices.getSqlStatementLogger().isLogToStdout() );
serviceRegistry.destroy();
}
}

View File

@ -28,6 +28,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.test.common.ConnectionProviderBuilder;
/**
@ -49,6 +50,28 @@ public class ConnectionProviderImpl implements ConnectionProvider {
public void configure(Properties props) throws HibernateException {
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return ConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ||
ConnectionProvider.class.isAssignableFrom( unwrapType ) ||
getActualConnectionProvider().getClass().isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( ConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else if ( ConnectionProvider.class.isAssignableFrom( unwrapType ) ||
getActualConnectionProvider().getClass().isAssignableFrom( unwrapType ) ) {
return (T) getActualConnectionProvider();
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
public Connection getConnection() throws SQLException {
SimpleJtaTransactionImpl currentTransaction = SimpleJtaTransactionManagerImpl.getInstance().getCurrentTransaction();
if ( currentTransaction == null ) {

View File

@ -27,6 +27,7 @@ import java.sql.SQLException;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.test.common.ConnectionProviderBuilder;
/**
@ -40,6 +41,26 @@ public class DualNodeConnectionProviderImpl implements ConnectionProvider {
private String nodeId;
private boolean isTransactional;
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return DualNodeConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ||
ConnectionProvider.class.isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( DualNodeConnectionProviderImpl.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else if ( ConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
return (T) actualConnectionProvider;
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
public static ConnectionProvider getActualConnectionProvider() {
return actualConnectionProvider;
}

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.test.common.ConnectionProviderBuilder;
/**
@ -42,34 +43,57 @@ public class XaConnectionProvider implements ConnectionProvider {
return actualConnectionProvider;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return XaConnectionProvider.class.isAssignableFrom( unwrapType ) ||
ConnectionProvider.class.equals( unwrapType ) ||
actualConnectionProvider.getClass().isAssignableFrom( unwrapType );
}
@Override
@SuppressWarnings( {"unchecked"})
public <T> T unwrap(Class<T> unwrapType) {
if ( XaConnectionProvider.class.isAssignableFrom( unwrapType ) ) {
return (T) this;
}
else if ( ConnectionProvider.class.isAssignableFrom( unwrapType ) ||
actualConnectionProvider.getClass().isAssignableFrom( unwrapType ) ) {
return (T) getActualConnectionProvider();
}
else {
throw new UnknownUnwrapTypeException( unwrapType );
}
}
public void configure(Properties props) throws HibernateException {
}
public Connection getConnection() throws SQLException {
XaTransactionImpl currentTransaction = XaTransactionManagerImpl.getInstance().getCurrentTransaction();
if (currentTransaction == null) {
if ( currentTransaction == null ) {
isTransactional = false;
return actualConnectionProvider.getConnection();
} else {
}
else {
isTransactional = true;
Connection connection = currentTransaction.getEnlistedConnection();
if (connection == null) {
if ( connection == null ) {
connection = actualConnectionProvider.getConnection();
currentTransaction.enlistConnection(connection);
currentTransaction.enlistConnection( connection );
}
return connection;
}
}
public void closeConnection(Connection conn) throws SQLException {
if (!isTransactional) {
if ( !isTransactional ) {
conn.close();
}
}
public void close() throws HibernateException {
if ( actualConnectionProvider instanceof Stoppable ) {
( ( Stoppable ) actualConnectionProvider ).stop();
((Stoppable) actualConnectionProvider).stop();
}
}

View File

@ -30,6 +30,7 @@ import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.UnknownUnwrapTypeException;
import org.hibernate.util.ConfigHelper;
import org.hibernate.util.StringHelper;
import org.jboss.logging.Logger;
@ -79,6 +80,24 @@ public class ProxoolConnectionProvider implements ConnectionProvider {
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