package org.hibernate.service; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Startable; import org.junit.Test; import org.hibernate.testing.TestForIssue; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; public class ServiceRegistryTest { private final ServiceRegistry registry = buildRegistry(); private final static int NUMBER_OF_THREADS = 100; private StandardServiceRegistryBuilder standardServiceRegistryBuilder; @Test @TestForIssue(jiraKey = "HHH-10427") public void testOnlyOneInstanceOfTheServiceShouldBeCreated() throws InterruptedException, ExecutionException { Future<SlowInitializationService>[] serviceIdentities = execute(); SlowInitializationService previousResult = null; for ( Future<SlowInitializationService> future : serviceIdentities ) { final SlowInitializationService result = future.get(); if ( previousResult == null ) { previousResult = result; } else { assertTrue( "There are more than one instance of the service", result == previousResult ); } } standardServiceRegistryBuilder.destroy( registry ); } @Test @TestForIssue(jiraKey = "HHH-11395") public void testGetService() { assertThat( registry.getService( SlowInitializationService.class ), instanceOf( SlowInitializationService.class ) ); } @Test @TestForIssue(jiraKey = "HHH-11395") public void testGetServiceReturnsNullWhenTheServiceInitiatorInitiateServiceReturnsNull() { assertNull( registry.getService( FakeService.class ) ); } @Test @TestForIssue(jiraKey = "HHH-11395") public void testRequireService() { assertThat( registry.requireService( SlowInitializationService.class ), instanceOf( SlowInitializationService.class ) ); } @Test(expected = NullServiceException.class) @TestForIssue(jiraKey = "HHH-11395") public void testRequireServiceThrowsAnExceptionWhenTheServiceInitiatorInitiateServiceReturnsNull() { assertNull( registry.requireService( FakeService.class ) ); } private ServiceRegistry buildRegistry() { standardServiceRegistryBuilder = new StandardServiceRegistryBuilder(); return standardServiceRegistryBuilder.addInitiator( new SlowServiceInitiator() ) .addInitiator( new NullServiceInitiator() ) .build(); } private FutureTask<SlowInitializationService>[] execute() throws InterruptedException, ExecutionException { FutureTask<SlowInitializationService>[] results = new FutureTask[NUMBER_OF_THREADS]; ExecutorService executor = Executors.newFixedThreadPool( NUMBER_OF_THREADS ); for ( int i = 0; i < NUMBER_OF_THREADS; i++ ) { results[i] = new FutureTask<>( new ServiceCallable( registry ) ); executor.execute( results[i] ); } return results; } public class ServiceCallable implements Callable<SlowInitializationService> { private final ServiceRegistry registry; public ServiceCallable(ServiceRegistry registry) { this.registry = registry; } @Override public SlowInitializationService call() throws Exception { final SlowInitializationService service = registry.getService( SlowInitializationService.class ); assertTrue( "The service is not initialized", service.isInitialized() ); assertTrue( "The service is not configured", service.isConfigured() ); assertTrue( "The service is not started", service.isStarted() ); return service; } } public class SlowInitializationService implements ServiceRegistryAwareService, Configurable, Startable, Service { private final static int TIME_TO_SLEEP = 100; private boolean initialized; private boolean configured; private boolean started; public SlowInitializationService() { try { Thread.sleep( TIME_TO_SLEEP ); } catch (InterruptedException e) { } } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { try { Thread.sleep( TIME_TO_SLEEP ); } catch (InterruptedException e) { } initialized = true; } @Override public void configure(Map configurationValues) { try { Thread.sleep( TIME_TO_SLEEP ); } catch (InterruptedException e) { } configured = true; } @Override public void start() { try { Thread.sleep( TIME_TO_SLEEP ); } catch (InterruptedException e) { } started = true; } public boolean isInitialized() { return initialized; } public boolean isConfigured() { return configured; } public boolean isStarted() { return started; } } public class SlowServiceInitiator implements StandardServiceInitiator<SlowInitializationService> { @Override public Class<SlowInitializationService> getServiceInitiated() { return SlowInitializationService.class; } @Override public SlowInitializationService initiateService(Map configurationValues, ServiceRegistryImplementor registry) { return new SlowInitializationService(); } } public class NullServiceInitiator implements StandardServiceInitiator<FakeService> { @Override public Class<FakeService> getServiceInitiated() { return FakeService.class; } @Override public FakeService initiateService(Map configurationValues, ServiceRegistryImplementor registry) { return null; } } public class FakeService implements ServiceRegistryAwareService, Configurable, Startable, Service { @Override public void start() { } @Override public void configure(Map configurationValues) { } @Override public void injectServices(ServiceRegistryImplementor serviceRegistry) { } } }