continuum-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tryg...@apache.org
Subject svn commit: r165648 - /maven/continuum/trunk/continuum-core-it /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue /maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store /maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus /maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum /maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue /maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification /maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store /maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum /maven/continuum/trunk/continuum-plexus-application/src/conf /maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc
Date Mon, 02 May 2005 17:17:07 GMT
Author: trygvis
Date: Mon May  2 10:17:06 2005
New Revision: 165648

URL: http://svn.apache.org/viewcvs?rev=165648&view=rev
Log:
Fixes CONTINUUM-60: checkout in background
o The background check outs are implemented with a CheckOutProjectTask and
  COPTExecutor reading from the check out TaskQueue.
o Adding two more states: "checking out" and "updating".
o Adding a "project state guard" that's consulted by the ContinuumStore to
  ensure that the project is in a legal state at all times. This might not be
  the ideal solution to this problem but it's good enough for now.
o Updated some test to use the utility methods from
  ModelloJPoxContinuumStoreTest to create projects it's a bit more complicated
  now with the extra state transitions required to create a "new" project.
o Updating the integration tests as the tests have to wait for the check out to
  complete before continuing.
o Cleaned up the exception handling in Continuum a bit, making all exception
  instanciation go through a method to be able to centralize all logging. This
  implies that the core will log every exception it throws.
o Removed all logging from the ContinuumXmlRpc interface as the core does it
  now. The XML RPC clients will still get any exceptions returned as before.

Added:
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuard.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuardException.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/DefaultContinuumProjectStateGuard.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTask.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java
    maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java
    maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum/DefaultContinuumTest.xml
Modified:
    maven/continuum/trunk/continuum-core-it/continuum.py
    maven/continuum/trunk/continuum-core-it/it.py
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/BuildProjectTaskExecutor.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/ContinuumProjectState.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java
    maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStore.java
    maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus/components.xml
    maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue/BuildQueueTest.java
    maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcherTest.java
    maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStoreTest.java
    maven/continuum/trunk/continuum-plexus-application/src/conf/application.xml
    maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc/DefaultContinuumXmlRpc.java

Modified: maven/continuum/trunk/continuum-core-it/continuum.py
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core-it/continuum.py?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core-it/continuum.py (original)
+++ maven/continuum/trunk/continuum-core-it/continuum.py Mon May  2 10:17:06 2005
@@ -11,6 +11,8 @@
 STATE_ERROR = "error"
 STATE_BUILD_SIGNALED = "build signaled"
 STATE_BUILDING = "building"
+STATE_CHECKING_OUT = "checking out"
+STATE_UPDATING = "updating"
 
 server = xmlrpclib.Server("http://localhost:8000")
 
@@ -45,8 +47,12 @@
         return STATE_BUILD_SIGNALED
     elif ( state == 6 ):
         return STATE_BUILDING
+    elif ( state == 7 ):
+        return STATE_CHECKING_OUT
+    elif ( state == 8 ):
+        return STATE_UPDATING
     else:
-       return "UNKNOWN STATE (" + state + ")."
+       return "UNKNOWN STATE (" + str( state ) + ")."
 
 ####################################################################
 # These methods correspods 1<=>1 with the ContinuumXmlRpc interface
@@ -154,7 +160,11 @@
         self.version = map[ "version" ]
         self.builderId = map[ "builderId" ]
         self.configuration = map[ "configuration" ]
-        self.checkOutScmResult = CheckOutScmResult( map[ "checkOutScmResult" ] )
+
+        if ( map.has_key( "checkOutScmResult" ) ):
+            self.checkOutScmResult = CheckOutScmResult( map[ "checkOutScmResult" ] )
+        else:
+            self.checkOutScmResult = None
 
     def __str__( self ):
         str = "id: " + self.id + os.linesep +\

Modified: maven/continuum/trunk/continuum-core-it/it.py
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core-it/it.py?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core-it/it.py (original)
+++ maven/continuum/trunk/continuum-core-it/it.py Mon May  2 10:17:06 2005
@@ -165,7 +165,9 @@
 
     build = continuum.getBuild( buildId )
 
-    while( build.state == continuum.STATE_BUILD_SIGNALED or build.state == continuum.STATE_BUILDING ):
+    while( build.state == continuum.STATE_BUILD_SIGNALED or 
+           build.state == continuum.STATE_BUILDING or
+           build.state == continuum.STATE_UPDATING ):
         build = continuum.getBuild( buildId )
         time.sleep( sleepInterval )
         timeout -= sleepInterval
@@ -175,6 +177,24 @@
 
     return build
 
+def waitForCheckOut( projectId ):
+    timeout = 60
+    sleepInterval = 0.1
+
+    project = continuum.getProject( projectId )
+
+    while( project.state == continuum.STATE_CHECKING_OUT ):
+        project = continuum.getProject( projectId )
+        time.sleep( sleepInterval )
+        timeout -= sleepInterval
+
+        if ( timeout <= 0 ):
+            fail( "Timeout while waiting for checkout (project id=%(id)s) to complete" % { "id" : project.id } )
+
+    assertEquals( "The check out was not successful for project #" + project.id, continuum.STATE_NEW, project.state )
+
+    return project
+
 def cleanDirectory( dir ):
     if ( os.path.isdir( dir ) ):
         shutil.rmtree( dir )
@@ -336,6 +356,7 @@
     initMaven1Project( maven1Project, "cvs", cvsroot, "maven-1" )
     progress( "Adding Maven 1 project" )
     maven1Id = continuum.addMavenOneProject( "file:" + maven1Project + "/project.xml" )
+    waitForCheckOut( maven1Id );
     maven1 = continuum.getProject( maven1Id )
     assertProject( maven1Id, "Maven 1 Project", email, continuum.STATE_NEW, "1.0", "maven-1", maven1 )
     assertCheckedOutFiles( maven1, [ "/project.xml", "/src/main/java/Foo.java" ] )
@@ -372,6 +393,7 @@
     initMaven2Project( maven2Project, cvsroot, "maven-2" )
     progress( "Adding Maven 2 project" )
     maven2Id = continuum.addMavenTwoProject( "file:" + maven2Project + "/pom.xml" )
+    waitForCheckOut( maven2Id );
     maven2 = continuum.getProject( maven2Id )
     assertProject( maven2Id, "Maven 2 Project", email, continuum.STATE_NEW, "2.0-SNAPSHOT", "maven2", maven2 )
 
@@ -396,6 +418,7 @@
                                             "executable": "ant",
                                             "targets" : "clean, build"
                                         } )
+    waitForCheckOut( antSvnId );
     antSvn = continuum.getProject( antSvnId )
     assertProject( antSvnId, "Ant SVN Project", email, continuum.STATE_NEW, "3.0", "ant", antSvn )
     progress( "Building SVN Ant project" )
@@ -410,6 +433,7 @@
     cvsImport( antProject, cvsroot, "ant-cvs" )
     antCvsId = continuum.addAntProject( "scm:cvs:local:" + basedir + "/cvsroot:ant-cvs", "Ant CVS Project", email, "3.0",
                                       { "executable": "ant", "targets" : "clean, build"} )
