[jbpm-commits] JBoss JBPM SVN: r2003 - in jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src: main/java/org/jbpm/command and 14 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Mon Aug 25 21:11:36 EDT 2008


Author: alex.guizar at jboss.com
Date: 2008-08-25 21:11:36 -0400 (Mon, 25 Aug 2008)
New Revision: 2003

Added:
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/NoJobExecutorDbTest.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/TimerOnTimerDbTest.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/timerOnTimer.jpdl.xml
Modified:
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/JbpmContext.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/command/AbstractCancelCommand.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/JobSession.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/hibernate.queries.hbm.xml
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Event.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/GraphElement.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Node.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Transition.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/exe/ProcessInstance.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/Decision.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/ProcessFactory.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/TaskNode.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/instantiation/BeanInstantiator.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteActionJob.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteNodeJob.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/Timer.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/executor/JobExecutorThread.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/msg/db/DbMessageService.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/db/DbSchedulerService.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/def/CreateTimerAction.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/svc/Services.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskInstance.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskMgmtInstance.java
   jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/AllDbTests.java
Log:
[JBPM-1704] merged revisions 1475, 1477, 1483, 1484, 1558, 1829, 1938 and 1947 from https://svn.jboss.org/repos/jbpm/jbpm3/trunk/

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/JbpmContext.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/JbpmContext.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/JbpmContext.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -543,15 +543,13 @@
    */
   public ContextSession getContextSession() {
     PersistenceService persistenceService = getPersistenceService();
-    if (persistenceService==null) return null;
-    return persistenceService.getContextSession();
+    return persistenceService!=null ? persistenceService.getContextSession() : null;
   }
   /**
    * more logging related database access.
    */
   public LoggingSession getLoggingSession() {
     PersistenceService persistenceService = getPersistenceService();
-    if (persistenceService==null) return null;
     return (persistenceService!=null ? persistenceService.getLoggingSession() : null);
   }
   /**
@@ -559,7 +557,6 @@
    */
   public JobSession getJobSession() {
     PersistenceService persistenceService = getPersistenceService();
-    if (persistenceService==null) return null;
     return (persistenceService!=null ? persistenceService.getJobSession() : null);
   }
   /**
@@ -567,7 +564,6 @@
    */
   public GraphSession getGraphSession() {
     PersistenceService persistenceService = getPersistenceService();
-    if (persistenceService==null) return null;
     return (persistenceService!=null ? persistenceService.getGraphSession() : null);
   }
   /**
@@ -575,7 +571,6 @@
    */
   public TaskMgmtSession getTaskMgmtSession() {
     PersistenceService persistenceService = getPersistenceService();
-    if (persistenceService==null) return null;
     return (persistenceService!=null ? persistenceService.getTaskMgmtSession() : null);
   }
 
