[jbpm-commits] JBoss JBPM SVN: r6138 - in jbpm4/trunk/modules: devguide/src/main/docbook/en/images and 12 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Wed Jan 27 07:03:08 EST 2010


Author: jbarrez
Date: 2010-01-27 07:03:08 -0500 (Wed, 27 Jan 2010)
New Revision: 6138

Added:
   jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.timer.start.event.png
   jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/bpmn/event/timerstart/
   jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/bpmn/event/timerstart/TimerStartTest.java
   jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/bpmn/event/timerstart/
   jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/bpmn/event/timerstart/timer_start_event.bpmn.xml
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/StartProcessTimer.java
Removed:
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java
Modified:
   jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java
   jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/DbSessionImpl.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/DbSession.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/RepositorySession.java
   jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml
   jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java
Log:
JBPM-2722: completed implementation of timer start event

Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -21,11 +21,16 @@
  */
 package org.jbpm.bpmn.flownodes;
 
+import java.util.List;
+
 import org.jbpm.bpmn.model.BpmnProcessDefinition;
 import org.jbpm.bpmn.parser.BpmnParser;
-import org.jbpm.pvm.internal.job.PeriodicStartProcessTimer;
+import org.jbpm.internal.log.Log;
+import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.job.StartProcessTimer;
 import org.jbpm.pvm.internal.model.ActivityImpl;
 import org.jbpm.pvm.internal.model.TimerDefinitionImpl;
+import org.jbpm.pvm.internal.session.DbSession;
 import org.jbpm.pvm.internal.util.XmlUtil;
 import org.jbpm.pvm.internal.xml.Parse;
 import org.jbpm.pvm.internal.xml.Parser;
@@ -34,6 +39,8 @@
 
 
 public class StartEventBinding extends BpmnBinding {
+  
+  private static final Log LOG = Log.getLog(StartEventBinding.class.getName());
 
   public StartEventBinding() {
 	  super("startEvent");
@@ -61,6 +68,9 @@
     return new NoneStartEventActivity(); // default
   }
   
+  /**
+   * Timer start event
+   */
   protected TimerStartEventActivity createTimerStartEvent(BpmnProcessDefinition processDefinition, 
           Element timerEventDefinition, String eventId, BpmnParser parser, Parse parse) {
     
@@ -71,7 +81,7 @@
       return null;
     }
     
-    PeriodicStartProcessTimer startProcessTimer = new PeriodicStartProcessTimer();
+    StartProcessTimer startProcessTimer = new StartProcessTimer();
     startProcessTimer.setProcessDefinitionName(processDefinition.getName());
     
     if (timerDefinition.getDueDate() != null) {
@@ -82,8 +92,31 @@
       startProcessTimer.setIntervalExpression(timerDefinition.getCronExpression());
     }
     
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Scheduling a new start process timer for process definition " 
+              + processDefinition.getName());
+    }
+    
+    deleteStartProcessTimers(processDefinition.getName()); // Only the latest procDef should have a timer start
     startProcessTimer.schedule();
     return timerStartEvent;
   }
   
+  /**
+   * Deletes all existing timer start events for a given process definition.
+   * 
+   * This is required when a new version of a process definition with a timer start is deployed:
+   * only the latest may version may be started by the timer start event.
+   */
+  protected void deleteStartProcessTimers(String processDefinitionName) {
+    DbSession dbSession = EnvironmentImpl.getCurrent().get(DbSession.class);
+    List<StartProcessTimer> existingTimers = dbSession.findStartProcessTimers(processDefinitionName);
+    for (StartProcessTimer spt : existingTimers) {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Removing existing start process timer: " + spt);
+      }
+      dbSession.delete(spt);
+    }
+  }
+  
 }

Added: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.timer.start.event.png
===================================================================
(Binary files differ)


Property changes on: jbpm4/trunk/modules/devguide/src/main/docbook/en/images/bpmn2.timer.start.event.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml	2010-01-27 12:03:08 UTC (rev 6138)
@@ -1219,6 +1219,124 @@
   
     <title>Advanced constructs</title>
     