+    waitForCheckOut( antCvsId );
     antCvs = continuum.getProject( antCvsId )
     assertProject( antCvsId, "Ant CVS Project", email, continuum.STATE_NEW, "3.0", "ant", antCvs )
     progress( "Building CVS Ant project" )
@@ -424,8 +448,11 @@
 
     progress( "Adding CVS Shell project" )
     shellId = continuum.addShellProject( "scm:cvs:local:" + basedir + "/cvsroot:shell", "Shell Project", email, "3.0",
-                                         { "executable": "script.sh", "arguments" : ""} )
-
+                                         { 
+                                            "executable": "script.sh", 
+                                            "arguments" : ""
+                                         } )
+    waitForCheckOut( shellId );
     shell = continuum.getProject( shellId )
     assertProject( shellId, "Shell Project", email, continuum.STATE_NEW, "3.0", "shell", shell )
 

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/DefaultContinuum.java Mon May  2 10:17:06 2005
@@ -40,9 +40,9 @@
 import org.apache.maven.continuum.project.MavenOneProject;
 import org.apache.maven.continuum.project.MavenTwoProject;
 import org.apache.maven.continuum.project.ShellProject;
-import org.apache.maven.continuum.scm.CheckOutScmResult;
 import org.apache.maven.continuum.scm.ContinuumScm;
 import org.apache.maven.continuum.scm.ContinuumScmException;
+import org.apache.maven.continuum.scm.queue.CheckOutTask;
 import org.apache.maven.continuum.store.ContinuumStore;
 import org.apache.maven.continuum.store.ContinuumStoreException;
 
@@ -80,12 +80,6 @@
     private BuilderManager builderManager;
 
     /** @requirement */
-//    private BuildController buildController;
-
-    /** @requirement */
-//    private BuildQueue buildQueue;
-
-    /** @requirement */
     private TaskQueue buildQueue;
 
     /** @requirement */
@@ -107,8 +101,6 @@
     //
     // ----------------------------------------------------------------------
 
-//    private BuilderThread builderThread;
-
     private Thread builderThreadThread;
 
     // ----------------------------------------------------------------------
@@ -293,9 +285,7 @@
         }
         catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Error while updating project.", ex );
-
-            throw new ContinuumException( "Error while updating project from SCM.", ex );
+            throw logAndCreateException( "Error while updating project from SCM.", ex );
         }
     }
 
@@ -308,9 +298,7 @@
         }
         catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Error while updating project configuration.", ex );
-
-            throw new ContinuumException( "Error while updating project configuration.", ex );
+            throw logAndCreateException( "Error while updating project configuration.", ex );
         }
     }
 
@@ -323,9 +311,7 @@
         }
         catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Error while updating project.", ex );
-
-            throw new ContinuumException( "Error while removing project.", ex );
+            logAndCreateException( "Error while removing project.", ex );
         }
     }
 
@@ -340,9 +326,7 @@
         }
         catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Error while finding all projects.", ex );
-
-            throw new ContinuumException( "Exception while getting all projects.", ex );
+            throw logAndCreateException( "Exception while getting all projects.", ex );
         }
     }
 
@@ -357,9 +341,7 @@
         }
         catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Error while finding all projects.", ex );
-
-            throw new ContinuumException( "Exception while getting all projects.", ex );
+            throw logAndCreateException( "Exception while getting all projects.", ex );
         }
     }
 
@@ -382,15 +364,11 @@
         }
         catch ( ContinuumStoreException e )
         {
-            getLogger().error( "Error while building project.", e );
-
-            throw new ContinuumException( "Error while creating build object.", e );
+            throw logAndCreateException( "Error while creating build object.", e );
         }
         catch ( TaskQueueException e )
         {
-            getLogger().error( "Error while enqueuing project.", e );
-
-            throw new ContinuumException( "Error while creating enqueuing object.", e );
+            throw logAndCreateException( "Error while creating enqueuing object.", e );
         }
     }
 
@@ -407,7 +385,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Unable to retrieve build with id = " + buildId, e );
+            throw logAndCreateException( "Unable to retrieve build with id = " + buildId, e );
         }
     }
 
@@ -420,7 +398,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Cannot retrieve builds for project with id = " + projectId, e );
+            throw logAndCreateException( "Cannot retrieve builds for project with id = " + projectId, e );
         }
     }
 
@@ -433,7 +411,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Cannot retrieve build result for build with id = " + buildId, e );
+            throw logAndCreateException( "Cannot retrieve build result for build with id = " + buildId, e );
         }
     }
 
@@ -446,7 +424,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Cannot retrieve build result for build with id = " + buildId, e );
+            throw logAndCreateException( "Cannot retrieve build result for build with id = " + buildId, e );
         }
     }
 
@@ -655,7 +633,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Error while updating the project.", e );
+            throw logAndCreateException( "Error while updating the project.", e );
         }
     }
 
@@ -681,26 +659,30 @@
     private ContinuumProject addProjectAndCheckOutSources( ContinuumProject project, String builderType )
         throws ContinuumException
     {
+        String projectId;
+
+        File projectWorkingDirectory;
+
         try
         {
             // ----------------------------------------------------------------------
             // Store the project
             // ----------------------------------------------------------------------
 
-            String projectId = store.addProject( project.getName(),
-                                                 project.getScmUrl(),
-                                                 project.getNagEmailAddress(),
-                                                 project.getVersion(),
-                                                 builderType,
-                                                 null,
-                                                 project.getConfiguration() );
+            projectId = store.addProject( project.getName(),
+                                          project.getScmUrl(),
+                                          project.getNagEmailAddress(),
+                                          project.getVersion(),
+                                          builderType,
+                                          null,
+                                          project.getConfiguration() );
 
             // ----------------------------------------------------------------------
             // Set the working directory
             // ----------------------------------------------------------------------
 
 
-            File projectWorkingDirectory = new File( workingDirectory, projectId );
+            projectWorkingDirectory = new File( workingDirectory, projectId );
 
             if ( !projectWorkingDirectory.exists() && !projectWorkingDirectory.mkdirs() )
             {
@@ -714,27 +696,24 @@
             // ----------------------------------------------------------------------
 
             store.setWorkingDirectory( projectId, projectWorkingDirectory.getAbsolutePath() );
-
-            CheckOutScmResult result = scm.checkOutProject( project );
-
-            store.setProjectCheckOutScmResult( projectId, result );
-
-            project = store.getProject( projectId );
-
-            return project;
         }
-        catch ( ContinuumScmException ex )
+        catch ( ContinuumStoreException ex )
         {
-            getLogger().error( "Exception while checking out the project.", ex );
-
-            throw new ContinuumException( "Exception while checking out the project.", ex );
+            throw logAndCreateException( "Exception while adding project.", ex );
         }
-        catch ( ContinuumStoreException ex )
+
+        try
         {
-            getLogger().error( "Exception while adding project.", ex );
+            CheckOutTask checkOutTask = new CheckOutTask( projectId, projectWorkingDirectory );
 
-            throw new ContinuumException( "Exception while adding project.", ex );
+            checkOutQueue.put( checkOutTask );
+        }
+        catch ( TaskQueueException e )
+        {
+            throw logAndCreateException( "Exception while adding the project to the check out queue.", e );
         }
+
+        return getProject( projectId );
     }
 
     private void doTempCheckOut( ContinuumProject project )
@@ -750,14 +729,14 @@
             }
             catch ( IOException ex )
             {
-                throw new ContinuumException( "Error while cleaning out " + checkoutDirectory.getAbsolutePath() );
+                throw logAndCreateException( "Error while cleaning out " + checkoutDirectory.getAbsolutePath() );
             }
         }
         else
         {
             if ( !checkoutDirectory.mkdirs() )
             {
-                throw new ContinuumException( "Could not make the check out directory (" + checkoutDirectory.getAbsolutePath() + ")." );
+                throw logAndCreateException( "Could not make the check out directory (" + checkoutDirectory.getAbsolutePath() + ")." );
             }
         }
 
