<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.comp.java.xooctory.scm">
    <title>gmane.comp.java.xooctory.scm</title>
    <link>http://blog.gmane.org/gmane.comp.java.xooctory.scm</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/726"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/724"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/723"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/664"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/663"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/659"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/658"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/657"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/645"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/644"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/643"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/642"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/641"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/640"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/639"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/638"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/636"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/635"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/634"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.java.xooctory.scm/633"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/726">
    <title>Best Sales 2010!</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/726</link>
    <description>&lt;pre&gt;http://groups.yahoo.com/group/xkipuk/message



&lt;/pre&gt;</description>
    <dc:creator>xooctory-commit&lt; at &gt;xoocode.org</dc:creator>
    <dc:date>2010-08-10T06:50:16</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/724">
    <title>xooctory-commit&lt; at &gt;xoocode.org 16% OFF on Pfizer!</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/724</link>
    <description>&lt;pre&gt;http://groups.yahoo.com/group/charltounpapaseq/message

















































































eutsch-
Osterreich sofort an Bayern anschlie.en wurde, da. der Friede dann viel besser wurde und ahnlichen 
Unsinn mehr. Da konnte ich denn nicht anders, als mich ebenfalls zum Wort zu melden und dem 
gelahrten Herrn meine Meinung uber diesen Punkt zu sagen  mit dem Erfolg, da.



&lt;/pre&gt;</description>
    <dc:creator>xooctory-commit&lt; at &gt;xoocode.org</dc:creator>
    <dc:date>2010-08-09T01:05:18</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/723">
    <title>xooctory-commit&lt; at &gt;xoocode.org 08% OFF on Pfizer!</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/723</link>
    <description>&lt;pre&gt;http://groups.yahoo.com/group/genoholbrooksaw/message

















































































i seiner politischen Klugheit nie mit einem Staate verbunden, der dem Untergange geweiht ist. Im 
ubrigen hat Bismarck schon seinerzeit die deutsche Kolonial- und Handelspolitik mit gemischten 
Gefuhlen betrachtet, da ihm zunachst nur daran lag, die Konsolidierung und innere Festigung des von 
ihm geschaffenen Staatengebildes auf sicherstem Wege zu ermoglichen. Dies war auch der ein



&lt;/pre&gt;</description>
    <dc:creator>xooctory-commit&lt; at &gt;xoocode.org</dc:creator>
    <dc:date>2010-08-06T23:41:44</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/664">
    <title>r480 - in org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins: resource/ivy trigger/dependency/ivy</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/664</link>
    <description>&lt;pre&gt;Author: ludo
Date: Fri May 28 02:06:48 2010
New Revision: 480

Log:
update to the current Ivy API

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/resource/ivy/IvyResource.java
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/trigger/dependency/ivy/IvyDependencyTrigger.java

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/resource/ivy/IvyResource.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/resource/ivy/IvyResource.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/resource/ivy/IvyResource.javaFri May 28 02:06:48 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -7,7 +7,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
 import org.apache.ivy.core.settings.IvySettings;
 import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry;
-import org.apache.ivy.util.DefaultMessageImpl;
+import org.apache.ivy.util.DefaultMessageLogger;
 import org.apache.ivy.util.Message;
 import org.xoocode.xooctory.job.model.JobModel;
 import org.xoocode.xooctory.jobplan.JobResource;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -61,7 +61,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 super(res);
 this.scmRegistry = scmRegistry;
 this.jobPlanService = jobPlanService;
-Message.init(new DefaultMessageImpl(Message.MSG_WARN));
+Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_WARN));
 this.settings = new IvySettings();
 try {
 settings.loadDefault();

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/trigger/dependency/ivy/IvyDependencyTrigger.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/trigger/dependency/ivy/IvyDependencyTrigger.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/plugins/trigger/dependency/ivy/IvyDependencyTrigger.javaFri May 28 02:06:48 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,7 +2,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
 import org.apache.ivy.core.settings.IvySettings;
-import org.apache.ivy.util.DefaultMessageImpl;
+import org.apache.ivy.util.DefaultMessageLogger;
 import org.apache.ivy.util.Message;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,7 +47,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 this.jobPlanService = jobPlanService;
 
-Message.init(new DefaultMessageImpl(Message.MSG_WARN));
+Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_WARN));
 settings = new IvySettings();
 try {
 settings.loadDefault();

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-28T00:06:49</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/663">
    <title>r481 - org.xoocode.xooctory/trunk/xooctory</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/663</link>
    <description>&lt;pre&gt;Author: ludo
Date: Fri May 28 02:06:51 2010
New Revision: 481

Log:
upgrade to joda-time 1.6

Modified:
   org.xoocode.xooctory/trunk/xooctory/ivy.xml

Modified: org.xoocode.xooctory/trunk/xooctory/ivy.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/ivy.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/ivy.xmlFri May 28 02:06:51 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -124,7 +124,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 &amp;lt;!-- Util --&amp;gt;
 &amp;lt;dependency org="net.jcip" name="annotations" rev="1.0" /&amp;gt;
-&amp;lt;dependency org="joda-time" name="joda-time" rev="1.4" /&amp;gt;
+&amp;lt;dependency org="joda-time" name="joda-time" rev="1.6" /&amp;gt;
 &amp;lt;dependency org="xerces" name="xercesImpl" rev="2.8.1" /&amp;gt;
 &amp;lt;dependency org="commons-io" name="commons-io" rev="1.3.1" /&amp;gt;
 &amp;lt;dependency org="commons-digester" name="commons-digester" rev="1.8" /&amp;gt;

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-28T00:06:51</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/659">
    <title>r478 - in org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy: one two</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/659</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May 27 01:56:04 2010
New Revision: 478

Log:
fix Ivy boilerplate in the `dependent-modules-ivy' example

Modified:
   org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/build.xml
   org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivy.xml
   org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivysettings.xml
   org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/build.xml
   org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/ivysettings.xml

Modified: org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/build.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/build.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/build.xmlThu May 27 01:56:04 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,7 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;project name="xooctory-stupid-library"
  xmlns:ivy="antlib:org.apache.ivy.ant"&amp;gt;
   &amp;lt;property name="builddir" value="build" /&amp;gt;
-  &amp;lt;property name="repository.dir" value="repository" /&amp;gt;
+  &amp;lt;property name="repository.dir" value="${basedir}/repository" /&amp;gt;
 
   &amp;lt;target name="compile"&amp;gt;
     &amp;lt;javac source="1.6" encoding="utf-8"

Modified: org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivy.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivy.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivy.xmlThu May 27 01:56:04 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,4 +1,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;ivy-module version="1.0"&amp;gt;
     &amp;lt;info organisation="chbouib" module="Library"
   revision="latest" /&amp;gt;
+    &amp;lt;publications&amp;gt;
+      &amp;lt;artifact name="Library" ext="jar" /&amp;gt;
+    &amp;lt;/publications&amp;gt;
 &amp;lt;/ivy-module&amp;gt;

Modified: org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivysettings.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivysettings.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/one/ivysettings.xmlThu May 27 01:56:04 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -4,7 +4,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   &amp;lt;!-- &amp;lt;settings defaultCache="${cache.dir}" defaultResolver="ibiblio" checkUpToDate="false" /&amp;gt;
        --&amp;gt;
   &amp;lt;resolvers&amp;gt;
-    &amp;lt;ibiblio name="ibiblio" /&amp;gt;
     &amp;lt;filesystem name="internal"&amp;gt;
       &amp;lt;ivy pattern="${repository.dir}/[module]/ivy-[revision].xml" /&amp;gt;
       &amp;lt;artifact pattern="${repository.dir}/[module]/[artifact]-[revision].[ext]" /&amp;gt;

Modified: org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/build.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/build.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/build.xmlThu May 27 01:56:04 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,7 +2,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  xmlns:ivy="antlib:org.apache.ivy.ant"&amp;gt;
 
   &amp;lt;property name="builddir" value="build" /&amp;gt;
-  &amp;lt;property name="repository.dir" value="../one/repository" /&amp;gt;
+  &amp;lt;property name="repository.dir" value="${basedir}/../one/repository" /&amp;gt;
 
   &amp;lt;target name="init"&amp;gt;
     &amp;lt;ivy:resolve /&amp;gt;

Modified: org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/ivysettings.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/ivysettings.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/workloads/dependent-modules-ivy/two/ivysettings.xmlThu May 27 01:56:04 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,6 +1,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;ivysettings&amp;gt;
   &amp;lt;resolvers&amp;gt;
-    &amp;lt;ibiblio name="ibiblio" /&amp;gt;
     &amp;lt;filesystem name="internal"&amp;gt;
       &amp;lt;ivy pattern="${repository.dir}/[module]/ivy-[revision].xml" /&amp;gt;
       &amp;lt;artifact pattern="${repository.dir}/[module]/[artifact]-[revision].[ext]" /&amp;gt;

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-26T23:56:05</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/658">
    <title>r479 - org.xoocode.xooctory/trunk/xooctory/examples/job-plans</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/658</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May 27 01:56:06 2010
New Revision: 479

Log:
dependent-modules-ivy: pass dependencies as part of the sink's job plan

Modified:
   org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules-ivy.scala

Modified: org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules-ivy.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules-ivy.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules-ivy.scalaThu May 27 01:56:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9,12 +9,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.xoocode.xooctory.plugins.trigger.dependency.adhoc.AdhocDependencyTriggerModel
 
 import org.xoocode.xooctory.plugins.resource.fs.FileSystemResourceModel
-import org.xoocode.xooctory.plugins.resource.ivy.IvyResourceModel;
 import org.xoocode.xooctory.plugins.procedure.ant.AntJobProcedure.{ANT_TARGET_KEY,
                                                                    ANT_CLASSPATH_KEY};
 import org.xoocode.xooctory.util.HostUtil
 
-import java.util.HashMap
+import java.io.File
+import java.net.URL
+
+import org.apache.ivy.core.settings.IvySettings
+import org.apache.ivy.plugins.parser.ModuleDescriptorParserRegistry
 
 def dirname(path: String): String = {
   assert(path.contains("/"))
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,6 +27,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 val xooPath =
   dirname(getXooctoryClassPath.getAbsolutePath)
 
+val when = {
+  // Dummy trigger.
+  val trigger =
+    new JobTriggerModel("scm-change", "scm-change")
+
+  new JobPlanControllerModel("controller", HostUtil.getNodeName, trigger)
+}
+
 val how  =
   // FIXME: There's no way to specify the `repository.dir' property when
   // compiling `two', which means we have to play tricks (e.g., manually
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -32,54 +43,66 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                         ANT_TARGET_KEY, "test",
                         ANT_CLASSPATH_KEY, xooPath + "../../lib/default/ivy.jar")
 
