HHH-6796 - Services retrieved after SessionFactoryServiceRegistry has started are not configured (Configurable)

This commit is contained in:
Steve Ebersole 2011-11-03 12:10:30 -05:00
parent 4739c5dc0c
commit 3c3482bd59
5 changed files with 90 additions and 58 deletions

View File

@ -51,15 +51,20 @@ import org.hibernate.service.spi.Stoppable;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImplementor, ServiceBinding.OwningRegistry { public abstract class AbstractServiceRegistryImpl
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, AbstractServiceRegistryImpl.class.getName() ); implements ServiceRegistryImplementor, ServiceBinding.ServiceLifecycleOwner {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
AbstractServiceRegistryImpl.class.getName()
);
private final ServiceRegistryImplementor parent; private final ServiceRegistryImplementor parent;
private ConcurrentHashMap<Class,ServiceBinding> serviceBindingMap; private ConcurrentHashMap<Class,ServiceBinding> serviceBindingMap;
// 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
private List<Service> serviceList = new ArrayList<Service>(); private List<ServiceBinding> serviceBindingList = new ArrayList<ServiceBinding>();
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings( {"UnusedDeclaration"})
protected AbstractServiceRegistryImpl() { protected AbstractServiceRegistryImpl() {
@ -75,7 +80,7 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
private void prepare() { private void prepare() {
// assume 20 services for initial sizing // assume 20 services for initial sizing
this.serviceBindingMap = CollectionHelper.concurrentMap( 20 ); this.serviceBindingMap = CollectionHelper.concurrentMap( 20 );
this.serviceList = CollectionHelper.arrayList( 20 ); this.serviceBindingList = CollectionHelper.arrayList( 20 );
} }
public AbstractServiceRegistryImpl(BootstrapServiceRegistry bootstrapServiceRegistry) { public AbstractServiceRegistryImpl(BootstrapServiceRegistry bootstrapServiceRegistry) {
@ -138,12 +143,8 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
protected <R extends Service> void registerService(ServiceBinding<R> serviceBinding, R service) { protected <R extends Service> void registerService(ServiceBinding<R> serviceBinding, R service) {
R priorServiceInstance = serviceBinding.getService();
serviceBinding.setService( service ); serviceBinding.setService( service );
if ( priorServiceInstance != null ) { serviceBindingList.add( serviceBinding );
serviceList.remove( priorServiceInstance );
}
serviceList.add( service );
} }
private <R extends Service> R initializeService(ServiceBinding<R> serviceBinding) { private <R extends Service> R initializeService(ServiceBinding<R> serviceBinding) {
@ -158,25 +159,18 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
// PHASE 2 : inject service (***potentially recursive***) // PHASE 2 : inject service (***potentially recursive***)
injectService( service ); serviceBinding.getLifecycleOwner().injectDependencies( serviceBinding );
// PHASE 3 : configure service // PHASE 3 : configure service
serviceBinding.getServiceRegistry().configureService( service ); serviceBinding.getLifecycleOwner().configureService( serviceBinding );
// PHASE 4 : Start service // PHASE 4 : Start service
serviceBinding.getLifecycleOwner().startService( serviceBinding );
startService( serviceBinding ); startService( serviceBinding );
return service; return service;
} }
protected <T extends Service> void injectService(T service) {
applyInjections( service );
if ( ServiceRegistryAwareService.class.isInstance( service ) ) {
( (ServiceRegistryAwareService) service ).injectServices( this );
}
}
@SuppressWarnings( {"unchecked"}) @SuppressWarnings( {"unchecked"})
protected <R extends Service> R createService(ServiceBinding<R> serviceBinding) { protected <R extends Service> R createService(ServiceBinding<R> serviceBinding) {
final ServiceInitiator<R> serviceInitiator = serviceBinding.getServiceInitiator(); final ServiceInitiator<R> serviceInitiator = serviceBinding.getServiceInitiator();
@ -186,7 +180,7 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
try { try {
R service = serviceBinding.getServiceRegistry().initiateService( serviceInitiator ); R service = serviceBinding.getLifecycleOwner().initiateService( serviceInitiator );
// IMPL NOTE : the register call here is important to avoid potential stack overflow issues // IMPL NOTE : the register call here is important to avoid potential stack overflow issues
// from recursive calls through #configureService // from recursive calls through #configureService
registerService( serviceBinding, service ); registerService( serviceBinding, service );
@ -200,7 +194,18 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
} }
protected <T extends Service> void applyInjections(T service) { @Override
public <R extends Service> void injectDependencies(ServiceBinding<R> serviceBinding) {
final R service = serviceBinding.getService();
applyInjections( service );
if ( ServiceRegistryAwareService.class.isInstance( service ) ) {
( (ServiceRegistryAwareService) service ).injectServices( this );
}
}
private <R extends Service> void applyInjections(R service) {
try { try {
for ( Method method : service.getClass().getMethods() ) { for ( Method method : service.getClass().getMethods() ) {
InjectService injectService = method.getAnnotation( InjectService.class ); InjectService injectService = method.getAnnotation( InjectService.class );
@ -208,7 +213,7 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
continue; continue;
} }
applyInjection( service, method, injectService ); processInjection( service, method, injectService );
} }
} }
catch (NullPointerException e) { catch (NullPointerException e) {
@ -217,7 +222,7 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
private <T extends Service> void applyInjection(T service, Method injectionMethod, InjectService injectService) { private <T extends Service> void processInjection(T service, Method injectionMethod, InjectService injectService) {
if ( injectionMethod.getParameterTypes() == null || injectionMethod.getParameterTypes().length != 1 ) { if ( injectionMethod.getParameterTypes() == null || injectionMethod.getParameterTypes().length != 1 ) {
throw new ServiceDependencyException( throw new ServiceDependencyException(
"Encountered @InjectService on method with unexpected number of parameters" "Encountered @InjectService on method with unexpected number of parameters"
@ -249,8 +254,9 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
} }
@Override
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
protected <R extends Service> void startService(ServiceBinding<R> serviceBinding) { public <R extends Service> void startService(ServiceBinding<R> serviceBinding) {
if ( Startable.class.isInstance( serviceBinding.getService() ) ) { if ( Startable.class.isInstance( serviceBinding.getService() ) ) {
( (Startable) serviceBinding.getService() ).start(); ( (Startable) serviceBinding.getService() ).start();
} }
@ -262,11 +268,24 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
); );
} }
} }
@Override @Override
@SuppressWarnings( {"unchecked"})
public void destroy() { public void destroy() {
ListIterator<Service> serviceIterator = serviceList.listIterator( serviceList.size() ); ListIterator<ServiceBinding> serviceBindingsIterator = serviceBindingList.listIterator( serviceBindingList.size() );
while ( serviceIterator.hasPrevious() ) { while ( serviceBindingsIterator.hasPrevious() ) {
final Service service = serviceIterator.previous(); final ServiceBinding serviceBinding = serviceBindingsIterator.previous();
serviceBinding.getLifecycleOwner().stopService( serviceBinding );
}
serviceBindingList.clear();
serviceBindingList = null;
serviceBindingMap.clear();
serviceBindingMap = null;
}
@Override
public <R extends Service> void stopService(ServiceBinding<R> binding) {
final Service service = binding.getService();
if ( Stoppable.class.isInstance( service ) ) { if ( Stoppable.class.isInstance( service ) ) {
try { try {
( (Stoppable) service ).stop(); ( (Stoppable) service ).stop();
@ -276,10 +295,4 @@ public abstract class AbstractServiceRegistryImpl implements ServiceRegistryImpl
} }
} }
} }
serviceList.clear();
serviceList = null;
serviceBindingMap.clear();
serviceBindingMap = null;
}
} }

View File

@ -47,7 +47,7 @@ import org.hibernate.service.spi.ServiceRegistryImplementor;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class BootstrapServiceRegistryImpl public class BootstrapServiceRegistryImpl
implements ServiceRegistryImplementor, BootstrapServiceRegistry, ServiceBinding.OwningRegistry { implements ServiceRegistryImplementor, BootstrapServiceRegistry, ServiceBinding.ServiceLifecycleOwner {
private static final LinkedHashSet<Integrator> NO_INTEGRATORS = new LinkedHashSet<Integrator>(); private static final LinkedHashSet<Integrator> NO_INTEGRATORS = new LinkedHashSet<Integrator>();
private final ServiceBinding<ClassLoaderService> classLoaderServiceBinding; private final ServiceBinding<ClassLoaderService> classLoaderServiceBinding;
@ -112,13 +112,27 @@ public class BootstrapServiceRegistryImpl
@Override @Override
public <R extends Service> R initiateService(ServiceInitiator<R> serviceInitiator) { public <R extends Service> R initiateService(ServiceInitiator<R> serviceInitiator) {
// the bootstrap registry should currently be made up of only directly built services. throw new ServiceException( "Boot-strap registry should only contain provided services" );
throw new ServiceException( "Boot-strap registry should only contain directly built services" );
} }
@Override @Override
public <R extends Service> void configureService(R service) { public <R extends Service> void configureService(ServiceBinding<R> binding) {
//nothing do to for bootstrap style services throw new ServiceException( "Boot-strap registry should only contain provided services" );
}
@Override
public <R extends Service> void injectDependencies(ServiceBinding<R> binding) {
throw new ServiceException( "Boot-strap registry should only contain provided services" );
}
@Override
public <R extends Service> void startService(ServiceBinding<R> binding) {
throw new ServiceException( "Boot-strap registry should only contain provided services" );
}
@Override
public <R extends Service> void stopService(ServiceBinding<R> binding) {
throw new ServiceException( "Boot-strap registry should only contain provided services" );
} }
} }

View File

@ -27,8 +27,8 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.source.MetadataImplementor; import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.service.Service; import org.hibernate.service.Service;
import org.hibernate.service.spi.ServiceBinding;
import org.hibernate.service.spi.ServiceInitiator; import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceInitiator; import org.hibernate.service.spi.SessionFactoryServiceInitiator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry; import org.hibernate.service.spi.SessionFactoryServiceRegistry;
@ -96,7 +96,7 @@ public class SessionFactoryServiceRegistryImpl extends AbstractServiceRegistryIm
} }
@Override @Override
public <T extends Service> void configureService(T service) { public <R extends Service> void configureService(ServiceBinding<R> serviceBinding) {
//TODO nothing to do here or should we inject SessionFactory properties? //TODO nothing to do here or should we inject SessionFactory properties?
} }
} }

View File

@ -31,8 +31,8 @@ import org.hibernate.service.Service;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.BasicServiceInitiator; import org.hibernate.service.spi.BasicServiceInitiator;
import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.ServiceBinding;
import org.hibernate.service.spi.ServiceInitiator; import org.hibernate.service.spi.ServiceInitiator;
import org.hibernate.service.spi.ServiceRegistryAwareService;
/** /**
* Hibernate implementation of the standard service registry. * Hibernate implementation of the standard service registry.
@ -70,9 +70,9 @@ public class StandardServiceRegistryImpl extends AbstractServiceRegistryImpl imp
} }
@Override @Override
public <T extends Service> void configureService(T service) { public <R extends Service> void configureService(ServiceBinding<R> serviceBinding) {
if ( Configurable.class.isInstance( service ) ) { if ( Configurable.class.isInstance( serviceBinding.getService() ) ) {
( (Configurable) service ).configure( configurationValues ); ( (Configurable) serviceBinding.getService() ).configure( configurationValues );
} }
} }

View File

@ -35,31 +35,36 @@ import org.hibernate.service.Service;
public final class ServiceBinding<R extends Service> { public final class ServiceBinding<R extends Service> {
private static final Logger log = Logger.getLogger( ServiceBinding.class ); private static final Logger log = Logger.getLogger( ServiceBinding.class );
public static interface OwningRegistry { public static interface ServiceLifecycleOwner {
public <R extends Service> R initiateService(ServiceInitiator<R> serviceInitiator); public <R extends Service> R initiateService(ServiceInitiator<R> serviceInitiator);
public <R extends Service> void configureService(R service);
public <R extends Service> void configureService(ServiceBinding<R> binding);
public <R extends Service> void injectDependencies(ServiceBinding<R> binding);
public <R extends Service> void startService(ServiceBinding<R> binding);
public <R extends Service> void stopService(ServiceBinding<R> binding);
} }
private final OwningRegistry serviceRegistry; private final ServiceLifecycleOwner lifecycleOwner;
private final Class<R> serviceRole; private final Class<R> serviceRole;
private final ServiceInitiator<R> serviceInitiator; private final ServiceInitiator<R> serviceInitiator;
private R service; private R service;
public ServiceBinding(OwningRegistry serviceRegistry, Class<R> serviceRole, R service) { public ServiceBinding(ServiceLifecycleOwner lifecycleOwner, Class<R> serviceRole, R service) {
this.serviceRegistry = serviceRegistry; this.lifecycleOwner = lifecycleOwner;
this.serviceRole = serviceRole; this.serviceRole = serviceRole;
this.serviceInitiator = null; this.serviceInitiator = null;
this.service = service; this.service = service;
} }
public ServiceBinding(OwningRegistry serviceRegistry, ServiceInitiator<R> serviceInitiator) { public ServiceBinding(ServiceLifecycleOwner lifecycleOwner, ServiceInitiator<R> serviceInitiator) {
this.serviceRegistry = serviceRegistry; this.lifecycleOwner = lifecycleOwner;
this.serviceRole = serviceInitiator.getServiceInitiated(); this.serviceRole = serviceInitiator.getServiceInitiated();
this.serviceInitiator = serviceInitiator; this.serviceInitiator = serviceInitiator;
} }
public OwningRegistry getServiceRegistry() { public ServiceLifecycleOwner getLifecycleOwner() {
return serviceRegistry; return lifecycleOwner;
} }
public Class<R> getServiceRole() { public Class<R> getServiceRole() {