@@ -770,7 +749,7 @@
         }
         catch ( ContinuumScmException e )
         {
-            throw new ContinuumException( "Error while checking out the project.", e );
+            throw logAndCreateException( "Error while checking out the project.", e );
         }
     }
 
@@ -803,7 +782,7 @@
         }
         catch ( ContinuumStoreException e )
         {
-            throw new ContinuumException( "Error while storing the updated project.", e );
+            throw logAndCreateException( "Error while storing the updated project.", e );
         }
 
         getLogger().info( "Updated project: " + project.getName() );
@@ -824,14 +803,14 @@
         {
             if ( !wdFile.isDirectory() )
             {
-                throw new ContinuumException( "The specified working directory isn't a directory: " + wdFile.getAbsolutePath() );
+                throw logAndCreateException( "The specified working directory isn't a directory: " + wdFile.getAbsolutePath() );
             }
         }
         else
         {
             if ( !wdFile.mkdirs() )
             {
-                throw new ContinuumException( "Could not making the working directory: " + wdFile.getAbsolutePath() );
+                throw logAndCreateException( "Could not making the working directory: " + wdFile.getAbsolutePath() );
             }
         }
 
@@ -850,20 +829,6 @@
     {
         getLogger().info( "Starting Continuum." );
 
-        // start the builder thread
-/*
-        builderThread = new BuilderThread( buildController, buildQueue, getLogger() );
-
-        builderThreadThread = new Thread( builderThread );
-
-        builderThreadThread.setDaemon( true );
-
-        builderThreadThread.start();
-*/
-        // ----------------------------------------------------------------------
-        //
-        // ----------------------------------------------------------------------
-
         // check to see if the tables exists or not.
         File file = new File( appHome, "continuum.properties" );
 
@@ -908,43 +873,7 @@
         throws Exception
     {
         getLogger().info( "Stopping Continuum." );
-/*
-        int maxSleep = 10 * 1000; // 10 seconds
-        int interval = 1000;
-        int slept = 0;
-
-        // signal the thread to stop
-        builderThread.shutdown();
-
-        builderThreadThread.interrupt();
-
-        while ( !builderThread.isDone() )
-        {
-            if ( slept > maxSleep )
-            {
-                getLogger().warn( "Timeout, stopping Continuum." );
-
-                break;
-            }
-
-            getLogger().info( "Waiting until Continuum is idling..." );
-
-            try
-            {
-                synchronized ( builderThread )
-                {
-                    builderThread.wait( interval );
-                }
-            }
-            catch ( InterruptedException ex )
-            {
-                // ignore
-            }
 
-            // TODO: should use System.currentTimeMillis()
-            slept += interval;
-        }
-*/
         getLogger().info( "Continuum stopped." );
     }
 
@@ -960,5 +889,19 @@
         properties.setProperty( DATABASE_INITIALIZED, "true" );
 
         properties.store( new FileOutputStream( file ), null );
+    }
+
+    private ContinuumException logAndCreateException( String message )
+    {
+        getLogger().error( message );
+
+        return new ContinuumException( message );
+    }
+
+    private ContinuumException logAndCreateException( String message, Throwable cause )
+    {
+        getLogger().error( message, cause );
+
+        return new ContinuumException( message, cause );
     }
 }

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/BuildProjectTaskExecutor.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/BuildProjectTaskExecutor.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/BuildProjectTaskExecutor.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/BuildProjectTaskExecutor.java Mon May  2 10:17:06 2005
@@ -19,9 +19,8 @@
 import org.apache.maven.continuum.buildqueue.BuildProjectTask;
 
 import org.codehaus.plexus.logging.AbstractLogEnabled;
-import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
-import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
 import org.codehaus.plexus.taskqueue.Task;
+import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
 
 /**
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
@@ -29,24 +28,15 @@
  */
 public class BuildProjectTaskExecutor
     extends AbstractLogEnabled