-val jobOne = {
-  val filesystem =
-    new FileSystemResourceModel("filesystem",
-                                "examples/workloads/dependent-modules-ivy/one")
 
-  val ivy =
-    new IvyResourceModel("ivy.xml")
-  ivy.setName("ivy") // ugliness
-  ivy.setType("ivy") // ugliness
+val ivyRepository =
+  xooPath + "../../examples/workloads/dependent-modules-ivy/one/repository"
 
-  val what =
-    // The doc of `IvyDependencyTrigger' says that "you need to add an
-    // IvyResource on all job plans for which you want Ivy dependency
-    // management to be enabled".
-    new JobResourcesModel(filesystem, ivy)
-
-  val when = {
-    val trigger =
-      new JobTriggerModel("scm-change", "scm-change")
+// Mapping from Ivy dependency identifiers to source directories.
+val moduleSourceDirectories =
+  List(("chbouib#Library", xooPath +
+        "../../examples/workloads/dependent-modules-ivy/one"))
+
+// Ivy module descriptor of the "sink" job plan.
+val mdFile =
+  new File("examples/workloads/dependent-modules-ivy/two", "ivy.xml")
+
+// Job plans for the "changing dependencies" of the sink job plan.
+val dependencies = {
+  val ivyParser = ModuleDescriptorParserRegistry.getInstance
+
+  // Parse the module descriptor of the "sink" job plan.
+  val mdURL = mdFile.toURI.toURL
+  val md = ivyParser.parseDescriptor(new IvySettings, mdURL, false)
+  val deps = md.getDependencies // .filter { _ isChanging }
+  println("module `" + md.getModuleRevisionId.getModuleId + "' has "
+          + deps.length + " dependencies")
+
+  // Job plans for `deps'.
+  deps map(dep =&amp;gt; {
+    val depSource =
+      moduleSourceDirectories find (x =&amp;gt; {
+        val org = dep.getDependencyId.getOrganisation
+        val name = dep.getDependencyId.getName
+        x._1 == org + "#" + name
+      })
+
+    println("creating job plan for `" + dep
+            + "' (source: " + depSource.get._2 + ")")
+
+    val what = {
+      val filesystem =
+        new FileSystemResourceModel("filesystem", depSource.get._2)
+      new JobResourcesModel(filesystem)
+    }
 
-    new JobPlanControllerModel("controller", HostUtil.getNodeName, trigger)
-  }
+    val name = dep.getDependencyId.getName
+    val sid  = "sid-" + name
 
-  new JobPlanModel("one", "sid-one", what, when, how)
+    new JobPlanModel(name, sid, what, when, how)
+  })
 }
 
-val jobTwo = {
+
+val sink = {
   val filesystem =
     new FileSystemResourceModel("filesystem",
                                 "examples/workloads/dependent-modules-ivy/two")
 
-  val ivy =
-    new IvyResourceModel("ivy.xml")
-  ivy.setName("ivy") // ugliness
-  ivy.setType("ivy") // ugliness
-
   val what =
-    new JobResourcesModel(filesystem, ivy)
-
-  val when = {
-    val trigger =
-      new JobTriggerModel("ivy-dependency-trigger", "ivy-dependency-trigger")
-
-    new JobPlanControllerModel("controller", HostUtil.getNodeName, trigger)
-  }
+    new JobResourcesModel(filesystem)
 
-  new JobPlanModel("two", "sid-two", what, when, how)
+  new JobPlanModel("two", "sid-two", what, when, how, dependencies: _*)
 }
 
-// Return the job plan.
-jobTwo
+// Return the "sink" job plan.
+sink

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-26T23:56:06</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/657">
    <title>r477 - org.xoocode.xooctory/trunk/xooctory</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/657</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May 27 01:56:01 2010
New Revision: 477

Log:
upgrade to Ivy 2.1.0

Modified:
   org.xoocode.xooctory/trunk/xooctory/build.xml
   org.xoocode.xooctory/trunk/xooctory/ivy.xml

Modified: org.xoocode.xooctory/trunk/xooctory/build.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/build.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/build.xmlThu May 27 01:56:01 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -15,7 +15,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;target name="download-ivy" unless="no.download"&amp;gt;
       &amp;lt;mkdir dir="${ivy.jar.dir}"/&amp;gt;
   &amp;lt;!-- download Ivy from web site so that it can be used even without any special installation --&amp;gt;
-      &amp;lt;get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/2.0.0/ivy-2.0.0.jar"
+      &amp;lt;get src="http://maven2.mirrors.skynet.be/pub/maven2/org/apache/ivy/ivy/2.1.0/ivy-2.1.0.jar"
            dest="${ivy.jar.file}" usetimestamp="true"/&amp;gt;
 &amp;lt;/target&amp;gt;
 

Modified: org.xoocode.xooctory/trunk/xooctory/ivy.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/ivy.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/ivy.xmlThu May 27 01:56:01 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -97,7 +97,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;dependency org="org.tmatesoft.svnkit" name="svnkit" rev="1.3.1"/&amp;gt;
 
 &amp;lt;!-- Dependencies --&amp;gt;
-&amp;lt;dependency org="org.apache.ivy" name="ivy" rev="2.0-alpha2-incubating" /&amp;gt;
+&amp;lt;dependency org="org.apache.ivy" name="ivy" rev="2.1.0" /&amp;gt;
 
 &amp;lt;!-- Security --&amp;gt;
 &amp;lt;dependency org="org.acegisecurity" name="acegi-security" rev="1.0.3" /&amp;gt;

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-26T23:56:02</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/645">
    <title>r476 - org.xoocode.xooctory/trunk/xooctory/examples/job-plans</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/645</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May  6 00:29:01 2010
New Revision: 476

Log:
use result collectors in the `dependent-modules' job plan

Modified:
   org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala

Modified: org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scalaThu May  6 00:29:01 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3,11 +3,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                                            JobResourcesModel,
                                            JobPlanControllerModel,
                                            JobProcedureModel,
-                                           JobTriggerModel}
+                                           JobTriggerModel,
+                                           ResultCollectorModel}
 import org.xoocode.xooctory.job.model.JobModel
 
 import org.xoocode.xooctory.plugins.resource.fs.FileSystemResourceModel
 import org.xoocode.xooctory.plugins.procedure.ant.AntJobProcedure.ANT_TARGET_KEY
+import org.xoocode.xooctory.plugins.result.workspace.WorkspaceResultCollector.POLL_FREQUENCY_KEY
 import org.xoocode.xooctory.util.HostUtil
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,8 +26,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   val when =
     new JobPlanControllerModel("controller", HostUtil.getNodeName, trigger)
 
+  val collectors =
+    List(new ResultCollectorModel("compilation"),
+         new ResultCollectorModel("workspace", POLL_FREQUENCY_KEY, "PT2s"))
+
   val how  =
-    new JobProcedureModel("antDefault", "ant", null,
+    new JobProcedureModel("antDefault", "ant", collectors,
                           ANT_TARGET_KEY, "test")
 
   (what, when, how)

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T22:29:01</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/644">
    <title>r475 - org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/644</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May  6 00:28:59 2010
New Revision: 475

Log:
BatchServerMain: stop after the "sink" plans have been processed

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scalaThu May  6 00:28:59 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,7 +21,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import scala.io.Source;
 import scala.actors;
 import scala.actors.Actor;
-import scala.actors.Actor._;
+import scala.actors.Actor.react;
 
 /**
  * A lightweight implementation of the Xooctory server without support for
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,19 +34,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;author &amp;lt;a href="mailto:ludovic.courtes&amp;lt; at &amp;gt;inria.fr"&amp;gt;Ludovic Courtès&amp;lt;/a&amp;gt;
  */
 
-class Monitor(total: Int, jobService: JobResultDAO) extends Actor {
+class Monitor(plansToWaitFor: List[JobPlanModel], jobService: JobResultDAO) extends Actor {
   private val logger = LoggerFactory.getLogger(classOf[Monitor])
 
   def act: Unit = {
-    var processed = 0
-    loop {
+    def loop(plansLeft: List[JobPlanModel]): Unit = {
       react {
         case e: JobLogCreatedEvent =&amp;gt; {
           logger info("log: {}", e.getLogs)
+          loop(plansLeft)
         }
 
         case e: JobResultItemCreatedEvent =&amp;gt; {
           logger info("new result item for job {}: {}", e.getJob, e)
+          loop(plansLeft)
         }
 
         case e: JobFinishedEvent =&amp;gt; {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -61,13 +62,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
           logger info("job " + job + " has {} result groups, {} result items",
                       groups.length, items.length)
 
-          processed += 1
-          if (processed &amp;gt;= total) {
-            logger info("{} jobs processed, exiting.", processed)
+          val remainder = plansLeft remove { _ == e.getJob.getPlan }
+          if (remainder isEmpty) {
+            logger info("the {} job plans have been processed, exiting.",
+                        plansToWaitFor length)
 
             // FIXME: Find something less brutal.
             Thread sleep(1)
             System exit(0)
+          } else {
+            loop(remainder)
           }
 
           ()
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -75,9 +79,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
         case e: XooEvent =&amp;gt; {
           logger debug("event -&amp;gt; " + e)
+          loop(plansLeft)
         }
       }
     }
+
+    loop(plansToWaitFor)
   }
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -155,7 +162,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     val eventService = ctx.getBean("eventService").asInstanceOf[EventService]
     val jobService = ctx.getBean("jobResultDAO").asInstanceOf[JobResultDAO]
 
-    val monitor = new Monitor(jobPlans length, jobService)
+    val monitor = new Monitor(jobPlans toList, jobService)
     val eventActor = new XooEventActor(eventService, monitor)
     eventActor.start
     monitor.start

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T22:28:59</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/643">
    <title>r474 - org.xoocode.xooctory/trunk/xooctory/examples/job-plans</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/643</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May  6 00:28:57 2010
New Revision: 474

Log:
update the `dependent-modules' job plan to use the new JobPlanController features

Modified:
   org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala

Modified: org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/examples/job-plans/dependent-modules.scalaThu May  6 00:28:57 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -5,23 +5,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                                            JobProcedureModel,
                                            JobTriggerModel}
 import org.xoocode.xooctory.job.model.JobModel
-import org.xoocode.xooctory.plugins.trigger.dependency.adhoc.AdhocDependencyTriggerModel
 
 import org.xoocode.xooctory.plugins.resource.fs.FileSystemResourceModel
 import org.xoocode.xooctory.plugins.procedure.ant.AntJobProcedure.ANT_TARGET_KEY
 import org.xoocode.xooctory.util.HostUtil
 
-import java.util.HashMap
 
-println("hello, world")
-
-def makeWhatWhenHow(path: String, trigger: JobTriggerModel) = {
+def makeWhatWhenHow(path: String) = {
   val filesystem =
     new FileSystemResourceModel("filesystem", path)
 
   val what =
     new JobResourcesModel(filesystem)
 
+  val trigger =
+    new JobTriggerModel("scm-change", "scm-change")
+
   val when =
     new JobPlanControllerModel("controller", HostUtil.getNodeName, trigger)
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,27 +32,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 
 val jobOne = {
-  val trigger =
-    new JobTriggerModel("scm-change", "scm-change")
-
   val (what, when, how) =
-    makeWhatWhenHow("examples/workloads/dependent-modules/one", trigger)
+    makeWhatWhenHow("examples/workloads/dependent-modules/one")
 
   new JobPlanModel("one", "sid-one", what, when, how)
 }
 
 val jobTwo = {
-  val trigger =
-    new AdhocDependencyTriggerModel("deptrig", "dependency-trigger", "one")
-
   val (what, when, how) =
-    makeWhatWhenHow("examples/workloads/dependent-modules/two", trigger)
+    makeWhatWhenHow("examples/workloads/dependent-modules/two")
 
-  new JobPlanModel("two", "sid-two", what, when, how)
+  new JobPlanModel("two", "sid-two", what, when, how, jobOne)
 }
 
-// Return the job plan.
-// FIXME: When running the job plan with `BatchServerMain', "two" is
-// triggered but the dependency (i.e., "one") is not triggered, so "two"
-// fails to build.
+// Return the "sink" job plan.  This will automatically trigger `jobOne'
+// before `jobTwo'.
 jobTwo

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T22:28:57</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/642">
    <title>r473 - org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/642</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu May  6 00:28:54 2010
New Revision: 473

Log:
JobPlanController: be less verbose

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaThu May  6 00:28:54 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -89,7 +89,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     }
 
     def loop(state: State, timeouts: TaskQueue[Timeout]): Unit = {
-      logger info("loop {} {} {}", Array[Object](plan, state, timeouts))
+      logger debug("loop {} {} {}", Array[Object](plan, state, timeouts))
 
       // Extend `pf' so that it's passed `state' in addition to the message
       // received.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -198,12 +198,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       react {
         matchMessageAndState {
   case (Tick, _) =&amp;gt; {
-            logger info("tick!")
+            logger debug("tick!")
             val (tasksToRun, remainingTasks) = timeouts partition(500)
             val newState =
               tasksToRun.foldLeft(state)((state, task) =&amp;gt; {
                 val handleTimeout = task.task._2
-                logger info("handling timeout with {}", handleTimeout)
+                logger debug("handling timeout with {}", handleTimeout)
         handleTimeout(state)
               })
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -328,7 +328,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
           }
 
           case (e: XooEvent, _) =&amp;gt; {
-            logger info("unhandled event {}", e)
+            logger debug("unhandled event {}", e)
             loop(state, timeouts)
           }
 

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T22:28:55</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/641">
    <title>r472 - org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/641</link>
    <description>&lt;pre&gt;Author: ludo
Date: Wed May  5 02:08:03 2010
New Revision: 472

Log:
JobPlanController: remove commented out code of `reload'

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaWed May  5 02:08:03 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -365,16 +365,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   def ping: Unit = this !? Ping
 
   /**
-   * Reloads the model of this controller.
-   */
-  // def reload: Unit = {
-  //   this synchronized {
-  //     triggers foreach { _ stop }
-  //     triggers foreach { _ start }
-  //   }
-  // }
-
-  /**
    * Returns the maximum time the controller can stay in quiet state,
    * or null if the controller can stay in quiet state indefinitly.
    * &amp;lt; at &amp;gt;return the maximum time the controller can stay in quiet state

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T00:08:04</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/640">
    <title>r471 - in org.xoocode.xooctory/trunk/xooctory/src: main/java/org/xoocode/xooctory/jobplan main/java/org/xoocode/xooctory/jobplan/service/impl test/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/640</link>
    <description>&lt;pre&gt;Author: ludo
Date: Wed May  5 02:08:00 2010
New Revision: 471

Log:
JobPlanController: wait for dependent job plans; trigger them if needed

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java
   org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaWed May  5 02:08:00 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,6 +16,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   JobPlanWaitForEvent};
 import org.xoocode.xooctory.jobplan.model.{JobPlanControllerModel,
   JobPlanModel, JobTriggerModel};
+import org.xoocode.xooctory.job.event.JobFinishedEvent;
 import org.xoocode.xooctory.plugin.PluginRegistry;
 import org.xoocode.xooctory.plugins.trigger.JobTriggerPlugin;
 import org.xoocode.xooctory.timer.{TimerService, TaskQueue};
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -26,6 +27,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.xoocode.xooctory.timer.TimerActor;
 import org.xoocode.xooctory.timer.TimerActor._;
 
+
 /**
  * A controller of job plan, in charge of instantiating new jobs out of a job
  * plan when a job plan is triggered.  This is the 'when' in a {&amp;lt; at &amp;gt;link JobPlan}.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,7 +45,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;author Ludovic Courtès &amp;lt;ludovic.courtes&amp;lt; at &amp;gt;inria.fr&amp;gt;
  * &amp;lt; at &amp;gt;author Xavier Hanin
  */
-class JobPlanController(plan: JobPlanModel, how: JobProcedure, pluginRegistry: PluginRegistry,
+class JobPlanController(plan: JobPlanModel, how: JobProcedure,
+                        pluginRegistry: PluginRegistry,
+                        controllerInstantiator: {
+                          // A `JobPlanService' of some sort.
+                          def getJobPlanController(model: JobPlanModel): JobPlanController
+                        },
 eventService: EventService, timer: TimerActor,
 historyService: JobHistoryService, scheduler: Scheduler)
 extends Actor {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -76,21 +83,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     def doTrigger(trigger: JobPlanTriggeredEvent): Unit = {
       val inputs = toJavaList(jobPlanResults(plan.getDependencies))
       val job = how.createJobModel(trigger.getWho, trigger.getWhy, inputs)
-      logger info("scheduling job {} of job plan {} ", job, plan)
+      logger info("scheduling job {} of job plan {} with inputs {}",
+                  Array(job, plan, inputs))
       scheduler.schedule(job)
     }
 
-    // Return a function that triggers the job specified by `trigger' and
-    // returns `IdleState'.
-    def triggerFunction(trigger: JobPlanTriggeredEvent): (State) =&amp;gt; State = {
-      (state: State) =&amp;gt; {
-        doTrigger(trigger)
-        IdleState
-      }
-    }
-
     def loop(state: State, timeouts: TaskQueue[Timeout]): Unit = {
-      logger info("loop {} {}", state, timeouts)
+      logger info("loop {} {} {}", Array[Object](plan, state, timeouts))
 
       // Extend `pf' so that it's passed `state' in addition to the message
       // received.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -109,22 +108,86 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         loop(IdleState, new TaskQueue[Timeout])
       }
 
-      // Enter WaitingState and return the new state and task queue.
-      def enterWaitingState(e: JobPlanWaitForEvent, trigger: JobPlanTriggeredEvent) = {
-        logger info("{}: {} -&amp;gt; waiting", state, plan)
-        val newTimeouts = {
-          if (getMaxWaitingTime != null) {
-            val now = new DateTime
-            val elapsed = new Duration(e.getTriggerDate, now)
-            val duration = getMaxWaitingTime minus elapsed
-            val handle = (timer !? duration).asInstanceOf[TimerHandle]
-            val t = (handle, triggerFunction(trigger))
-            (new TaskQueue[Timeout]).insert(duration, t)
+      // Trigger the job plan and return to IdleState, or trigger whichever
+      // dependencies are missing and enter WaitingState.
+      def maybeTrigger(trigger: JobPlanTriggeredEvent) = {
+        val go = triggerFunction(trigger)
+        loop(go(state), new TaskQueue[Timeout])
+      }
+
+      // Return a function that triggers the job specified by `trigger' and
+      // returns `IdleState' or `WaitingState', depending on whether
+      // dependencies are missing.
+      def triggerFunction(trigger: JobPlanTriggeredEvent): (State) =&amp;gt; State = {
+        (state: State) =&amp;gt; {
+          val deps = plan.getDependencies
+          val missingDeps =
+            deps filter (historyService.getLastSuccessfulJob(_) == null)
+
+          if (missingDeps isEmpty) {
+            // All the dependencies have been built, so go ahead.
+            doTrigger(trigger)
+            IdleState
           } else {
-            new TaskQueue[Timeout]
+            // Some dependencies are missing, so wait for them.
+            logger info("job plan {} lacks dependencies; waiting for them: {}",
+                        plan, missingDeps)
+
+            val events =
+              missingDeps map (dep =&amp;gt; {
+                new JobPlanWaitForEvent(plan, dep getName)
+              })
+            val timeouts =
+              events.foldLeft(new TaskQueue[Timeout]) ((timeouts, e) =&amp;gt; {
+                insertWaitingStateTimeout(timeouts, e, trigger)
+              })
+            val waitList = {
+              val init = new HashMap[String, JobPlanWaitForEvent]
+              events.foldLeft(init.asInstanceOf[Map[String, JobPlanWaitForEvent]])((l, e) =&amp;gt; {
+                l + ((e.getWaitFor, e))
+              })
+            }
+
+            // Trigger the dependent job plans.
+            // FIXME: Should not trigger plans that are being built.
+            missingDeps foreach(dep =&amp;gt; {
+              val controller = controllerInstantiator.getJobPlanController(dep)
+              val trigger = new JobPlanTriggeredEvent(dep, plan.getName,
+                                                      "dependency")
+
+              logger info("triggering dependency: {} -&amp;gt; {}", controller, trigger)
+              controller ! trigger
+            })
+
+            // FIXME: Change `Timeout' to be `(State, TaskQueue[Timeout]) =&amp;gt;
+            // (State, TaskQueue[Timeout])'.
+            WaitingState(trigger, waitList)
           }
         }
+      }
+
+      // Return a new timeout queue based on `timeouts' relative to the
+      // waiting state entered as a consequence of `waitFor'.
+      def insertWaitingStateTimeout(timeouts: TaskQueue[Timeout],
+                                    waitFor: JobPlanWaitForEvent,
+                                    trigger: JobPlanTriggeredEvent) = {
+        if (getMaxWaitingTime != null) {
+          val now = new DateTime
+          val elapsed = new Duration(waitFor.getTriggerDate, now)
+          val duration = getMaxWaitingTime minus elapsed
+          val handle = (timer !? duration).asInstanceOf[TimerHandle]
+          val t = (handle, triggerFunction(trigger))
+          timeouts insert(duration, t)
+        } else {
+          timeouts
+        }
+      }
 
+      // Enter WaitingState and return the new state and task queue.
+      def enterWaitingState(e: JobPlanWaitForEvent, trigger: JobPlanTriggeredEvent) = {
+        logger info("{}: {} -&amp;gt; waiting", state, plan)
+        val newTimeouts =
+          insertWaitingStateTimeout(new TaskQueue[Timeout], e, trigger)
         val waitList =
           (new HashMap[String, JobPlanWaitForEvent]).+ ((e.getWaitFor, e))
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -184,6 +247,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
             }
           }
 
+          case (e: JobFinishedEvent, WaitingState(trigger, waitList)) =&amp;gt; {
+            val remainder = waitList - e.getLifecycleStep.getJob.getPlan.getName
+            logger info("job {} finished while waiting -&amp;gt; {}",
+                        e.getLifecycleStep.getJob, remainder)
+            if (remainder isEmpty) {
+              triggerThenIdle(trigger)
+            } else {
+              loop(WaitingState(trigger, remainder), timeouts)
+            }
+          }
+
           case (e: JobPlanReleaseWaitForEvent, _) =&amp;gt; {
             logger info("unexpected JobPlanReleaseWaitForEvent {} while in state {}",
                         e, state)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -192,7 +266,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
   case (e: JobPlanTriggeredEvent, IdleState) =&amp;gt; {
     if (e.isForced) {
-              triggerThenIdle(e)
+              maybeTrigger(e)
     } else {
               if (getQuietTime != null) {
                 logger info("{}: idle -&amp;gt; quiet", plan)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -211,14 +285,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                 }
                 loop(QuietState(e), newTimeouts)
               } else {
-                triggerThenIdle(e)
+                maybeTrigger(e)
               }
             }
           }
 
           case(e: JobPlanTriggeredEvent, QuietState(t)) =&amp;gt; {
     if (e.isForced) {
-              triggerThenIdle(e)
+              maybeTrigger(e)
     } else {
               logger info("{}: resetting quiet period", e)
               timeouts.tasks foreach (timer ! _.task._1)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -237,7 +311,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
           case(e: JobPlanTriggeredEvent, WaitingState(_, waitList)) =&amp;gt; {
     if (e.isForced) {
-              triggerThenIdle(e)
+              maybeTrigger(e)
     } else {
               // Stay in waiting state and associate `e' with it.
               loop (WaitingState(e, waitList), timeouts)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -246,7 +320,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
           case (e: JobPlanTriggeredEvent, _) =&amp;gt; {
     if (e.isForced) {
-              triggerThenIdle(e)
+              maybeTrigger(e)
     } else {
               logger info("{}: triggered but state unchanged: {}", plan, state)
               loop(state, timeouts)

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.javaWed May  5 02:08:00 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -136,7 +136,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 protected JobPlanController newJobPlanController(JobPlanModel model, JobProcedure how) {
 Scheduler scheduler = getScheduler(model.getWhen().getScheduler());
 JobPlanController when = new JobPlanController(
-model, how, pluginRegistry, eventService, timer,
+    model, how, pluginRegistry, this, eventService, timer,
 jobManagementService, scheduler);
 
 return when;

Modified: org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.javaWed May  5 02:08:00 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,7 +6,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 import junit.framework.TestCase;
 
-import org.easymock.EasyMock;
+import org.easymock.classextension.EasyMock;
 import org.xoocode.xooctory.event.EventService;
 import org.xoocode.xooctory.job.Job;
 import org.xoocode.xooctory.job.Scheduler;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -29,6 +29,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.xoocode.xooctory.scm.DefaultSCMRegistry;
 import org.xoocode.xooctory.plugins.trigger.JobTriggerPlugin;
 import org.xoocode.xooctory.timer.TimerActor;
+import org.xoocode.xooctory.jobplan.service.JobPlanService;
+import org.xoocode.xooctory.job.event.JobFinishedEvent;
+import org.xoocode.xooctory.job.model.JobLifecycleStep;
+import org.xoocode.xooctory.job.model.AgentModel;
+import org.xoocode.xooctory.job.event.JobProcessedEvent;
+import org.xoocode.xooctory.jobplan.service.impl.AbstractJobPlanService;
+import java.util.LinkedList;
 
 import static org.easymock.EasyMock.expect;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -77,7 +84,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 expect(pluginRegistry.getPlugin("scm-change", JobTriggerPlugin.class)).andReturn(new SCMChangeTriggerPlugin(eventService, scmRegistry)).anyTimes();
 EasyMock.replay(pluginRegistry);
 
-controller = new JobPlanController(plan, how, pluginRegistry, eventService,
+controller = new JobPlanController(plan, how, pluginRegistry, null, eventService,
    timer, historyService, scheduler);
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -265,14 +272,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 return null;
 }
 };
-controller = new JobPlanController(plan, how, pluginRegistry, eventService,
+JobPlanService jobPlanService = EasyMock.createMock(JobPlanService.class);
+controller = new JobPlanController(plan, how, pluginRegistry, jobPlanService,
+   eventService,
    timer, historyService, scheduler);
 
 JobPlanEvent triggerEvent = new JobPlanTriggeredEvent(plan, "who", "why");
 JobModel job = new JobModel();
 job.setInputs(Arrays.asList(new ResultItem[] { depResult }));
 scheduler.schedule(job);
-expect(historyService.getLastSuccessfulJob(dep)).andReturn(depBuild);
+expect(historyService.getLastSuccessfulJob(dep))
+.andReturn(depBuild).anyTimes();
 expect(historyService.getResultGroups(depBuild))
 .andReturn(Arrays.asList(new ResultGroup[] { depResultGroup }));
 expect(historyService.getResultItems(depResultGroup, 0, Integer.MAX_VALUE))
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -291,4 +301,90 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 EasyMock.reset(scheduler);
 EasyMock.reset(historyService);
 }
+
+public void testJobPlanWaitsForItsDependencies() throws Exception {
+JobPlanModel dep = JobPlanTestHelper.newJobPlanModel();
+dep.setName("DEPENDENCY");
+JobPlanModel plan = JobPlanTestHelper.newJobPlanModel(dep);
+plan.setName("MASTER-PLAN");
+Build depBuild = new Build();
+depBuild.setName("DEPENDENCY-0001");
+depBuild.setPlan(dep);
+final ResultGroup depResultGroup = new ResultGroup(depBuild, "foo", null);
+final ResultItem depResult =
+new ResultItem(depResultGroup,
+   new ResultCategory("cat", TTL.ALWAYS),
+   new DateTime());
+
+JobProcedure how = EasyMock.createMock(JobProcedure.class);
+AbstractJobPlanService jobPlanService =
+EasyMock.createMock(AbstractJobPlanService.class);
+controller = new JobPlanController(plan, how, pluginRegistry, jobPlanService,
+   eventService,
+   timer, historyService, scheduler);
+
+EasyMock.reset(historyService);
+
+JobPlanController depController =
+new JobPlanController(dep, how, pluginRegistry, jobPlanService,
+  eventService,
+  timer, historyService, scheduler);
+
+// Triggering the master plan should trigger its dependency.
+expect(historyService.getLastSuccessfulJob(dep)).andReturn(null);
+expect(jobPlanService.getJobPlanController(dep)).andReturn(depController);
+expect(how.createJobModel(plan.getName(), "dependency",
+  new LinkedList&amp;lt;ResultItem&amp;gt;())).andReturn(depBuild);
+scheduler.schedule(depBuild);
+EasyMock.replay(scheduler, historyService, jobPlanService, how);
+
+JobPlanEvent triggerEvent = new JobPlanTriggeredEvent(plan, "who", "why");
+controller.onEvent(triggerEvent);
+Thread.sleep(800); // processing is done asynchronously
+
+EasyMock.verify(scheduler);
+EasyMock.verify(historyService);
+EasyMock.verify(jobPlanService);
+EasyMock.verify(how);
+
+EasyMock.reset(scheduler);
+EasyMock.reset(historyService);
+EasyMock.reset(jobPlanService);
+EasyMock.reset(how);
+
+// Once the dependency is built, the master plan should get triggered.
+JobModel masterBuild = new JobModel();
+masterBuild.setName("MASTER-0001");
+masterBuild.setPlan(plan);
+masterBuild.setInputs(Arrays.asList(new ResultItem[] { depResult }));
+
+expect(historyService.getLastSuccessfulJob(dep)).andReturn(depBuild);
+expect(historyService.getResultGroups(depBuild))
+.andReturn(Arrays.asList(new ResultGroup[] { depResultGroup }));
+expect(historyService.getResultItems(depResultGroup, 0, Integer.MAX_VALUE))
+.andReturn(Arrays.asList(new ResultItem[] { depResult }));
+expect(how.createJobModel("who", "why",
+  masterBuild.getInputs())).andReturn(masterBuild);
+scheduler.schedule(masterBuild);
+
+EasyMock.replay(scheduler, historyService, how);
+
+JobFinishedEvent depFinished =
+new JobProcessedEvent
+(new JobLifecycleStep(depBuild, JobLifecycleStep.PROCESSED,
+  new DateTime(), "who", "why",
+  new AgentModel()),
+ null);
+controller.onEvent(depFinished);
+
+Thread.sleep(800); // processing is done asynchronously
+
+EasyMock.verify (how);
+EasyMock.verify (historyService);
+EasyMock.verify (scheduler);
+
+EasyMock.reset(scheduler);
+EasyMock.reset(historyService);
+EasyMock.reset(how);
+}
 }

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-05-05T00:08:01</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/639">
    <title>r470 - org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/639</link>
    <description>&lt;pre&gt;Author: ludo
Date: Fri Apr 30 01:28:49 2010
New Revision: 470

Log:
JobPlanController: flatten event processing into a single `match'

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaFri Apr 30 01:28:49 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -92,170 +92,176 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     def loop(state: State, timeouts: TaskQueue[Timeout]): Unit = {
       logger info("loop {} {}", state, timeouts)
 
-      react {
-case Tick =&amp;gt; {
-          logger info("tick!")
-          val (tasksToRun, remainingTasks) = timeouts partition(500)
-          val newState =
-            tasksToRun.foldLeft(state)((state, task) =&amp;gt; {
-              val handleTimeout = task.task._2
-              logger info("handling timeout with {}", handleTimeout)
-      handleTimeout(state)
-            })
+      // Extend `pf' so that it's passed `state' in addition to the message
+      // received.
+      def matchMessageAndState(pf: PartialFunction[(Any, State), Unit]) = {
+        new PartialFunction[Any, Unit] {
+          def isDefinedAt(e: Any) = pf isDefinedAt (e, state)
+          def apply(e: Any) = pf apply (e, state)
+        }
+      }
 
-          loop(newState, remainingTasks)
-}
+      // Cancel timers, trigger a job, and switch back to IdleState.
+      def triggerThenIdle(trigger: JobPlanTriggeredEvent) = {
+        logger info("{} triggered (was in {})", plan, state)
+        timeouts.tasks foreach (timer ! _.task._1)
+        doTrigger(trigger)
+        loop(IdleState, new TaskQueue[Timeout])
+      }
 
-case e: JobPlanCancellingEvent =&amp;gt; {
-          logger info("canceling job plan: {}", e)
-  cancel(e.getJob, e.getWho, e.getWhy)
-}
+      // Enter WaitingState and return the new state and task queue.
+      def enterWaitingState(e: JobPlanWaitForEvent, trigger: JobPlanTriggeredEvent) = {
+        logger info("{}: {} -&amp;gt; waiting", state, plan)
+        val newTimeouts = {
+          if (getMaxWaitingTime != null) {
+            val now = new DateTime
+            val elapsed = new Duration(e.getTriggerDate, now)
+            val duration = getMaxWaitingTime minus elapsed
+            val handle = (timer !? duration).asInstanceOf[TimerHandle]
+            val t = (handle, triggerFunction(trigger))
+            (new TaskQueue[Timeout]).insert(duration, t)
+          } else {
+            new TaskQueue[Timeout]
+          }
+        }
 
-case e: JobPlanWaitForEvent =&amp;gt; {
-          logger info("wait-for event: {}", e)
-          def enterWaitingState(trigger: JobPlanTriggeredEvent) = {
-            logger info("{}: {} -&amp;gt; waiting", state, plan)
-            val newTimeouts = {
-              if (getMaxWaitingTime != null) {
-                val now = new DateTime
-                val elapsed = new Duration(e.getTriggerDate, now)
-                val duration = getMaxWaitingTime minus elapsed
-                val handle = (timer !? duration).asInstanceOf[TimerHandle]
-                val t = (handle, triggerFunction(trigger))
-                (new TaskQueue[Timeout]).insert(duration, t)
-              } else {
-                new TaskQueue[Timeout]
-              }
-            }
+        val waitList =
+          (new HashMap[String, JobPlanWaitForEvent]).+ ((e.getWaitFor, e))
 
-            val waitList =
-              (new HashMap[String, JobPlanWaitForEvent]).+ ((e.getWaitFor, e))
+        loop(WaitingState(trigger, waitList), newTimeouts)
+      }
 
-            (WaitingState(trigger, waitList), newTimeouts)
+      // Process incoming messages (events and timer ticks.)
+      react {
+        matchMessageAndState {
+  case (Tick, _) =&amp;gt; {
+            logger info("tick!")
+            val (tasksToRun, remainingTasks) = timeouts partition(500)
+            val newState =
+              tasksToRun.foldLeft(state)((state, task) =&amp;gt; {
+                val handleTimeout = task.task._2
+                logger info("handling timeout with {}", handleTimeout)
+        handleTimeout(state)
+              })
+
+            loop(newState, remainingTasks)
+  }
+
+  case (e: JobPlanCancellingEvent, _) =&amp;gt; {
+            logger info("canceling job plan: {}", e)
+    cancel(e.getJob, e.getWho, e.getWhy)
+            // Exit.
+  }
+
+  case (e: JobPlanWaitForEvent, WaitingState(trigger, waitList)) =&amp;gt; {
+            // Add the given job plan to the wait list.
+            logger info("adding {} to the wait list", e.getWaitFor)
+            loop(WaitingState(trigger, waitList.+ ((e.getWaitFor, e))), timeouts)
           }
 
-  val (next: State, newTimeouts: TaskQueue[Timeout]) = {
-            state match {
-              case WaitingState(trigger, waitList) =&amp;gt; {
-                // Add the given job plan to the wait list.
-                logger info("adding {} to the wait list", e.getWaitFor)
-                (WaitingState(trigger, waitList.+ ((e.getWaitFor, e))),
-                 timeouts)
-              }
+          case (e: JobPlanWaitForEvent, QuietState(trigger)) =&amp;gt; {
+            // Cancel previous timers.
+            timeouts.tasks foreach (timer ! _.task._1)
+            enterWaitingState(e, trigger)
+          }
 
-              case QuietState(trigger) =&amp;gt; {
-                // Cancel previous timers.
-                timeouts.tasks foreach (timer ! _.task._1)
-                enterWaitingState(trigger)
-              }
+          case (e: JobPlanWaitForEvent, IdleState) =&amp;gt; {
+            enterWaitingState(e, null)
+          }
 
-              case IdleState =&amp;gt; {
-                enterWaitingState(null)
-              }
+          case(e: JobPlanWaitForEvent, _) =&amp;gt; {
+            logger warn("ignoring {} while in {}", e, state)
+            loop(state, timeouts)
+          }
 
-              case s: State =&amp;gt; {
-                logger warn("ignoring {} while in {}", e, s)
-                (state, timeouts)
-              }
+  case (e: JobPlanReleaseWaitForEvent, WaitingState(trigger, waitList)) =&amp;gt; {
+    val remainder = waitList - e.getWaitFor
+            logger info("release wait-for {} -&amp;gt; {}", e, remainder)
+            if (remainder isEmpty) {
+              triggerThenIdle(trigger)
+            } else {
+              loop(WaitingState(trigger, remainder), timeouts)
             }
           }
 
-          loop(next, newTimeouts)
-        }
+          case (e: JobPlanReleaseWaitForEvent, _) =&amp;gt; {
+            logger info("unexpected JobPlanReleaseWaitForEvent {} while in state {}",
+                        e, state)
+            loop(state, timeouts)
+          }
 
-case e: JobPlanReleaseWaitForEvent =&amp;gt; {
-          logger info("release wait-for event: {}", e)
-          val (next: State, newTimeouts: TaskQueue[Timeout]) = {
-            state match {
-              case WaitingState(trigger, waitList) =&amp;gt; {
-        val remainder = waitList - e.getWaitFor
-                logger info("release wait-for {} -&amp;gt; {}", e, remainder)
-                if (remainder isEmpty) {
-                  // Nothing left to wait for, so trigger.
-                  timeouts.tasks foreach (timer ! _.task._1)
-                  doTrigger(trigger)
-                  (IdleState, new TaskQueue[Timeout])
-                } else {
-                  (WaitingState(trigger, remainder), timeouts)
+  case (e: JobPlanTriggeredEvent, IdleState) =&amp;gt; {
+    if (e.isForced) {
+              triggerThenIdle(e)
+    } else {
+              if (getQuietTime != null) {
+                logger info("{}: idle -&amp;gt; quiet", plan)
+                val quietTime = getQuietTime
+                val maxQuietTime = getMaxQuietTime
+                val handle1 = (timer !? quietTime).asInstanceOf[TimerHandle]
+                val quietTimeout = (handle1, triggerFunction(e))
+                val newTimeouts = {
+                  if (maxQuietTime != null) {
+                    val handle2 = (timer !? maxQuietTime).asInstanceOf[TimerHandle]
+                    val maxQuietTimeout = (handle2, triggerFunction(e))
+                      timeouts.insert(maxQuietTime, maxQuietTimeout)
+                  } else {
+                    timeouts
+                  }.insert(quietTime, quietTimeout)
                 }
-              }
-              case _ =&amp;gt; {
-                logger info("unexpected JobPlanReleaseWaitForEvent while in state {}",
-                            state)
-                (state, timeouts)
+                loop(QuietState(e), newTimeouts)
+              } else {
+                triggerThenIdle(e)
               }
             }
           }
 
-          loop(next, newTimeouts)
-}
-
-case e: JobPlanTriggeredEvent =&amp;gt; {
-          logger info("triggered: {}", e)
-          val (next: State, newTimeouts: TaskQueue[Timeout]) = {
+          case(e: JobPlanTriggeredEvent, QuietState(t)) =&amp;gt; {
     if (e.isForced) {
-              logger info("servicing forced trigger")
-              timeouts.tasks foreach (timer ! _.task._1)
-              doTrigger(e)
-      (IdleState, new TaskQueue[Timeout])
+              triggerThenIdle(e)
     } else {
-      state match {
-                case IdleState =&amp;gt; {
-                  if (getQuietTime != null) {
-                    logger info("{}: idle -&amp;gt; quiet", plan)
-                    val quietTime = getQuietTime
-                    val maxQuietTime = getMaxQuietTime
-                    val handle1 = (timer !? quietTime).asInstanceOf[TimerHandle]
-                    val quietTimeout = (handle1, triggerFunction(e))
-                    val newTimeouts = {
-                      if (maxQuietTime != null) {
-                        val handle2 = (timer !? maxQuietTime).asInstanceOf[TimerHandle]
-                        val maxQuietTimeout = (handle2, triggerFunction(e))
-                        timeouts.insert(maxQuietTime, maxQuietTimeout)
-                      } else {
-                        timeouts
-                      }.insert(quietTime, quietTimeout)
-                    }
-                    (QuietState(e), newTimeouts)
-                  } else {
-                    logger info("{} idle -&amp;gt; trigger!", plan)
-                    doTrigger(e)
-                    timeouts.tasks foreach (timer ! _.task._1)
-                    (IdleState, new TaskQueue[Timeout])
-                  }
-                }
-                case QuietState(t) =&amp;gt; {
-                  // Reset the quiet period timeout.
-                  logger info("{}: quiet period starting anew")
-                  timeouts.tasks foreach (timer ! _.task._1)
-                  val delay = getQuietTime
-                  val handle = (timer !? delay).asInstanceOf[TimerHandle]
-                  val timeout = (handle, triggerFunction(e))
-                  (QuietState(e), (new TaskQueue).insert(delay, timeout))
-                }
-                case WaitingState(_, waitList) =&amp;gt; {
-                  // Stay in waiting state and associate `e' with it.
-                  (WaitingState(e, waitList), timeouts)
-                }
-                case _ =&amp;gt; {
-                  logger info("{}: state unchanged: {}", plan, state)
-                  (state, timeouts)
+              logger info("{}: resetting quiet period", e)
+              timeouts.tasks foreach (timer ! _.task._1)
+              val delay = {
+                if (getQuietTime != null) {
+                  getQuietTime
+                } else {
+                  toDuration("PT0S")
                 }
-      }
-    }
+              }
+              val handle = (timer !? delay).asInstanceOf[TimerHandle]
+              val timeout = (handle, triggerFunction(e))
+              loop(QuietState(e), (new TaskQueue).insert(delay, timeout))
+            }
           }
 
-          loop(next, newTimeouts)
-        }
+          case(e: JobPlanTriggeredEvent, WaitingState(_, waitList)) =&amp;gt; {
+    if (e.isForced) {
+              triggerThenIdle(e)
+    } else {
+              // Stay in waiting state and associate `e' with it.
+              loop (WaitingState(e, waitList), timeouts)
+            }
+          }
 
-        case e: XooEvent =&amp;gt; {
-          logger info("unhandled event {}", e)
-          loop(state, timeouts)
-        }
+          case (e: JobPlanTriggeredEvent, _) =&amp;gt; {
+    if (e.isForced) {
+              triggerThenIdle(e)
+    } else {
+              logger info("{}: triggered but state unchanged: {}", plan, state)
+              loop(state, timeouts)
+            }
+          }
 
-        case Ping =&amp;gt; {
-          sender ! Pong
-          loop(state, timeouts)
+          case (e: XooEvent, _) =&amp;gt; {
+            logger info("unhandled event {}", e)
+            loop(state, timeouts)
+          }
+
+          case (Ping, _) =&amp;gt; {
+            sender ! Pong
+            loop(state, timeouts)
+          }
         }
       }
     }

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-29T23:28:49</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/638">
    <title>r469 - org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/638</link>
    <description>&lt;pre&gt;Author: ludo
Date: Fri Apr 30 01:28:46 2010
New Revision: 469

Log:
JobPlanController: clean up and factorize import list

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaFri Apr 30 01:28:46 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,42 +1,30 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 package org.xoocode.xooctory.jobplan;
 
-import scala.actors.TIMEOUT;
 import scala.actors.Actor;
 import scala.actors.Actor.react;
-import scala.Function.{tupled, curried};
 import scala.collection.immutable.HashMap;
-import scala.collection.jcl.Conversions._;
 
-import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.joda.time.DateTime;
-import org.joda.time.Duration;
+import org.joda.time.{DateTime, Duration};
 
 import org.xoocode.xooctory.util.ScalaInterop._;
-import org.xoocode.xooctory.event.{XooEvent, EventService};
-import org.xoocode.xooctory.event.XooEventListener;
-import org.xoocode.xooctory.job.Job;
-import org.xoocode.xooctory.job.Scheduler;
+import org.xoocode.xooctory.event.{XooEvent, EventService, XooEventActor};
+import org.xoocode.xooctory.job.{Job, Scheduler};
 import org.xoocode.xooctory.job.model.JobModel;
 import org.xoocode.xooctory.jobplan.event.{JobPlanCancellingEvent,
   JobPlanEvent, JobPlanReleaseWaitForEvent, JobPlanTriggeredEvent,
   JobPlanWaitForEvent};
-import org.xoocode.xooctory.jobplan.model.JobPlanControllerModel;
-import org.xoocode.xooctory.jobplan.model.JobPlanModel;
-import org.xoocode.xooctory.jobplan.model.JobTriggerModel;
+import org.xoocode.xooctory.jobplan.model.{JobPlanControllerModel,
+  JobPlanModel, JobTriggerModel};
 import org.xoocode.xooctory.plugin.PluginRegistry;
 import org.xoocode.xooctory.plugins.trigger.JobTriggerPlugin;
 import org.xoocode.xooctory.timer.{TimerService, TaskQueue};
 import org.xoocode.xooctory.timer.TaskQueue._;
-import org.xoocode.xooctory.util.Check;
 import org.xoocode.xooctory.job.service.JobHistoryService;
-import org.xoocode.xooctory.job.model.ResultGroup;
-import java.util.LinkedList;
-import org.xoocode.xooctory.job.model.ResultItem;
+import org.xoocode.xooctory.job.model.{ResultGroup, ResultItem};
 
 import org.xoocode.xooctory.timer.TimerActor;
 import org.xoocode.xooctory.timer.TimerActor._;
-import org.xoocode.xooctory.event.XooEventActor;
 
 /**
  * A controller of job plan, in charge of instantiating new jobs out of a job

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-29T23:28:47</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/636">
    <title>r468 - org.xoocode.xooctory/trunk/xooctory</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/636</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu Apr 29 01:17:18 2010
New Revision: 468

Log:
compile Scala code with deprecation warnings

Modified:
   org.xoocode.xooctory/trunk/xooctory/build.xml

Modified: org.xoocode.xooctory/trunk/xooctory/build.xml
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/build.xml(original)
+++ org.xoocode.xooctory/trunk/xooctory/build.xmlThu Apr 29 01:17:18 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -89,7 +89,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 &amp;lt;mkdir dir="${target.main.classes.dir}" /&amp;gt;
 &amp;lt;scalacsrcdir="${src.main.java.dir}"
         destdir="${target.main.classes.dir}"
-        classpathref="compile.classpath" /&amp;gt;
+        classpathref="compile.classpath"
+deprecation="yes" /&amp;gt;
 &amp;lt;javac srcdir="${src.main.java.dir}"
         destdir="${target.main.classes.dir}"
         classpathref="compile.classpath"

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-28T23:17:18</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/635">
    <title>r467 - in org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job: . service</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/635</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu Apr 29 01:17:16 2010
New Revision: 467

Log:
fix uses of deprecated Scala types and methods

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/Schedule.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scalaThu Apr 29 01:17:16 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -299,7 +299,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
   // The job assignment timeout delay.
   // FIXME: Make this a parameter.
-  private val assignmentDelay = new Duration(5000.asInstanceOf[long])
+  private val assignmentDelay = new Duration(5000.asInstanceOf[Long])
 
   // The actual scheduling algorithm (a "static" method).
   def computeSchedule(sched: Schedule) = {

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/Schedule.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/Schedule.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/Schedule.scalaThu Apr 29 01:17:16 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -152,7 +152,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     Schedule(agents.idle(agent), jobs.idle(job))
   }
 
-  private def jobRefused(job: JobModel, agent: JobAgent, running: boolean) = {
+  private def jobRefused(job: JobModel, agent: JobAgent, running: Boolean) = {
     // TODO: Increase the job's priority.
     Schedule(agents.idle(agent), jobs.idle(job))
   }

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scalaThu Apr 29 01:17:16 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -68,7 +68,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     groupIds.foldLeft(List[ResultGroup]()) ((result: List[ResultGroup],
                                              group: (java.lang.Long, ResultGroup)) =&amp;gt; {
       if (group._2.getJob == jobModel) {
-        result + group._2
+        group._2 :: result
       } else {
         result
       }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -85,7 +85,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     itemIds.foldLeft(List[ResultItem]()) ((result: List[ResultItem],
                                            item: (java.lang.Long, ResultItem)) =&amp;gt; {
       if (item._2.getGroup == group) {
-        result + item._2
+        item._2 :: result
       } else {
         result
       }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -95,7 +95,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   def getResultItems(resultGroup: ResultGroup, klass: java.lang.Class[_ &amp;lt;: ResultItem],
                      start: Int, limit: Int): java.util.List[ResultItem] = null
 
-  def getResultItemCount(group: ResultGroup): long = {
+  def getResultItemCount(group: ResultGroup): Long = {
     itemIds.foldLeft(0)((count: Int, item: (java.lang.Long, ResultItem)) =&amp;gt; {
       if (item._2.getGroup == group) {
         count + 1
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -105,7 +105,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     })
   }
 
-  def getResultItemCount(group: ResultGroup, klass: java.lang.Class[_ &amp;lt;: ResultItem]): long = {
+  def getResultItemCount(group: ResultGroup, klass: java.lang.Class[_ &amp;lt;: ResultItem]): Long = {
     val count =
       itemIds.foldLeft(0)((count: Int, item: (java.lang.Long, ResultItem)) =&amp;gt; {
         if (item._2.getGroup == group &amp;amp;&amp;amp; item._2.getClass == klass) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -129,14 +129,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                                          string: java.lang.String):
     java.util.Map[java.lang.String, java.lang.Long] = null
 
-  def getResultGroupById(l: long): ResultGroup = groupIds get(l) getOrElse(null)
+  def getResultGroupById(l: Long): ResultGroup = groupIds get(l) getOrElse(null)
 
-  def getResultItemById(l: long): ResultItem = itemIds get(l) getOrElse(null)
+  def getResultItemById(l: Long): ResultItem = itemIds get(l) getOrElse(null)
 
   def getResultTargets(resultGroup: ResultGroup): java.util.List[String] = null
 
   def getResultFileCount(resultGroup: ResultGroup, sharedFile: SharedFile,
-                         stringArray: Array[String]): long = 0
+                         stringArray: Array[String]): Long = 0
 
   def getResultFiles(resultGroup: ResultGroup, sharedFile: SharedFile,
                      stringArray: Array[String], start: Int, limit: Int):
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -147,10 +147,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     java.util.List[ResultFile] = null
 
   def getResultFileCountByParent(resultGroup: ResultGroup, string: java.lang.String,
-                                 stringArray: Array[String]): long = 0
+                                 stringArray: Array[String]): Long = 0
 
   def getResultSharedFiles(resultGroup: ResultGroup):
     java.util.List[SharedFile] = null
 
-  def getResultTargetCount(resultGroup: ResultGroup): long = 0
+  def getResultTargetCount(resultGroup: ResultGroup): Long = 0
 }

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-28T23:17:17</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/634">
    <title>r466 - in org.xoocode.xooctory/trunk/xooctory/src: main/java/org/xoocode/xooctory/jobplan main/java/org/xoocode/xooctory/jobplan/service/impl test/java/org/xoocode/xooctory/jobplan</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/634</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu Apr 29 01:17:14 2010
New Revision: 466

Log:
JobPlanController: take a `TimerActor' instead of a `TimerService'

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java
   org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaThu Apr 29 01:17:14 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -56,14 +56,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * &amp;lt; at &amp;gt;author Xavier Hanin
  */
 class JobPlanController(plan: JobPlanModel, how: JobProcedure, pluginRegistry: PluginRegistry,
-eventService: EventService, timerService: TimerService,
+eventService: EventService, timer: TimerActor,
 historyService: JobHistoryService, scheduler: Scheduler)
 extends Actor {
 
   private val logger = LoggerFactory.getLogger(classOf[JobPlanController])
 
   private val model = plan.getWhen
-  private val timer = new TimerActor(timerService)
   private val event = new XooEventActor(eventService, this)
 
   private val triggerModels: List[JobTriggerModel] = model.getTriggers

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/service/impl/AbstractJobPlanService.javaThu Apr 29 01:17:14 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,6 +34,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.xoocode.xooctory.job.JobAgent;
 import org.xoocode.xooctory.job.model.AgentModel;
 import org.xoocode.xooctory.job.agent.AgentPlugin;
+import org.xoocode.xooctory.timer.TimerActor;
 
 public abstract class AbstractJobPlanService implements JobPlanService, XooEventListener {
 private final Logger logger = LoggerFactory.getLogger(AbstractJobPlanService.class);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,6 +44,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 protected final AgentManagementService agentManagementService;
 protected final JobManagementService jobManagementService;
 protected final TimerService timerService;
+protected final TimerActor timer;
 
 private final File workingDirectory = new File(System.getProperty("user.dir", ".")).getAbsoluteFile();
 private final Duration jobAssignmentDelay = new Duration(60 * 1000); // 60 seconds to start a job on an agent
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -58,6 +60,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 this.pluginRegistry = pluginRegistry;
 this.eventService = eventService;
 this.timerService = timerService;
+this.timer = new TimerActor(timerService);
 this.agentManagementService = agentManagementService;
 this.jobManagementService = jobManagementService;
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -133,8 +136,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 protected JobPlanController newJobPlanController(JobPlanModel model, JobProcedure how) {
 Scheduler scheduler = getScheduler(model.getWhen().getScheduler());
 JobPlanController when = new JobPlanController(
-model, how, pluginRegistry, eventService, timerService,
+model, how, pluginRegistry, eventService, timer,
 jobManagementService, scheduler);
+
 return when;
 }
 

Modified: org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.java(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/jobplan/JobPlanControllerTest.javaThu Apr 29 01:17:14 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -28,6 +28,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.xoocode.xooctory.scm.SCMRegistry;
 import org.xoocode.xooctory.scm.DefaultSCMRegistry;
 import org.xoocode.xooctory.plugins.trigger.JobTriggerPlugin;
+import org.xoocode.xooctory.timer.TimerActor;
 
 import static org.easymock.EasyMock.expect;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,6 +39,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 private PluginRegistry pluginRegistry;
 private EventService eventService;
 private MockTimerService timerService;
+private TimerActor timer;
 private JobHistoryService historyService;
 private Scheduler scheduler;
 private List&amp;lt;String&amp;gt; jobs;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -65,6 +67,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 pluginRegistry = EasyMock.createMock(PluginRegistry.class);
 eventService = EasyMock.createMock(EventService.class);
 timerService = new MockTimerService();
+timer = new TimerActor(timerService);
 scheduler = EasyMock.createMock(Scheduler.class);
 
 // `JobPlanTestHelper' uses `scm-change' triggers, which the job plan
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -75,7 +78,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 EasyMock.replay(pluginRegistry);
 
 controller = new JobPlanController(plan, how, pluginRegistry, eventService,
-   timerService, historyService, scheduler);
+   timer, historyService, scheduler);
 }
 
 public void testTrigger() throws Exception {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -263,7 +266,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 }
 };
 controller = new JobPlanController(plan, how, pluginRegistry, eventService,
-   timerService, historyService, scheduler);
+   timer, historyService, scheduler);
 
 JobPlanEvent triggerEvent = new JobPlanTriggeredEvent(plan, "who", "why");
 JobModel job = new JobModel();

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-28T23:17:15</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/633">
    <title>r465 - in org.xoocode.xooctory/trunk/xooctory/src: main/java/org/xoocode/xooctory/jobplan main/java/org/xoocode/xooctory/timer test/java/org/xoocode/xooctory/job</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/633</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu Apr 29 01:17:12 2010
New Revision: 465

Log:
TimerActor: start automatically

Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/timer/TimerActor.scala
   org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/job/FunctionalSchedulerSingleAgentTest.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaThu Apr 29 01:17:12 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -277,8 +277,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     val triggers = triggerModels map { newJobTrigger _ }
     triggers foreach { _ start }
 
-    // Start the auxiliary actors.
-    timer.start
+    // Start the auxiliary actor.
     event.start
 
     logger info("started, for job plan {}", plan)

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/timer/TimerActor.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/timer/TimerActor.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/timer/TimerActor.scalaThu Apr 29 01:17:12 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,6 +38,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
       }
     }
   }
