[jboss-cvs] JBossAS SVN: r89637 - in projects/bootstrap/trunk: impl-base/src/test/java/org/jboss/bootstrap/impl/base/server and 2 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Jun 1 23:18:46 EDT 2009


Author: ALRubinger
Date: 2009-06-01 23:18:46 -0400 (Mon, 01 Jun 2009)
New Revision: 89637

Added:
   projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/InterruptibleStartupServer.java
   projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/TestExceptionOnStartServer.java
   projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/unit/ServerConcurrentStartShutdownTestCase.java
Modified:
   projects/bootstrap/trunk/impl-base/src/main/java/org/jboss/bootstrap/impl/base/server/AbstractServer.java
   projects/bootstrap/trunk/impl-mc/src/main/java/org/jboss/bootstrap/impl/mc/server/AbstractMCServerBase.java
Log:
[JBBOOT-75] Allow shutdown to interrupt startup.  Dependent upon a server implmentation which responds to Thread interruption by quickly exiting from start lifecycle

Modified: projects/bootstrap/trunk/impl-base/src/main/java/org/jboss/bootstrap/impl/base/server/AbstractServer.java
===================================================================
--- projects/bootstrap/trunk/impl-base/src/main/java/org/jboss/bootstrap/impl/base/server/AbstractServer.java	2009-06-02 03:16:09 UTC (rev 89636)
+++ projects/bootstrap/trunk/impl-base/src/main/java/org/jboss/bootstrap/impl/base/server/AbstractServer.java	2009-06-02 03:18:46 UTC (rev 89637)
@@ -122,6 +122,13 @@
     */
    private final Map<LifecycleState, Set<LifecycleEventHandler>> eventHandlers = new ConcurrentHashMap<LifecycleState, Set<LifecycleEventHandler>>();
 
+   /**
+    * Thread used for startup.  Part of the server's internal state so we can interrupt
+    * this if necessary.  Volatile so we don't need to block in order to 
+    * get the correct view.
+    */
+   private volatile Thread startupThread = null;
+
    //-------------------------------------------------------------------------------------||
    // Constructors -----------------------------------------------------------------------||
    //-------------------------------------------------------------------------------------||
@@ -239,8 +246,8 @@
    /* (non-Javadoc)
     * @see org.jboss.bootstrap.spi.server.Server#shutdown()
     */
-   // Synchronized for atomicity
-   public synchronized void shutdown() throws IllegalStateException, Exception
+
+   public void shutdown() throws IllegalStateException, Exception
    {
       // Log
       if (log.isTraceEnabled())
@@ -248,57 +255,80 @@
          log.trace("Received request to shutdown");
       }
 
-      // Ensure running
-      LifecycleState required = LifecycleState.STARTED;
-      LifecycleState actual = this.getState();
-      this.checkState(required, actual);
+      // If we're in startup
+      final Thread startupThread = this.startupThread;
+      if (startupThread != null)
+      {
+         // Interrupt startup
+         startupThread.interrupt();
 
-      // Initiate shutdown sequence
-      log.info("Stopping: " + this);
-      final StopWatch watch = new StopWatch(true);
-      this.setState(LifecycleState.STOPPING);
-
-      // Shutdown the Bootstraps
-      if (log.isTraceEnabled())
-      {
-         log.trace("Shutting down bootstraps");
+         // Wait until it's done
+         try
+         {
+            startupThread.join();
+         }
+         catch (final InterruptedException ie)
+         {
+            // Warn and clear the flag
+            log.warn("Interrupted while shutdown is waiting for server startup to complete");
+            Thread.interrupted();
+         }
       }
-      this.shutdownBootstraps();
 
-      // Shutdown
-      if (log.isTraceEnabled())
+      // Synchronized for atomicity
+      synchronized (this)
       {
-         log.trace("Calling implementation class shutdown...");
-      }
-      this.doShutdown();
+         // Ensure running
+         LifecycleState required = LifecycleState.STARTED;
+         LifecycleState actual = this.getState();
+         this.checkState(required, actual);
 
-      // Let the initializer clean up
-      final ServerInitializer<K, T> serverInitializer = this.getServerInitializer();
-      if (serverInitializer != null)
-      {
+         // Initiate shutdown sequence
+         log.info("Stopping: " + this);
+         final StopWatch watch = new StopWatch(true);
+         this.setState(LifecycleState.STOPPING);
+
+         // Shutdown the Bootstraps
          if (log.isTraceEnabled())
          {
-            log.trace("Calling to clean up for shutdown: " + serverInitializer);
+            log.trace("Shutting down bootstraps");
          }
-         serverInitializer.cleanup(this.covarientReturn());
-      }
+         this.shutdownBootstraps();
 
-      // Send JMX Notification
-      this.sendStopJmxNotification();
+         // Shutdown
+         if (log.isTraceEnabled())
+         {
+            log.trace("Calling implementation class shutdown...");
+         }
+         this.doShutdown();
 
-      // Done and set states
-      log.info("Stopped: " + this + " in " + watch);
-      // So we fire "stopped" events and draw the difference
-      // between IDLE (which may also designate pre-start)
-      this.setState(LifecycleState.STOPPED);
-      this.setState(LifecycleState.IDLE);
+         // Let the initializer clean up
+         final ServerInitializer<K, T> serverInitializer = this.getServerInitializer();
+         if (serverInitializer != null)
+         {
+            if (log.isTraceEnabled())
+            {
+               log.trace("Calling to clean up for shutdown: " + serverInitializer);
+            }
+            serverInitializer.cleanup(this.covarientReturn());
+         }
+
+         // Send JMX Notification
+         this.sendStopJmxNotification();
+
+         // Done and set states
+         log.info("Stopped: " + this + " in " + watch);
+         // So we fire "stopped" events and draw the difference
+         // between IDLE (which may also designate pre-start)
+         this.setState(LifecycleState.STOPPED);
+         this.setState(LifecycleState.IDLE);
+      }
    }
 
    /* (non-Javadoc)
     * @see org.jboss.bootstrap.spi.server.Server#start()
     */
