[jboss-cvs] JBossAS SVN: r91582 - in projects/kernel/trunk/dependency/src: test/java/org/jboss/test/dependency/controller/support and 1 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Wed Jul 22 17:18:58 EDT 2009
Author: kabir.khan at jboss.com
Date: 2009-07-22 17:18:58 -0400 (Wed, 22 Jul 2009)
New Revision: 91582
Added:
projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/PushControllerStateModel.java
projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/support/UninstallAsynchronousInProgressTestDelegate.java
Modified:
projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/AbstractController.java
projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/test/AsynchronousTestCase.java
Log:
[JBKERNEL-25] Test and fixes for uninstalling an asynchronous context in progress
Modified: projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/AbstractController.java
===================================================================
--- projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/AbstractController.java 2009-07-22 21:06:01 UTC (rev 91581)
+++ projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/AbstractController.java 2009-07-22 21:18:58 UTC (rev 91582)
@@ -33,6 +33,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -94,9 +95,6 @@
/** The contexts that are currently being installed by the executor */
ContextsInstalledByExecutor contextsInstalledByExecutor = new ContextsInstalledByExecutor();
- /** Indicates that a context is to be installed by the executor */
- private final static Thread SCHEDULED_FOR_EXECUTOR = new Thread();
-
/** The parent controller */
private AbstractController parentController;
@@ -670,7 +668,7 @@
if (errorContexts.remove(name) != null && trace)
log.trace("Tidied up context in error state: " + name);
- ControllerContext context = getRegisteredControllerContext(name, false);
+ ControllerContext context = getRegisteredContextAndInterruptAsynchronousInstall(name);
if (context != null)
{
if (trace)
@@ -722,7 +720,25 @@
}
}
+
/**
+ * Obtains the context, having interrupted its installation process if it is an asynchronous context
+ * currently being installed
+ * @param name The name of the context
+ * @return the context or null if not found
+ */
+ private ControllerContext getRegisteredContextAndInterruptAsynchronousInstall(Object name)
+ {
+ ControllerContext context = getRegisteredControllerContext(name, false);
+ if (context != null)
+ {
+ contextsInstalledByExecutor.interruptTaskAndBlock(context, this);
+ context = getRegisteredControllerContext(name, false);
+ }
+ return context;
+ }
+
+ /**
* Install a context
*
* @param context the context
@@ -1168,12 +1184,12 @@
Executor foundExecutor = searchForExecutor();
if (foundExecutor != null)
{
- contextsInstalledByExecutor.markForThreadExecution(context);
+ InstallControllerContextTask task = new InstallControllerContextTask(context, trace);
+ contextsInstalledByExecutor.markForTaskExecution(context, task);
if (trace)
log.trace("Recorded for asynchronous installation " + context.getName());
-
- InstallControllerContextTask task = new InstallControllerContextTask(context, trace);
+
try
{
foundExecutor.execute(task);
@@ -1183,7 +1199,7 @@
{
Object ctx = trace ? context : context.getName();
log.warn("Asynchronous execution rejected by executor for context " + ctx + ":" + e.getMessage());
- contextsInstalledByExecutor.disassociateWithThread(context);
+ contextsInstalledByExecutor.disassociateWithTask(context);
}
}
}
@@ -1353,8 +1369,11 @@
for (ControllerContext dependent : dependents)
{
+ contextsInstalledByExecutor.interruptTaskAndBlock(dependent, this);
if (isBeforeState(dependent.getState(), whenRequired) == false)
+ {
uninstallContext(dependent, whenRequired, trace);
+ }
}
}
}
@@ -2232,8 +2251,100 @@
else
return states.get(index);
}
+
+ /**
+ * A task being handled asyynchronously by the executor
+ *
+ */
+ abstract class InterruptibleControllerTask implements Runnable
+ {
+ /**
+ * The thread used to handle the asynchronous task
+ */
+ Thread thread;
+
+ /**
+ * True if the task is interrupted
+ */
+ volatile boolean interrupted;
+
+ /**
+ * Latch counted down by interrupted tasks once they have reached a state where they finish
+ */
+ CountDownLatch interruptedLatch;
+
+ /**
+ * Gets the thread that is currently used to install the asyncronous task
+ * @return The thread, or null if still queued in the executor
+ */
+ Thread getThread()
+ {
+ return thread;
+ }
+
+ /**
+ * Interrupt the task, and if associated with a thread
+ * return a countdown latch that will have a count of 0
+ * once the job has broken out
+ * @return the latch or null if not yet interrupted
+ */
+ synchronized CountDownLatch interrupt()
+ {
+ interrupted = true;
+ if (thread != null)
+ {
+ interruptedLatch = new CountDownLatch(1);
+ return interruptedLatch;
+ }
+ return null;
+ }
+
+ /**
+ * Check the interrupted status
+ * @return true if interrupted
+ */
+ boolean isInterrupted()
+ {
+ return interrupted;
+ }
+
+ /**
+ * Associate the current thread with the task, or clear it in contextsInstalledByExecutor
+ * if it has been interrupted. This should be the first thing tasks do once they run.
+ * @return true if interrupted
+ */
+ synchronized boolean associateWithThreadOrDisassociateIfInterrupted(ControllerContext context)
+ {
+ if (interrupted)
+ {
+ contextsInstalledByExecutor.disassociateWithTask(context);
+ return true;
+ }
+ thread = Thread.currentThread();
+ return false;
+ }
+
+ /**
+ * Disassociate the thread with the task, and if interrupted count down the latch so those
+ * awaiting the latch know the task has finished.
+ */
+ synchronized void disassociateWithThreadAndSignalEnd()
+ {
+ thread = null;
+ if (interruptedLatch != null)
+ {
+ interruptedLatch.countDown();
+ }
+ }
+ }
+
- class InstallControllerContextTask implements Runnable
+ /**
+ * Interruptible task used to install a controller context asynchronously.
+ * It will install the context as far as possible towards its required state,
+ * before resolving the other contexts.
+ */
+ class InstallControllerContextTask extends InterruptibleControllerTask implements Runnable
{
ControllerContext context;
ClassLoader classLoader;
@@ -2248,12 +2359,14 @@
public void run()
{
+ if (associateWithThreadOrDisassociateIfInterrupted(context))
+ return;
+
if (trace)
log.trace(Thread.currentThread().getName() + " starting asyncronous install of " + context.getName());
lockWrite();
ClassLoader tcl = SecurityActions.setContextClassLoader(classLoader);
- contextsInstalledByExecutor.associateWithThread(context);
try
{
//Move the given context as far through the states as possible
@@ -2264,11 +2377,11 @@
}
finally
{
- contextsInstalledByExecutor.disassociateWithThread(context);
+ contextsInstalledByExecutor.disassociateWithTask(context);;
}
//The given context had its state changed, now see if anybody was dependent on it
- if (stateChanged)
+ if (stateChanged && !interrupted)
{
resolveContexts(trace);
}
@@ -2284,6 +2397,8 @@
log.trace(Thread.currentThread().getName() + " asynchronous install done for " + context.getName());
SecurityActions.resetContextClassLoader(tcl);
unlockWrite();
+
+ disassociateWithThreadAndSignalEnd();
}
}
@@ -2298,7 +2413,7 @@
boolean resolved = true;
- while(resolved && currentIndex < requiredIndex)
+ while(resolved && currentIndex < requiredIndex && !interrupted)
{
resolved = false;
ControllerState toState = states.get(currentIndex + 1);
@@ -2306,6 +2421,7 @@
{
try
{
+// PushControllerStateModel.push(AbstractController.this);
if (resolveDependencies(context, toState))
{
resolved = true;
@@ -2319,6 +2435,10 @@
errorContexts.put(context.getName(), context);
context.setError(error);
}
+// finally
+// {
+// PushControllerStateModel.pop();
+// }
if (resolved)
{
@@ -2335,46 +2455,109 @@
return stateChanged;
}
}
+
+
+ /**
+ * Class used to keep track of contexts that are scheduled for asynchronous install,
+ * or are in the process of being installed asynchronously.
+ *
+ */
private static class ContextsInstalledByExecutor
{
/** The contexts that are currently being installed by the executor */
- Map<ControllerContext, Thread> executorThreadsByContext = new ConcurrentHashMap<ControllerContext, Thread>();
-
+ Map<ControllerContext, InterruptibleControllerTask> executorTasksByContext = new ConcurrentHashMap<ControllerContext, InterruptibleControllerTask>();
+ /**
+ * Checks whether context should be installed asynchronously, by checking the controller mode and the current thread
+ * @param context The context
+ * @return Whether the context should be installed in the executor
+ */
boolean shouldInstallAsynchronously(ControllerContext context)
{
if (context.getMode() == ControllerMode.ASYNCHRONOUS)
{
- final Thread ctxThread = executorThreadsByContext.get(context);
- return ctxThread == null || ctxThread != Thread.currentThread();
+ final InterruptibleControllerTask task = executorTasksByContext.get(context);
+ return task == null || task.getThread() != Thread.currentThread();
}
return false;
}
- void markForThreadExecution(ControllerContext context)
+ /**
+ * Records the context and the asynchronous task to install it
+ * @param context The context to be installed asynchronously
+ * @param task The task that will be used to install the context
+ */
+ void markForTaskExecution(ControllerContext context, InterruptibleControllerTask task)
{
- executorThreadsByContext.put(context, SCHEDULED_FOR_EXECUTOR);
+ executorTasksByContext.put(context, task);
}
- void associateWithThread(ControllerContext context)
+ /**
+ * Removes the task that was used to install the context
+ * @param context The context whose task we want to remove
+ */
+ void disassociateWithTask(ControllerContext context)
{
- executorThreadsByContext.put(context, Thread.currentThread());
+ executorTasksByContext.remove(context);
}
- void disassociateWithThread(ControllerContext context)
+ /**
+ * Checks if the context is recorded for asynchronous install, and if the thread used is different
+ * from the current thread.
+ * @param context The context to check
+ * @return true if installed by another thread
+ */
+ boolean isInstalledByOtherThread(ControllerContext context)
{
- executorThreadsByContext.remove(context);
+ final InterruptibleControllerTask task = executorTasksByContext.get(context);
+ return task != null && Thread.currentThread() != task.getThread();
}
- boolean isInstalledByOtherThread(ControllerContext context)
+ /**
+ * Checks in the context is recorded for asynchronous install
+ * @param context The context to check
+ * @return true if recorded for asynchronous install
+ */
+ boolean isBeingInstalled(ControllerContext context)
{
- final Thread ctxThread = executorThreadsByContext.get(context);
- return ctxThread != null && Thread.currentThread() != ctxThread;
+ return executorTasksByContext.get(context) != null;
}
- boolean isBeingInstalled(ControllerContext context)
+ /**
+ * Checks if the passed in context is recorded for asynchronous install,
+ * and if it is interrupts the asynchronous task.<p>
+ *
+ * This method must be called with the write lock taken
+ *
+ * @param context The context to interrupt
+ */
+ void interruptTaskAndBlock(ControllerContext context, AbstractController controller)
{
- return executorThreadsByContext.get(context) != null;
+ InterruptibleControllerTask task = executorTasksByContext.get(context);
+ if (task != null)
+ {
+ controller.unlockWrite();
+ try
+ {
+ CountDownLatch latch = task.interrupt();
+ if (latch != null)
+ {
+ try
+ {
+ latch.await();
+ }
+ catch(InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ finally
+ {
+ controller.lockWrite();
+ }
+ }
}
+
}
}
Added: projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/PushControllerStateModel.java
===================================================================
--- projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/PushControllerStateModel.java (rev 0)
+++ projects/kernel/trunk/dependency/src/main/java/org/jboss/dependency/plugins/PushControllerStateModel.java 2009-07-22 21:18:58 UTC (rev 91582)
@@ -0,0 +1,52 @@
+/*
+* JBoss, Home of Professional Open Source.
+* Copyright 2006, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file in the
+* distribution for a full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software 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 software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.dependency.plugins;
+
+import org.jboss.dependency.spi.ControllerStateModel;
+
+/**
+ *
+ * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
+ * @version $Revision: 1.1 $
+ */
+public class PushControllerStateModel
+{
+ private static ThreadLocal<ControllerStateModel> controllerStateModel = new ThreadLocal<ControllerStateModel>();
+
+ public static void push(ControllerStateModel model)
+ {
+ controllerStateModel.set(model);
+ }
+
+ public static ControllerStateModel peek()
+ {
+ return controllerStateModel.get();
+ }
+
+ public static ControllerStateModel pop()
+ {
+ ControllerStateModel model = peek();
+ controllerStateModel.remove();
+ return model;
+ }
+
+}
Added: projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/support/UninstallAsynchronousInProgressTestDelegate.java
===================================================================
--- projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/support/UninstallAsynchronousInProgressTestDelegate.java (rev 0)
+++ projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/support/UninstallAsynchronousInProgressTestDelegate.java 2009-07-22 21:18:58 UTC (rev 91582)
@@ -0,0 +1,181 @@
+/*
+* JBoss, Home of Professional Open Source.
+* Copyright 2006, Red Hat Middleware LLC, and individual contributors
+* as indicated by the @author tags. See the copyright.txt file in the
+* distribution for a full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software 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 software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.test.dependency.controller.support;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.jboss.dependency.spi.ControllerState;
+import org.jboss.logging.Logger;
+
+/**
+ *
+ * @author <a href="kabir.khan at jboss.com">Kabir Khan</a>
+ * @version $Revision: 1.1 $
+ */
+public class UninstallAsynchronousInProgressTestDelegate extends TestDelegate
+{
+ Logger log = Logger.getLogger(UninstallAsynchronousInProgressTestDelegate.class);
+ CountDownLatch signalInWaitStateLatch;
+ ControllerState waitInState;
+ CountDownLatch waitForMainLatch;
+
+ public UninstallAsynchronousInProgressTestDelegate(Object name, CountDownLatch signalInWaitStateLatch, ControllerState waitInState, CountDownLatch waitForMainLatch)
+ {
+ super(name);
+ this.signalInWaitStateLatch = signalInWaitStateLatch;
+ this.waitInState = waitInState;
+ this.waitForMainLatch = waitForMainLatch;
+ }
+
+ public UninstallAsynchronousInProgressTestDelegate(Object name)
+ {
+ this(name, null, null, null);
+ }
+
+ @Override
+ public void configureInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.CONFIGURED);
+ super.configureInstall();
+ debugLogThread("Configure");
+ }
+
+ @Override
+ public void createInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.CREATE);
+ super.createInstall();
+ debugLogThread("Create");
+ }
+
+ @Override
+ public void describeInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.DESCRIBED);
+ super.describeInstall();
+ debugLogThread("Describe");
+ }
+
+ @Override
+ public void installInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.INSTALLED);
+ super.installInstall();
+ debugLogThread("Install");
+ }
+
+ @Override
+ public void instantiateInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.INSTANTIATED);
+ super.instantiateInstall();
+ debugLogThread("Instantiate");
+ }
+
+ @Override
+ public void startInstall()
+ {
+ signalInWaitInStateAndWaitForMainLatch(ControllerState.START);
+ super.startInstall();
+ debugLogThread("Start");
+ }
+
+ @Override
+ public void configureUninstall()
+ {
+ super.configureUninstall();
+ debugLogThread("Configure--");
+ }
+
+ @Override
+ public void createUninstall()
+ {
+ super.createUninstall();
+ debugLogThread("Create--");
+ }
+
+ @Override
+ public void describeUninstall()
+ {
+ super.describeUninstall();
+ debugLogThread("Describe--");
+ }
+
+ @Override
+ public void installUninstall()
+ {
+ super.installUninstall();
+ debugLogThread("Install--");
+ }
+
+ @Override
+ public void instantiateUninstall()
+ {
+ super.instantiateUninstall();
+ debugLogThread("Instantiate--");
+ }
+
+ @Override
+ public void startUninstall()
+ {
+ super.startUninstall();
+ debugLogThread("Start--");
+ }
+
+ private void awaitMainLatch()
+ {
+ if (waitForMainLatch == null)
+ return;
+ try
+ {
+ debugLogThread("Awaiting main latch for " + getName());
+ waitForMainLatch.await();
+ debugLogThread("Got main latch for " + getName());
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void signalInWaitInState(ControllerState state)
+ {
+ if (signalInWaitStateLatch == null)
+ return;
+ signalInWaitStateLatch.countDown();
+ debugLogThread("I am in " + state + " " + getName());
+ }
+
+
+ private void signalInWaitInStateAndWaitForMainLatch(ControllerState state)
+ {
+ if (!state.equals(waitInState))
+ return;
+ signalInWaitInState(state);
+ awaitMainLatch();
+ }
+
+ private void debugLogThread(String msg)
+ {
+ log.debug(Thread.currentThread().getName() + " " + getName() + " " + msg);
+ }
+}
Modified: projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/test/AsynchronousTestCase.java
===================================================================
--- projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/test/AsynchronousTestCase.java 2009-07-22 21:06:01 UTC (rev 91581)
+++ projects/kernel/trunk/dependency/src/test/java/org/jboss/test/dependency/controller/test/AsynchronousTestCase.java 2009-07-22 21:18:58 UTC (rev 91582)
@@ -22,8 +22,12 @@
package org.jboss.test.dependency.controller.test;
import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
@@ -40,6 +44,8 @@
import org.jboss.test.dependency.controller.support.AsynchronousTestDelegate;
import org.jboss.test.dependency.controller.support.Synchronizer;
import org.jboss.test.dependency.controller.support.TestControllerContext;
+import org.jboss.test.dependency.controller.support.TestDelegate;
+import org.jboss.test.dependency.controller.support.UninstallAsynchronousInProgressTestDelegate;
/**
*
@@ -452,7 +458,6 @@
ctx2 = createAndInstallContext(delegate2, ControllerState.INSTALLED);
synchronizer2.waitForWorkersAndEmitStartSignal();
- assertNotSame(ControllerState.INSTALLED, ctx2.getState());
synchronizer2.waitForWorkersToEnd();
synchronizer1.waitForWorkersToEnd();
@@ -782,6 +787,257 @@
}
}
+ public void testUninstallAsynchronousContextInProgress() throws Throwable
+ {
+ setExecutorInController(2);
+
+ final CountDownLatch waitForMainLatch = new CountDownLatch(1);
+ final CountDownLatch signalInConfigureLatch = new CountDownLatch(1);
+ final CountDownLatch callUninstall = new CountDownLatch(1);
+ UninstallAsynchronousInProgressTestDelegate delegate = new UninstallAsynchronousInProgressTestDelegate("Bean", signalInConfigureLatch, ControllerState.CONFIGURED, waitForMainLatch);
+ delegate.setMode(ControllerMode.ASYNCHRONOUS);
+ ControllerContext ctx = null;
+ try
+ {
+ ctx = createAndInstallContext(delegate, ControllerState.INSTALLED);
+ signalInConfigureLatch.await();
+ if (ctx.getState() == ControllerState.INSTALLED)
+ {
+ fail("Should have been installed asynchronously");
+ }
+ ExecutorService executorService = Executors.newFixedThreadPool(1);
+ Future<Void> wait = executorService.submit(new Callable<Void>() {
+ public Void call() throws Exception
+ {
+ callUninstall.await();
+ //Make sure uninstall is in progress
+ TimeUnit.MILLISECONDS.sleep(750);
+ waitForMainLatch.countDown();
+ return null;
+ }
+ });
+ callUninstall.countDown();
+ uninstallContext(ctx);
+ wait.get();
+
+ ctx = null;
+ assertEquals(1, delegate.describeInstallOrder);
+ assertEquals(2, delegate.instantiateInstallOrder);
+ assertEquals(3, delegate.configureInstallOrder);
+ assertEquals(4, delegate.configureUninstallOrder);
+ assertEquals(5, delegate.instantiateUninstallOrder);
+ assertEquals(6, delegate.describeUninstallOrder);
+ }
+ finally
+ {
+ try
+ {
+ uninstallContext(ctx);
+ }
+ finally
+ {
+ clearExecutorInController();
+ }
+ }
+ }
+
+ public void testUninstallContextWithAsynchronousDependencyInProgress_Configured_Configured() throws Throwable
+ {
+ TestDelegate expectedDependency = new TestDelegate("D");
+ TestDelegate expectedBean = new TestDelegate("DB");
+ expectedDependency.describeInstallOrder = 1;
+ expectedDependency.instantiateInstallOrder = 2;
+ expectedDependency.configureInstallOrder = 3;
+ expectedDependency.createInstallOrder = 4;
+ expectedDependency.startInstallOrder = 5;
+ expectedDependency.installInstallOrder = 6;
+
+ expectedBean.describeInstallOrder = 7;
+ expectedBean.instantiateInstallOrder = 8;
+ expectedBean.configureInstallOrder = 9;
+ expectedBean.configureUninstallOrder = 10;
+
+ expectedDependency.installUninstallOrder = 11;
+ expectedDependency.startUninstallOrder = 12;
+ expectedDependency.createUninstallOrder = 13;
+ expectedDependency.configureUninstallOrder = 14;
+ expectedDependency.instantiateUninstallOrder = 15;
+ expectedDependency.describeUninstallOrder = 16;
+
+ runUninstallContextWithAsynchronousDependencyInProgress(ControllerState.CONFIGURED, ControllerState.CONFIGURED, expectedDependency, expectedBean);
+ }
+
+ public void testUninstallContextWithAsynchronousDependencyInProgress_Configured_Start() throws Throwable
+ {
+ TestDelegate expectedDependency = new TestDelegate("D");
+ TestDelegate expectedBean = new TestDelegate("DB");
+ expectedDependency.describeInstallOrder = 1;
+ expectedDependency.instantiateInstallOrder = 2;
+ expectedDependency.configureInstallOrder = 3;
+ expectedDependency.createInstallOrder = 4;
+ expectedDependency.startInstallOrder = 5;
+ expectedDependency.installInstallOrder = 6;
+
+ expectedBean.describeInstallOrder = 7;
+ expectedBean.instantiateInstallOrder = 8;
+ expectedBean.configureInstallOrder = 9;
+ expectedBean.createInstallOrder = 10;
+ expectedBean.startInstallOrder = 11;
+ expectedBean.startUninstallOrder = 12;
+ expectedBean.createUninstallOrder = 13;
+ expectedBean.configureUninstallOrder = 14;
+
+ expectedDependency.installUninstallOrder = 15;
+ expectedDependency.startUninstallOrder = 16;
+ expectedDependency.createUninstallOrder = 17;
+ expectedDependency.configureUninstallOrder = 18;
+ expectedDependency.instantiateUninstallOrder = 19;
+ expectedDependency.describeUninstallOrder = 20;
+
+ runUninstallContextWithAsynchronousDependencyInProgress(ControllerState.CONFIGURED, ControllerState.START, expectedDependency, expectedBean);
+ }
+
+ public void testUninstallContextWithAsynchronousDependencyInProgress_Create_Start() throws Throwable
+ {
+ TestDelegate expectedDependency = new TestDelegate("D");
+ TestDelegate expectedBean = new TestDelegate("DB");
+ expectedDependency.describeInstallOrder = 1;
+ expectedDependency.instantiateInstallOrder = 2;
+ expectedDependency.configureInstallOrder = 3;
+ expectedDependency.createInstallOrder = 4;
+ expectedDependency.startInstallOrder = 5;
+ expectedDependency.installInstallOrder = 6;
+
+ expectedBean.describeInstallOrder = 7;
+ expectedBean.instantiateInstallOrder = 8;
+ expectedBean.configureInstallOrder = 9;
+ expectedBean.createInstallOrder = 10;
+ expectedBean.startInstallOrder = 11;
+ expectedBean.startUninstallOrder = 12;
+ expectedBean.createUninstallOrder = 13;
+
+ expectedDependency.installUninstallOrder = 14;
+ expectedDependency.startUninstallOrder = 15;
+ expectedDependency.createUninstallOrder = 16;
+ expectedDependency.configureUninstallOrder = 17;
+ expectedDependency.instantiateUninstallOrder = 18;
+ expectedDependency.describeUninstallOrder = 19;
+
+ runUninstallContextWithAsynchronousDependencyInProgress(ControllerState.CREATE, ControllerState.START, expectedDependency, expectedBean);
+ }
+
+ public void testUninstallContextWithAsynchronousDependencyInProgress_Configured_Described() throws Throwable
+ {
+ TestDelegate expectedDependency = new TestDelegate("D");
+ TestDelegate expectedBean = new TestDelegate("DB");
+ expectedDependency.describeInstallOrder = 1;
+ expectedDependency.instantiateInstallOrder = 2;
+ expectedDependency.configureInstallOrder = 3;
+ expectedDependency.createInstallOrder = 4;
+ expectedDependency.startInstallOrder = 5;
+ expectedDependency.installInstallOrder = 6;
+
+ expectedDependency.installUninstallOrder = 7;
+ expectedDependency.startUninstallOrder = 8;
+ expectedDependency.createUninstallOrder = 9;
+ expectedDependency.configureUninstallOrder = 10;
+ expectedDependency.instantiateUninstallOrder = 11;
+ expectedDependency.describeUninstallOrder = 12;
+
+ expectedBean.describeInstallOrder = 13;
+ expectedBean.instantiateInstallOrder = 14;
+
+ runUninstallContextWithAsynchronousDependencyInProgress(ControllerState.CONFIGURED, ControllerState.DESCRIBED, expectedDependency, expectedBean);
+ }
+
+ private void runUninstallContextWithAsynchronousDependencyInProgress(
+ ControllerState whenRequiredState,
+ ControllerState waitInState,
+ TestDelegate expectedDependency,
+ TestDelegate expectedBean) throws Throwable
+ {
+ setExecutorInController(1);
+
+ final CountDownLatch waitForMainLatch = new CountDownLatch(1);
+ final CountDownLatch signalInWaitStateLatch = new CountDownLatch(1);
+ final CountDownLatch callUninstall = new CountDownLatch(1);
+
+ UninstallAsynchronousInProgressTestDelegate dependencyDelegate = new UninstallAsynchronousInProgressTestDelegate("Dependency");
+
+ UninstallAsynchronousInProgressTestDelegate beanDelegate = new UninstallAsynchronousInProgressTestDelegate("Bean", signalInWaitStateLatch, waitInState, waitForMainLatch);
+ beanDelegate.addDependency(new AbstractDependencyItem("Bean", "Dependency", whenRequiredState, ControllerState.INSTALLED));
+ beanDelegate.setMode(ControllerMode.ASYNCHRONOUS);
+
+ ControllerContext dependencyContext = null;
+ ControllerContext beanContext = null;
+ try
+ {
+ dependencyContext = createAndInstallContext(dependencyDelegate, ControllerState.INSTALLED);
+ beanContext = createAndInstallContext(beanDelegate, ControllerState.INSTALLED);
+ signalInWaitStateLatch.await();
+ if (beanContext.getState() == ControllerState.INSTALLED)
+ {
+ fail("Should have been installed asynchronously");
+ }
+ ExecutorService executorService = Executors.newFixedThreadPool(1);
+ Future<Void> wait = executorService.submit(new Callable<Void>() {
+ public Void call() throws Exception
+ {
+ callUninstall.await();
+ //Make sure uninstall is in progress
+ TimeUnit.MILLISECONDS.sleep(200);
+ waitForMainLatch.countDown();
+ //Give tasks time to finish
+ TimeUnit.MILLISECONDS.sleep(200);
+ return null;
+ }
+ });
+ callUninstall.countDown();
+
+ uninstallContext(dependencyContext);
+
+ wait.get();
+
+ assertEquals(expectedDependency.describeInstallOrder, dependencyDelegate.describeInstallOrder);
+ assertEquals(expectedDependency.instantiateInstallOrder, dependencyDelegate.instantiateInstallOrder);
+ assertEquals(expectedDependency.configureInstallOrder, dependencyDelegate.configureInstallOrder);
+ assertEquals(expectedDependency.createInstallOrder, dependencyDelegate.createInstallOrder);
+ assertEquals(expectedDependency.startInstallOrder, dependencyDelegate.startInstallOrder);
+ assertEquals(expectedDependency.installInstallOrder, dependencyDelegate.installInstallOrder);
+ assertEquals(expectedDependency.installUninstallOrder, dependencyDelegate.installUninstallOrder);
+ assertEquals(expectedDependency.startUninstallOrder, dependencyDelegate.startUninstallOrder);
+ assertEquals(expectedDependency.createUninstallOrder, dependencyDelegate.createUninstallOrder);
+ assertEquals(expectedDependency.configureUninstallOrder, dependencyDelegate.configureUninstallOrder);
+ assertEquals(expectedDependency.instantiateUninstallOrder, dependencyDelegate.instantiateUninstallOrder);
+ assertEquals(expectedDependency.describeUninstallOrder, dependencyDelegate.describeUninstallOrder);
+
+
+ assertEquals(expectedBean.describeInstallOrder, beanDelegate.describeInstallOrder);
+ assertEquals(expectedBean.instantiateInstallOrder, beanDelegate.instantiateInstallOrder);
+ assertEquals(expectedBean.configureInstallOrder, beanDelegate.configureInstallOrder);
+ assertEquals(expectedBean.createInstallOrder, beanDelegate.createInstallOrder);
+ assertEquals(expectedBean.startInstallOrder, beanDelegate.startInstallOrder);
+ assertEquals(expectedBean.installInstallOrder, beanDelegate.installInstallOrder);
+ assertEquals(expectedBean.installUninstallOrder, beanDelegate.installUninstallOrder);
+ assertEquals(expectedBean.startUninstallOrder, beanDelegate.startUninstallOrder);
+ assertEquals(expectedBean.createUninstallOrder, beanDelegate.createUninstallOrder);
+ assertEquals(expectedBean.configureUninstallOrder, beanDelegate.configureUninstallOrder);
+ assertEquals(expectedBean.instantiateUninstallOrder, beanDelegate.instantiateUninstallOrder);
+ assertEquals(expectedBean.describeUninstallOrder, beanDelegate.describeUninstallOrder);
+ }
+ finally
+ {
+ try
+ {
+ uninstallContext(beanContext);
+ }
+ finally
+ {
+ clearExecutorInController();
+ }
+ }
+ }
+
private void setExecutorInController(int threads)
{
Executor executor = null;
@@ -829,7 +1085,7 @@
return result;
}
- private ControllerContext createAndInstallContext(AsynchronousTestDelegate delegate, ControllerState expected) throws Throwable
+ private ControllerContext createAndInstallContext(TestDelegate delegate, ControllerState expected) throws Throwable
{
TestControllerContext context = new TestControllerContext(delegate);
controller.install(context);
@@ -901,5 +1157,5 @@
count.incrementAndGet();
throw new RejectedExecutionException();
}
- }
+ }
}
More information about the jboss-cvs-commits
mailing list