-    implements TaskExecutor, Initializable
+    implements TaskExecutor
 {
     private BuildController controller;
 
     // ----------------------------------------------------------------------
-    // Component Lifecycle
-    // ----------------------------------------------------------------------
-
-    public void initialize()
-    {
-    }
-
-    // ----------------------------------------------------------------------
     // TaskExecutor Implementation
     // ----------------------------------------------------------------------
 
     public void executeTask( Task task )
-        throws Exception
     {
         BuildProjectTask buildProjectTask = (BuildProjectTask) task;
 

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/buildcontroller/DefaultBuildController.java Mon May  2 10:17:06 2005
@@ -60,17 +60,6 @@
 
     public void build( String buildId )
     {
-        try
-        {
-            store.setBuildResult( buildId, ContinuumProjectState.BUILDING, null, null );
-        }
-        catch ( ContinuumStoreException ex )
-        {
-            getLogger().error( "Exception while setting the state flag.", ex );
-
-            return;
-        }
-
         ContinuumProject project;
 
         ContinuumBuild build;
@@ -198,11 +187,13 @@
 
         try
         {
+            store.setIsUpdating( build.getId() );
+
             notifier.checkoutStarted( build );
 
             scmResult = scm.updateProject( project );
 
-            store.setBuildUpdateScmResult( build.getId(), scmResult );
+            store.setUpdateDone( build.getId(), scmResult );
         }
         finally
         {

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/ContinuumProjectState.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/ContinuumProjectState.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/ContinuumProjectState.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/ContinuumProjectState.java Mon May  2 10:17:06 2005
@@ -68,6 +68,10 @@
 //    public final static ContinuumProjectState BUILDING = new ContinuumProjectState( "building" );
     public final static int BUILDING = 6;
 
+    public final static int CHECKING_OUT = 7;
+
+    public final static int UPDATING = 8;
+
     private String name;
 
     protected ContinuumProjectState( String name )

Added: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuard.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuard.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuard.java (added)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuard.java Mon May  2 10:17:06 2005
@@ -0,0 +1,40 @@
+package org.apache.maven.continuum.project.state;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.apache.maven.continuum.project.ContinuumProject;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public interface ContinuumProjectStateGuard
+{
+    String ROLE = ContinuumProjectStateGuard.class.getName();
+
+    void assertTransition( ContinuumProject project, int newState )
+        throws ContinuumProjectStateGuardException;
+
+    void assertDeletable( ContinuumProject project )
+        throws ContinuumProjectStateGuardException;
+
+    void assertUpdatable( ContinuumProject project )
+        throws ContinuumProjectStateGuardException;
+
+    void assertCanChangeWorkingDirectory( ContinuumProject project )
+        throws ContinuumProjectStateGuardException;
+}

Added: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuardException.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuardException.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuardException.java (added)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/ContinuumProjectStateGuardException.java Mon May  2 10:17:06 2005
@@ -0,0 +1,35 @@
+package org.apache.maven.continuum.project.state;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public class ContinuumProjectStateGuardException
+    extends Exception
+{
+    public ContinuumProjectStateGuardException( String message )
+    {
+        super( message );
+    }
+
+    public ContinuumProjectStateGuardException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}

Added: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/DefaultContinuumProjectStateGuard.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/DefaultContinuumProjectStateGuard.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/DefaultContinuumProjectStateGuard.java (added)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/project/state/DefaultContinuumProjectStateGuard.java Mon May  2 10:17:06 2005
@@ -0,0 +1,269 @@
+package org.apache.maven.continuum.project.state;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.apache.maven.continuum.project.ContinuumProject;
+import org.apache.maven.continuum.project.ContinuumProjectState;
+
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public class DefaultContinuumProjectStateGuard
+    extends AbstractLogEnabled
+    implements ContinuumProjectStateGuard
+{
+    // ----------------------------------------------------------------------
+    // ContinuumProjectStateGuard Implementation
+    // ----------------------------------------------------------------------
+
+    private final static int[] NEW_PREVIOUS_STATES = {
+        ContinuumProjectState.CHECKING_OUT,
+    };
+
+    private final static int[] ERROR_PREVIOUS_STATES = {
+        ContinuumProjectState.CHECKING_OUT,
+    };
+
+    private final static int[] BUILD_SIGNALED_PREVIOUS_STATES = {
+        ContinuumProjectState.NEW,
+        ContinuumProjectState.ERROR,
+        ContinuumProjectState.OK,
+        ContinuumProjectState.FAILED,
+        ContinuumProjectState.BUILD_SIGNALED,
+    };
+
+    private final static int[] UPDATING_PREVIOUS_STATES = {
+        ContinuumProjectState.BUILD_SIGNALED,
+    };
+
+    private final static int[] BUILDING_PREVIOUS_STATES = {
+        ContinuumProjectState.UPDATING,
+    };
+
+    private final static int[] OK_PREVIOUS_STATES = {
+        ContinuumProjectState.BUILDING,
+    };
+
+    private final static int[] FAILED_PREVIOUS_STATES = {
+        ContinuumProjectState.BUILDING,
+    };
+
+    private final static int[] DELETABLE_PREVIOUS_STATES = {
+        ContinuumProjectState.NEW,
+        ContinuumProjectState.ERROR,
+        ContinuumProjectState.OK,
+        ContinuumProjectState.FAILED,
+    };
+
+    private static final int[] UPDATABLE_PREVIOUS_STATES = {
+        ContinuumProjectState.NEW,
+        ContinuumProjectState.ERROR,
+        ContinuumProjectState.OK,
+        ContinuumProjectState.FAILED,
+        ContinuumProjectState.BUILDING,
+        ContinuumProjectState.CHECKING_OUT,
+    };
+
+    private static final int[] CHANGE_WORKING_DIRECTORY_PREVIOUS_STATES = {
+        ContinuumProjectState.CHECKING_OUT,
+    };
+
+    // ----------------------------------------------------------------------
+    // ContinuumProjectStateGuard Implementation
+    // ----------------------------------------------------------------------
+
+    public void assertTransition( ContinuumProject project, int newState )
+        throws ContinuumProjectStateGuardException
+    {
+        if ( newState == ContinuumProjectState.NEW )
+        {
+            assertInStates( project.getState(), NEW_PREVIOUS_STATES, "new" );
+        }
+        else if ( newState == ContinuumProjectState.ERROR )
+        {
+            assertInStates( project.getState(), ERROR_PREVIOUS_STATES, "error" );
+        }
+        else if ( newState == ContinuumProjectState.UPDATING )
+        {
+            assertInStates( project.getState(), UPDATING_PREVIOUS_STATES, "updating" );
+        }
+        else if ( newState == ContinuumProjectState.BUILD_SIGNALED )
+        {
+            assertInStates( project.getState(), BUILD_SIGNALED_PREVIOUS_STATES, "build signaled" );
+        }
+        else if ( newState == ContinuumProjectState.BUILDING )
+        {
+            assertInStates( project.getState(), BUILDING_PREVIOUS_STATES, "building" );
+        }
+        else if ( newState == ContinuumProjectState.OK )
+        {
+            assertInStates( project.getState(), OK_PREVIOUS_STATES, "ok" );
+        }
+        else if ( newState == ContinuumProjectState.FAILED )
+        {
+            assertInStates( project.getState(), FAILED_PREVIOUS_STATES, "failed" );
+        }
+        else
+        {
+            throw new ContinuumProjectStateGuardException( "Unknown state '" + newState + "'." );
+        }
+    }
+
+    public void assertDeletable( ContinuumProject project )
+        throws ContinuumProjectStateGuardException
+    {
+        int[] expectedStates = DELETABLE_PREVIOUS_STATES;
+
+        int actualState = project.getState();
+
+        if ( isInState( expectedStates, actualState ) )
+        {
+            return;
+        }
+
+        String stateString = makeStateString( expectedStates );
+
+        throw new ContinuumProjectStateGuardException(
+            "To be able to delete a project the project as to be in one of the states in " + stateString + " " +
+            "but the project was in the '" + decodeState( actualState ) + "' state." );
+    }
+
+    public void assertUpdatable( ContinuumProject project )
+        throws ContinuumProjectStateGuardException
+    {
+        int[] expectedStates = UPDATABLE_PREVIOUS_STATES;
+
+        int actualState = project.getState();
+
+        if ( isInState( expectedStates, actualState ) )
+        {
+            return;
+        }
+
+        String stateString = makeStateString( expectedStates );
+
+        throw new ContinuumProjectStateGuardException(
+            "To be able to update a project the project as to be in one of the states in " + stateString + " " +
+            "but the project was in the '" + decodeState( actualState ) + "' state." );
+    }
+
+    public void assertCanChangeWorkingDirectory( ContinuumProject project )
+        throws ContinuumProjectStateGuardException
+    {
+        int[] expectedStates = CHANGE_WORKING_DIRECTORY_PREVIOUS_STATES;
+
+        int actualState = project.getState();
+
+        if ( isInState( expectedStates, actualState ) )
+        {
+            return;
+        }
+
+        String stateString = makeStateString( expectedStates );
+
+        throw new ContinuumProjectStateGuardException(
+            "To be able to change the working directory of a project the " +
+            "project as to be in one of the states in " + stateString + " " +
+            "but the project was in the '" + decodeState( actualState ) + "' state." );
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    private static void assertInStates( int actualState,
+                                        int[] expectedStates,
+                                        String actionName )
+        throws ContinuumProjectStateGuardException
+    {
+        if ( isInState( expectedStates, actualState ) )
+            return;
+
+        String stateString = makeStateString( expectedStates );
+
+        throw new ContinuumProjectStateGuardException(
+            "To be able to go into the state '" + actionName + "', " +
+            "the project as to be in one of the states in " + stateString + " " +
+            "but the project was in the '" + decodeState( actualState ) + "' state." );
+    }
+
+    private static boolean isInState( int[] expectedStates,
+                                      int actualState )
+    {
+        for ( int i = 0; i < expectedStates.length; i++ )
+        {
+            int expectedState = expectedStates[ i ];
+
+            if ( actualState == expectedState )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private static String makeStateString( int[] states )
+    {
+        String stateString = "[";
+
+        for ( int i = 0; i < states.length; i++ )
+        {
+            int expectedState = states[ i ];
+
+            if ( i > 0 )
+            {
+                stateString += ", ";
+            }
+
+            stateString += "'" + decodeState( expectedState ) + "'";
+        }
+
+        stateString += "]";
+
+        return stateString;
+    }
+
+    // TODO: Externalize
+    private static String decodeState( int state )
+    {
+        switch ( state )
+        {
+            case ContinuumProjectState.NEW:
+                return "new";
+            case ContinuumProjectState.OK:
+                return "ok";
+            case ContinuumProjectState.FAILED:
+                return "failed";
+            case ContinuumProjectState.ERROR:
+                return "error";
+            case ContinuumProjectState.BUILD_SIGNALED:
+                return "build signaled";
+            case ContinuumProjectState.BUILDING:
+                return "building";
+            case ContinuumProjectState.CHECKING_OUT:
+                return "checking out";
+            case ContinuumProjectState.UPDATING:
+                return "updating";
+            default:
+                return "UNKNOWN (id '" + state + "')";
+        }
+    }
+}

Added: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTask.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTask.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTask.java (added)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTask.java Mon May  2 10:17:06 2005
@@ -0,0 +1,50 @@
+package org.apache.maven.continuum.scm.queue;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import java.io.File;
+
+import org.codehaus.plexus.taskqueue.Task;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public class CheckOutTask
+    implements Task
+{
+    private String projectId;
+
+    private File workingDirectory;
+
+    public CheckOutTask( String projectId, File workingDirectory )
+    {
+        this.projectId = projectId;
+
+        this.workingDirectory = workingDirectory;
+    }
+
+    public String getProjectId()
+    {
+        return projectId;
+    }
+
+    public File getWorkingDirectory()
+    {
+        return workingDirectory;
+    }
+}

Added: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java (added)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/scm/queue/CheckOutTaskExecutor.java Mon May  2 10:17:06 2005
@@ -0,0 +1,91 @@
+package org.apache.maven.continuum.scm.queue;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import java.io.File;
+
+import org.apache.maven.continuum.scm.ContinuumScm;
+import org.apache.maven.continuum.scm.ContinuumScmException;
+import org.apache.maven.continuum.scm.CheckOutScmResult;
+import org.apache.maven.continuum.store.ContinuumStore;
+import org.apache.maven.continuum.store.ContinuumStoreException;
+import org.apache.maven.continuum.project.ContinuumProject;
+
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.taskqueue.Task;
+import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
+import org.codehaus.plexus.taskqueue.execution.TaskExecutionException;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public class CheckOutTaskExecutor
+    extends AbstractLogEnabled
+    implements TaskExecutor
+{
+    /** @requirement */
+    private ContinuumScm scm;
+
+    /** @requirement */
+    private ContinuumStore store;
+
+    // ----------------------------------------------------------------------
+    // TaskExecutor Implementation
+    // ----------------------------------------------------------------------
+
+    public void executeTask( Task t )
+        throws TaskExecutionException
+    {
+        CheckOutTask task = (CheckOutTask) t;
+
+        String projectId = task.getProjectId();
+
+        File workingDirectory = task.getWorkingDirectory();
+
+        ContinuumProject project;
+
+        try
+        {
+            project = store.getProject( projectId );
+        }
+        catch ( ContinuumStoreException e )
+        {
+            throw new TaskExecutionException( "Error while reading the project from the store.", e );
+        }
+
+        CheckOutScmResult result;
+
+        try
+        {
+            result = scm.checkOut( project, workingDirectory );
+        }
+        catch ( ContinuumScmException e )
+        {
+            throw new TaskExecutionException( "Error while reading the project from the store.", e );
+        }
+
+        try
+        {
+            store.setCheckoutDone( projectId, result );
+        }
+        catch ( ContinuumStoreException e )
+        {
+            throw new TaskExecutionException( "Error while storing the check out result.", e );
+        }
+    }
+}

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ContinuumStore.java Mon May  2 10:17:06 2005
@@ -57,9 +57,6 @@
     void setWorkingDirectory( String projectId, String workingDirectory )
         throws ContinuumStoreException;
 
-    void setProjectCheckOutScmResult( String projectId, CheckOutScmResult result )
-        throws ContinuumStoreException;
-
     void updateProject( String projectId, String name, String scmUrl, String nagEmailAddress, String version )
         throws ContinuumStoreException;
 
@@ -106,6 +103,16 @@
     List getChangedFilesForBuild( String buildId )
         throws ContinuumStoreException;
 
-    void setBuildUpdateScmResult( String buildId, UpdateScmResult scmResult )
+    // ----------------------------------------------------------------------
+    // SCM
+    // ----------------------------------------------------------------------
+
+    void setCheckoutDone( String projectId, CheckOutScmResult scmResult )
+        throws ContinuumStoreException;
+
+    void setIsUpdating( String buildId )
+        throws ContinuumStoreException;
+
+    void setUpdateDone( String buildId, UpdateScmResult scmResult )
         throws ContinuumStoreException;
 }

Modified: maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStore.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStore.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStore.java (original)
+++ maven/continuum/trunk/continuum-core/src/main/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStore.java Mon May  2 10:17:06 2005
@@ -31,6 +31,7 @@
 import org.apache.maven.continuum.project.ContinuumJPoxStore;
 import org.apache.maven.continuum.project.ContinuumProject;
 import org.apache.maven.continuum.project.ContinuumProjectState;
+import org.apache.maven.continuum.project.state.ContinuumProjectStateGuard;
 import org.apache.maven.continuum.scm.CheckOutScmResult;
 import org.apache.maven.continuum.scm.ScmFile;
 import org.apache.maven.continuum.scm.UpdateScmResult;
@@ -49,6 +50,9 @@
     /** @requirement */
     private JdoFactory jdoFactory;
 
+    /** @requirement */
+    private ContinuumProjectStateGuard projectStateGuard;
+
     private ContinuumJPoxStore store;
 
     // ----------------------------------------------------------------------
@@ -94,7 +98,7 @@
         project.setVersion( version );
         project.setBuilderId( builderId );
         project.setWorkingDirectory( workingDirectory );
-        project.setState( ContinuumProjectState.NEW );
+        project.setState( ContinuumProjectState.CHECKING_OUT );
         project.setConfiguration( configuration );
 
         try
@@ -125,11 +129,15 @@
 //            System.err.println( "getProject()" );
             ContinuumProject project = store.getContinuumProject( projectId, false );
 
-            // TODO: This is dumb.
+            projectStateGuard.assertDeletable( project );
+
+            // TODO: This whole section is dumb.
             PersistenceManager pm = store.getThreadState().getPersistenceManager();
 
-//            System.err.println( "getBuilds()" );
-            for ( Iterator it = project.getBuilds().iterator(); it.hasNext(); )
+//            System.err.println( "project.getBuilds()" );
+            List builds = project.getBuilds();
+
+            for ( Iterator it = builds.iterator(); it.hasNext(); )
             {
                 ContinuumBuild build = (ContinuumBuild) it.next();
 
@@ -155,10 +163,10 @@
 
 //                System.err.println( "pm.deletePersistent( result )" );
                 pm.deletePersistent( result );
-            }
 
-//            System.err.println( "project.getBuilds()" );
-            List builds = new ArrayList( project.getBuilds() );
+//                System.err.println( "build.setProject( null )" );
+                build.setProject( null );
+            }
 
             for ( Iterator it = builds.iterator(); it.hasNext(); )
             {
@@ -166,10 +174,12 @@
 
 //                System.err.println( "build.setProject( null )" );
                 build.setProject( null );
+
+                pm.deletePersistent( build );
             }
 
 //            System.err.println( "pm.deletePersistentAll( builds )" );
-            pm.deletePersistentAll( project.getBuilds() );
+            pm.deletePersistentAll( builds );
 
 //            System.err.println( "store.deleteContinuumProject( projectId )" );
             store.deleteContinuumProject( projectId );
@@ -193,6 +203,8 @@
 
             ContinuumProject project = store.getContinuumProject( projectId, false );
 
+            projectStateGuard.assertCanChangeWorkingDirectory( project );
+
             project.setWorkingDirectory( workingDirectory );
 
             store.commit();
@@ -205,27 +217,6 @@
         }
     }
 
-    public void setProjectCheckOutScmResult( String projectId, CheckOutScmResult result )
-        throws ContinuumStoreException
-    {
-        try
-        {
-            store.begin();
-
-            ContinuumProject project = store.getContinuumProject( projectId, false );
-
-            project.setCheckOutScmResult( result );
-
-            store.commit();
-        }
-        catch ( Exception e )
-        {
-            rollback( store );
-
-            throw new ContinuumStoreException( "Error while setting scm check out result for project with id: '" + projectId + "'.", e );
-        }
-    }
-
     public void updateProject( String projectId, String name, String scmUrl, String nagEmailAddress, String version )
         throws ContinuumStoreException
     {
@@ -235,6 +226,8 @@
 
             ContinuumProject project = store.getContinuumProject( projectId, false );
 
+            projectStateGuard.assertUpdatable( project );
+
             project.setName( name );
             project.setScmUrl( scmUrl );
             project.setNagEmailAddress( nagEmailAddress );
@@ -259,6 +252,8 @@
 
             ContinuumProject project = store.getContinuumProject( projectId, false );
 
+            projectStateGuard.assertUpdatable( project );
+
             project.setConfiguration( configuration );
 
             store.commit();
@@ -374,12 +369,6 @@
 
             store.commit();
 
-            for ( Iterator it = result.getCheckedOutFiles().iterator(); it.hasNext(); )
-            {
-                ScmFile scmFile = (ScmFile) it.next();
-                System.err.println( "scmfile.path: " + scmFile.getPath() );
-            }
-
             return result;
         }
         catch ( Exception e )
@@ -403,6 +392,8 @@
 
             ContinuumProject project = store.getContinuumProject( projectId, false );
 
+            projectStateGuard.assertTransition( project, ContinuumProjectState.BUILD_SIGNALED );
+
             project.setState( ContinuumProjectState.BUILD_SIGNALED );
 
             ContinuumBuild build = new ContinuumBuild();
@@ -440,6 +431,8 @@
 
             ContinuumProject project = build.getProject();
 
+            projectStateGuard.assertTransition( project, state );
+
             project.setState( state );
 
             build.setState( state );
@@ -598,7 +591,74 @@
         }
     }
 
-    public void setBuildUpdateScmResult( String buildId, UpdateScmResult scmResult )
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    public void setCheckoutDone( String projectId, CheckOutScmResult scmResult )
+        throws ContinuumStoreException
+    {
+        try
+        {
+            store.begin();
+
+            ContinuumProject project = store.getContinuumProject( projectId, false );
+
+            int state;
+
+            if ( scmResult.isSuccess() )
+            {
+                state = ContinuumProjectState.NEW;
+            }
+            else
+            {
+                state = ContinuumProjectState.ERROR;
+            }
+
+            projectStateGuard.assertTransition( project, state );
+
+            project.setState( state );
+
+            project.setCheckOutScmResult( scmResult );
+
+            store.commit();
+        }
+        catch ( Exception e )
+        {
+            rollback( store );
+
+            throw new ContinuumStoreException( "Error while setting check out scm result.", e );
+        }
+    }
+
+    public void setIsUpdating( String buildId )
+        throws ContinuumStoreException
+    {
+        try
+        {
+            store.begin();
+
+            ContinuumBuild build = store.getContinuumBuild( buildId, false );
+
+            ContinuumProject project = build.getProject();
+
+            projectStateGuard.assertTransition( project, ContinuumProjectState.UPDATING );
+
+            project.setState( ContinuumProjectState.UPDATING );
+
+            build.setState( ContinuumProjectState.UPDATING );
+
+            store.commit();
+        }
+        catch ( Exception e )
+        {
+            rollback( store );
+
+            throw new ContinuumStoreException( "Error while setting build state.", e );
+        }
+    }
+
+    public void setUpdateDone( String buildId, UpdateScmResult scmResult )
         throws ContinuumStoreException
     {
         try
@@ -609,13 +669,21 @@
 
             build.setUpdateScmResult( scmResult );
 
+            ContinuumProject project = build.getProject();
+
+            projectStateGuard.assertTransition( project, ContinuumProjectState.BUILDING );
+
+            project.setState( ContinuumProjectState.BUILDING );
+
+            build.setState( ContinuumProjectState.BUILDING );
+
             store.commit();
         }
         catch ( Exception e )
         {
             rollback( store );
 
-            throw new ContinuumStoreException( "Error while setting scm update result for build: '" + buildId + "'.", e );
+            throw new ContinuumStoreException( "Error while setting update scm result.", e );
         }
     }
 