+    <section id="Timer start event">
+    
+      <title>Timer start event</title>
+      
+      <para>
+        A timer start event is used to indicate that a process should be started when a given
+        time condition is met. This could be a specific point in time (eg. October 10th, 2010 at
+        5am), but also and more typically a recurring time (eg. every Friday at midnight).  
+      </para>  
+      
+      <para>
+        A timer start event is visualized as a circle with the clock icon inside.
+       <mediaobject><imageobject><imagedata align="center" fileref="images/bpmn2.timer.start.event.png"/></imageobject></mediaobject>
+      </para>
+      
+      <para>
+        Using a Timer Start event is done by adding a <emphasis role="bold">timerEventDefinition</emphasis>
+        element below the startEvent element:
+        <programlisting>
+&lt;startEvent name=&quot;Every Monday morning&quot; id=&quot;myStart&quot;&gt;
+  <emphasis role="bold">&lt;timerEventDefinition/&gt;</emphasis>
+&lt;/startEvent&gt;        
+        </programlisting>
+        Following time definitions are possible:
+        <itemizedlist>
+          <listitem>
+            <emphasis role="bold">timeDate: </emphasis>specifies a fixed date when a process instance
+            must be created. The default format of the date specification is
+            &quot;dd/MM/yyyy hh:mm:ss&quot;. This can engine-wide be changed by setting the 
+            <emphasis role="bold">jbpm.duedatetime.format</emphasis> property in the configuration.
+            <programlisting>
+&lt;startEvent id=&quot;myStartEvent&quot; &gt;
+  &lt;timerEventDefinition&gt;
+    <emphasis role="bold">&lt;timeDate&gt;10/10/2099 00:00:00&lt;/timeDate&gt;</emphasis>
+  &lt;/timerEventDefinition&gt;
+&lt;/startEvent&gt;           
+            </programlisting>
+            Note that using a fixed duedate makes the process only useable for a single time.
+            After the process instance is created, the timer start event will never fire again.
+          </listitem>
+          <listitem>
+            <emphasis role="bold">timeCycle: </emphasis>specifies the recurring time when a new
+            process instance will be created. Two types are possible
+
+            <para>
+                <emphasis role="bold">Duration expression: </emphasis> 
+                <programlisting>
+quantity [business] {second | seconds | minute | minutes | 
+                     hour | hours | day | days | week | 
+                     weeks | month | months | year | years}                
+                </programlisting>
+                 This is completely similar to a timer duration definition in JPDL. Note that the 
+                 BPMN2 start timer event also understands &quot;business time&quot;. This
+                 allows for example to define a &quot;business day&quot; as an interval from
+                 9am to 5pm. This way, the time from 5pm to 9am will not be taken in account when
+                 the time on which the event will fire is calculated. 
+                 Please refer to the JPDL userguide for more details on how this business calendar can be customized.
+                 The following example shows a timer start event that will start a new process
+                 instance every five hours.
+                 <programlisting>
+&lt;startEvent id=&quot;myStartEvent&quot; &gt;
+  &lt;timerEventDefinition&gt;
+    <emphasis role="bold">&lt;timeCycle&gt;5 hours&lt;/timeCycle&gt;</emphasis>
+  &lt;/timerEventDefinition&gt;
+&lt;/startEvent&gt;               
+                 </programlisting>
+              </para>
+              <para>
+                <emphasis role="bold"><ulink url="http://en.wikipedia.org/wiki/CRON_expression">Cron expression:</ulink></emphasis>
+                altough duration expressions cover already a great deal of recurring time definitions, 
+                sometimes they are not easy to use. 
+                When for example a process instance should be started every Friday night 23pm,
+                cron expressions allow a more natural way of defining such repeating occurrences.
+              </para>
+              <para>
+                The following example shows a timer start event that will start a new process
+                instance every Friday at 23pm. 
+                <programlisting>
+&lt;startEvent id=&quot;myStartEvent&quot; &gt;
+  &lt;timerEventDefinition&gt;
+    <emphasis role="bold">&lt;timeCycle&gt;0 0 23 ? * FRI&lt;/timeCycle&gt;</emphasis>
+&lt;/timerEventDefinition&gt;
+&lt;/startEvent&gt;               
+                </programlisting>
+              </para>
+          </listitem>
+        </itemizedlist>
+      </para>
+      
+      <para>
+        The timer start event implementation in jBPM also has following features:
+        <itemizedlist>
+          <listitem>
+            Process definitions that have a timer start event, can be started as if it also
+            were a none start event. This means that calling for example 
+            executionService.startProcessInstanceByKey(key) just works.
+          </listitem>
+          <listitem>
+            The timer start event is internally implemented as a scheduled job. This means
+            that a <emphasis role="bold">job executor</emphasis> has to be configured for
+            the timer start event to work. The advantage of this implementation is that the
+            timer start event firing is transactional (eg. if a service tasks right after the 
+            timer start event fails, the transaction will be rolled back and the timer start event
+            will be retried later) and able to cope with a server crash (ie. the when the server
+            comes back up, the timer start event will be picked up by the job executor just as if
+            nothing has happened).
+          </listitem>
+          <listitem>
+            When a new version of a process definition with a timer start event is deployed, the
+            old timer start event job is removed from the system. This means that 
+            <emphasis role="bold">only the latest version of the process definition will be used</emphasis>
+            to create a new process instances.
+          </listitem>
+        </itemizedlist>        
+      </para>
+    
+    </section> <!-- end of Timer start event -->
+    
     <section id="intermediateEvents">
     
       <title>Intermediate events</title>
@@ -1275,7 +1393,7 @@
       </para>
       
       <para>