-   // Synchronized for atomicity
-   public synchronized void start() throws IllegalStateException, Exception
+   public void start() throws IllegalStateException, Exception
    {
       // Log
       if (log.isTraceEnabled())
@@ -307,42 +337,131 @@
       }
 
       // Invoke init() if necessary
-      if (this.getState().equals(LifecycleState.PRE_INIT))
+      if (getState().equals(LifecycleState.PRE_INIT))
       {
          log.debug("Invoking implicit initialization from start()");
-         this.initialize();
+         AbstractServer.this.initialize();
       }
 
-      // Ensure idle
-      final LifecycleState required = LifecycleState.IDLE;
-      final LifecycleState actual = this.getState();
-      this.checkState(required, actual);
+      // Make a new Thread to run startup, so we may interrupt it 
+      // if necessary for shutdown
+      final StartServerTask task = new StartServerTask();
+      final Thread thread = new Thread(task);
+      this.startupThread = thread;
+      thread.start();
 
-      // Initiate start sequence
-      log.info("Starting: " + this);
-      final StopWatch watch = new StopWatch(true);
-      this.setState(LifecycleState.STARTING);
+      // Wait on startup to complete
+      try
+      {
+         thread.join();
+      }
+      catch (final InterruptedException ie)
+      {
+         // Clear the flag
+         Thread.interrupted();
+      }
 
-      // Start
-      if (log.isTraceEnabled())
+      // Check for Exceptions encountered during run()
+      final Exception exceptionOnStart = task.getException();
+      if (exceptionOnStart != null)
       {
-         log.trace("Entering implementation class start...");
+         // Throw up the stack
+         throw exceptionOnStart;
       }
-      this.doStart();
+   }
 