Modified: maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus/components.xml
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus/components.xml?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus/components.xml (original)
+++ maven/continuum/trunk/continuum-core/src/main/resources/META-INF/plexus/components.xml Mon May  2 10:17:06 2005
@@ -7,26 +7,16 @@
         <requirement>
           <role>org.apache.maven.continuum.builder.manager.BuilderManager</role>
         </requirement>
-<!--
-        <requirement>
-          <role>org.apache.maven.continuum.buildcontroller.BuildController</role>
-        </requirement>
-        <requirement>
-          <role>org.apache.maven.continuum.buildqueue.BuildQueue</role>
-        </requirement>
--->
         <requirement>
           <role>org.codehaus.plexus.taskqueue.TaskQueue</role>
           <role-hint>build-project</role-hint>
           <field-name>buildQueue</field-name>
         </requirement>
-<!--
         <requirement>
           <role>org.codehaus.plexus.taskqueue.TaskQueue</role>
-          <role-hint>check-out-queue</role-hint>
+          <role-hint>check-out-project</role-hint>
           <field-name>checkOutQueue</field-name>
         </requirement>
--->
         <requirement>
           <role>org.apache.maven.continuum.store.ContinuumStore</role>
         </requirement>
@@ -111,9 +101,17 @@
         <requirement>
           <role>org.codehaus.plexus.jdo.JdoFactory</role>
         </requirement>