-        Following delay definitions are possible.
+        Following delay definitions are possible (similar to those for a Timer Start Event).
         <itemizedlist>
           <listitem>
             <emphasis role="bold">timeDate: </emphasis>specifies a fixed date when the timer will
@@ -1292,7 +1410,7 @@
           </listitem>
           <listitem>
             <emphasis role="bold">timeCycle: </emphasis>specifies a delay duration relative to the
-            time when the execution enters the timer event. Two possible definitions are possible
+            time when the execution enters the timer event. Two types are possible
 
             <para>
                 <emphasis role="bold">Duration expression: </emphasis> 

Added: jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/bpmn/event/timerstart/TimerStartTest.java
===================================================================
--- jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/bpmn/event/timerstart/TimerStartTest.java	                        (rev 0)
+++ jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/bpmn/event/timerstart/TimerStartTest.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.examples.bpmn.event.timerstart;
+
+import java.util.Calendar;
+
+import org.jbpm.api.NewDeployment;
+import org.jbpm.api.ProcessInstanceQuery;
+import org.jbpm.api.job.Job;
+import org.jbpm.pvm.internal.util.Clock;
+import org.jbpm.test.JbpmTestCase;
+import org.jbpm.test.util.DateUtils;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class TimerStartTest extends JbpmTestCase {
+  
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    Clock.setExplicitTime(DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099));
+    NewDeployment deployment = repositoryService.createDeployment();
+    deployment.addResourceFromClasspath("org/jbpm/examples/bpmn/event/timerstart/timer_start_event.bpmn.xml");
+    registerDeployment(deployment.deploy());
+  }
+  
+  @Override
+  protected void tearDown() throws Exception {
+    Clock.setExplicitTime(null);
+    super.tearDown();
+  }
+  
+  public void testTimerStartEventWithDurationAsTimeCycle() {
+    
+    // After deployment, there should be one job in the database that starts a new process instance
+    Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+    assertNotNull(startProcessTimer);
+    assertEquals(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 10, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+    
+    // Triggering the job should start a new process instance of the deployed process definition
+    ProcessInstanceQuery procInstQuery = executionService.createProcessInstanceQuery();
+    assertEquals(0, procInstQuery.count());
+    
+    // need to change current date to calculate the next duedate internally correctl
+    Clock.setExplicitTime(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 10, 0, 0)); 
+    managementService.executeJob(startProcessTimer.getId());
+    assertEquals(1, procInstQuery.count());
+    
+    // Since a timeCycle was used, the job should have been recreated with a new duedate
+    startProcessTimer = managementService.createJobQuery().uniqueResult();
+    assertEquals(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 20, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+    
+    
+    // So we need to manually delete it
+    managementService.deleteJob(Long.valueOf(startProcessTimer.getId()));
+  }
+
+}