@@ -593,8 +588,7 @@
    */
   public void setActorId(String actorId) {
     DefaultAuthenticationService authenticationService = (DefaultAuthenticationService) services.getAuthenticationService();
-    DefaultAuthenticationService defaultAuthenticationService = (DefaultAuthenticationService) authenticationService;
-    defaultAuthenticationService.setActorId(actorId);
+    authenticationService.setActorId(actorId);
   }
 
   // private methods //////////////////////////////////////////////////////////

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/command/AbstractCancelCommand.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/command/AbstractCancelCommand.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/command/AbstractCancelCommand.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -21,8 +21,8 @@
   protected static final Log log = LogFactory.getLog(AbstractCancelCommand.class);
 
   protected void cancelTokens(Collection tokens) {
-    log.info("cancel " + tokens.size() + " tokens");
     if (tokens != null && tokens.size() > 0) {
+      log.info("cancel " + tokens.size() + " tokens");
       for (Iterator itr = tokens.iterator(); itr.hasNext();) {
         cancelToken((Token) itr.next());
       }
@@ -49,8 +49,8 @@
   }
 
   protected void cancelTasks(List tasks) {
-    log.info("cancel " + tasks.size() + " tasks");
     if (tasks != null && tasks.size() > 0) {
+      log.info("cancel " + tasks.size() + " tasks");
       for (Iterator it = tasks.iterator(); it.hasNext();) {
         TaskInstance ti = (TaskInstance) it.next();
 

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/JobSession.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/JobSession.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/JobSession.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -1,25 +1,23 @@
 package org.jbpm.db;
 
-import java.io.Serializable;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 
-import javax.transaction.Synchronization;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.hibernate.LockMode;
 import org.hibernate.Query;
 import org.hibernate.Session;
-import org.hibernate.Transaction;
+import org.jbpm.JbpmContext;
 import org.jbpm.JbpmException;
 import org.jbpm.graph.def.Action;
 import org.jbpm.graph.exe.ProcessInstance;
 import org.jbpm.graph.exe.Token;
 import org.jbpm.job.Job;
 import org.jbpm.job.Timer;
+import org.jbpm.svc.save.SaveOperation;
 
 public class JobSession {
 
@@ -155,60 +153,54 @@
 
   public void cancelTimersByName(String name, Token token) {
     try {
-      // the bulk delete was replaced with a query and session.deletes on 
-      // the retrieved elements to prevent stale object exceptions.  
-      // With a bulk delete, the hibernate session is not aware and gives a problem 
-      // if a later session.delete doesn't return 1.
-      Query query = session.getNamedQuery("JobSession.getTimersByName");
+      log.debug("canceling timers by name " + name + " for " + token);
+      Query query = session.getNamedQuery("JobSession.deleteTimersByName");
       query.setString("name", name);
       query.setParameter("token", token);
-      List results = query.list();
-      if (results!=null) {
-        Iterator iter = results.iterator();
-        while (iter.hasNext()) {
-          Timer timer = (Timer) iter.next();
-          log.debug("deleting timer "+timer+" by name "+name);
-          session.delete(timer);
-        }
-      }
-
+      int entityCount = query.executeUpdate();
+      log.debug(entityCount+" timers by name " + name + " for " + token + " were deleted");
     } catch (Exception e) {
       log.error(e);
-      throw new JbpmException("couldn't cancel timers '"+name+"' for '"+token+"'", e);
+      throw new JbpmException("couldn't cancel timers by name '"+name+"' for '"+token+"'", e);
     }
   }
 
-  private class DeleteJobsSynchronization implements Synchronization, Serializable {
+  private static class DeleteJobsOperation implements SaveOperation {
+
+    private ProcessInstance targetProcessInstance;
+
     private static final long serialVersionUID = 1L;
-    ProcessInstance processInstance;
-    public DeleteJobsSynchronization(ProcessInstance processInstance) {
-      this.processInstance = processInstance;
+
+    DeleteJobsOperation(ProcessInstance processInstance) {
+      targetProcessInstance = processInstance;
     }
-    public void beforeCompletion() {
-      log.debug("deleting timers for process instance "+processInstance);
+
+    public void save(ProcessInstance processInstance, JbpmContext jbpmContext) {
+      // avoid deleting jobs for process instances that did not request job deletion
+      if (!targetProcessInstance.equals(processInstance)) {
+        log.debug("forgiving " + processInstance + ", it is not the target of this operation");
+        return;
+      }
+
+      log.debug("deleting timers for "+processInstance);
+      Session session = jbpmContext.getSession();
       Query query = session.getNamedQuery("JobSession.deleteTimersForProcessInstance");
       query.setParameter("processInstance", processInstance);
-      int result = query.executeUpdate();
-      log.debug(Integer.toString(result)+" remaining timers for '"+processInstance+"' are deleted");
-      
-      log.debug("deleting execute-node-jobs for process instance "+processInstance);
+      int entityCount = query.executeUpdate();
+      log.debug(entityCount+" remaining timers for "+processInstance+" were deleted");
+
+      log.debug("deleting execute-node-jobs for "+processInstance);
       query = session.getNamedQuery("JobSession.deleteExecuteNodeJobsForProcessInstance");
       query.setParameter("processInstance", processInstance);
-      result = query.executeUpdate();
-      log.debug(Integer.toString(result)+" remaining execute-node-jobs for '"+processInstance+"' are deleted");
+      entityCount = query.executeUpdate();
+      log.debug(entityCount+" remaining execute-node-jobs for "+processInstance+" were deleted");
     }
-    public void afterCompletion(int arg0) {
-    }
+    
   }
 
   public void deleteJobsForProcessInstance(ProcessInstance processInstance) {
-    try {
-      Transaction transaction = session.getTransaction();
-      transaction.registerSynchronization(new DeleteJobsSynchronization(processInstance));
-    } catch (Exception e) {
-      log.error(e);
-      throw new JbpmException("couldn't delete jobs for '"+processInstance+"'", e);
-    }
+    SaveOperation operation = new DeleteJobsOperation(processInstance);
+    JbpmContext.getCurrentJbpmContext().getServices().addSaveOperation(operation);
   }
 
 

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/hibernate.queries.hbm.xml
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/hibernate.queries.hbm.xml	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/db/hibernate.queries.hbm.xml	2008-08-26 01:11:36 UTC (rev 2003)
@@ -304,13 +304,14 @@
       where job.token = :token
     ]]>
   </query>
-  
-  <query name="JobSession.getTimersByName">
+
+  <query name="JobSession.deleteTimersByName">
     <![CDATA[
-      select timer
-      from org.jbpm.job.Timer timer
+      delete from org.jbpm.job.Timer timer
       where timer.token = :token
         and timer.name = :name
+        and (timer.lockOwner is null
+         or timer.repeat is not null)
     ]]>
   </query>
 
@@ -318,13 +319,16 @@
     <![CDATA[
       delete from org.jbpm.job.Timer timer
       where timer.processInstance = :processInstance
+        and (timer.lockOwner is null
+         or timer.repeat is not null)
     ]]>
   </query>
 
   <query name="JobSession.deleteExecuteNodeJobsForProcessInstance">
     <![CDATA[
-      delete from org.jbpm.job.ExecuteNodeJob executeNodeJob
-      where executeNodeJob.processInstance = :processInstance
+      delete from org.jbpm.job.ExecuteNodeJob job
+      where job.processInstance = :processInstance
+        and job.lockOwner is null
     ]]>
   </query>
 

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Event.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Event.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Event.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -46,6 +46,7 @@
   public static final String EVENTTYPE_TASK_ASSIGN = "task-assign";
   public static final String EVENTTYPE_TASK_START = "task-start";
   public static final String EVENTTYPE_TASK_END = "task-end";
+  public static final String EVENTTYPE_TIMER_CREATE = "timer-create";
   public static final String EVENTTYPE_TIMER = "timer";
 
   long id = 0;

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/GraphElement.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/GraphElement.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/GraphElement.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -160,10 +160,7 @@
   // event handling ///////////////////////////////////////////////////////////
 
   public void fireEvent(String eventType, ExecutionContext executionContext) {
-    Token token = executionContext.getToken();
-
-    log.debug( "event '"+eventType+"' on '"+this+"' for '"+token+"'" );
-
+    log.debug( "event '"+eventType+"' on '"+this+"' for '"+executionContext.getToken()+"'" );
     try {
       executionContext.setEventSource(this);
       fireAndPropagateEvent(eventType, executionContext);

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Node.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Node.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Node.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -182,14 +182,10 @@
    */
   public String generateNextLeavingTransitionName() {
     String name = null;
-    if (leavingTransitions!=null) {
-      if (!containsName(leavingTransitions, null)) {
-        name = null;
-      } else {
-        int n = 1;
-        while (containsName(leavingTransitions, Integer.toString(n))) n++;
-        name = Integer.toString(n);
-      }
+    if (leavingTransitions!=null && containsName(leavingTransitions, null)) {
+      int n = 1;
+      while (containsName(leavingTransitions, Integer.toString(n))) n++;
+      name = Integer.toString(n);
     }
     return name;
   }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Transition.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Transition.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/def/Transition.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -154,8 +154,9 @@
   Node fireSuperStateEnterEvents(ExecutionContext executionContext) {
     // calculate the actual destinationNode node
     Node destination = to;
-    while (destination.isSuperStateNode()) {
-      destination = (Node) destination.getNodes().get(0);
+    while (destination != null && destination.isSuperStateNode()) {
+      List nodes = destination.getNodes();
+      destination = nodes != null && !nodes.isEmpty() ? (Node) nodes.get(0) : null;
     }
     
     if (destination==null) {

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/exe/ProcessInstance.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/exe/ProcessInstance.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/exe/ProcessInstance.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -448,6 +448,10 @@
     return EqualsUtil.equals(this, o);
   }
   
+  public String toString() {
+    return "ProcessInstance" + (key != null ? '(' + key + ')' : "@" + Integer.toHexString(hashCode()));
+  }
+  
   // getters and setters //////////////////////////////////////////////////////
 
   public long getId() {

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/Decision.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/Decision.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/Decision.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -109,11 +109,11 @@
           DecisionCondition decisionCondition = (DecisionCondition) iter.next();
           Object result = JbpmExpressionEvaluator.evaluate(decisionCondition.getExpression(), executionContext);
           if (Boolean.TRUE.equals(result)) {
+            String transitionName = decisionCondition.getTransitionName();
+            transition = getLeavingTransition(transitionName);
             if (transition!=null) {
               transition.removeConditionEnforcement();
             }
-            String transitionName = decisionCondition.getTransitionName();
-            transition = getLeavingTransition(transitionName);
           }
         }
         

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/ProcessFactory.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/ProcessFactory.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/ProcessFactory.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -62,8 +62,8 @@
     
     Node node = null;
     
-    String typeName = null;
-    String name = null;
+    String typeName;
+    String name;
     
     text = text.trim();
     int spaceIndex = text.indexOf(' ');

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/TaskNode.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/TaskNode.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/graph/node/TaskNode.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -41,11 +41,11 @@
   private static final long serialVersionUID = 1L;
 
   /**
-   * execution always continues, regardless wether tasks are created or still unfinished.
+   * execution always continues, regardless whether tasks are created or still unfinished.
    */
   public static final int SIGNAL_UNSYNCHRONIZED = 0;
   /**
-   * execution never continues, regardless wether tasks are created or still unfinished.
+   * execution never continues, regardless whether tasks are created or still unfinished.
    */
   public static final int SIGNAL_NEVER = 1;
   /**
@@ -55,12 +55,12 @@
   public static final int SIGNAL_FIRST = 2;
   /**
    * proceeds execution when the first task instance is completed.   
-   * when no tasks are created on entrance of this node, execution is continued.   
+   * when no tasks are created on entrance of this node, execution waits in the task node till tasks are created.   
    */
   public static final int SIGNAL_FIRST_WAIT = 3;
   /**
    * proceeds execution when the last task instance is completed.
-   * when no tasks are created on entrance of this node, execution waits in the task node till tasks are created.   
+   * when no tasks are created on entrance of this node, execution is continued.
    */
   public static final int SIGNAL_LAST = 4;
   /**
@@ -171,19 +171,17 @@
     }
 
     // check if we should continue execution
-    boolean continueExecution = false;
+    boolean continueExecution;
     switch (signal) {
       case SIGNAL_UNSYNCHRONIZED:
         continueExecution = true;
         break;
-      case SIGNAL_FIRST_WAIT:
-      case SIGNAL_LAST_WAIT:
-      case SIGNAL_NEVER:
-        continueExecution = false;
-        break;
       case SIGNAL_FIRST:
       case SIGNAL_LAST:
         continueExecution = tmi.getSignallingTasks(executionContext).isEmpty();
+        break;
+      default:
+        continueExecution = false;
     }
 
     if (continueExecution) {
@@ -213,14 +211,18 @@
   /////////////////////////////////////////////////////////////////////////////
 
   public boolean completionTriggersSignal(TaskInstance taskInstance) {
-    boolean completionTriggersSignal = false;
-    if ( (signal==SIGNAL_FIRST)
-         || (signal==SIGNAL_FIRST_WAIT) ) {
+    boolean completionTriggersSignal;
+    switch (signal) {
+    case SIGNAL_FIRST:
+    case SIGNAL_FIRST_WAIT:
       completionTriggersSignal = true;
-    } else if ( ( (signal==SIGNAL_LAST)
-                  || (signal==SIGNAL_LAST_WAIT) )
-                && (isLastToComplete(taskInstance) ) ){
-      completionTriggersSignal = true;
+      break;
+    case SIGNAL_LAST:
+    case SIGNAL_LAST_WAIT:
+      completionTriggersSignal = isLastToComplete(taskInstance);
+      break;
+    default:
+      completionTriggersSignal = false;
     }
     return completionTriggersSignal;
   }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/instantiation/BeanInstantiator.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/instantiation/BeanInstantiator.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/instantiation/BeanInstantiator.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -36,13 +36,13 @@
       
       // find the setter method
       Method method = findSetter(clazz, setterMethodName);
-      Class propertyType = method.getParameterTypes()[0];
 
       // if the setter method was found
       if (method!=null) {
         // make it accessible
         method.setAccessible(true);
         // invoke it
+        Class propertyType = method.getParameterTypes()[0];
         method.invoke(newInstance, new Object[]{ getValue(propertyType, propertyElement) });
       } else {
         log.error( "couldn't set property '"+propertyName+"' to value '"+propertyElement.asXML()+"'" );

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteActionJob.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteActionJob.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteActionJob.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -34,7 +34,7 @@
       action.execute(executionContext);
     }
 
-    jbpmContext.save(token);
+    jbpmContext.save(processInstance);
 
     return true;
   }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteNodeJob.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteNodeJob.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/ExecuteNodeJob.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -25,7 +25,7 @@
     token.unlock(this.toString());
     ExecutionContext executionContext = new ExecutionContext(token);
     node.execute(executionContext);
-    jbpmContext.save(token);
+    jbpmContext.save(processInstance);
     return true;
   }
   

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/Timer.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/Timer.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/Timer.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -1,7 +1,7 @@
 package org.jbpm.job;
 
-import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Date;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -18,6 +18,7 @@
 
   private static final long serialVersionUID = 1L;
 
+  private final static String dateFormat = "yyyy-MM-dd HH:mm:ss,SSS";
   static BusinessCalendar businessCalendar = new BusinessCalendar();
   
   String name;
@@ -34,8 +35,6 @@
   }
 
   public boolean execute(JbpmContext jbpmContext) throws Exception {
-    boolean deleteThisJob = true;
-
     ExecutionContext executionContext = new ExecutionContext(token);
     executionContext.setTimer(this);
 
@@ -51,7 +50,7 @@
     // then execute the action if there is one
     if (action!=null) {
       try {
-        log.debug("executing timer '"+this+"'");
+        log.debug("executing '"+this+"'");
         if (graphElement!=null) {
           graphElement.executeAction(action, executionContext);
         } else {
@@ -60,28 +59,19 @@
       } catch (Exception actionException) {
         // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
         log.warn("timer action threw exception", actionException);
-
-        // we put the exception in t
-        Exception t = actionException;
-        try {
-          // if there is a graphElement connected to this timer...
-          if (graphElement != null) {
+        // if there is a graphElement connected to this timer...
+        if (graphElement != null) {
+          try {
             // we give that graphElement a chance to catch the exception
             graphElement.raiseException(actionException, executionContext);
             log.debug("timer exception got handled by '"+graphElement+"'");
-            t = null;
+          } catch (Exception handlerException) {
+            // if the exception handler rethrows or the original exception results in a DelegationException...
+            throw handlerException;
           }
-        } catch (Exception rethrowOrDelegationException) {
-          // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
-          // if the exception handler rethrows or the original exception results in a DelegationException...
-          t = rethrowOrDelegationException;
+        } else {
+          throw actionException;
         }
-        
-        if (t!=null) {
-          // This is either the original exception wrapped as a delegation exception
-          // or an exception that was throws from an exception handler
-          throw t;
-        }
       }
     }
 
@@ -99,23 +89,19 @@
     
     // if repeat is specified, reschedule the job
     if (repeat!=null) {
-      deleteThisJob = false;
-
       // suppose that it took the timer runner thread a 
       // very long time to execute the timers.
       // then the repeat action dueDate could already have passed.
       while (dueDate.getTime()<=System.currentTimeMillis()) {
-        dueDate = businessCalendar
-              .add(dueDate, 
-                new Duration(repeat));
+        dueDate = businessCalendar.add(dueDate, new Duration(repeat));
       }
-      log.debug("updated timer for repetition '"+this+"' in '"+(dueDate.getTime()-System.currentTimeMillis())+"' millis");
-    } 
+      log.debug("updated '"+this+"' for repetition on '"+formatDueDate(dueDate)+"'");
+      return false;
+    }
     
-    return deleteThisJob;
+    return true;
   }
   
-  static DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss,SSS"); 
   public String toString() {
     StringBuffer buffer = new StringBuffer();
     buffer.append("timer");
@@ -126,20 +112,23 @@
         buffer.append(name).append(",");
       }
       if (dueDate!=null) {
-          buffer.append(dateFormat.format(dueDate)).append(",");
+        buffer.append(formatDueDate(dueDate)).append(",");
       }
       if (taskInstance!=null)
-        buffer.append("TaskInstance: ").append(taskInstance.getId()).append(",");
+        buffer.append(taskInstance).append(",");
       if (token!=null)
-        buffer.append("Token: ").append(token.getId());
+        buffer.append(token);
       else if (processInstance!=null)
-        buffer.append("ProcessInstance: ").append(processInstance.getId());
+        buffer.append(processInstance);
 
       buffer.append(")");
     }
     return buffer.toString();
   }
 
+  public static String formatDueDate(Date date) {
+    return new SimpleDateFormat(dateFormat).format(date);
+  }
   
   public String getRepeat() {
     return repeat;

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/executor/JobExecutorThread.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/executor/JobExecutorThread.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/job/executor/JobExecutorThread.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -2,7 +2,6 @@
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -19,6 +18,7 @@
 import org.jbpm.job.Timer;
 import org.jbpm.persistence.JbpmPersistenceException;
 import org.jbpm.persistence.db.StaleObjectLogConfigurer;
+import org.jbpm.svc.Services;
 
 public class JobExecutorThread extends Thread {
 
@@ -36,77 +36,71 @@
     this.idleInterval = idleInterval;
     this.maxIdleInterval = maxIdleInterval;
     this.maxLockTime = maxLockTime;
-    this.maxHistory = maxHistory;
   }
 
-  JobExecutor jobExecutor; 
-  JbpmConfiguration jbpmConfiguration;
-  int idleInterval;
-  int maxIdleInterval;
-  long maxLockTime;
-  int maxHistory;
+  final JobExecutor jobExecutor; 
+  final JbpmConfiguration jbpmConfiguration;
+  final int idleInterval;
+  final int maxIdleInterval;
+  final long maxLockTime;
 
-  Collection history = new ArrayList();
   int currentIdleInterval;
   volatile boolean isActive = true;
 
   public void run() {
-    try {
-      currentIdleInterval = idleInterval;
-      while (isActive) {
-        try {
-          Collection acquiredJobs = acquireJobs();
+    currentIdleInterval = idleInterval;
+    while (isActive) {
+      try {
+        Collection acquiredJobs = acquireJobs();
 
-          if (! acquiredJobs.isEmpty()) {
-            Iterator iter = acquiredJobs.iterator();
-            while (iter.hasNext() && isActive) {
-              Job job = (Job) iter.next();
-              executeJob(job);
-            }
+        if (! acquiredJobs.isEmpty()) {
+          Iterator iter = acquiredJobs.iterator();
+          while (iter.hasNext() && isActive) {
+            Job job = (Job) iter.next();
+            executeJob(job);
+          }
 
-          } else { // no jobs acquired
-            if (isActive) {
-              long waitPeriod = getWaitPeriod();
-              if (waitPeriod>0) {
-                synchronized(jobExecutor) {
-                  jobExecutor.wait(waitPeriod);
-                }
+        } else { // no jobs acquired
+          if (isActive) {
+            long waitPeriod = getWaitPeriod();
+            if (waitPeriod>0) {
+              synchronized(jobExecutor) {
+                jobExecutor.wait(waitPeriod);
               }
             }
           }
-          
-          // no exception so resetting the currentIdleInterval
-          currentIdleInterval = idleInterval;
+        }
+        
+        // no exception so resetting the currentIdleInterval
+        currentIdleInterval = idleInterval;
 
-        } catch (InterruptedException e) {
-          log.info((isActive? "active" : "inactive")+" job executor thread '"+getName()+"' got interrupted");
-        } catch (Exception e) {
-          log.error("exception in job executor thread. waiting "+currentIdleInterval+" milliseconds", e);
-          try {
-            synchronized(jobExecutor) {
-              jobExecutor.wait(currentIdleInterval);
-            }
-          } catch (InterruptedException e2) {
-            log.debug("delay after exception got interrupted", e2);
+      } catch (InterruptedException e) {
+        log.info((isActive? "active" : "inactive")+" job executor thread '"+getName()+"' got interrupted");
+      } catch (Exception e) {
+        log.error("exception in job executor thread. waiting "+currentIdleInterval+" milliseconds", e);
+        try {
+          synchronized(jobExecutor) {
+            jobExecutor.wait(currentIdleInterval);
           }
-          // after an exception, the current idle interval is doubled to prevent 
-          // continuous exception generation when e.g. the db is unreachable
-          currentIdleInterval = currentIdleInterval*2;
+        } catch (InterruptedException e2) {
+          log.debug("delay after exception got interrupted", e2);
         }
+        // after an exception, the current idle interval is doubled to prevent 
+        // continuous exception generation when e.g. the db is unreachable
+        currentIdleInterval <<= 1;
+        if (currentIdleInterval > maxIdleInterval || currentIdleInterval < 0) {
+          currentIdleInterval = maxIdleInterval;
+        }
       }
-    } catch (Exception e) {
-      // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
-      log.error("exception in job executor thread", e);
-    } finally {
-      log.info(getName()+" leaves cyberspace");
     }
+    log.info(getName()+" leaves cyberspace");
   }
 
   protected Collection acquireJobs() {
     Collection acquiredJobs;
     synchronized (jobExecutor) {
-      Collection jobsToLock = new ArrayList();
       log.debug("acquiring jobs for execution...");
+      Collection jobsToLock = Collections.EMPTY_LIST;
       JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
       try {
         JobSession jobSession = jbpmContext.getJobSession();
@@ -116,11 +110,11 @@
           if (job.isExclusive()) {
             log.debug("exclusive acquirable job found ("+job+"). querying for other exclusive jobs to lock them all in one tx...");
             List otherExclusiveJobs = jobSession.findExclusiveJobs(getName(), job.getProcessInstance());
-            jobsToLock.addAll(otherExclusiveJobs);
+            jobsToLock = otherExclusiveJobs;
             log.debug("trying to obtain a process-instance exclusive locks for '"+otherExclusiveJobs+"'");
           } else {
             log.debug("trying to obtain a lock for '"+job+"'");
-            jobsToLock.add(job);
+            jobsToLock = Collections.singletonList(job);
           }
           
           Iterator iter = jobsToLock.iterator();
@@ -145,17 +139,13 @@
           log.debug("obtained lock on jobs: "+acquiredJobs);
         }
         catch (JbpmPersistenceException e) {
-          // if this is a stale object exception, the jbpm configuration has control over the logging
-          if ("org.hibernate.StaleObjectStateException".equals(e.getCause().getClass().getName())) {
-            log.info("problem committing job acquisition transaction: optimistic locking failed");
-            StaleObjectLogConfigurer.staleObjectExceptionsLog.error("problem committing job acquisition transaction: optimistic locking failed", e);
+          // if this is a stale object exception, keep it quiet
+          if (Services.isCausedByStaleState(e)) {
+            log.debug("optimistic locking failed, couldn't obtain lock on jobs: "+jobsToLock);
+            acquiredJobs = Collections.EMPTY_LIST;
           } else {
-            // TODO run() will log this exception, log it here too?
-            log.error("problem committing job acquisition transaction", e);
             throw e;
           }
-          acquiredJobs = Collections.EMPTY_LIST;
-          log.debug("couldn't obtain lock on jobs: "+jobsToLock); 
         }
       }
     }
@@ -173,7 +163,6 @@
         if (job.execute(jbpmContext)) {
           jobSession.deleteJob(job);
         }
-
       } catch (Exception e) {
         log.debug("exception while executing '"+job+"'", e);
         StringWriter sw = new StringWriter();
@@ -187,7 +176,6 @@
       if (totalLockTimeInMillis>maxLockTime) {
         jbpmContext.setRollbackOnly();
       }
-
     } finally {
       try {
         jbpmContext.close();

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/msg/db/DbMessageService.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/msg/db/DbMessageService.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/msg/db/DbMessageService.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -37,9 +37,8 @@
   
   private static final long serialVersionUID = 1L;
 
-  JbpmConfiguration jbpmConfiguration;
   JobSession jobSession = null;
-  Collection destinations = null;
+  JobExecutor jobExecutor = null;
   boolean hasProducedJobs = false;
   
   public DbMessageService() {
@@ -47,8 +46,8 @@
     if (jbpmContext==null) {
       throw new JbpmException("instantiation of the DbMessageService requires a current JbpmContext");
     }
-    this.jbpmConfiguration = jbpmContext.getJbpmConfiguration();
-    this.jobSession = jbpmContext.getJobSession();
+    jobSession = jbpmContext.getJobSession();
+    jobExecutor = jbpmContext.getJbpmConfiguration().getJobExecutor();
   }
 
   public void send(Job job) {
@@ -58,11 +57,10 @@
   }
 
   public void close() {
-    JobExecutor jobExecutor = jbpmConfiguration.getJobExecutor();
     if ( (hasProducedJobs)
          && (jobExecutor!=null)
        ) {
-      log.debug("messages were produced the jobExecutor will be signalled");
+      log.debug("messages were produced, job executor will be signalled");
       synchronized(jobExecutor) {
         jobExecutor.notify();
       }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/db/DbSchedulerService.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/db/DbSchedulerService.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/db/DbSchedulerService.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -21,26 +21,39 @@
  */
 package org.jbpm.scheduler.db;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.jbpm.JbpmContext;
 import org.jbpm.JbpmException;
 import org.jbpm.db.JobSession;
 import org.jbpm.graph.exe.ProcessInstance;
 import org.jbpm.graph.exe.Token;
 import org.jbpm.job.Timer;
+import org.jbpm.job.executor.JobExecutor;
 import org.jbpm.scheduler.SchedulerService;
 
 public class DbSchedulerService implements SchedulerService {
 
   private static final long serialVersionUID = 1L;
+
+  private static final Log log = LogFactory.getLog(DbSchedulerService.class);
   
   JobSession jobSession = null;
-  
+  JobExecutor jobExecutor = null;
+  boolean hasProducedJobs = false;
+
   public DbSchedulerService() {
-    this.jobSession = JbpmContext.getCurrentJbpmContext().getJobSession();
+    JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();
+    if (jbpmContext==null) {
+      throw new JbpmException("instantiation of the DbSchedulerService requires a current JbpmContext");
+    }
+    this.jobSession = jbpmContext.getJobSession();
+    this.jobExecutor = jbpmContext.getJbpmConfiguration().getJobExecutor();
   }
   
   public void createTimer(Timer timerJob) {
     jobSession.saveJob(timerJob);
+    hasProducedJobs = true;
   }
 
   public void deleteTimersByName(String timerName, Token token) {
@@ -55,5 +68,11 @@
   }
 
   public void close() {
+    if (hasProducedJobs && jobExecutor != null) {
+      log.debug("timers were produced, job executor will be signalled");
+      synchronized (jobExecutor) {
+        jobExecutor.notify();
+      }
+    }
   }
 }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/def/CreateTimerAction.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/def/CreateTimerAction.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/scheduler/def/CreateTimerAction.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -29,6 +29,7 @@
 import org.jbpm.calendar.BusinessCalendar;
 import org.jbpm.calendar.Duration;
 import org.jbpm.graph.def.Action;
+import org.jbpm.graph.def.Event;
 import org.jbpm.graph.def.GraphElement;
 import org.jbpm.graph.exe.ExecutionContext;
 import org.jbpm.job.Timer;
@@ -133,7 +134,7 @@
       try {
         executionContext.setTimer(timer);
         // fire the create timer event on the same graph element
-        graphElement.fireEvent("timer-create", executionContext);
+        graphElement.fireEvent(Event.EVENTTYPE_TIMER_CREATE, executionContext);
       } finally {
         executionContext.setTimer(null);
       }

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/svc/Services.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/svc/Services.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/svc/Services.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -23,6 +23,7 @@
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -30,6 +31,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.hibernate.StaleStateException;
 import org.jbpm.JbpmContext;
 import org.jbpm.JbpmException;
 import org.jbpm.graph.exe.ProcessInstance;
@@ -62,16 +64,18 @@
   public static final String SERVICENAME_JCR             = "jcr";
   public static final String SERVICENAME_ADDRESSRESOLVER = "addressresolver";
 
-  static final List defaultSaveOperations = new ArrayList();
+  static final List defaultSaveOperations = createDefaultSaveOperations();
 
-  static {
-    defaultSaveOperations.add(new CheckUnpersistableVariablesOperation());
+  private static List createDefaultSaveOperations() {
+    SaveOperation[] operations = new SaveOperation[4];
+    operations[0] = new CheckUnpersistableVariablesOperation();
     // first we save the runtime data (process instance)
-    defaultSaveOperations.add(new HibernateSaveOperation());
+    operations[1] = new HibernateSaveOperation();
     // then we insert the logs cause the logs can have references 
     // to the runtime data
-    defaultSaveOperations.add(new SaveLogsOperation());
-    defaultSaveOperations.add(new CascadeSaveOperation());
+    operations[2] = new SaveLogsOperation();
+    operations[3] = new CascadeSaveOperation();
+    return Arrays.asList(operations);
   }
 
   Map serviceFactories = null;
@@ -80,7 +84,7 @@
   List saveOperations = null;
   
   public static Service getCurrentService(String name) {
-   return getCurrentService(name, true); 
+    return getCurrentService(name, true); 
   }
   
   public static Service getCurrentService(String name, boolean isRequired) {
@@ -102,17 +106,26 @@
   public Services(Map serviceFactories, List serviceNames, List saveOperations) {
     this.serviceFactories = serviceFactories;
     this.serviceNames = serviceNames;
-    if (saveOperations!=null) {
-      this.saveOperations = saveOperations;
-    } else {
-      this.saveOperations = defaultSaveOperations;
-    }
+    this.saveOperations = saveOperations != null ? saveOperations : defaultSaveOperations;
   }
 
   public void setSaveOperations(List saveOperations) {
+    if (saveOperations == null) {
+      throw new IllegalArgumentException("saveOperations cannot be null");
+    }
     this.saveOperations = saveOperations;
   }
 
+  public void addSaveOperation(SaveOperation saveOperation) {
+    if (saveOperation == null) {
+      throw new IllegalArgumentException("saveOperation cannot be null");
+    }
+    if (saveOperations == defaultSaveOperations) {
+      saveOperations = new ArrayList(defaultSaveOperations);
+    }
+    saveOperations.add(saveOperation);
+  }
+
   public Map getServiceFactories() {
     if (serviceFactories==null) {
       serviceFactories = new HashMap();
@@ -222,8 +235,8 @@
             log.debug("closing service '"+serviceName+"': "+service);
             service.close();
           } catch (JbpmPersistenceException e) {
-            // if this is a stale object exception, the jbpm configuration has control over the logging
-            if ("org.hibernate.StaleObjectStateException".equals(e.getCause().getClass().getName())) {
+            // if this is a stale state exception, the jbpm configuration has control over the logging
+            if (isCausedByStaleState(e)) {
               log.info("problem closing service '"+serviceName+"': optimistic locking failed");
               StaleObjectLogConfigurer.staleObjectExceptionsLog.error("problem closing service '"+serviceName+"': optimistic locking failed", e);
             } else {
@@ -251,6 +264,14 @@
     }
   }
 
+  public static boolean isCausedByStaleState(JbpmPersistenceException persistenceException) {
+    for (Throwable cause = persistenceException.getCause(); cause != null; cause = cause.getCause()) {
+      if (cause instanceof StaleStateException)
+        return true;
+    }
+    return false;
+  }
+
   public static void assignId(Object object) {
     JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();
     if (jbpmContext!=null) {

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskInstance.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskInstance.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskInstance.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -41,7 +41,6 @@
 import org.jbpm.graph.exe.ExecutionContext;
 import org.jbpm.graph.exe.ProcessInstance;
 import org.jbpm.graph.exe.Token;
-import org.jbpm.graph.node.TaskNode;
 import org.jbpm.security.SecurityHelper;
 import org.jbpm.taskmgmt.def.Swimlane;
 import org.jbpm.taskmgmt.def.Task;
@@ -103,14 +102,7 @@
     this.task = task;
     this.isBlocking = task.isBlocking();
     this.priority = task.getPriority();
-    if (task.getTaskNode()!=null) {
-      int signal = task.getTaskNode().getSignal();
-      this.isSignalling = ( (signal==TaskNode.SIGNAL_FIRST ) 
-                            || (signal==TaskNode.SIGNAL_LAST ) 
-                            || (signal==TaskNode.SIGNAL_FIRST_WAIT ) 
-                            || (signal==TaskNode.SIGNAL_LAST_WAIT ) 
-                          );
-    }
+    this.isSignalling = task.isSignalling();
   }
   
   void submitVariables() {
@@ -562,7 +554,7 @@
   }
   
   public String toString() {
-    return "TaskInstance"+(name!=null ? "["+name+"]" : Integer.toHexString(System.identityHashCode(this)));
+    return "TaskInstance"+(name!=null ? "("+name+")" : "@"+Integer.toHexString(hashCode()));
   }
 
   // private //////////////////////////////////////////////////////////////////
@@ -577,7 +569,7 @@
         pooledActor.addTaskInstance(this);
       }
     } else {
-      pooledActors = null;
+      this.pooledActors = null;
     }
   }
   

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskMgmtInstance.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskMgmtInstance.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/main/java/org/jbpm/taskmgmt/exe/TaskMgmtInstance.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -109,8 +109,6 @@
 
     // bind the task instance to the TaskMgmtInstance
     addTaskInstance(taskInstance);
-    // ... add a reference to the process instance
-    taskInstance.setProcessInstance(executionContext.getProcessInstance());
 
     // initialize the task instance
     if (task!=null) taskInstance.setTask(task);
@@ -119,6 +117,7 @@
     Services.assignId(taskInstance);
 
     // copy the task properties
+    /* XXX property initialization was already done in taskInstance.setTask(task)
     String description = null;
     if (task!=null) {
       description = task.getDescription();
@@ -126,50 +125,50 @@
       taskInstance.setBlocking(task.isBlocking());
       taskInstance.setSignalling(task.isSignalling());
     }
+    */
 
     if (executionContext!=null) {
       Token token = executionContext.getToken();
       taskInstance.setToken(token);
+      taskInstance.setProcessInstance(token.getProcessInstance());
       
       taskInstance.initializeVariables();
       
       if (task != null && task.getDueDate()!=null) {
-        Date baseDate = null;
-        Date dueDateDate = null;
-        String dueDate = task.getDueDate();
+        Date baseDate;
+        String dueDateString = task.getDueDate();
         String durationString = null;
-        String durationSeparator = null;
         
-        if (dueDate.startsWith("#")) {
-          String baseDateEL = dueDate.substring(0,dueDate.indexOf("}")+1);
-          Object o = JbpmExpressionEvaluator.evaluate(baseDateEL, executionContext);
-          if (o instanceof Date) {
-            baseDate = (Date) o;          
+        if (dueDateString.startsWith("#")) {
+          String baseDateEL = dueDateString.substring(0,dueDateString.indexOf("}")+1);
+          Object result = JbpmExpressionEvaluator.evaluate(baseDateEL, executionContext);
+          if (result instanceof Date) {
+            baseDate = (Date) result;          
+          } else if (result instanceof Calendar) {
+            baseDate = ((Calendar) result).getTime();
           } else {
-            if (o instanceof Calendar) {
-              baseDate = ((Calendar) o).getTime();
-            } else {
-              throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + o.getClass().getName() +". Only Date and Calendar are supported");
-            }
+            throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + result.getClass().getName() +". Only Date and Calendar are supported");
           }
-          int endOfELIndex = dueDate.indexOf("}");
-          if (endOfELIndex < (dueDate.length() -1) ) {
-            durationSeparator = dueDate.substring(endOfELIndex+1).trim().substring(0,1);
-            if ( !(durationSeparator.equals("+") || durationSeparator.equals("-") ) ){ 
+          int endOfELIndex = dueDateString.indexOf("}");
+          if (endOfELIndex < (dueDateString.length() -1) ) {
+            char durationSeparator = dueDateString.substring(endOfELIndex+1).trim().charAt(0);
+            if (durationSeparator != '+' && durationSeparator != '-'){ 
               throw new JbpmException("Invalid duedate, + or - missing after EL");
             }
-            durationString = dueDate.substring(endOfELIndex+1).trim();
+            durationString = dueDateString.substring(endOfELIndex+1).trim();
           }
         } else {
-          durationString = dueDate;
+          baseDate = Clock.getCurrentTime();
+          durationString = dueDateString;
         }
-        if (baseDate != null && (durationString == null || "".equals(durationString))) {
-          dueDateDate = baseDate;
+        Date dueDate;
+        if (durationString == null || durationString.length() == 0) {
+          dueDate = baseDate;
         } else {
           BusinessCalendar businessCalendar = new BusinessCalendar(); 
-          dueDateDate = businessCalendar.add( (baseDate != null) ? baseDate : Clock.getCurrentTime(), new Duration(durationString) );
+          dueDate = businessCalendar.add(baseDate, new Duration(durationString) );
         }        
-        taskInstance.setDueDate(dueDateDate); 
+        taskInstance.setDueDate(dueDate); 
       }
       
       
@@ -180,12 +179,15 @@
         executionContext.setEventSource(task);
 
         // evaluate the description
-        if ( (description!=null) 
-             && (description.indexOf("#{")!=-1)
-           ) {
-          Object result = JbpmExpressionEvaluator.evaluate(description, executionContext);
-          if (result!=null) {
-            taskInstance.setDescription(result.toString());
+        if (task != null) {
+          String description = task.getDescription();
+          if ( (description!=null) 
+              && (description.indexOf("#{")!=-1)
+          ) {
+            Object result = JbpmExpressionEvaluator.evaluate(description, executionContext);
+            if (result!=null) {
+              taskInstance.setDescription(result.toString());
+            }
           }
         }
 

Modified: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/AllDbTests.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/AllDbTests.java	2008-08-26 01:03:36 UTC (rev 2002)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/AllDbTests.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -34,6 +34,7 @@
 import org.jbpm.graph.exe.GraphExeDbTests;
 import org.jbpm.graph.log.GraphLogDbTests;
 import org.jbpm.graph.node.GraphNodeDbTests;
+import org.jbpm.job.executor.JobExecutorDbTests;
 import org.jbpm.jpdl.el.JpdlElDbTests;
 import org.jbpm.jpdl.exe.JpdlExeDbTests;
 import org.jbpm.jpdl.par.JpdlParDbTests;
@@ -62,6 +63,7 @@
       suite.addTest(GraphExeDbTests.suite());
       suite.addTest(GraphLogDbTests.suite());
       suite.addTest(GraphNodeDbTests.suite());
+      suite.addTest(JobExecutorDbTests.suite());
       suite.addTest(JpdlElDbTests.suite());
       suite.addTest(JpdlExeDbTests.suite());
       suite.addTest(JpdlParDbTests.suite());

Added: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/NoJobExecutorDbTest.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/NoJobExecutorDbTest.java	                        (rev 0)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/NoJobExecutorDbTest.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -0,0 +1,62 @@
+/*
+ * 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.job.executor;
+
+import junit.framework.TestCase;
+
+import org.jbpm.JbpmConfiguration;
+import org.jbpm.JbpmContext;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+
+/**
+ * Test case or JBPM-1452
+ * @author Alejandro Guizar
+ */
+public class NoJobExecutorDbTest extends TestCase {
+
+  private JbpmContext jbpmContext;
+
+  private static JbpmConfiguration jbpmConfiguration = JbpmConfiguration.parseXmlString(
+      "<jbpm-configuration>" +
+      "  <null name='jbpm.job.executor' />" +
+      "</jbpm-configuration>");
+
+  protected void setUp() throws Exception {
+    jbpmConfiguration.createSchema();
+    jbpmContext = jbpmConfiguration.createJbpmContext();
+  }
+
+  protected void tearDown() throws Exception {
+    jbpmContext.close();
+    jbpmConfiguration.dropSchema();
+  }
+
+  public void testJobExecutorDoesNotExist() {
+    // check the job executor is properly nullified
+    assertNull(jbpmContext.getObjectFactory().createObject("jbpm.job.executor"));
+    // start and end a process instance, confirm no exception gets thrown
+    jbpmContext.deployProcessDefinition(new ProcessDefinition("Audit"));
+    ProcessInstance processInstance = jbpmContext.newProcessInstanceForUpdate("Audit");
+    processInstance.end();
+  }
+}

Added: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/TimerOnTimerDbTest.java
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/TimerOnTimerDbTest.java	                        (rev 0)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/TimerOnTimerDbTest.java	2008-08-26 01:11:36 UTC (rev 2003)
@@ -0,0 +1,144 @@
+/*
+ * 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.job.executor;
+
+import java.io.Serializable;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jbpm.db.AbstractDbTestCase;
+import org.jbpm.graph.def.Event;
+import org.jbpm.graph.def.ProcessDefinition;
+import org.jbpm.graph.exe.ProcessInstance;
+
+/**
+ * Test case for JBPM-1135
+ * @author Alejandro Guizar
+ */
+public class TimerOnTimerDbTest extends AbstractDbTestCase {
+
+  public void testTimerOnTimer() {
+    ProcessDefinition processDefinition = ProcessDefinition.parseXmlResource("org/jbpm/job/executor/timerOnTimer.jpdl.xml");
+    jbpmContext.deployProcessDefinition(processDefinition);
+
+    ProcessInstance processInstance = jbpmContext.newProcessInstanceForUpdate("timerTest");
+    processInstance.getContextInstance().setVariable("testCallback", new TestCallback());
+    processInstance.signal();
+    assertEquals("firstNode", processInstance.getRootToken().getNode().getName());
+    commitAndCloseSession();
+
+    startJobExecutor();
+    try {
+      TestCallback.waitForEvent(Event.EVENTTYPE_NODE_ENTER);
+      beginSessionTransaction();
+      long processInstanceId = processInstance.getId();
+      assertEquals("secondNode", jbpmContext.loadProcessInstance(processInstanceId)
+          .getRootToken()
+          .getNode()
+          .getName());
+      commitAndCloseSession();
+
+      TestCallback.waitForEvent(Event.EVENTTYPE_PROCESS_END);
+      beginSessionTransaction();
+      assertTrue(jbpmContext.loadProcessInstance(processInstanceId).hasEnded());
+    }
+    finally {
+      stopJobExecutor();
+    }
+  }
+
+  public static class TestCallback implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private static final Log log = LogFactory.getLog(TestCallback.class);
+
+    public void processStart() {
+      registerNotification(Event.EVENTTYPE_PROCESS_START);
+    }
+
+    public void processEnd() {
+      registerNotification(Event.EVENTTYPE_PROCESS_END);
+    }
+
+    public void nodeEnter() {
+      registerNotification(Event.EVENTTYPE_NODE_ENTER);
+    }
+
+    public void nodeLeave() {
+      registerNotification(Event.EVENTTYPE_NODE_LEAVE);
+    }
+
+    public void taskCreate() {
+      registerNotification(Event.EVENTTYPE_TASK_CREATE);
+    }
+
+    public void taskEnd() {
+      registerNotification(Event.EVENTTYPE_TASK_END);
+    }
+
+    public void timerCreate() {
+      registerNotification(Event.EVENTTYPE_TIMER_CREATE);
+    }
+
+    public void timer() {
+      registerNotification(Event.EVENTTYPE_TIMER);
+    }
+
+    private static void registerNotification(final String event) {
+      Synchronization notification = new Synchronization() {
+
+        public void beforeCompletion() {
+          // nothing to do here
+        }
+
+        public void afterCompletion(int status) {
+          if (status == Status.STATUS_COMMITTED) {
+            log.info("delivering " + event + " notification");
+            synchronized (event) {
+              event.notify();
+            }
+          }
+        }
+
+      };
+      jbpmConfiguration.getCurrentJbpmContext()
+          .getSession()
+          .getTransaction()
+          .registerSynchronization(notification);
+    }
+
+    public static void waitForEvent(String event) {
+      synchronized (event) {
+        try {
+          event.wait(60000);
+        }
+        catch (InterruptedException e) {
+          // reassert interruption
+          Thread.currentThread().interrupt();
+        }
+      }
+    }
+  }
+}

Added: jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/timerOnTimer.jpdl.xml
===================================================================
--- jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/timerOnTimer.jpdl.xml	                        (rev 0)
+++ jbpm3/branches/jpdl-3.2.3.GA_JBPM-1704/jpdl/jar/src/test/java/org/jbpm/job/executor/timerOnTimer.jpdl.xml	2008-08-26 01:11:36 UTC (rev 2003)
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<process-definition name="timerTest" xmlns="urn:jbpm.org:jpdl-3.2"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="urn:jbpm.org:jpdl-3.2 http://jbpm.org/xsd/jpdl-3.2.xsd">
+
+  <event type="process-start">
+    <action expression="#{testCallback.processStart}"/>
+  </event>
+  <event type="process-end">
+    <action expression="#{testCallback.processEnd}"/>
+  </event>
+  <event type="node-enter">
+    <action expression="#{testCallback.nodeEnter}" />
+  </event>
+  <event type="node-leave">
+    <action expression="#{testCallback.nodeLeave}" />
+  </event>
+  <event type="task-create">
+    <action expression="#{testCallback.taskCreate}" />
+  </event>
+  <event type="task-end">
+    <action expression="#{testCallback.taskEnd}" />
+  </event>
+  <event type="timer-create">
+    <action expression="#{testCallback.timerCreate}" />
+  </event>
+  <event type="timer">
+    <action expression="#{testCallback.timer}"/>
+  </event>
+
+  <start-state name="start">
+    <transition name="doneStart" to="firstNode" />
+  </start-state>
+
+  <task-node name="firstNode" end-tasks="yes">
+    <task name="firstTask">
+      <assignment actor-id="admin" />
+      <timer duedate="1 second" transition="doneFirst" />
+    </task>
+    <transition name="doneFirst" to="secondNode" />
+  </task-node>
+
+  <task-node name="secondNode" end-tasks="yes">
+    <task name="secondTask">
+      <assignment actor-id="admin" />
+      <timer duedate="1 second" transition="doneSecond" />
+    </task>
+    <transition name="doneSecond" to="end" />
+  </task-node>
+
+  <end-state name="end" />
+
+</process-definition>
\ No newline at end of file




More information about the jbpm-commits mailing list