+        <requirement>
+          <role>org.apache.maven.continuum.project.state.ContinuumProjectStateGuard</role>
+        </requirement>
       </requirements>
     </component>
 
+    <component>
+      <role>org.apache.maven.continuum.project.state.ContinuumProjectStateGuard</role>
+      <implementation>org.apache.maven.continuum.project.state.DefaultContinuumProjectStateGuard</implementation>
+    </component>
+
     <!-- Triggers -->
 
     <component>
@@ -165,8 +163,11 @@
       <implementation>org.apache.maven.continuum.notification.console.ConsoleNotifier</implementation>
     </component>
 
-    <!-- Builder -->
-
+    <!--
+     |
+     | Builders
+     |
+     |-->
     <component>
       <role>org.apache.maven.continuum.builder.ContinuumBuilder</role>
       <role-hint>maven2</role-hint>
@@ -259,7 +260,7 @@
 
     <!--
      |
-     | Build Task Queue
+     | Build Project Task Queue
      |
      |-->
 
@@ -330,13 +331,20 @@
       <implementation>org.codehaus.plexus.taskqueue.DefaultTaskQueue</implementation>
       <lifecycle-handler>plexus-configurable</lifecycle-handler>
     </component>
-<!--
     <component>
       <role>org.codehaus.plexus.taskqueue.execution.TaskExecutor</role>
       <role-hint>check-out-project</role-hint>