Added: jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/bpmn/event/timerstart/timer_start_event.bpmn.xml
===================================================================
--- jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/bpmn/event/timerstart/timer_start_event.bpmn.xml	                        (rev 0)
+++ jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/bpmn/event/timerstart/timer_start_event.bpmn.xml	2010-01-27 12:03:08 UTC (rev 6138)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<definitions 
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://schema.omg.org/spec/BPMN/2.0 ../../../../../../../../../../bpmn/src/main/resources/BPMN20.xsd"
+  xmlns="http://schema.omg.org/spec/BPMN/2.0"
+  typeLanguage="http://www.w3.org/2001/XMLSchema"
+  expressionLanguage="http://www.w3.org/1999/XPath" 
+  targetNamespace="http://jbpm.org/example/bpmn2/timer_start_end_event"
+  xmlns:jbpm="http://jbpm.org/bpmn2">
+
+  <process id="noneStartEndEvent">
+
+    <startEvent id="start" >
+      <timerEventDefinition>
+        <timeCycle>10 hours</timeCycle>
+      </timerEventDefinition>
+    </startEvent>
+
+    <sequenceFlow id="flow1" sourceRef="start" targetRef="wait" />
+      
+    <receiveTask id="wait" />
+    
+     <sequenceFlow id="flow2" sourceRef="wait" targetRef="end" />
+
+    <endEvent id="end" />
+
+  </process>
+  
+</definitions>

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -110,52 +110,59 @@
   }
   
   public static Date calculateDueDate(String durationExpression) {
-    Date dueDate;
-    // is due date description in date_expression +|- fixed_duration format?
-    Matcher dateDurationMatcher = dateDurationPattern.matcher(durationExpression);
-    if (dateDurationMatcher.matches()) {
-      // evaluate date expression
-      String dateExpression = dateDurationMatcher.group(1);
-      Object result = ScriptManager.getScriptManager().evaluateExpression(dateExpression, null);
-      // convert result to Date
-      if (result instanceof Date) {
-        dueDate = (Date) result;
-      } else if (result instanceof Calendar) {
-        Calendar calendar = (Calendar) result;
-        dueDate = calendar.getTime();
-      } else if (result instanceof String) {
-        try {
-          // TODO use a locale-sensitive date format?
-          dueDate = new SimpleDateFormat(dateFormat).parse((String) result);
-        } catch (ParseException e) {
-          throw new JbpmException("invalid base date: " + result, e);
+    Date duedate = null;
+    if (durationExpression != null) {
+      ScriptManager scriptManager = ScriptManager.getScriptManager();
+
+      Date baseDate;
+      String durationString = null;
+      char durationSeparator = '+'; // needs to be initialized
+
+      if (durationExpression.startsWith("#")) {
+
+        String baseDateEL = durationExpression.substring(0, durationExpression.indexOf("}") + 1);
+        Object result = scriptManager.evaluateExpression(baseDateEL, null);
+
+        if (result instanceof Date) {
+          baseDate = (Date) result;
+        } else if (result instanceof Calendar) {
+          baseDate = ((Calendar) result).getTime();
+        } else {
+          throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + result.getClass().getName()
+                  + ". Only Date and Calendar are supported");
         }
+
+        int endOfELIndex = durationExpression.indexOf("}");
+        if (endOfELIndex < (durationExpression.length() - 1)) {
+          durationSeparator = durationExpression.substring(endOfELIndex + 1).trim().charAt(0);
+          if (durationSeparator != '+' && durationSeparator != '-') {
+            throw new JbpmException("Invalid duedate, + or - missing after EL");
+          }
+          durationString = durationExpression.substring(endOfELIndex + 1).substring(2).trim();
+        }
+
       } else {
-        throw new JbpmException("invalid base date: " + result);
+
+        baseDate = Clock.getTime();
+        durationString = durationExpression;
+
       }
 
-      // fixed duration is optional
-      String operationString = dateDurationMatcher.group(2);
-      if (operationString != null) {
-        char operation = operationString.charAt(0);
-        String duration = dateDurationMatcher.group(3);
-        // add duration to base date
+      if (durationString == null || durationString.length() == 0) {
+        duedate = baseDate;
+      } else {
+        if (durationString.contains("business") && durationSeparator == '-') {
+          throw new JbpmException("Invalid duedate, subtraction ('-') not supported if duedate contains 'business'");
+        }
         BusinessCalendar businessCalendar = EnvironmentImpl.getFromCurrent(BusinessCalendar.class);
-        dueDate = operation == '+' ? businessCalendar.add(dueDate, duration)
-            : businessCalendar.subtract(dueDate, duration);
+        if (durationSeparator == '+') {
+          duedate = businessCalendar.add(baseDate, durationString);
+        } else {
+          duedate = businessCalendar.subtract(baseDate, durationString);
+        }
       }
-    } else {
-      // is due date description in fixed_duration format?
-      Matcher durationMatcher = durationPattern.matcher(durationExpression);
-      if (durationMatcher.matches()) {
-        // add duration to current date
-        dueDate = EnvironmentImpl.getFromCurrent(BusinessCalendar.class).add(
-            Clock.getTime(), durationMatcher.group(1));
-      } else {
-        throw new JbpmException("invalid due date duration: " + durationExpression);
-      }
     }
-    return dueDate;
+    return duedate;
   }
 
   public Duration(boolean isBusinessTime, int millis, int seconds, int minutes, int hours, int days, int weeks, int months, int years) {

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/DbSessionImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/DbSessionImpl.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/hibernate/DbSessionImpl.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -43,6 +43,7 @@
 import org.jbpm.pvm.internal.history.model.HistoryProcessInstanceImpl;
 import org.jbpm.pvm.internal.id.DbidGenerator;
 import org.jbpm.pvm.internal.job.JobImpl;
+import org.jbpm.pvm.internal.job.StartProcessTimer;
 import org.jbpm.pvm.internal.model.ExecutionImpl;
 import org.jbpm.pvm.internal.query.DeploymentQueryImpl;
 import org.jbpm.pvm.internal.query.HistoryActivityInstanceQueryImpl;
@@ -427,6 +428,14 @@
     return (JobImpl<?>) query.uniqueResult();
   }
   
+  public List<StartProcessTimer> findStartProcessTimers(String processDefinitionName) {
+    Query query = session.createQuery(
+      "select spt from " + StartProcessTimer.class.getName() + " as spt " +
+      "where spt.signalName = :procDefName");
+    query.setString("procDefName", processDefinitionName);
+    return query.list();
+  }
+  
   public ProcessInstanceQueryImpl createProcessInstanceQuery() {
     return new ProcessInstanceQueryImpl();
   }

Deleted: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -1,200 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jbpm.pvm.internal.job;
-
-import java.text.ParseException;
-
-import org.jbpm.api.ExecutionService;
-import org.jbpm.api.JbpmException;
-import org.jbpm.api.RepositoryService;
-import org.jbpm.api.cmd.Environment;
-import org.jbpm.internal.log.Log;
-import org.jbpm.pvm.internal.cal.CronExpression;
-import org.jbpm.pvm.internal.cal.Duration;
-import org.jbpm.pvm.internal.env.EnvironmentImpl;
-import org.jbpm.pvm.internal.session.DbSession;
-import org.jbpm.pvm.internal.util.Clock;
-
-
-/**
- * Job that periodically startes a new process instance of a given process definition.
- * 
- * @author Joram Barrez
- */
-public class PeriodicStartProcessTimer extends TimerImpl {
-
-  private static final long serialVersionUID = 1L;
-  
-  private static final Log LOG = Log.getLog(PeriodicStartProcessTimer.class.getName());
-
-  // Override execution logic of regular timer
-  public Boolean execute(Environment environment) throws Exception {
-    
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Periodic start process triggered at " + Clock.getTime());
-    }
-    
-    boolean processDefinitionExists = processDefinitionExists(environment);
-    boolean newDueDateCalculated = false;
-    
-    if (processDefinitionExists) {
-      startProcessInstance(environment);
-      newDueDateCalculated = calculateDueDate(environment);
-    } 
-    
-    if (!processDefinitionExists || !newDueDateCalculated) {
-      deleteThisJob(environment);
-    } else {
-      saveThisJob(environment);
-    }
-    
-    return null;
-  }
-  
-  protected boolean processDefinitionExists(Environment environment) {
-    RepositoryService repositoryService = environment.get(RepositoryService.class);
-    boolean processExists = !repositoryService.createProcessDefinitionQuery()
-                                .processDefinitionName(getProcessDefinitionName()).list().isEmpty();
-
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Process definition with name " + getProcessDefinitionName() + " still exists: " + processExists);
-    }
-    
-    return processExists;
-  }
-
-  protected void startProcessInstance(Environment environment) {
-    ExecutionService executionService = environment.get(ExecutionService.class);
-    if (executionService == null) {
-      throw new JbpmException("no " + ExecutionService.class.getName() + " in environment"); 
-    }
-    
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Starting a new process instance for process definition with name " + getProcessDefinitionName());
-    }
-    
-    executionService.startProcessInstanceByKey(getProcessDefinitionName());
-  }
-  
-  protected boolean calculateDueDate(Environment environment) throws ParseException {
-      
-    if (getIntervalExpression() != null && Duration.isValidExpression(getIntervalExpression())) {
-      duedate = Duration.calculateDueDate(getIntervalExpression());
-    } else if (getIntervalExpression() != null &&  CronExpression.isValidExpression(getIntervalExpression())) {
-      duedate = new CronExpression(getIntervalExpression()).getNextValidTimeAfter(Clock.getTime());
-    } else {
-      if (LOG.isDebugEnabled()) {
-        LOG.debug("No next duedate calculated for periodic start process job " +
-                "with intervalExpression " + getIntervalExpression());
-      }
-      return false;
-    }
-    
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Next process start duedate: " + duedate);
-    }
-    
-    return true;
-  }
-  
-  protected void saveThisJob(Environment environment) {
-    DbSession dbSession = environment.get(DbSession.class);
-    if (dbSession == null) {
-      throw new JbpmException("no " + DbSession.class.getName() + " in environment"); 
-    }
-    dbSession.save(this);
-  }
-  
-  protected void deleteThisJob(Environment environment) {
-    if (LOG.isDebugEnabled()) {
-      LOG.debug("Deleting periodic start job for process definition with name " + getProcessDefinitionName());
-    }
-    
-    DbSession dbSession = environment.get(DbSession.class);
-    if (dbSession == null) {
-      throw new JbpmException("no " + DbSession.class.getName() + " in environment"); 
-    }
-    dbSession.delete(this);
-  }
-  
-  @Override
-  public void schedule() {
-    if (duedate == null && getIntervalExpression() != null) {
-      try {
-        calculateDueDate(EnvironmentImpl.getCurrent());
-      } catch (ParseException e) {
-        throw new JbpmException("Cannot parse intervalExpression", e);
-      }
-    } else if (duedate == null) {
-      throw new JbpmException("Cannot schedule periodic start process timer: " +
-                              "no duedate or intervalExpression set");
-    }
-    super.schedule();
-  }
-  
-  @Override
-  public void validate() {
-    if (getProcessDefinitionName() == null) {
-      throw new JbpmException("No process definition name set for periodic start process timer");
-    }
-    if (duedate == null && getIntervalExpression() == null) {
-      throw new JbpmException("No duedate or intervalExpression found for periodic start process timer");
-    }
-  }
-  
-  public String getProcessDefinitionName() {
-    return signalName;
-  }
-  
-  public void setProcessDefinitionName(String processDefinitionName) {
-    this.signalName = processDefinitionName;
-  }
-
-  public String getIntervalExpression() {
-    return eventName;
-  }
-
-  /**
-   * Sets the expression that will define the interval between 
-   * two sequential process starts by this job.
-   * 
-   * Possible expression types are {@link Duration} and {@link CronExpression}.
-   */
-  public void setIntervalExpression(String intervalExpression) {
-    this.eventName = intervalExpression;
-  }
-  
-  @Override
-  public String toString() {
-    StringBuilder strb = new StringBuilder();
-    strb.append("PeriodicProcessStart[");
-    if (duedate != null) {
-      strb.append(duedate);
-    }
-    if (getIntervalExpression() != null) {
-      strb.append("| " + getIntervalExpression());
-    }
-    strb.append("]");
-    return strb.toString();
-  }
-
-}

