Added test case for ServiceManagerRegistry and fixed a few bugs.
git-svn-id: https://svn.apache.org/repos/asf/geronimo/xbean/branches/new@380371 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/kernel/project.xml b/kernel/project.xml
index ba892bc..397742a 100644
--- a/kernel/project.xml
+++ b/kernel/project.xml
@@ -64,6 +64,12 @@
<artifactId>backport-util-concurrent</artifactId>
<version>2.0_01_pd</version>
</dependency>
+ <dependency>
+ <groupId>cglib</groupId>
+ <artifactId>cglib-nodep</artifactId>
+ <version>2.1_2</version>
+ <type>test</type>
+ </dependency>
</dependencies>
<build>
diff --git a/kernel/src/java/org/gbean/kernel/standard/ServiceManagerRegistry.java b/kernel/src/java/org/gbean/kernel/standard/ServiceManagerRegistry.java
index c910622..c65e622 100644
--- a/kernel/src/java/org/gbean/kernel/standard/ServiceManagerRegistry.java
+++ b/kernel/src/java/org/gbean/kernel/standard/ServiceManagerRegistry.java
@@ -76,8 +76,9 @@
List managerFutures;
synchronized (serviceManagers) {
- managerFutures = new ArrayList();
+ managerFutures = new ArrayList(serviceManagers.values());
serviceManagers.clear();
+
}
List managers = new ArrayList(managerFutures.size());
diff --git a/kernel/src/test/org/gbean/kernel/standard/ServiceManagerRegistryTest.java b/kernel/src/test/org/gbean/kernel/standard/ServiceManagerRegistryTest.java
new file mode 100644
index 0000000..042fdea
--- /dev/null
+++ b/kernel/src/test/org/gbean/kernel/standard/ServiceManagerRegistryTest.java
@@ -0,0 +1,846 @@
+/**
+ *
+ * Copyright 2005 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gbean.kernel.standard;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import edu.emory.mathcs.backport.java.util.concurrent.Callable;
+import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
+import edu.emory.mathcs.backport.java.util.concurrent.ExecutionException;
+import edu.emory.mathcs.backport.java.util.concurrent.FutureTask;
+import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
+import junit.framework.TestCase;
+import org.gbean.kernel.IllegalServiceStateException;
+import org.gbean.kernel.KernelErrorsError;
+import org.gbean.kernel.ServiceAlreadyExistsException;
+import org.gbean.kernel.ServiceFactory;
+import org.gbean.kernel.ServiceName;
+import org.gbean.kernel.ServiceNotFoundException;
+import org.gbean.kernel.ServiceRegistrationException;
+import org.gbean.kernel.StaticServiceFactory;
+import org.gbean.kernel.StopStrategies;
+import org.gbean.kernel.StopStrategy;
+import org.gbean.kernel.StringServiceName;
+import org.gbean.kernel.UnsatisfiedConditionsException;
+
+/**
+ * Test the ServiceManagerRegistry.
+ *
+ * @author Dain Sundstrom
+ * @version $Id$
+ * @since 1.0
+ */
+public class ServiceManagerRegistryTest extends TestCase {
+ private static final int TIMEOUT_DURATION = 5;
+ private static final TimeUnit TIMEOUT_UNITS = TimeUnit.SECONDS;
+
+ private static final StringServiceName SERVICE_NAME = new StringServiceName("Service");
+ private static final StaticServiceFactory SERVICE_FACTORY = new StaticServiceFactory(new Object());
+ private static final ClassLoader CLASS_LOADER = new URLClassLoader(new URL[0]);
+ private final MockServiceManager serviceManager = new MockServiceManager();
+ private final MockServiceManagerFactory serviceManagerFactory = new MockServiceManagerFactory();
+ private final ServiceManagerRegistry registry = new ServiceManagerRegistry(serviceManagerFactory);
+
+ /**
+ * Tests the initial state of the registry.
+ */
+ public void testInitialState() {
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ assertFalse(serviceManager.isInitializeCalled());
+ assertFalse(serviceManager.isDestroyCalled());
+ }
+
+ /**
+ * Test the registration and unregistration.
+ * Strategy:
+ * <ul><li>
+ * Register a service
+ * </li><li>
+ * Verify the service was registered and callbacks were made
+ * <ul><li>
+ * Unregister the service
+ * </li><li>
+ * Verify the service was unregistered and callbacks were made
+ * </li></ul>
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testRegisterUnregister() throws Exception {
+ register();
+ unregister();
+ }
+
+ /**
+ * Tests the destroy method.
+ * Strategy:
+ * <ul><li>
+ * Register a service
+ * </li><li>
+ * Verify the service was registered and callbacks were made
+ * <ul><li>
+ * Destroy the registry
+ * </li><li>
+ * Verify the service was stopped and callbacks were made
+ * </li></ul>
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testDestroy() throws Exception {
+ register();
+ destroy();
+ }
+
+ /**
+ * Tests that an exception is thrown if an attempt is made to register.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testDoubleRegister() throws Exception {
+ register();
+ try {
+ registry.registerService(SERVICE_NAME, SERVICE_FACTORY, CLASS_LOADER);
+ fail("should have thrown an exception");
+ } catch (ServiceAlreadyExistsException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ }
+
+ /**
+ * Test that an attempt to unregister a service that is not registered throws an exception.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testUnregisterUnknown() throws Exception {
+ try {
+ registry.unregisterService(SERVICE_NAME, StopStrategies.SYNCHRONOUS);
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ }
+
+ /**
+ * Tests that when the initialize method throws an exception the service is not registered.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testRegisterException() throws Exception {
+ register(new Exception("register exception"));
+ register(new RuntimeException("register runtime exception"));
+ register(new Error("register error"));
+ register();
+ unregister();
+ }
+
+ /**
+ * Tests that when the destroy method throws an exception the service is not unregistered.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testUnregisterException() throws Exception {
+ register();
+ unregister(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ unregister(new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ unregister(new RuntimeException("destroy exception"));
+ unregister(new Error("destroy exception"));
+ unregister();
+ }
+
+ /**
+ * Tests that when the destroy and/or stop methods throw an exception during registry destroy, that destruction
+ * continues and the exceptions are thrown in a single KernelErrorsError.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testDestroyException() throws Exception {
+ register();
+ destroy(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET), null);
+ register();
+ destroy(new RuntimeException("destroy exception"), null);
+ register();
+ destroy(new Error("destroy exception"), null);
+ register();
+ destroy(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET), new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ register();
+ destroy(new RuntimeException("destroy exception"), new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ register();
+ destroy(new Error("destroy exception"), new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ register();
+ destroy(null, new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ register();
+ destroy(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET), new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ register();
+ destroy(new RuntimeException("destroy exception"), new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ register();
+ destroy(new Error("destroy exception"), new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ register();
+ destroy(null, new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ register();
+ destroy(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET), new RuntimeException("destroy exception"));
+ register();
+ destroy(new RuntimeException("destroy exception"), new RuntimeException("destroy exception"));
+ register();
+ destroy(new Error("destroy exception"), new RuntimeException("destroy exception"));
+ register();
+ destroy(null, new RuntimeException("destroy exception"));
+ register();
+ destroy(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET), new Error("destroy exception"));
+ register();
+ destroy(new RuntimeException("destroy exception"), new Error("destroy exception"));
+ register();
+ destroy(new Error("destroy exception"), new Error("destroy exception"));
+ register();
+ destroy(null, new Error("destroy exception"));
+ }
+
+ /**
+ * Tests that when a service manager blocks during registration, that the registry blocks isRegistered and
+ * getServiceManager calls until the registration completes.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testRegisterWaiting() throws Exception {
+ registerWaiting(null);
+ }
+
+ /**
+ * Tests that when a service manager blocks during registration and then throws an exception, that the registry
+ * blocks isRegistered and getServiceManager calls until the registration completes, and then returns the correct
+ * values for an unregistered service.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testRegisterWaitingException() throws Exception {
+ registerWaiting(new Exception("register exception"));
+ registerWaiting(new RuntimeException("register runtime exception"));
+ registerWaiting(new Error("register error"));
+ }
+
+ /**
+ * Tests that when a blocking service throws an exception during registration a nother service can wait be waiting
+ * to take over the registration from the failed thread.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testDoubleRegisterWaiting() throws Exception {
+ // start thread to attempt to register but throw an exception
+ FutureTask registerFailTask = registerWaitingTask(new Exception("register exception"));
+
+ // start thread to successfully register
+ final CountDownLatch registerStartedSignal = new CountDownLatch(1);
+ final MockServiceManager newServiceManager = new MockServiceManager();
+ newServiceManager.setWait();
+ FutureTask registerTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ registerStartedSignal.countDown();
+ register(null, newServiceManager);
+ return Boolean.TRUE;
+ }
+ });
+ Thread registerThread = new Thread(registerTask, "registerTask");
+ registerThread.setDaemon(true);
+ registerThread.start();
+ registerStartedSignal.await(TIMEOUT_DURATION, TIMEOUT_UNITS);
+
+ // sleep a bit to assure that the register thread entered the registry code
+ Thread.sleep(100);
+
+ // verify all are not done
+ assertFalse(registerFailTask.isDone());
+ assertFalse(registerTask.isDone());
+
+ // finish register fail, and verify it failed
+ serviceManager.signalExit();
+ assertEquals(Boolean.FALSE, registerFailTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+
+ // verify success registration and verify itworked
+ newServiceManager.signalExit();
+ assertEquals(Boolean.TRUE, registerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertTrue(registry.isRegistered(SERVICE_NAME));
+ assertEquals(newServiceManager, registry.getServiceManager(SERVICE_NAME));
+ }
+
+ /**
+ * Tests that when a service manager blocks during unregistration, that the registry blocks isRegistered and
+ * getServiceManager calls until the unregistration completes.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testUnregisterWaiting() throws Exception {
+ register();
+ unregisterWaiting(null);
+ }
+
+ /**
+ * Tests that when a service manager blocks during unregistration and then throws an exception, that the registry
+ * blocks isRegistered and getServiceManager calls until the unregistration completes, and then returns the correct
+ * values for an unregistered service.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testUnregisterWaitingException() throws Exception {
+ register();
+ unregisterWaiting(new UnsatisfiedConditionsException("destroy exception", SERVICE_NAME, Collections.EMPTY_SET));
+ unregisterWaiting(new IllegalServiceStateException("destroy exception", SERVICE_NAME));
+ unregisterWaiting(new RuntimeException("destroy exception"));
+ unregisterWaiting(new Error("destroy exception"));
+ unregisterWaiting(null);
+ }
+
+ /**
+ * Tests that when a service manager blocks during destroy, that the registry does not block isRegistered and
+ * getServiceManager calls, and then returns the correct values for an unregistered service.
+ *
+ * @throws Exception if there is a failure
+ */
+ public void testDestroyWaiting() throws Exception {
+ register();
+
+ // start thread to destroy and wait
+ FutureTask destroyTask = destroyWaitingTask();
+
+ // verify all are not done
+ assertFalse(destroyTask.isDone());
+
+ // verify that the service already appears to be unregistered
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+
+ // finish register
+ serviceManager.signalExit();
+
+ // verify registration worked
+ assertEquals(Boolean.TRUE, destroyTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ }
+
+ private void registerWaiting(Throwable throwable) throws Exception {
+ // start thread to register and wait
+ FutureTask registerTask = registerWaitingTask(throwable);
+
+ // start thread to attempt getService
+ FutureTask getServiceManagerTask = getServiceWaiting();
+
+ // start thread to attempt isRegistered
+ FutureTask isRegisteredTask = isRegisteredWaiting();
+
+ // not necessary, but sleep a bit anyway
+ Thread.sleep(100);
+
+ // verify all are not done
+ assertFalse(registerTask.isDone());
+ assertFalse(getServiceManagerTask.isDone());
+ assertFalse(isRegisteredTask.isDone());
+
+ // finish register
+ serviceManager.signalExit();
+
+ if (throwable == null) {
+ // verify registration worked
+ assertEquals(Boolean.TRUE, registerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertTrue(registry.isRegistered(SERVICE_NAME));
+ assertEquals(serviceManager, registry.getServiceManager(SERVICE_NAME));
+
+ // verify waiting isRegistered worked
+ assertEquals(Boolean.TRUE, isRegisteredTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+
+ // verify getServiceManager worked
+ assertEquals(serviceManager, getServiceManagerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ } else {
+ // verify registration failed
+ assertEquals(Boolean.FALSE, registerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+
+ // verify waiting isRegistered worked
+ assertEquals(Boolean.FALSE, isRegisteredTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+
+ // verify getServiceManager worked
+ try {
+ getServiceManagerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ fail("should have thrown an exception");
+ } catch (ExecutionException e) {
+ assertTrue(e.getCause() instanceof ServiceNotFoundException);
+ ServiceNotFoundException serviceNotFoundException = (ServiceNotFoundException) e.getCause();
+ assertSame(SERVICE_NAME, serviceNotFoundException.getServiceName());
+ }
+ }
+ }
+
+ private FutureTask registerWaitingTask(final Throwable throwable) throws InterruptedException {
+ serviceManager.setWait();
+ FutureTask registerTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ register(throwable);
+ return Boolean.valueOf(throwable == null);
+ }
+ });
+ Thread registerThread = new Thread(registerTask, throwable == null ? "registerTask" : "registerExceptionTask");
+ registerThread.setDaemon(true);
+ registerThread.start();
+
+ // wait for register to block
+ assertTrue(serviceManager.awaitEnterSignal());
+ return registerTask;
+ }
+
+ private void unregisterWaiting(Throwable throwable) throws Exception {
+ // start thread to unregister and wait
+ FutureTask unregisterTask = unregisterWaitingTask(throwable);
+
+ // start thread to attempt getService
+ FutureTask getServiceManagerTask = getServiceWaiting();
+
+ // start thread to attempt isRegistered
+ FutureTask isRegisteredTask = isRegisteredWaiting();
+
+ // not necessary, but sleep a bit anyway
+ Thread.sleep(100);
+
+ // verify all are not done
+ assertFalse(unregisterTask.isDone());
+ assertFalse(getServiceManagerTask.isDone());
+ assertFalse(isRegisteredTask.isDone());
+
+ // finish register
+ serviceManager.signalExit();
+
+ if (throwable == null) {
+ // verify registration worked
+ assertEquals(Boolean.TRUE, unregisterTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+
+ // verify waiting isRegistered worked
+ assertEquals(Boolean.FALSE, isRegisteredTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+
+ // verify getServiceManager worked
+ try {
+ getServiceManagerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ fail("should have thrown an exception");
+ } catch (ExecutionException e) {
+ assertTrue(e.getCause() instanceof ServiceNotFoundException);
+ ServiceNotFoundException serviceNotFoundException = (ServiceNotFoundException) e.getCause();
+ assertSame(SERVICE_NAME, serviceNotFoundException.getServiceName());
+ }
+ } else {
+ // verify unregistration failed
+ assertEquals(Boolean.FALSE, unregisterTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ assertTrue(registry.isRegistered(SERVICE_NAME));
+ assertEquals(serviceManager, registry.getServiceManager(SERVICE_NAME));
+
+ // verify waiting isRegistered worked
+ assertEquals(Boolean.TRUE, isRegisteredTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+
+ // verify getServiceManager worked
+ assertEquals(serviceManager, getServiceManagerTask.get(TIMEOUT_DURATION, TIMEOUT_UNITS));
+ }
+ }
+
+ private FutureTask unregisterWaitingTask(final Throwable throwable) throws InterruptedException {
+ serviceManager.setWait();
+ FutureTask unregisterTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ unregister(throwable);
+ return Boolean.valueOf(throwable == null);
+ }
+ });
+ Thread unregisterThread = new Thread(unregisterTask, throwable == null ? "unregisterTask" : "unregisterExceptionTask");
+ unregisterThread.setDaemon(true);
+ unregisterThread.start();
+
+ // wait for register to block
+ assertTrue(serviceManager.awaitEnterSignal());
+ return unregisterTask;
+ }
+
+ private FutureTask destroyWaitingTask() throws InterruptedException {
+ serviceManager.setWait();
+ FutureTask unregisterTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ destroy();
+ return Boolean.TRUE;
+ }
+ });
+ Thread destroyThread = new Thread(unregisterTask, "destroyTask");
+ destroyThread.setDaemon(true);
+ destroyThread.start();
+
+ // wait for register to block
+ assertTrue(serviceManager.awaitEnterSignal());
+ return unregisterTask;
+ }
+
+ private FutureTask getServiceWaiting() throws InterruptedException {
+ final CountDownLatch getServiceManagerSignal = new CountDownLatch(1);
+ FutureTask getServiceManagerTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ getServiceManagerSignal.countDown();
+ return registry.getServiceManager(SERVICE_NAME);
+ }
+ });
+ Thread getServiceManagerThread = new Thread(getServiceManagerTask, "getServiceManagerTask");
+ getServiceManagerThread.setDaemon(true);
+ getServiceManagerThread.start();
+
+ // wait for thread started
+ getServiceManagerSignal.await(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ return getServiceManagerTask;
+ }
+
+ private FutureTask isRegisteredWaiting() throws InterruptedException {
+ final CountDownLatch isRegisteredSignal = new CountDownLatch(1);
+ FutureTask isRegisteredTask = new FutureTask(new Callable() {
+ public Object call() throws Exception {
+ isRegisteredSignal.countDown();
+ return Boolean.valueOf(registry.isRegistered(SERVICE_NAME));
+ }
+ });
+ Thread isRegisteredThread = new Thread(isRegisteredTask, "isRegisteredTask");
+ isRegisteredThread.setDaemon(true);
+ isRegisteredThread.start();
+
+ // wait for thread started
+ isRegisteredSignal.await(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ return isRegisteredTask;
+ }
+
+ private void register() throws Exception {
+ register(null, serviceManager);
+ }
+
+ private void register(Throwable throwable) throws Exception {
+ register(throwable, serviceManager);
+ }
+
+ private void register(Throwable throwable, MockServiceManager serviceManager) throws Exception {
+ serviceManager.reset();
+ serviceManager.setInitializeException(throwable);
+ serviceManagerFactory.addServiceManager(serviceManager);
+ try {
+ registry.registerService(SERVICE_NAME, SERVICE_FACTORY, CLASS_LOADER);
+ assertNull(throwable);
+ } catch (ServiceRegistrationException expected) {
+ // expected
+ assertSame(throwable, expected.getCause());
+ assertSame(SERVICE_NAME, expected.getServiceName());
+ }
+
+ if (throwable == null) {
+ assertTrue(registry.isRegistered(SERVICE_NAME));
+ assertEquals(serviceManager, registry.getServiceManager(SERVICE_NAME));
+ } else {
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ }
+ assertTrue(serviceManager.isInitializeCalled());
+ assertFalse(serviceManager.isDestroyCalled());
+ }
+
+ private void unregister() throws ServiceNotFoundException {
+ unregister(null);
+ }
+
+ private void unregister(Throwable throwable) throws ServiceNotFoundException {
+ serviceManager.reset();
+ serviceManager.setDestroyException(throwable);
+ try {
+ registry.unregisterService(SERVICE_NAME, StopStrategies.SYNCHRONOUS);
+ assertNull(throwable);
+ } catch (ServiceRegistrationException expected) {
+ // expected
+ assertSame(SERVICE_NAME, expected.getServiceName());
+ assertSame(throwable, expected.getCause());
+ }
+
+ if (throwable == null) {
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ } else {
+ assertTrue(registry.isRegistered(SERVICE_NAME));
+ assertEquals(serviceManager, registry.getServiceManager(SERVICE_NAME));
+ }
+ assertFalse(serviceManager.isInitializeCalled());
+ assertTrue(serviceManager.isDestroyCalled());
+ }
+
+ private void destroy() {
+ destroy(null, null);
+ }
+
+ private void destroy(Throwable stopException, Throwable destroyException) {
+ serviceManager.reset();
+ serviceManager.setStopException(stopException);
+ serviceManager.setDestroyException(destroyException);
+
+ try {
+ registry.destroy();
+ assertNull(stopException);
+ assertNull(destroyException);
+ } catch (KernelErrorsError kernelErrorsError) {
+ List errors = new ArrayList(kernelErrorsError.getErrors());
+ if (stopException != null) {
+ assertTrue(errors.size() >= 3);
+ assertTrue(errors.get(0) instanceof AssertionError);
+ assertSame(stopException, ((AssertionError) errors.get(0)).getCause());
+ assertTrue(errors.get(1) instanceof AssertionError);
+ assertSame(stopException, ((AssertionError) errors.get(1)).getCause());
+ assertTrue(errors.get(2) instanceof AssertionError);
+ assertSame(stopException, ((AssertionError) errors.get(2)).getCause());
+ errors = errors.subList(3, errors.size());
+ }
+
+ if (destroyException != null) {
+ assertEquals(1, errors.size());
+ assertTrue(errors.get(0) instanceof AssertionError);
+ assertSame(destroyException, ((AssertionError) errors.get(0)).getCause());
+ errors = Collections.EMPTY_LIST;
+ }
+
+ assertEquals(Collections.EMPTY_LIST, errors);
+ }
+
+ assertFalse(registry.isRegistered(SERVICE_NAME));
+ try {
+ assertNull(registry.getServiceManager(SERVICE_NAME));
+ fail("should have thrown an exception");
+ } catch (ServiceNotFoundException expected) {
+ // expected
+ assertEquals(SERVICE_NAME, expected.getServiceName());
+ }
+ assertFalse(serviceManager.isInitializeCalled());
+ assertTrue(serviceManager.isStopCalled());
+ assertTrue(serviceManager.isDestroyCalled());
+ }
+
+ private static class MockServiceManagerFactory extends ServiceManagerFactory {
+ private final LinkedList serviceManagers = new LinkedList();
+
+ private MockServiceManagerFactory() {
+ super(null, null, null, 0, null);
+ }
+
+ public ServiceManager createServiceManager(ServiceName serviceName, ServiceFactory serviceFactory, ClassLoader classLoader) {
+ assertEquals(SERVICE_NAME, serviceName);
+ assertEquals(SERVICE_FACTORY, serviceFactory);
+ assertEquals(CLASS_LOADER, classLoader);
+ synchronized (serviceManagers) {
+ return (ServiceManager) serviceManagers.removeFirst();
+ }
+ }
+
+ public void addServiceManager(ServiceManager serviceManager) {
+ synchronized (serviceManagers) {
+ serviceManagers.add(serviceManager);
+ }
+ }
+ }
+
+ private static class MockServiceManager extends ServiceManager {
+ private boolean initializeCalled;
+ private boolean destroyCalled;
+ private boolean stopCalled;
+ private Throwable initializeException;
+ private Throwable destroyException;
+ private Throwable stopException;
+ private CountDownLatch enterWaiting = new CountDownLatch(1);
+ private CountDownLatch exitWaiting = new CountDownLatch(0);
+
+
+ private MockServiceManager() {
+ super(null, null, null, null, null, null, 0, null);
+ }
+
+ private synchronized void reset() {
+ initializeCalled = false;
+ destroyCalled = false;
+ stopCalled = false;
+ initializeException = null;
+ destroyException = null;
+ stopException = null;
+ }
+
+ public void initialize() throws IllegalServiceStateException, UnsatisfiedConditionsException, Exception {
+ synchronized (this) {
+ assertFalse(initializeCalled);
+ initializeCalled = true;
+ }
+
+ signalEnter();
+ awaitExitSignal();
+
+ synchronized (this) {
+ if (initializeException instanceof Exception) {
+ throw (Exception) initializeException;
+ } else if (initializeException instanceof Error) {
+ throw (Error) initializeException;
+ }
+ }
+ }
+
+ public void destroy(StopStrategy stopStrategy) throws IllegalServiceStateException, UnsatisfiedConditionsException {
+ synchronized (this) {
+ assertFalse(destroyCalled);
+ destroyCalled = true;
+ }
+
+ try {
+ signalEnter();
+ awaitExitSignal();
+ } catch (InterruptedException e) {
+ fail("destroyCondition.await() threw an exception");
+ }
+
+ synchronized (this) {
+ if (destroyException instanceof UnsatisfiedConditionsException) {
+ throw (UnsatisfiedConditionsException) destroyException;
+ } else if (destroyException instanceof IllegalServiceStateException) {
+ throw (IllegalServiceStateException) destroyException;
+ } else if (destroyException instanceof RuntimeException) {
+ throw (RuntimeException) destroyException;
+ } else if (destroyException instanceof Error) {
+ throw (Error) destroyException;
+ }
+ }
+ }
+
+ public synchronized boolean stop(StopStrategy stopStrategy) throws UnsatisfiedConditionsException {
+ stopCalled = true;
+
+ if (stopException instanceof UnsatisfiedConditionsException) {
+ throw (UnsatisfiedConditionsException) stopException;
+ } else if (stopException instanceof RuntimeException) {
+ throw (RuntimeException) stopException;
+ } else if (stopException instanceof Error) {
+ throw (Error) stopException;
+ }
+ return true;
+ }
+
+ public synchronized boolean isInitializeCalled() {
+ return initializeCalled;
+ }
+
+ public synchronized boolean isDestroyCalled() {
+ return destroyCalled;
+ }
+
+ public synchronized boolean isStopCalled() {
+ return stopCalled;
+ }
+
+ public synchronized void setInitializeException(Throwable initializeException) {
+ this.initializeException = initializeException;
+ }
+
+ public synchronized void setDestroyException(Throwable destroyException) {
+ this.destroyException = destroyException;
+ }
+
+ public synchronized void setStopException(Throwable stopException) {
+ this.stopException = stopException;
+ }
+
+ public boolean awaitEnterSignal() throws InterruptedException {
+ CountDownLatch signal;
+ synchronized (this) {
+ signal = enterWaiting;
+ }
+ boolean worked = signal.await(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ return worked;
+ }
+
+ private void signalEnter() {
+ CountDownLatch signal;
+ synchronized (this) {
+ signal = enterWaiting;
+ }
+ signal.countDown();
+ }
+
+ public synchronized void setWait() {
+ exitWaiting = new CountDownLatch(1);
+ enterWaiting = new CountDownLatch(1);
+ }
+
+ public void signalExit() {
+ CountDownLatch signal;
+ synchronized (this) {
+ signal = exitWaiting;
+ }
+ signal.countDown();
+ }
+
+ private void awaitExitSignal() throws InterruptedException {
+ CountDownLatch signal;
+ synchronized (this) {
+ signal = exitWaiting;
+ }
+ signal.await(TIMEOUT_DURATION, TIMEOUT_UNITS);
+ }
+ }
+}