-      <implementation>org.apache.maven.continuum.buildcontroller.BuildProjectTaskExecutor</implementation>
+      <implementation>org.apache.maven.continuum.scm.queue.CheckOutTaskExecutor</implementation>
+      <requirements>
+        <requirement>
+          <role>org.apache.maven.continuum.store.ContinuumStore</role>
+        </requirement>
+        <requirement>
+          <role>org.apache.maven.continuum.scm.ContinuumScm</role>
+        </requirement>
+      </requirements>
     </component>
--->
+
     <component>
       <role>org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor</role>
       <role-hint>check-out-project</role-hint>
@@ -358,7 +366,7 @@
 
     <!--
      |
-     | Check Out Task Queue
+     | JDO
      |
      |-->
     <component>
@@ -402,6 +410,11 @@
       </configuration>
     </component>
 
+    <!--
+     |
+     | Velocity
+     |
+     |-->
     <component>
       <role>org.codehaus.plexus.velocity.VelocityComponent</role>
       <implementation>org.codehaus.plexus.velocity.DefaultVelocityComponent</implementation>

Added: maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java (added)
+++ maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/DefaultContinuumTest.java Mon May  2 10:17:06 2005
@@ -0,0 +1,41 @@
+package org.apache.maven.continuum;
+
+/*
+ * Copyright 2004-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.taskqueue.TaskQueue;
+import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
+ * @version $Id:$
+ */
+public class DefaultContinuumTest
+    extends PlexusTestCase
+{
+    public void testLookups()
+        throws Exception
+    {
+        lookup( TaskQueue.ROLE, "build-project" );
+
+        lookup( TaskQueue.ROLE, "check-out-project" );
+
+        lookup( TaskQueueExecutor.ROLE, "build-project" );
+
+        lookup( TaskQueueExecutor.ROLE, "check-out-project" );
+    }
+}

Modified: maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue/BuildQueueTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue/BuildQueueTest.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue/BuildQueueTest.java (original)
+++ maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/buildqueue/BuildQueueTest.java Mon May  2 10:17:06 2005
@@ -19,6 +19,7 @@
 import java.util.Properties;
 
 import org.apache.maven.continuum.store.ContinuumStore;
+import org.apache.maven.continuum.store.ModelloJPoxContinuumStoreTest;
 
 import org.codehaus.plexus.PlexusTestCase;
 