Copied: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/StartProcessTimer.java (from rev 6135, jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java)
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/StartProcessTimer.java	                        (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/StartProcessTimer.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -0,0 +1,213 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.job;
+
+import java.text.ParseException;
+
+import org.jbpm.api.ExecutionService;
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.ProcessDefinition;
+import org.jbpm.api.RepositoryService;
+import org.jbpm.api.cmd.Environment;
+import org.jbpm.internal.log.Log;
+import org.jbpm.pvm.internal.cal.CronExpression;
+import org.jbpm.pvm.internal.cal.Duration;
+import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.session.DbSession;
+import org.jbpm.pvm.internal.session.RepositorySession;
+import org.jbpm.pvm.internal.util.Clock;
+
+
+/**
+ * Job that starts a new process instance of a given process definition 
+ * on a fixed duedate/periodic time.
+ * 
+ * @author Joram Barrez
+ */
+public class StartProcessTimer extends TimerImpl {
+
+  private static final long serialVersionUID = 1L;
+  
+  private static final Log LOG = Log.getLog(StartProcessTimer.class.getName());
+
+  // Override execution logic of regular timer
+  public Boolean execute(Environment environment) throws Exception {
+    
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Periodic start process triggered at " + Clock.getTime());
+    }
+    
+    boolean processDefinitionExists = processDefinitionExists(environment);
+    boolean newDueDateCalculated = false;
+    
+    if (processDefinitionExists) {
+      startProcessInstance(environment);
+      newDueDateCalculated = calculateDueDate(environment);
+    } 
+    
+    if (!processDefinitionExists || !newDueDateCalculated) {
+      deleteThisJob(environment);
+    } else {
+      saveThisJob(environment);
+    }
+    
+    return null;
+  }
+  
+  protected boolean processDefinitionExists(Environment environment) {
+    RepositoryService repositoryService = environment.get(RepositoryService.class);
+    boolean processExists = !repositoryService.createProcessDefinitionQuery()
+                                .processDefinitionName(getProcessDefinitionName()).list().isEmpty();
+
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Process definition with name " + getProcessDefinitionName() + " still exists: " + processExists);
+    }
+    
+    return processExists;
+  }
+
+  protected void startProcessInstance(Environment environment) {
+    ExecutionService executionService = environment.get(ExecutionService.class);
+    if (executionService == null) {
+      throw new JbpmException("no " + ExecutionService.class.getName() + " in environment"); 
+    }
+    
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Starting a new process instance for process definition with name " + getProcessDefinitionName());
+    }
+    
+    RepositorySession repoSession = environment.get(RepositorySession.class);
+    if (repoSession == null) {
+      throw new JbpmException("Could not find a" + RepositorySession.class.getName() + " impl in environment");
+    }
+    
+    ProcessDefinition procDef = repoSession.findLatestProcessDefinitionByName(getProcessDefinitionName());
+    executionService.startProcessInstanceById(procDef.getId());
+  }
+  
+  protected boolean calculateDueDate(Environment environment) throws ParseException {
+      
+    if (getIntervalExpression() != null && Duration.isValidExpression(getIntervalExpression())) {
+      duedate = Duration.calculateDueDate(getIntervalExpression());
+    } else if (getIntervalExpression() != null &&  CronExpression.isValidExpression(getIntervalExpression())) {
+      duedate = new CronExpression(getIntervalExpression()).getNextValidTimeAfter(Clock.getTime());
+    } else {
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("No next duedate calculated for start process job " +
+                "with intervalExpression " + getIntervalExpression());
+      }
+      return false;
+    }
+    
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Next process start duedate: " + duedate);
+    }
+    
+    return true;
+  }
+  
+  protected void saveThisJob(Environment environment) {
+    DbSession dbSession = environment.get(DbSession.class);
+    if (dbSession == null) {
+      throw new JbpmException("no " + DbSession.class.getName() + " in environment"); 
+    }
+    dbSession.save(this);
+  }
+  
+  protected void deleteThisJob(Environment environment) {
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Deleting start process job for process definition with name " + getProcessDefinitionName());
+    }
+    
+    DbSession dbSession = environment.get(DbSession.class);
+    if (dbSession == null) {
+      throw new JbpmException("no " + DbSession.class.getName() + " in environment"); 
+    }
+    dbSession.delete(this);
+  }
+  
+  @Override
+  public void schedule() {
+    if (duedate == null && getIntervalExpression() != null) {
+      try {
+        calculateDueDate(EnvironmentImpl.getCurrent());
+      } catch (ParseException e) {
+        throw new JbpmException("Cannot parse intervalExpression", e);
+      }
+    } else if (duedate == null) {
+      throw new JbpmException("Cannot schedule start process timer: " +
+                              "no duedate or intervalExpression set");
+    }
+    super.schedule();
+  }
+  
+  @Override
+  public void validate() {
+    if (getProcessDefinitionName() == null) {
+      throw new JbpmException("No process definition name set for start process timer");
+    }
+    if (duedate == null && getIntervalExpression() == null) {
+      throw new JbpmException("No duedate or intervalExpression found for start process timer");
+    }
+  }
+  
+  public String getProcessDefinitionName() {
+    return signalName;
+  }
+  
+  public void setProcessDefinitionName(String processDefinitionName) {
+    this.signalName = processDefinitionName;
+  }
+
+  public String getIntervalExpression() {
+    return eventName;
+  }
+
+  /**
+   * Sets the expression that will define the interval between 
+   * two sequential process starts by this job.
+   * 
+   * Possible expression types are {@link Duration} and {@link CronExpression}.
+   */
+  public void setIntervalExpression(String intervalExpression) {
+    this.eventName = intervalExpression;
+  }
+  
+  @Override
+  public String toString() {
+    StringBuilder strb = new StringBuilder();
+    strb.append("PeriodicProcessStart[");
+    if (getProcessDefinitionName() != null) {
+      strb.append(getProcessDefinitionName());
+    }
+    if (duedate != null) {
+      strb.append("| " + duedate);
+    }
+    if (getIntervalExpression() != null) {
+      strb.append("| " + getIntervalExpression());
+    }
+    
+    strb.append("]");
+    return strb.toString();
+  }
+
+}

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/repository/RepositorySessionImpl.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -179,7 +179,23 @@
 
     return null;
   }