-      // Run the bootstraps
-      if (log.isTraceEnabled())
+   /**
+    * StartServerTask
+    * 
+    * Task to start the server in a new Thread of execution.  This will
+    * allow the calling Thread to interrupt the startup process
+    * in the case the server is requested to shutdown during start.
+    * 
+    * JBBOOT-75
+    *
+    * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+    * @version $Revision: $
+    */
+   class StartServerTask implements Runnable
+   {
+      /**
+       * Any exception encountered while
+       * the task was run
+       */
+      private Exception exception;
+
+      /*
+       * (non-Javadoc)
+       * @see java.lang.Runnable#run()
+       */
+      public void run()
       {
-         log.trace("Starting bootstraps...");
+         // Get a reference to this of the outer class
+         final AbstractServer<?, ?> thisRef = AbstractServer.this;
+
+         /*
+          * Synchronized for atomicity
+          */
+         synchronized (thisRef)
+         {
+            try
+            {
+               // Ensure idle
+               final LifecycleState required = LifecycleState.IDLE;
+               final LifecycleState actual = getState();
+               checkState(required, actual);
+
+               // Initiate start sequence
+               log.info("Starting: " + thisRef);
+               final StopWatch watch = new StopWatch(true);
+               setState(LifecycleState.STARTING);
+
+               // Start
+               if (log.isTraceEnabled())
+               {
+                  log.trace("Entering implementation class start...");
+               }
+               doStart();
+
+               // Run the bootstraps
+               if (log.isTraceEnabled())
+               {
+                  log.trace("Starting bootstraps...");
+               }
+               startBootstraps();
+
+               // Send JMX Start Notification
+               sendStartJmxNotification();
+
+               // Done
+               log.info("Started: " + thisRef + " in " + watch);
+               setState(LifecycleState.STARTED);
+            }
+            catch (final Exception e)
+            {
+               log.debug("Encountered exception while starting, caching it to be thrown later: " + e);
+               this.exception = e;
+               return;
+            }
+            finally
+            {
+               // Clear the startup Thread
+               AbstractServer.this.startupThread = null;
+            }
+         }
       }
-      this.startBootstraps();
 
-      // Send JMX Start Notification
-      this.sendStartJmxNotification();
+      /**
+       * Obtains the exception encountered during start, or null
+       * if none was thrown
+       * 
+       * @return
+       */
+      Exception getException()
+      {
+         return this.exception;
+      }
 
-      // Done
-      log.info("Started: " + this + " in " + watch);
-      this.setState(LifecycleState.STARTED);
    }
 
    /* (non-Javadoc)

Added: projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/InterruptibleStartupServer.java
===================================================================
--- projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/InterruptibleStartupServer.java	                        (rev 0)
+++ projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/InterruptibleStartupServer.java	2009-06-02 03:18:46 UTC (rev 89637)
@@ -0,0 +1,164 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.bootstrap.impl.base.server;
+
+import java.util.concurrent.CyclicBarrier;
+
+import org.jboss.bootstrap.impl.base.config.TestServerConfig;
+import org.jboss.bootstrap.spi.server.Server;
+import org.jboss.logging.Logger;
+
+/**
+ * InterruptibleStartupServer
+ * 
+ * A server used in testing which spins infinitely in startup, responding
+ * only to Thread interruption.  This mocks a server with a long startup process
+ * which responds properly to interruption by quickly returning from the startup
+ * process.  This will allow shutdown to take place.  Otherwise we end up blocking
+ * on a completed start in order to shut down.
+ * 
+ * It is the responsibility of the client to reset the "interrupted" flag 
+ * if this server is to be started more than once.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class InterruptibleStartupServer extends AbstractServer<InterruptibleStartupServer, TestServerConfig>
+      implements
+         Server<InterruptibleStartupServer, TestServerConfig>,
+         TestNoOpServerMBean
+{
+
+   //-------------------------------------------------------------------------------------||
+   // Class Members ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   private static final Logger log = Logger.getLogger(InterruptibleStartupServer.class);
+
+   //-------------------------------------------------------------------------------------||
+   // Instance Members -------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Barrier upon which we'll wait until the test signals it's ready 
+    */
+   private CyclicBarrier barrier;
+
+   /**
+    * Flag to let us know if we were interrupted as expected
+    */
+   private volatile boolean interrupted;
+
+   //-------------------------------------------------------------------------------------||
+   // Constructor ------------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Constructor
+    */
+   public InterruptibleStartupServer()
+   {
+      super(InterruptibleStartupServer.class);
+
+      // Set properties
+      this.setBarrier(new CyclicBarrier(2));
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Required Implementations -----------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.spi.server.AbstractServer#doShutdown()
+    */
+   @Override
+   protected void doShutdown() throws Exception
+   {
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.spi.server.AbstractServer#doStart()
+    */
+   @Override
+   protected void doStart() throws Exception
+   {
+      // Wait for the test to be ready
+      this.getBarrier().await();
+
+      // Get the current Thread
+      final Thread current = Thread.currentThread();
+
+      // Loop until we can break out
+      while (true)
+      {
+         try
+         {
+            // Wait a bit
+            log.info("Waiting for interruption...");
+            current.join(20);
+         }
+         catch (final InterruptedException ie)
+         {
+            // Clear the status and break out
+            log.info("Startup has been interrupted");
+            Thread.interrupted();
+            this.setInterrupted(true);
+            break;
+         }
+      }
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.impl.base.server.AbstractServer#getDefaultServerConfigClass()
+    */
+   @Override
+   protected Class<TestServerConfig> getDefaultServerConfigClass()
+   {
+      return TestServerConfig.class;
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Accessors / Mutators ---------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   public CyclicBarrier getBarrier()
+   {
+      return barrier;
+   }
+
+   private void setBarrier(final CyclicBarrier barrier)
+   {
+      this.barrier = barrier;
+   }
+
+   public boolean wasInterrupted()
+   {
+      return interrupted;
+   }
+
+   private void setInterrupted(boolean interrupted)
+   {
+      this.interrupted = interrupted;
+   }
+
+}

Added: projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/TestExceptionOnStartServer.java
===================================================================
--- projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/TestExceptionOnStartServer.java	                        (rev 0)
+++ projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/TestExceptionOnStartServer.java	2009-06-02 03:18:46 UTC (rev 89637)
@@ -0,0 +1,110 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.bootstrap.impl.base.server;
+
+import org.jboss.bootstrap.impl.base.config.TestServerConfig;
+import org.jboss.bootstrap.spi.server.Server;
+import org.jboss.logging.Logger;
+
+/**
+ * TestExceptionOnStartServer
+ * 
+ * A server used in testing which throws an Exception on Start
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class TestExceptionOnStartServer extends AbstractServer<TestExceptionOnStartServer, TestServerConfig>
+      implements
+         Server<TestExceptionOnStartServer, TestServerConfig>,
+         TestNoOpServerMBean
+{
+
+   //-------------------------------------------------------------------------------------||
+   // Class Members ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   private static final Logger log = Logger.getLogger(TestExceptionOnStartServer.class);
+
+   //-------------------------------------------------------------------------------------||
+   // Constructor ------------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Constructor
+    */
+   public TestExceptionOnStartServer()
+   {
+      super(TestExceptionOnStartServer.class);
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Required Implementations -----------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.spi.server.AbstractServer#doShutdown()
+    */
+   @Override
+   protected void doShutdown() throws Exception
+   {
+      log.debug("NOOP doShutdown");
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.spi.server.AbstractServer#doStart()
+    */
+   @Override
+   protected void doStart() throws Exception
+   {
+      throw new StartException();
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.bootstrap.impl.base.server.AbstractServer#getDefaultServerConfigClass()
+    */
+   @Override
+   protected Class<TestServerConfig> getDefaultServerConfigClass()
+   {
+      return TestServerConfig.class;
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Inner Classes ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Exception thrown upon start by this server
+    */
+   public static class StartException extends Exception
+   {
+      private static final long serialVersionUID = 1L;
+
+      public StartException()
+      {
+         super("This test exception is expected to be thrown by " + TestExceptionOnStartServer.class.getName()
+               + ".start()");
+      }
+   }
+
+}

Added: projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/unit/ServerConcurrentStartShutdownTestCase.java
===================================================================
--- projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/unit/ServerConcurrentStartShutdownTestCase.java	                        (rev 0)
+++ projects/bootstrap/trunk/impl-base/src/test/java/org/jboss/bootstrap/impl/base/server/unit/ServerConcurrentStartShutdownTestCase.java	2009-06-02 03:18:46 UTC (rev 89637)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.bootstrap.impl.base.server.unit;
+
+import junit.framework.TestCase;
+
+import org.jboss.bootstrap.impl.base.config.unit.ConfigValidationTestCase;
+import org.jboss.bootstrap.impl.base.server.InterruptibleStartupServer;
+import org.jboss.bootstrap.impl.base.server.TestExceptionOnStartServer;
+import org.jboss.bootstrap.impl.base.server.TestExceptionOnStartServer.StartException;
+import org.jboss.bootstrap.spi.lifecycle.LifecycleState;
+import org.jboss.logging.Logger;
+import org.junit.Test;
+
+/**
+ * ServerConcurrentStartShutdownTestCase
+ * 
+ * Tests that the server may be shutdown, interrupting
+ * startup.
+ *
+ * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
+ * @version $Revision: $
+ */
+public class ServerConcurrentStartShutdownTestCase
+{
+   //-------------------------------------------------------------------------------------||
+   // Class Members ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   private static final Logger log = Logger.getLogger(ConfigValidationTestCase.class);
+
+   //-------------------------------------------------------------------------------------||
+   // Tests ------------------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   /**
+    * Ensures that any exceptions received during start propagate up
+    * the call stack
+    */
+   @Test
+   public void testExceptionFromStartThrownUpCallStack() throws Throwable
+   {
+      // Log
+      log.info("testExceptionFromStartThrownUpCallStack");
+
+      // Make a server that throws exceptions upon start
+      final TestExceptionOnStartServer server = new TestExceptionOnStartServer();
+
+      // Start
+      boolean exceptionReceived = false;
+      try
+      {
+         server.start();
+      }
+      // Catch the expected exception
+      catch (final StartException expected)
+      {
+         exceptionReceived = true;
+         log.info("Got expected exception: " + expected);
+      }
+
+      // Ensure exception was thrown up the call stack
+      TestCase.assertTrue("Exception from start was not received", exceptionReceived);
+   }
+
+   /**
+    * Ensures that the server may be shutdown while still in startup
+    */
+   @Test
+   public void testShutdownWhileInStartup() throws Throwable
+   {
+      // Log
+      log.info("testShutdownWhileInStartup");
+
+      // Make a new server
+      final InterruptibleStartupServer server = new InterruptibleStartupServer();
+
+      // Start in a new Thread
+      final StartTask startTask = new StartTask(server);
+      startTask.start();
+
+      // Await on the common barrier so that both the test and the server are ready
+      server.getBarrier().await();
+
+      // Ensure we're in state STARTING
+      final LifecycleState expectedStarting = LifecycleState.STARTING;
+      final LifecycleState actualStarting = server.getState();
+      TestCase.assertEquals("Server should be in state: " + expectedStarting, expectedStarting, actualStarting);
+
+      /*
+      * At this point the server will be continuously waiting for an interruption
+      */
+
+      // Signal Shutdown
+      server.shutdown();
+
+      /*
+       * This should break the server out of it's loop via interruption, and let shutdown complete normally
+       */
+
+      // Ensure no exceptions in startup
+      final Exception startException = startTask.startException;
+      TestCase.assertNull("Server should not have encountered an exception on startup", startException);
+
+      // Ensure we shut down because of the interruption
+      final boolean wasInterrupted = server.wasInterrupted();
+      TestCase.assertTrue("Server did not shut down due to the interruption", wasInterrupted);
+
+      // Ensure we're in state IDLE
+      final LifecycleState expectedIdle = LifecycleState.IDLE;
+      final LifecycleState actualIdle = server.getState();
+      TestCase.assertEquals("Server should be in state: " + expectedIdle, expectedIdle, actualIdle);
+
+   }
+
+   //-------------------------------------------------------------------------------------||
+   // Inner Classes ----------------------------------------------------------------------||
+   //-------------------------------------------------------------------------------------||
+
+   class StartTask extends Thread
+   {
+      /**
+       * Any exception encountered in starting the server
+       */
+      Exception startException;
+
+      /**
+       * The server to start
+       */
+      InterruptibleStartupServer server;
+
+      /**
+       * Constructor
+       * 
+       * @param server The server to start when this Thread is run
+       * @throws IllegalArgumentException If the server is null
+       */
+      StartTask(final InterruptibleStartupServer server) throws IllegalArgumentException
+      {
+         if (server == null)
+         {
+            throw new IllegalArgumentException("Server must be specified");
+         }
+         this.server = server;
+         this.setDaemon(true);
+      }
+
+      public void run()
+      {
+         try
+         {
+            server.start();
+         }
+         catch (final Exception e)
+         {
+            // Remember the exception so we can get at it later
+            startException = e;
+         }
+      }
+   };
+
+}

Modified: projects/bootstrap/trunk/impl-mc/src/main/java/org/jboss/bootstrap/impl/mc/server/AbstractMCServerBase.java
===================================================================
--- projects/bootstrap/trunk/impl-mc/src/main/java/org/jboss/bootstrap/impl/mc/server/AbstractMCServerBase.java	2009-06-02 03:16:09 UTC (rev 89636)
+++ projects/bootstrap/trunk/impl-mc/src/main/java/org/jboss/bootstrap/impl/mc/server/AbstractMCServerBase.java	2009-06-02 03:18:46 UTC (rev 89637)
@@ -216,7 +216,7 @@
     * @see org.jboss.bootstrap.impl.base.server.AbstractServer#start()
     */
    @Override
-   public synchronized void start() throws IllegalStateException, Exception
+   public void start() throws IllegalStateException, Exception
    {
       /*
        * In the case that we're re-started, we need to reconstruct




More information about the jboss-cvs-commits mailing list