HHH-8619 - Account for "shadow" services as part of ServiceRegistry impls

This commit is contained in:
Steve Ebersole 2013-10-17 15:18:32 -05:00
parent c88494698e
commit 859eaaa1c5
7 changed files with 73 additions and 36 deletions

View File

@ -56,6 +56,7 @@ import org.hibernate.engine.loading.internal.EntityLoadContext;
import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.service.Service;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.SerializationException; import org.hibernate.type.SerializationException;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -1629,4 +1630,11 @@ public interface CoreMessageLogger extends BasicLogger {
"using 'key'/'value' as required by spec; attempting to DoTheRightThing" "using 'key'/'value' as required by spec; attempting to DoTheRightThing"
) )
void nonCompliantMapConversion(String collectionRole); void nonCompliantMapConversion(String collectionRole);
@LogMessage(level = WARN)
@Message(
id = 450,
value = "Encountered request for Service by non-primary service role [%s -> %s]; please update usage"
)
void alternateServiceRole(String requestedRole, String targetRole);
} }

View File

@ -28,11 +28,12 @@ import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger; import org.hibernate.cfg.Environment;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.Service; import org.hibernate.service.Service;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.UnknownServiceException; import org.hibernate.service.UnknownServiceException;
@ -48,19 +49,22 @@ import org.hibernate.service.spi.Startable;
import org.hibernate.service.spi.Stoppable; import org.hibernate.service.spi.Stoppable;
/** /**
* Basic implementation of the ServiceRegistry and ServiceRegistryImplementor contracts
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractServiceRegistryImpl public abstract class AbstractServiceRegistryImpl
implements ServiceRegistryImplementor, ServiceBinding.ServiceLifecycleOwner { implements ServiceRegistryImplementor, ServiceBinding.ServiceLifecycleOwner {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( private static final CoreMessageLogger log = CoreLogging.messageLogger( AbstractServiceRegistryImpl.class );
CoreMessageLogger.class,
AbstractServiceRegistryImpl.class.getName() public static final String ALLOW_CRAWLING = "hibernate.service.allow_crawling";
);
private final ServiceRegistryImplementor parent; private final ServiceRegistryImplementor parent;
private final boolean allowCrawling;
private final ConcurrentHashMap<Class,ServiceBinding> serviceBindingMap = CollectionHelper.concurrentMap( 20 ); private final ConcurrentHashMap<Class,ServiceBinding> serviceBindingMap = CollectionHelper.concurrentMap( 20 );
private ConcurrentHashMap<Class,Class> roleXref;
// IMPL NOTE : the list used for ordered destruction. Cannot used map above because we need to // IMPL NOTE : the list used for ordered destruction. Cannot used map above because we need to
// iterate it in reverse order which is only available through ListIterator // iterate it in reverse order which is only available through ListIterator
@ -74,13 +78,15 @@ public abstract class AbstractServiceRegistryImpl
protected AbstractServiceRegistryImpl(ServiceRegistryImplementor parent) { protected AbstractServiceRegistryImpl(ServiceRegistryImplementor parent) {
this.parent = parent; this.parent = parent;
this.allowCrawling = ConfigurationHelper.getBoolean( ALLOW_CRAWLING, Environment.getProperties(), true );
} }
public AbstractServiceRegistryImpl(BootstrapServiceRegistry bootstrapServiceRegistry) { public AbstractServiceRegistryImpl(BootstrapServiceRegistry bootstrapServiceRegistry) {
if ( ! ServiceRegistryImplementor.class.isInstance( bootstrapServiceRegistry ) ) { if ( ! ServiceRegistryImplementor.class.isInstance( bootstrapServiceRegistry ) ) {
throw new IllegalArgumentException( "Boot-strap registry was not " ); throw new IllegalArgumentException( "ServiceRegistry parent needs to implement ServiceRegistryImplementor" );
} }
this.parent = (ServiceRegistryImplementor) bootstrapServiceRegistry; this.parent = (ServiceRegistryImplementor) bootstrapServiceRegistry;
this.allowCrawling = ConfigurationHelper.getBoolean( ALLOW_CRAWLING, Environment.getProperties(), true );
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
@ -117,9 +123,49 @@ public abstract class AbstractServiceRegistryImpl
// look in parent // look in parent
serviceBinding = parent.locateServiceBinding( serviceRole ); serviceBinding = parent.locateServiceBinding( serviceRole );
} }
if ( serviceBinding != null ) {
return serviceBinding; return serviceBinding;
} }
if ( !allowCrawling ) {
return null;
}
// look for a previously resolved alternate registration
if ( roleXref != null ) {
if ( roleXref.containsKey( serviceRole ) ) {
return serviceBindingMap.get( roleXref.get( serviceRole ) );
}
}
// perform a crawl looking for an alternate registration
for ( ServiceBinding binding : serviceBindingMap.values() ) {
if ( serviceRole.isAssignableFrom( binding.getServiceRole() ) ) {
// we found an alternate...
log.alternateServiceRole( serviceRole.getName(), binding.getServiceRole().getName() );
registerAlternate( serviceRole, binding.getServiceRole() );
return binding;
}
if ( binding.getService() != null && serviceRole.isInstance( binding.getService() ) ) {
// we found an alternate...
log.alternateServiceRole( serviceRole.getName(), binding.getServiceRole().getName() );
registerAlternate( serviceRole, binding.getServiceRole() );
return binding;
}
}
return null;
}
private void registerAlternate(Class alternate, Class target) {
if ( roleXref == null ) {
roleXref = CollectionHelper.concurrentMap( 20 );
}
roleXref.put( alternate, target );
}
@Override @Override
public <R extends Service> R getService(Class<R> serviceRole) { public <R extends Service> R getService(Class<R> serviceRole) {
final ServiceBinding<R> serviceBinding = locateServiceBinding( serviceRole ); final ServiceBinding<R> serviceBinding = locateServiceBinding( serviceRole );
@ -143,8 +189,8 @@ public abstract class AbstractServiceRegistryImpl
} }
private <R extends Service> R initializeService(ServiceBinding<R> serviceBinding) { private <R extends Service> R initializeService(ServiceBinding<R> serviceBinding) {
if ( LOG.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
LOG.tracev( "Initializing service [role={0}]", serviceBinding.getServiceRole().getName() ); log.tracev( "Initializing service [role={0}]", serviceBinding.getServiceRole().getName() );
} }
// PHASE 1 : create service // PHASE 1 : create service
@ -211,7 +257,7 @@ public abstract class AbstractServiceRegistryImpl
} }
} }
catch (NullPointerException e) { catch (NullPointerException e) {
LOG.error("NPE injecting service deps : " + service.getClass().getName()); log.error( "NPE injecting service deps : " + service.getClass().getName() );
} }
} }
@ -285,7 +331,7 @@ public abstract class AbstractServiceRegistryImpl
( (Stoppable) service ).stop(); ( (Stoppable) service ).stop();
} }
catch ( Exception e ) { catch ( Exception e ) {
LOG.unableToStopService( service.getClass(), e.toString() ); log.unableToStopService( service.getClass(), e.toString() );
} }
} }
} }

View File

@ -40,3 +40,4 @@ hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFa
hibernate.jdbc.batch_versioned_data true hibernate.jdbc.batch_versioned_data true
javax.persistence.validation.mode=NONE javax.persistence.validation.mode=NONE
hibernate.service.allow_crawling=false

View File

@ -32,3 +32,4 @@ hibernate.cache.region_prefix hibernate.test
# NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle # NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle
hibernate.jdbc.batch_versioned_data true hibernate.jdbc.batch_versioned_data true
hibernate.service.allow_crawling=false

View File

@ -40,3 +40,4 @@ hibernate.jdbc.batch_size 0
# NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle # NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle
hibernate.jdbc.batch_versioned_data true hibernate.jdbc.batch_versioned_data true
hibernate.service.allow_crawling=false

View File

@ -37,3 +37,4 @@ hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFa
# NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle # NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle
hibernate.jdbc.batch_versioned_data true hibernate.jdbc.batch_versioned_data true
hibernate.service.allow_crawling=false

View File

@ -1,26 +1,4 @@
################################################################################
# Hibernate, Relational Persistence for Idiomatic Java #
# #
# Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates 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. and/or it's affiliates. #
# #
# 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 #
################################################################################
hibernate.dialect org.hibernate.dialect.H2Dialect hibernate.dialect org.hibernate.dialect.H2Dialect
hibernate.connection.driver_class org.h2.Driver hibernate.connection.driver_class org.h2.Driver
hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE hibernate.connection.url jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
@ -37,3 +15,4 @@ hibernate.generate_statistics true
# NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle # NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle
hibernate.jdbc.batch_versioned_data true hibernate.jdbc.batch_versioned_data true
hibernate.service.allow_crawling=false