+  
+  public ProcessDefinitionImpl findLatestProcessDefinitionByName(String processDefinitionName) {
+    ProcessDefinition processDefinition = createProcessDefinitionQuery()
+      .processDefinitionName(processDefinitionName)
+      .orderDesc(ProcessDefinitionQuery.PROPERTY_VERSION)
+      .page(0, 1)
+      .uniqueResult();
 
+  if (processDefinition != null) {
+    return findProcessDefinitionById(processDefinition.getId());
+  } else {
+    validateRepositoryCache();
+  }
+
+  return null;
+  }
+
   public DeploymentProperty findDeploymentPropertyByProcessDefinitionId(String processDefinitionId) {
     DeploymentProperty deploymentProperty = (DeploymentProperty) session.createQuery(
       "select deploymentProperty " +

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/DbSession.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/DbSession.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/DbSession.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -28,6 +28,7 @@
 import org.jbpm.pvm.internal.client.ClientExecution;
 import org.jbpm.pvm.internal.client.ClientProcessDefinition;
 import org.jbpm.pvm.internal.job.JobImpl;
+import org.jbpm.pvm.internal.job.StartProcessTimer;
 import org.jbpm.pvm.internal.model.ExecutionImpl;
 import org.jbpm.pvm.internal.model.ScopeInstanceImpl;
 import org.jbpm.pvm.internal.query.DeploymentQueryImpl;
@@ -122,4 +123,7 @@
 
   /** the first job to finish among non-owned jobs or null if none */
   public JobImpl<?> findFirstDueJob();
+  
+  /** returns a list of start process timers for the given process definition */
+  public List<StartProcessTimer> findStartProcessTimers(String processDefinitionId);
 }

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/RepositorySession.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/RepositorySession.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/session/RepositorySession.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -46,6 +46,8 @@
   ProcessDefinitionImpl findProcessDefinitionById(String processDefinitionId);
 
   ProcessDefinitionImpl findProcessDefinitionByKey(String processDefinitionKey);
+  
+  ProcessDefinitionImpl findLatestProcessDefinitionByName(String processDefinitionName);
 
   void updateDeploymentResource(String deploymentId, String resourceName, byte[] bytes);
 }

Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml	2010-01-27 12:03:08 UTC (rev 6138)
@@ -248,7 +248,7 @@
       <property name="eventName" column="EVENT_" />
       <property name="repeat" column="REPEAT_" />
       