+
+  // Automatically start.
+  this.start
 }
 
 object TimerActor {

Modified: org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/job/FunctionalSchedulerSingleAgentTest.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/job/FunctionalSchedulerSingleAgentTest.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/test/java/org/xoocode/xooctory/job/FunctionalSchedulerSingleAgentTest.scalaThu Apr 29 01:17:12 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -114,7 +114,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                                 new DefaultPluginRegistry,
                                 timer)
 
-      timer.start
       scheduler start
 
       agentModel associate(agent)

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-28T23:17:12</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.java.xooctory.scm/632">
    <title>r464 - in org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory: . job job/service jobplan util</title>
    <link>http://comments.gmane.org/gmane.comp.java.xooctory.scm/632</link>
    <description>&lt;pre&gt;Author: ludo
Date: Thu Apr 29 01:17:06 2010
New Revision: 464

Log:
factorize Scala/Java interoperability helpers

Added:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/util/ScalaInterop.scala
Modified:
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala
   org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/BatchServerMain.scalaThu Apr 29 01:17:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -105,15 +105,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                      "scala.collection.mutable.Buffer[Any]",
                      result)
 
-    // Provide an implicit Scala -&amp;gt; Java list conversion function so that job
-    // plans can use the simple Scala syntax, e.g., when listing result
-    // collectors.
-    interpreter.interpret("""
-        implicit def toJavaList[A](lst: List[A]): java.util.List[A] = {
-          val jlst = new java.util.ArrayList[A]
-          for (element &amp;lt;- lst) yield jlst.add(element)
-          jlst
-        }""")
+    // Provide Scala/Java interoperability helpers so that job plans can use
+    // the simple Scala syntax, e.g., when listing result collectors.
+    interpreter.interpret("import org.xoocode.xooctory.util.ScalaInterop._;")
     interpreter.interpret("interpreterResult += { " + source + " }")
     result.first
   }

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/FunctionalScheduler.scalaThu Apr 29 01:17:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,8 +6,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import scala.actors.Actor._;
 
 import org.slf4j.LoggerFactory;