@@ -48,7 +49,7 @@
     {
         String name = "Project 1";
 
-        String project = createProject( name );
+        String project = ModelloJPoxContinuumStoreTest.addProject( store, name );
 
         String build = enqueue( project );
 
@@ -75,9 +76,9 @@
 
         String name2 = "Project 2";
 
-        String project1 = createProject( name1 );
+        String project1 = ModelloJPoxContinuumStoreTest.addProject( store, name1 );
 
-        String project2 = createProject( name2 );
+        String project2 = ModelloJPoxContinuumStoreTest.addProject( store, name2 );
 
         String build1 = enqueue( project1 );
 
@@ -112,19 +113,6 @@
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
-
-    private String createProject( String name )
-        throws Exception
-    {
-        String scmUrl = "scm:local:src/test/projects/project-1";
-        String nagEmailAddress = "foo@bar";
-        String version = "1.0";
-        String builderId = "test";
-        String workingDirectory = getTestPath( "target/checkouts" );
-        Properties properties = new Properties();
-
-        return store.addProject( name, scmUrl, nagEmailAddress, version, builderId, workingDirectory, properties );
-    }
 
     private String enqueue( String projectId )
         throws Exception

Modified: maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcherTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcherTest.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcherTest.java (original)
+++ maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/notification/ContinuumNotificationDispatcherTest.java Mon May  2 10:17:06 2005
@@ -21,6 +21,7 @@
 import org.apache.maven.continuum.project.AntProject;
 import org.apache.maven.continuum.project.ContinuumBuild;
 import org.apache.maven.continuum.store.ContinuumStore;
+import org.apache.maven.continuum.store.ModelloJPoxContinuumStoreTest;
 
 import org.codehaus.plexus.PlexusTestCase;
 
@@ -39,7 +40,7 @@
 
         ContinuumStore store = (ContinuumStore) lookup( ContinuumStore.ROLE );
 
-        String projectId = store.addProject( "Test Project", "scm:local:foo", "foo@bar", "1.0", "ant", "/tmp", new Properties() );
+        String projectId = ModelloJPoxContinuumStoreTest.addProject( store, "Test Project" );
 
         String buildId = store.createBuild( projectId );
 

Modified: maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStoreTest.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStoreTest.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStoreTest.java (original)
+++ maven/continuum/trunk/continuum-core/src/test/java/org/apache/maven/continuum/store/ModelloJPoxContinuumStoreTest.java Mon May  2 10:17:06 2005
@@ -31,6 +31,7 @@
 import org.apache.maven.continuum.project.ContinuumProjectState;
 import org.apache.maven.continuum.scm.ScmFile;
 import org.apache.maven.continuum.scm.UpdateScmResult;
+import org.apache.maven.continuum.scm.CheckOutScmResult;
 
 import org.codehaus.plexus.PlexusTestCase;
 import org.codehaus.plexus.jdo.JdoFactory;
@@ -221,7 +222,27 @@
         //
         // ----------------------------------------------------------------------
 
-        assertNotNull( store.getProject( projectId ) );
+        ContinuumProject project = store.getProject( projectId );
+
+        assertNotNull( project );
+
+        assertEquals( ContinuumProjectState.CHECKING_OUT, project.getState() );
+
+        // ----------------------------------------------------------------------
+        //
+        // ----------------------------------------------------------------------
+
+        CheckOutScmResult checkOutScmResult = new CheckOutScmResult();
+
+        checkOutScmResult.setSuccess( true );
+
+        store.setCheckoutDone( projectId, checkOutScmResult );
+
+        project = store.getProject( projectId );
+
+        assertNotNull( project );
+
+        assertEquals( ContinuumProjectState.NEW, project.getState() );
 
         // ----------------------------------------------------------------------
         //
@@ -235,7 +256,7 @@
 
         store.updateProject( projectId, name2, scmUrl2, nagEmailAddress2, version2  );
 
-        ContinuumProject project = store.getProject( projectId );
+        project = store.getProject( projectId );
 
         assertProjectEquals( projectId, name2, scmUrl2, nagEmailAddress2, version2, builderId, workingDirectory,
                              properties2, project );
@@ -355,6 +376,8 @@
 
         String buildId = store.createBuild( projectId );
 
+        store.setIsUpdating( buildId );
+
         UpdateScmResult updateScmResult = new UpdateScmResult();
 
         ScmFile file = new ScmFile();
@@ -363,7 +386,7 @@
 
         updateScmResult.addUpdatedFile( file );
 
-        store.setBuildUpdateScmResult( buildId, updateScmResult );
+        store.setUpdateDone( buildId, updateScmResult );
 
         ContinuumBuildResult result = new ShellBuildResult();
 
@@ -511,6 +534,10 @@
 
         assertEquals( ContinuumProjectState.BUILD_SIGNALED, build.getState() );
 
+        store.setIsUpdating( buildId );
+
+        store.setUpdateDone( buildId, new UpdateScmResult() );
+
         // ----------------------------------------------------------------------
         // Check the build result
         // ----------------------------------------------------------------------
@@ -562,8 +589,12 @@
     private String addProject( String name )
         throws Exception
     {
-        ContinuumStore store = (ContinuumStore) lookup( ContinuumStore.ROLE );
+        return addProject( (ContinuumStore) lookup( ContinuumStore.ROLE ), name );
+    }
 
+    public static String addProject( ContinuumStore store, String name )
+        throws Exception
+    {
         String scmUrl = "scm:local:src/test/repo";
         String nagEmailAddress = "foo@bar.com";
         String version = "1.0";
@@ -571,7 +602,21 @@
         String workingDirectory = "/tmp";
         Properties configuration = new Properties();
 
-        return store.addProject( name, scmUrl, nagEmailAddress, version, builderId, workingDirectory, configuration );
+        String projectId = store.addProject( name, scmUrl, nagEmailAddress, version, builderId, workingDirectory, configuration );
+
+        CheckOutScmResult checkOutScmResult = new CheckOutScmResult();
+
+        checkOutScmResult.setSuccess( true );
+
+        store.setCheckoutDone( projectId, checkOutScmResult );
+
+        ContinuumProject project = store.getProject( projectId );
+
+        assertNotNull( project );
+
+        assertEquals( ContinuumProjectState.NEW, project.getState() );
+
+        return projectId;
     }
 
     private void assertProjectEquals( String projectId, String name, String scmUrl, String nagEmailAddress, String version, String builderId, String workingDirectory, Properties configuration, ContinuumProject project )

Added: maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum/DefaultContinuumTest.xml
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum/DefaultContinuumTest.xml?rev=165648&view=auto
==============================================================================
--- maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum/DefaultContinuumTest.xml (added)
+++ maven/continuum/trunk/continuum-core/src/test/resources/org/apache/maven/continuum/DefaultContinuumTest.xml Mon May  2 10:17:06 2005
@@ -0,0 +1,11 @@
+<plexus>
+  <components>
+    <component>
+      <role>org.codehaus.plexus.notification.RecipientSource</role>
+      <implementation>org.apache.maven.continuum.notification.ContinuumRecipientSource</implementation>
+      <configuration>
+        <toOverride>nobody@localhost</toOverride>
+      </configuration>
+    </component>
+  </components>
+</plexus>

Modified: maven/continuum/trunk/continuum-plexus-application/src/conf/application.xml
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-plexus-application/src/conf/application.xml?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-plexus-application/src/conf/application.xml (original)
+++ maven/continuum/trunk/continuum-plexus-application/src/conf/application.xml Mon May  2 10:17:06 2005
@@ -17,6 +17,14 @@
       <role>org.apache.maven.continuum.trigger.ContinuumTrigger</role>
       <role-hint>alarm-clock</role-hint>
     </component>
+    <component>
+      <role>org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor</role>
+      <role-hint>build-project</role-hint>
+    </component>
+    <component>
+      <role>org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor</role>
+      <role-hint>check-out-project</role-hint>
+    </component>
   </load-on-start>
 
   <resources>
@@ -165,6 +173,9 @@
       <requirements>
         <requirement>
           <role>org.codehaus.plexus.jdo.JdoFactory</role>
+        </requirement>
+        <requirement>
+          <role>org.apache.maven.continuum.project.state.ContinuumProjectStateGuard</role>
         </requirement>
       </requirements>
     </component>

Modified: maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc/DefaultContinuumXmlRpc.java
URL: http://svn.apache.org/viewcvs/maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc/DefaultContinuumXmlRpc.java?rev=165648&r1=165647&r2=165648&view=diff
==============================================================================
--- maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc/DefaultContinuumXmlRpc.java (original)
+++ maven/continuum/trunk/continuum-xmlrpc/src/main/java/org/apache/maven/continuum/xmlrpc/DefaultContinuumXmlRpc.java Mon May  2 10:17:06 2005
@@ -405,7 +405,7 @@
 
     private Hashtable handleException( String method, Throwable throwable )
     {
-        getLogger().error( "Error while executing '" + method + "'.", throwable );
+//        getLogger().error( "Error while executing '" + method + "'.", throwable );
 
         Hashtable hashtable = new Hashtable();
 



Mime
View raw message