-      <subclass name="org.jbpm.pvm.internal.job.PeriodicStartProcessTimer" discriminator-value="PeriodicStartProcess" />
+      <subclass name="org.jbpm.pvm.internal.job.StartProcessTimer" discriminator-value="PeriodicStartProcess" />
     
     </subclass>
     

Modified: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java	2010-01-27 07:59:50 UTC (rev 6137)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java	2010-01-27 12:03:08 UTC (rev 6138)
@@ -22,8 +22,12 @@
 package org.jbpm.bpmn.test.startevent;
 
 import java.util.Calendar;
+import java.util.List;
 
 import org.jbpm.api.JbpmException;
+import org.jbpm.api.ProcessDefinition;
+import org.jbpm.api.ProcessDefinitionQuery;
+import org.jbpm.api.ProcessInstance;
 import org.jbpm.api.ProcessInstanceQuery;
 import org.jbpm.api.job.Job;
 import org.jbpm.pvm.internal.util.Clock;
@@ -119,7 +123,7 @@
   
   private static final String TIMER_START_TIMECYCLE_CRON_EXPR = 
     "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
-    "  <process id='timerStartTimeCycleCronExpression'>" +
+    "  <process id='timerStartTimeCycleCronExpression' name='timerStartCron'>" +
     "    <startEvent id='theStart' >" +
     "      <timerEventDefinition >" +
     "        <timeCycle>0 0 22 * * ?</timeCycle>" + // every day at 22:00