-
 import org.joda.time.Duration;
+
+import org.xoocode.xooctory.util.ScalaInterop._;
 import org.xoocode.xooctory.timer.{TimerActor, TaskQueue};
 import org.xoocode.xooctory.timer.TimerActor.Tick;
 import org.xoocode.xooctory.timer.TaskQueue._;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -69,16 +70,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     }
   }
 
-  // Let's roll our own!
-  private implicit def toScalaList[A](l: java.util.List[A]) = {
-    var result = List[A]()
-    val it = l.iterator
-    while(it hasNext) {
-      result = it.next :: result
-    }
-    result reverse
-  }
-
   private def messageFold[A](f: (A, Any) =&amp;gt; A, seed: A): Unit = {
     react(new PartialFunction[Any, Unit] {
       def isDefinedAt(x: Any) = true

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/job/service/VolatileJobResultDAO.scalaThu Apr 29 01:17:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 package org.xoocode.xooctory.job.service;
 
+import org.xoocode.xooctory.util.ScalaInterop._;
 import org.xoocode.xooctory.repository.SharedFile;
 import org.xoocode.xooctory.job.model.{ResultGroup, ResultItem, ResultFile,
                                        ResultAnnotation, JobModel};
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -39,13 +40,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     r
   }
 
-
-  private implicit def toJavaList[A](lst: List[A]): java.util.List[A] = {
-    val jlst = new java.util.ArrayList[A]
-    for (element &amp;lt;- lst) yield jlst.add(element)
-    jlst
-  }
-
   def addResultGroup(group: ResultGroup): Unit = {
     synchronized {
       if (group.getId == null) {

Modified: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala
==============================================================================
--- org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scala(original)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/jobplan/JobPlanController.scalaThu Apr 29 01:17:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -11,6 +11,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 import org.slf4j.LoggerFactory;
 import org.joda.time.DateTime;
 import org.joda.time.Duration;
+
+import org.xoocode.xooctory.util.ScalaInterop._;
 import org.xoocode.xooctory.event.{XooEvent, EventService};
 import org.xoocode.xooctory.event.XooEventListener;
 import org.xoocode.xooctory.job.Job;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -64,18 +66,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   private val timer = new TimerActor(timerService)
   private val event = new XooEventActor(eventService, this)
 
-  private val triggerModels: List[JobTriggerModel] = {
-    val it = model.getTriggers.iterator
-    def toList(result: List[JobTriggerModel]): List[JobTriggerModel] = {
-      if (it hasNext) {
-        toList(it.next :: result)
-      } else {
-        result reverse
-      }
-    }
-
-    toList(List())
-  }
+  private val triggerModels: List[JobTriggerModel] = model.getTriggers
 
   // Ping-pong.
   private case object Ping
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -360,23 +351,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
   /* Helper methods.  */
 
-  // FIXME: Factorize these two methods somewhere.
-
-  implicit def toJavaList[A](lst: List[A]): java.util.List[A] = {
-    val jlst = new java.util.ArrayList[A]
-    for (element &amp;lt;- lst) yield jlst.add(element)
-    jlst
-  }
-
-  private implicit def toScalaList[A](l: java.util.List[A]): List[A] = {
-    var result = List[A]()
-    val it = l.iterator
-    while(it hasNext) {
-      result = it.next :: result
-    }
-    result reverse
-  }
-
   private def jobPlanResults(plans: List[JobPlanModel]): List[ResultItem] = {
     plans.flatMap((plan) =&amp;gt; {
       val job: JobModel = historyService.getLastSuccessfulJob(plan)

Added: org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/util/ScalaInterop.scala
==============================================================================
--- (empty file)
+++ org.xoocode.xooctory/trunk/xooctory/src/main/java/org/xoocode/xooctory/util/ScalaInterop.scalaThu Apr 29 01:17:06 2010
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+package org.xoocode.xooctory.util
+
+/**
+ * Implicit functions to ease interoperability between Scala and Java.
+ *
+ * &amp;lt; at &amp;gt;author &amp;lt;a href="mailto:ludovic.courtes&amp;lt; at &amp;gt;inria.fr"&amp;gt;Ludovic Courtès&amp;lt;/a&amp;gt;
+ */
+object ScalaInterop {
+
+  implicit def toJavaList[A](lst: List[A]): java.util.List[A] = {
+    val jlst = new java.util.LinkedList[A]
+    for (element &amp;lt;- lst) yield jlst.add(element)
+    jlst
+  }
+
+  implicit def toScalaList[A](l: java.util.Collection[A]): List[A] = {
+    val it = l.iterator
+
+    def convert(result: List[A]): List[A] = {
+      if (it hasNext) {
+        convert(it.next :: result)
+      } else {
+        result reverse
+      }
+    }
+
+    convert(Nil)
+  }
+}

&lt;/pre&gt;</description>
    <dc:creator>ludovic.courtes&lt; at &gt;inria.fr</dc:creator>
    <dc:date>2010-04-28T23:17:08</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.comp.java.xooctory.scm">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.comp.java.xooctory.scm</link>
  </textinput>
</rdf:RDF>