@@ -189,7 +193,7 @@
                       .processDefinitionId(findProcessDefinitionId("timerStartTimeCycleDuration"));
     assertEquals(0, procInstQuery.count());
     
-    // need to change current date to calculate the next duedate correctly
+    // need to change current date to calculate the next duedate internally correctly
     Clock.setExplicitTime(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 10, 0, 0)); 
     managementService.executeJob(startProcessTimer.getId());
     assertEquals(1, procInstQuery.count());
@@ -235,6 +239,7 @@
     String deployId = deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
     
     // Delete the process definition
+    String procDefId = findProcessDefinitionId("timerStartTimeCycleDuration");
     repositoryService.deleteDeploymentCascade(deployId);
     registeredDeployments.remove(0);
     
@@ -243,11 +248,65 @@
     assertNotNull(startProcessTimer);
     
     // When the timer triggers, it notices that the process definition is gone and it deletes itselves
+    // No new process instance should have been started
+    ProcessInstanceQuery procInstQuery = executionService.createProcessInstanceQuery().processDefinitionId(procDefId);
+    assertEquals(0, procInstQuery.count());
+    
     managementService.executeJob(startProcessTimer.getId());
     startProcessTimer = managementService.createJobQuery().uniqueResult();
     assertNull(startProcessTimer);
+    assertEquals(0, procInstQuery.count());
   }
   
+  /*
+   * Processes with a timer start event should be createable through the executionService.
+   */
+  public void testStartProcessInstanceByKey() {
+    deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+    ProcessInstance pi = executionService.startProcessInstanceByKey("timerStartTimeCycleDuration");
+    assertNotNull(pi);
+    
+    Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+    managementService.deleteJob(Long.valueOf(startProcessTimer.getId()));
+  }
+  
+  public void testOnlyOneStartProcessActiveAfterRedeploy() {
+    deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+    List<Job> startProcessTimers = managementService.createJobQuery().list();
+    assertEquals(1, startProcessTimers.size());
+    String firstJobId = startProcessTimers.get(0).getId();
+    
+    // Redeploy -> first job should be deleted
+    deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+    assertEquals(2, repositoryService.createProcessDefinitionQuery().list().size());
+    startProcessTimers = managementService.createJobQuery().list();
+    assertEquals(1, startProcessTimers.size());
+    
+    String secondJobId = startProcessTimers.get(0).getId();
+    assertTrue(!firstJobId.equals(secondJobId));
+    
+    managementService.deleteJob(Long.valueOf(secondJobId));
+  }
+  
+  public void testLatestProcessDefinitionUsedAfterRedeploy() {
+    deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+    Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+    
+    // Redeploy 
+    deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+    List<ProcessDefinition> procDefs = repositoryService.createProcessDefinitionQuery()
+                                          .orderAsc(ProcessDefinitionQuery.PROPERTY_VERSION).list();
+    assertEquals(2, procDefs.size());
+    
+    // Firing start process timer -> new process instance for latests version of proc def
+    startProcessTimer = managementService.createJobQuery().uniqueResult();
+    managementService.executeJob(startProcessTimer.getId());
+    ProcessInstance procInst = executionService.createProcessInstanceQuery().uniqueResult();
+    assertEquals(procDefs.get(1).getId(), procInst.getProcessDefinitionId());
+    
+    managementService.deleteJob(Long.valueOf(startProcessTimer.getId()));
+  }
+  
   private String findProcessDefinitionId(String processDefinitionKey) {
     return repositoryService.createProcessDefinitionQuery()
               .processDefinitionName(processDefinitionKey).uniqueResult().getId();



More information about the jbpm-commits mailing list