[jboss-svn-commits] JBL Code SVN: r22897 - in labs/jbossrules/trunk: drools-compiler/src/main/java/org/drools/xml and 18 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Sep 18 18:50:24 EDT 2008


Author: KrisVerlaenen
Date: 2008-09-18 18:50:23 -0400 (Thu, 18 Sep 2008)
New Revision: 22897

Added:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/EventBasedNodeBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerHandler.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerInstance.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/EventBasedNodeWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimerDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersCellEditor.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersPropertyDescriptor.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ExtendedNodeBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ProcessNodeBuilderRegistry.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/ProcessSemanticModule.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/AbstractNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ActionNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ConstraintHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/MilestoneNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/RuleSetNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SplitNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SubProcessNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/WorkItemNodeHandler.java
   labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-processes-4.0.xsd
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessMarchallingTest.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessTimerTest.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/xml/processes/XMLPersistenceTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/InputMarshaller.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/OutputMarshaller.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/timer/Timer.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerListener.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerManager.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/impl/ExtendedNodeImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/EventBasedNode.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/EventBasedNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/MilestoneNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/TimerNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/TimerTest.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditBeanDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditMapDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/MapItemDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/AbstractNodeWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/ExtendedNodeWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/HumanTaskNodeWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/MilestoneWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/RuleSetNodeWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SplitWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SubProcessWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/WorkItemWrapper.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlerDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlersDialog.java
   labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/variable/VariableDialog.java
Log:
 - Improved on-entry and on-exit support for nodes
JBRULES-1711: Timers for nodes
 - Allow nodes to have on-entry timers that are automatically deactivated if the node is left
 - Split Timer in definition part (Timer) and runtime part (TimerInstance)


Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/EventBasedNodeBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/EventBasedNodeBuilder.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/EventBasedNodeBuilder.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,28 @@
+package org.drools.process.builder;
+
+import java.util.Map;
+
+import org.drools.lang.descr.ProcessDescr;
+import org.drools.process.core.Process;
+import org.drools.process.core.timer.Timer;
+import org.drools.rule.builder.ProcessBuildContext;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.Node;
+import org.drools.workflow.core.node.EventBasedNode;
+
+public class EventBasedNodeBuilder extends ExtendedNodeBuilder {
+
+    public void build(Process process,
+                      ProcessDescr processDescr,
+                      ProcessBuildContext context,
+                      Node node) {
+        super.build(process, processDescr, context, node);
+        Map<Timer, DroolsAction> timers = ((EventBasedNode) node).getTimers();
+        if (timers != null) {
+	        for (DroolsAction action: timers.values()) {
+	        	buildAction(action, context);
+	        }
+        }
+    }
+    
+}

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ExtendedNodeBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ExtendedNodeBuilder.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ExtendedNodeBuilder.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -25,14 +25,18 @@
         	List<DroolsAction> actions = extendedNode.getActions(type);
         	if (actions != null) {
 	        	for (DroolsAction droolsAction: actions) {
-	                DroolsConsequenceAction action = (DroolsConsequenceAction) droolsAction;
-	                ActionDescr actionDescr = new ActionDescr();
-	                actionDescr.setText( action.getConsequence() );   
-	                Dialect dialect = context.getDialectRegistry().getDialect( action.getDialect() );            
-	                dialect.getActionBuilder().build( context, action, actionDescr );
+	                buildAction(droolsAction, context);
 	        	}
         	}
         }
     }
+    
+    protected void buildAction(DroolsAction droolsAction, ProcessBuildContext context) {
+    	DroolsConsequenceAction action = (DroolsConsequenceAction) droolsAction;
+        ActionDescr actionDescr = new ActionDescr();
+        actionDescr.setText( action.getConsequence() );   
+        Dialect dialect = context.getDialectRegistry().getDialect( action.getDialect() );            
+        dialect.getActionBuilder().build( context, action, actionDescr );
+    }
 
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ProcessNodeBuilderRegistry.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ProcessNodeBuilderRegistry.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/process/builder/ProcessNodeBuilderRegistry.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -7,6 +7,7 @@
 import org.drools.workflow.core.node.ActionNode;
 import org.drools.workflow.core.node.EndNode;
 import org.drools.workflow.core.node.FaultNode;
+import org.drools.workflow.core.node.HumanTaskNode;
 import org.drools.workflow.core.node.MilestoneNode;
 import org.drools.workflow.core.node.RuleSetNode;
 import org.drools.workflow.core.node.Split;
@@ -26,13 +27,15 @@
         register( EndNode.class,
                   new ExtendedNodeBuilder() );
         register( MilestoneNode.class,
-                  new ExtendedNodeBuilder() );
+                  new EventBasedNodeBuilder() );
         register( RuleSetNode.class,
-                  new ExtendedNodeBuilder() );
+                  new EventBasedNodeBuilder() );
         register( SubProcessNode.class,
-                  new ExtendedNodeBuilder() );
+                  new EventBasedNodeBuilder() );
+        register( HumanTaskNode.class,
+                  new EventBasedNodeBuilder() );
         register( WorkItemNode.class,
-                  new ExtendedNodeBuilder() );
+                  new EventBasedNodeBuilder() );
         register( FaultNode.class,
                   new ExtendedNodeBuilder() );
         register( TimerNode.class,

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/ProcessSemanticModule.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/ProcessSemanticModule.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/ProcessSemanticModule.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -25,6 +25,7 @@
 import org.drools.xml.processes.StartNodeHandler;
 import org.drools.xml.processes.SubProcessNodeHandler;
 import org.drools.xml.processes.SwimlaneHandler;
+import org.drools.xml.processes.TimerHandler;
 import org.drools.xml.processes.TimerNodeHandler;
 import org.drools.xml.processes.TypeHandler;
 import org.drools.xml.processes.ValueHandler;
@@ -56,7 +57,7 @@
                            new JoinNodeHandler() );
         addHandler( "milestone",
                            new MilestoneNodeHandler() );
-        addHandler( "timer",
+        addHandler( "timerNode",
                            new TimerNodeHandler() );
         addHandler( "humanTask",
                            new HumanTaskNodeHandler() );
@@ -98,5 +99,7 @@
      		   			   new FaultNodeHandler() );        
         addHandler( "exceptionHandler",
 	   			   		   new ExceptionHandlerHandler() );        
+        addHandler( "timer",
+                		   new TimerHandler() );
     }
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/AbstractNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/AbstractNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/AbstractNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -3,7 +3,9 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 
+import org.drools.process.core.timer.Timer;
 import org.drools.workflow.core.DroolsAction;
 import org.drools.workflow.core.Node;
 import org.drools.workflow.core.NodeContainer;
@@ -19,8 +21,7 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
-public abstract class AbstractNodeHandler extends BaseAbstractHandler implements
-        Handler {
+public abstract class AbstractNodeHandler extends BaseAbstractHandler implements Handler {
 
     protected final static String EOL = System.getProperty( "line.separator" );
 
@@ -31,12 +32,12 @@
     }
     
     protected void initValidParents() {
-        this.validParents = new HashSet();
+        this.validParents = new HashSet<Class<?>>();
         this.validParents.add(NodeContainer.class);
     }
     
     protected void initValidPeers() {
-        this.validPeers = new HashSet();
+        this.validPeers = new HashSet<Class<?>>();
         this.validPeers.add(null);
         this.validPeers.add(Node.class);
     }
@@ -199,6 +200,23 @@
     	}
     }
     
+    public void writeTimers(final Map<Timer, DroolsAction> timers, final StringBuffer xmlDump) {
+    	if (timers != null && !timers.isEmpty()) {
+    		xmlDump.append("      <timers>" + EOL);
+    		for (Map.Entry<Timer, DroolsAction> entry: timers.entrySet()) {
+    			Timer timer = entry.getKey();
+    			xmlDump.append("        <timer id=\"" + timer.getId() + "\" delay=\"" + timer.getDelay() + "\" ");
+                if (timer.getPeriod() > 0) {
+                    xmlDump.append("period=\"" + timer.getPeriod() + "\" ");
+                }
+                xmlDump.append(">" + EOL);
+                writeAction(entry.getValue(), xmlDump);
+                xmlDump.append("        </timer>" + EOL);
+    		}
+    		xmlDump.append("      </timers>" + EOL);
+    	}
+    }
+    
     protected void endNode(final StringBuffer xmlDump) {
         xmlDump.append("/>" + EOL);
     }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ActionNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ActionNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ActionNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -27,7 +27,8 @@
         }
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return ActionNode.class;
     }
 

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ConstraintHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ConstraintHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/ConstraintHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -4,6 +4,7 @@
 
 import org.drools.workflow.core.Constraint;
 import org.drools.workflow.core.impl.ConstraintImpl;
+import org.drools.workflow.core.node.MilestoneNode;
 import org.drools.workflow.core.node.Split;
 import org.drools.xml.BaseAbstractHandler;
 import org.drools.xml.ExtensibleXmlParser;
@@ -17,10 +18,11 @@
     
     public ConstraintHandler() {
         if ((this.validParents == null) && (this.validPeers == null)) {
-            this.validParents = new HashSet();
+            this.validParents = new HashSet<Class<?>>();
             this.validParents.add(Split.class);
+            this.validParents.add(MilestoneNode.class);
 
-            this.validPeers = new HashSet();
+            this.validPeers = new HashSet<Class<?>>();
             this.validPeers.add(null);
 
             this.allowNesting = false;
@@ -40,38 +42,56 @@
                       final String localName,
                       final ExtensibleXmlParser parser) throws SAXException {
         final Element element = parser.endElementBuilder();
-        Split splitNode = (Split) parser.getParent();
-        final String toNodeIdString = element.getAttribute("toNodeId");
-        emptyAttributeCheck(localName, "toNodeId", toNodeIdString, parser);
-        int toNodeId = new Integer(toNodeIdString);
-        final String toType = element.getAttribute("toType");
-        emptyAttributeCheck(localName, "toType", toType, parser);
-        Split.ConnectionRef connectionRef = new Split.ConnectionRef(toNodeId, toType);
-        Constraint constraint = new ConstraintImpl();
-        
-        final String name = element.getAttribute("name");
-        constraint.setName(name);
-        final String priority = element.getAttribute("priority");
-        if (priority != null && priority.length() != 0) {
-            constraint.setPriority(new Integer(priority));
+        Object parent = parser.getParent();
+        if (parent instanceof Split) {
+	        Split splitNode = (Split) parser.getParent();
+	        
+	        final String toNodeIdString = element.getAttribute("toNodeId");
+	        emptyAttributeCheck(localName, "toNodeId", toNodeIdString, parser);
+	        int toNodeId = new Integer(toNodeIdString);
+	        final String toType = element.getAttribute("toType");
+	        emptyAttributeCheck(localName, "toType", toType, parser);
+	        Split.ConnectionRef connectionRef = new Split.ConnectionRef(toNodeId, toType);
+	        Constraint constraint = new ConstraintImpl();
+	        
+	        final String name = element.getAttribute("name");
+	        constraint.setName(name);
+	        final String priority = element.getAttribute("priority");
+	        if (priority != null && priority.length() != 0) {
+	            constraint.setPriority(new Integer(priority));
+	        }
+	        final String type = element.getAttribute("type");
+	        constraint.setType(type);
+	        final String dialect = element.getAttribute("dialect");
+	        constraint.setDialect(dialect);
+	        
+	        String text = ((Text)element.getChildNodes().item( 0 )).getWholeText();
+	        if (text != null) {
+	            text = text.trim();
+	            if ("".equals(text)) {
+	                text = null;
+	            }
+	        }
+	        constraint.setConstraint(text);
+	        splitNode.internalSetConstraint(connectionRef, constraint);
+        } else if (parent instanceof MilestoneNode) {
+        	MilestoneNode milestoneNode = (MilestoneNode) parent;
+	        String text = ((Text)element.getChildNodes().item( 0 )).getWholeText();
+	        if (text != null) {
+	            text = text.trim();
+	            if ("".equals(text)) {
+	                text = null;
+	            }
+	        }
+	        milestoneNode.setConstraint(text);
+        } else {
+        	throw new SAXException("Invalid parent node " + parent);
         }
-        final String type = element.getAttribute("type");
-        constraint.setType(type);
-        final String dialect = element.getAttribute("dialect");
-        constraint.setDialect(dialect);
-        String text = ((Text)element.getChildNodes().item( 0 )).getWholeText();
-        if (text != null) {
-            text = text.trim();
-            if ("".equals(text)) {
-                text = null;
-            }
-        }
-        constraint.setConstraint(text);
-        splitNode.internalSetConstraint(connectionRef, constraint);
         return null;
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return Constraint.class;
     }    
 

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/MilestoneNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/MilestoneNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/MilestoneNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -2,11 +2,7 @@
 
 import org.drools.workflow.core.Node;
 import org.drools.workflow.core.node.MilestoneNode;
-import org.drools.xml.ExtensibleXmlParser;
 import org.drools.xml.XmlDumper;
-import org.w3c.dom.Element;
-import org.w3c.dom.Text;
-import org.xml.sax.SAXException;
 
 public class MilestoneNodeHandler extends AbstractNodeHandler {
 
@@ -14,22 +10,8 @@
         return new MilestoneNode();
     }
 
-    public void handleNode(final Node node, final Element element, final String uri,
-            final String localName, final ExtensibleXmlParser parser)
-            throws SAXException {
-        super.handleNode(node, element, uri, localName, parser);
-        MilestoneNode milestone = (MilestoneNode) node;
-        String text = ((Text)element.getChildNodes().item( 0 )).getWholeText();
-        if (text != null) {
-            text.trim();
-            if ("".equals(text)) {
-                text = null;
-            }
-        }
-        milestone.setConstraint(text);
-    }
-
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return MilestoneNode.class;
     }
 
@@ -37,8 +19,14 @@
 		MilestoneNode milestoneNode = (MilestoneNode) node;
 		writeNode("milestone", milestoneNode, xmlDump, includeMeta);
         String constraint = milestoneNode.getConstraint();
-        if (constraint != null) {
-            xmlDump.append(">" + XmlDumper.replaceIllegalChars(constraint.trim()) + "</milestone>" + EOL);
+        if (constraint != null || milestoneNode.getTimers() != null) {
+            xmlDump.append(">\n");
+            if (constraint != null) {
+            	xmlDump.append("      <constraint type=\"rule\" dialect=\"mvel\" >"
+            			+ XmlDumper.replaceIllegalChars(constraint.trim()) + "</constraint>" + EOL);
+            }
+            writeTimers(milestoneNode.getTimers(), xmlDump);
+            endNode("milestone", xmlDump);
         } else {
             endNode(xmlDump);
         }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/RuleSetNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/RuleSetNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/RuleSetNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -21,7 +21,8 @@
         ruleSetNode.setRuleFlowGroup(ruleFlowGroup);
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return RuleSetNode.class;
     }
 
@@ -32,7 +33,13 @@
         if (ruleFlowGroup != null) {
             xmlDump.append("ruleFlowGroup=\"" + ruleFlowGroup + "\" ");
         }
-        endNode(xmlDump);
+        if (ruleSetNode.getTimers() != null) {
+            xmlDump.append(">\n");
+            writeTimers(ruleSetNode.getTimers(), xmlDump);
+            endNode("ruleSet", xmlDump);
+        } else {
+            endNode(xmlDump);
+        }
 	}
 
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SplitNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SplitNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SplitNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -27,7 +27,8 @@
         }
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return Split.class;
     }
 

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SubProcessNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SubProcessNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/SubProcessNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -30,7 +30,8 @@
         }
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return SubProcessNode.class;
     }
 
@@ -65,6 +66,7 @@
         for (String eventType: subProcessNode.getActionTypes()) {
         	writeActions(eventType, subProcessNode.getActions(eventType), xmlDump);
         }
+        writeTimers(subProcessNode.getTimers(), xmlDump);
         endNode("subProcess", xmlDump);
 	}
 

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerHandler.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,70 @@
+package org.drools.xml.processes;
+
+import java.util.HashSet;
+
+import org.drools.process.core.timer.Timer;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.impl.ExtendedNodeImpl;
+import org.drools.workflow.core.node.EventBasedNode;
+import org.drools.xml.BaseAbstractHandler;
+import org.drools.xml.ExtensibleXmlParser;
+import org.drools.xml.Handler;
+import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class TimerHandler extends BaseAbstractHandler implements Handler {
+	
+    public TimerHandler() {
+        if ( (this.validParents == null) && (this.validPeers == null) ) {
+            this.validParents = new HashSet<Class<?>>();
+            this.validParents.add( ExtendedNodeImpl.class );
+
+            this.validPeers = new HashSet<Class<?>>();         
+            this.validPeers.add( null );
+
+            this.allowNesting = false;
+        }
+    }
+    
+    public Object start(final String uri,
+                        final String localName,
+                        final Attributes attrs,
+                        final ExtensibleXmlParser parser) throws SAXException {
+        parser.startElementBuilder( localName, attrs );
+        return null;
+    }    
+    
+    public Object end(final String uri,
+                      final String localName,
+                      final ExtensibleXmlParser parser) throws SAXException {
+        Element element = parser.endElementBuilder();
+        EventBasedNode eventBasedNode = (EventBasedNode) parser.getParent();
+        String id = element.getAttribute("id");
+        emptyAttributeCheck( localName, "id", id, parser );
+        String delay = element.getAttribute("delay");
+        String period = element.getAttribute("period");
+        Timer timer = new Timer();
+        timer.setId(new Long(id));
+        if (delay != null && delay.length() != 0 ) {
+            timer.setDelay(new Long(delay));
+        }
+        if (period != null && period.length() != 0 ) {
+            timer.setPeriod(new Long(period));
+        }
+        org.w3c.dom.Node xmlNode = element.getFirstChild();
+        DroolsAction action = null;
+        if (xmlNode instanceof Element) {
+    		Element actionXml = (Element) xmlNode;
+    		action = AbstractNodeHandler.extractAction(actionXml);
+        }
+        eventBasedNode.addTimer(timer, action);
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
+        return null;
+    }    
+
+}

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/TimerNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -35,13 +35,14 @@
         }
     }
 
-    public Class generateNodeFor() {
+    @SuppressWarnings("unchecked")
+	public Class generateNodeFor() {
         return TimerNode.class;
     }
 
 	public void writeNode(Node node, StringBuffer xmlDump, boolean includeMeta) {
 		TimerNode timerNode = (TimerNode) node;
-		writeNode("timer", timerNode, xmlDump, includeMeta);
+		writeNode("timerNode", timerNode, xmlDump, includeMeta);
         Timer timer = timerNode.getTimer();
         if (timer != null) {
             xmlDump.append("delay=\"" + timer.getDelay() + "\" ");

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/WorkItemNodeHandler.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/WorkItemNodeHandler.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/xml/processes/WorkItemNodeHandler.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -46,6 +46,7 @@
         for (String eventType: workItemNode.getActionTypes()) {
         	writeActions(eventType, workItemNode.getActions(eventType), xmlDump);
         }
+        writeTimers(workItemNode.getTimers(), xmlDump);
         endNode("workItem", xmlDump);
 	}
 	

Modified: labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-processes-4.0.xsd
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-processes-4.0.xsd	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-processes-4.0.xsd	2008-09-18 22:50:23 UTC (rev 22897)
@@ -121,7 +121,7 @@
 				<xs:element ref="drools:milestone"/>
 				<xs:element ref="drools:subProcess"/>
 				<xs:element ref="drools:workItem"/>
-				<xs:element ref="drools:timer"/>
+				<xs:element ref="drools:timerNode"/>
 				<xs:element ref="drools:humanTask"/>
 				<xs:element ref="drools:composite"/>
 				<xs:element ref="drools:forEach"/>
@@ -130,6 +130,23 @@
 			</xs:choice>
 		</xs:complexType>
 	</xs:element>
+	<xs:element name="timers">
+		<xs:complexType>
+			<xs:sequence minOccurs="0" maxOccurs="unbounded">
+				<xs:element ref="drools:timer"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="timer">
+		<xs:complexType>
+			<xs:choice minOccurs="0" maxOccurs="1">
+				<xs:element ref="drools:action"/>
+			</xs:choice>
+			<xs:attribute name="id" type="xs:string" use="required"/>
+			<xs:attribute name="delay" type="xs:string"/>
+			<xs:attribute name="period" type="xs:string"/>
+		</xs:complexType>
+	</xs:element>
 	<xs:element name="start">
 		<xs:complexType>
 			<xs:attribute name="id" type="xs:string" use="required"/>
@@ -177,6 +194,9 @@
 	</xs:element>
 	<xs:element name="ruleSet">
 		<xs:complexType>
+			<xs:choice minOccurs="0" maxOccurs="unbounded">
+				<xs:element ref="drools:timers"/>
+			</xs:choice>
 			<xs:attribute name="id" type="xs:string" use="required"/>
 			<xs:attribute name="name" type="xs:string"/>
 			<xs:attribute name="x" type="xs:string"/>
@@ -211,7 +231,7 @@
 		<xs:complexType>
 			<xs:simpleContent>
 				<xs:extension base="xs:string">
-					<xs:attribute name="toNodeId" type="xs:string" use="required"/>
+					<xs:attribute name="toNodeId" type="xs:string"/>
 					<xs:attribute name="toType" type="xs:string"/>
 					<xs:attribute name="name" type="xs:string"/>
 					<xs:attribute name="priority" type="xs:string"/>
@@ -234,22 +254,25 @@
 	</xs:element>
 	<xs:element name="milestone">
 		<xs:complexType>
-			<xs:simpleContent>
-				<xs:extension base="xs:string">
-					<xs:attribute name="id" type="xs:string" use="required"/>
-					<xs:attribute name="name" type="xs:string"/>
-					<xs:attribute name="x" type="xs:string"/>
-					<xs:attribute name="y" type="xs:string"/>
-					<xs:attribute name="width" type="xs:string"/>
-					<xs:attribute name="height" type="xs:string"/>
-				</xs:extension>
-			</xs:simpleContent>
+			<xs:choice minOccurs="0" maxOccurs="unbounded">
+				<xs:element ref="drools:constraint"/>
+				<xs:element ref="drools:timers"/>
+			</xs:choice>
+			<xs:attribute name="id" type="xs:string" use="required"/>
+			<xs:attribute name="name" type="xs:string"/>
+			<xs:attribute name="x" type="xs:string"/>
+			<xs:attribute name="y" type="xs:string"/>
+			<xs:attribute name="width" type="xs:string"/>
+			<xs:attribute name="height" type="xs:string"/>
 		</xs:complexType>
 	</xs:element>
 	<xs:element name="subProcess">
 		<xs:complexType>
 			<xs:choice minOccurs="0" maxOccurs="unbounded">
 				<xs:element ref="drools:mapping"/>
+				<xs:element ref="drools:timers"/>
+				<xs:element ref="drools:onEntry"/>
+				<xs:element ref="drools:onExit"/>
 			</xs:choice>
 			<xs:attribute name="id" type="xs:string" use="required"/>
 			<xs:attribute name="name" type="xs:string"/>
@@ -265,6 +288,7 @@
 	<xs:element name="workItem">
 		<xs:complexType>
 			<xs:choice minOccurs="0" maxOccurs="unbounded">
+				<xs:element ref="drools:timers"/>
 				<xs:element ref="drools:work"/>
 				<xs:element ref="drools:mapping"/>
 				<xs:element ref="drools:onEntry"/>
@@ -317,7 +341,7 @@
 			</xs:choice>
 		</xs:complexType>
 	</xs:element>
-	<xs:element name="timer">
+	<xs:element name="timerNode">
 		<xs:complexType>
 			<xs:attribute name="id" type="xs:string" use="required"/>
 			<xs:attribute name="name" type="xs:string"/>
@@ -334,6 +358,8 @@
 			<xs:choice minOccurs="0" maxOccurs="unbounded">
 				<xs:element ref="drools:work"/>
 				<xs:element ref="drools:mapping"/>
+				<xs:element ref="drools:onEntry"/>
+				<xs:element ref="drools:onExit"/>
 			</xs:choice>
 			<xs:attribute name="id" type="xs:string" use="required"/>
 			<xs:attribute name="name" type="xs:string"/>

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessMarchallingTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessMarchallingTest.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessMarchallingTest.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -185,13 +185,15 @@
             "    <subProcess id=\"6\" name=\"SubProcess\" processId=\"com.sample.subflow\" />\n" +
             "    <actionNode id=\"7\" name=\"Action\" >\n" +
             "      <action type=\"expression\" dialect=\"mvel\" >System.out.println(\"Executing action 1\");</action>\n" +
-            "	 </actionNode>/n" +
+            "	 </actionNode>\n" +
             "    <join id=\"8\" name=\"AND\" type=\"1\" />\n" +
             "    <actionNode id=\"9\" name=\"Action\" >\n" +
             "      <action type=\"expression\" dialect=\"mvel\" >System.out.println(\"Executing action 2\");</action>\n" +
             "    </actionNode>\n" +
             "    <ruleSet id=\"10\" name=\"RuleSet\" ruleFlowGroup=\"flowgroup\" />\n" +
-            "    <milestone id=\"11\" name=\"Event Wait\" >Person( )</milestone>\n" +
+            "    <milestone id=\"11\" name=\"Event Wait\" >\n" +
+            "      <constraint type=\"rule\" dialect=\"mvel\" >Person( )</constraint>\n" +
+			"    </milestone>\n" +
             "    <workItem id=\"12\" name=\"Log\" >\n" +
             "      <work name=\"Log\" >\n" +
             "        <parameter name=\"Message\" >\n" +
@@ -294,7 +296,9 @@
             "\n" +
             "  <nodes>\n" +
             "    <start id=\"1\" name=\"Start\" />\n" +
-            "    <milestone id=\"2\" name=\"Event Wait\" >Person( )</milestone>\n" +
+			"    <milestone id=\"2\" name=\"Event Wait\" >\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >Person( )</constraint>\n" +
+			"    </milestone>\n" +
             "    <end id=\"3\" name=\"End\" />\n" +
             "  </nodes>\n" +
             "\n" +
@@ -448,7 +452,7 @@
     		"\n" +
     		"    <nodes>\n" +
     		"      <start id=\"1\" name=\"Start\" />\n" +
-    		"      <timer id=\"4\" name=\"Timer\" delay=\"200\" />\n" +
+    		"      <timerNode id=\"4\" name=\"Timer\" delay=\"200\" />\n" +
     		"      <end id=\"3\" name=\"End\" />\n" +
     		"    </nodes>\n" +
     		"\n" +
@@ -488,7 +492,7 @@
     		"\n" +
     		"    <nodes>\n" +
     		"      <start id=\"1\" name=\"Start\" />\n" +
-    		"      <timer id=\"4\" name=\"Timer\" delay=\"200\" />\n" +
+    		"      <timerNode id=\"4\" name=\"Timer\" delay=\"200\" />\n" +
     		"      <end id=\"3\" name=\"End\" />\n" +
     		"    </nodes>\n" +
     		"\n" +

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessTimerTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessTimerTest.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/integrationtests/ProcessTimerTest.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -13,12 +13,14 @@
 import org.drools.RuleBase;
 import org.drools.RuleBaseFactory;
 import org.drools.StatefulSession;
+import org.drools.compiler.DroolsError;
 import org.drools.compiler.PackageBuilder;
 import org.drools.process.instance.ProcessInstance;
 import org.drools.rule.Package;
 
 public class ProcessTimerTest extends TestCase {
 	
+	@SuppressWarnings("unchecked")
 	public void testSimpleProcess() throws Exception {
 		PackageBuilder builder = new PackageBuilder();
 		Reader source = new StringReader(
@@ -40,14 +42,16 @@
 			"  <nodes>\n" +
 			"    <start id=\"1\" name=\"Start\" />\n" +
 			"    <end id=\"2\" name=\"End\" />\n" +
-			"    <timer id=\"3\" name=\"Timer\" delay=\"800\"  period=\"200\" />\n" +
+			"    <timerNode id=\"3\" name=\"Timer\" delay=\"800\" period=\"200\" />\n" +
 			"    <actionNode id=\"4\" name=\"Action\" >\n" +
 			"      <action type=\"expression\" dialect=\"java\" >System.out.println(\"Triggered\");\n" +
 			"myList.add( new Message() );\n" +
 			"insert( new Message() );\n" +
 			"</action>\n" +
 			"    </actionNode>\n" + 
-			"    <milestone id=\"5\" name=\"Wait\" >Number( intValue &gt;= 5 ) from accumulate ( m: Message( ), count( m ) )</milestone>\n" +
+			"    <milestone id=\"5\" name=\"Wait\" >\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >Number( intValue &gt;= 5 ) from accumulate ( m: Message( ), count( m ) )</constraint>\n" +
+			"    </milestone>\n" +
 			"  </nodes>\n" +
 			"\n" +
 			"  <connections>\n" +
@@ -59,6 +63,12 @@
 			"\n" +
 			"</process>");
 		builder.addRuleFlow(source);
+		if (!builder.getErrors().isEmpty()) {
+			for (DroolsError error: builder.getErrors().getErrors()) {
+				System.err.println(error);
+			}
+			fail("Could not build process");
+		}
 		
 		Package pkg = builder.getPackage();
 		RuleBase ruleBase = RuleBaseFactory.newRuleBase();
@@ -79,7 +89,6 @@
         assertEquals(1, session.getTimerManager().getTimers().size());
 
         // test that the delay works
-        System.out.println("Sleep1");
         try {
             Thread.sleep(600);
         } catch (InterruptedException e) {
@@ -88,7 +97,6 @@
         assertEquals(0, myList.size());
         
         // test that the period works
-        System.out.println("Sleep2");
         try {
         	Thread.sleep(1300);
         } catch (InterruptedException e) {
@@ -99,4 +107,253 @@
         assertEquals(ProcessInstance.STATE_COMPLETED, processInstance.getState());
 	}
 
+	@SuppressWarnings("unchecked")
+	public void testOnEntryTimerExecuted() throws Exception {
+		PackageBuilder builder = new PackageBuilder();
+		Reader source = new StringReader(
+			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+			"<process xmlns=\"http://drools.org/drools-4.0/process\"\n" +
+			"         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+			"         xs:schemaLocation=\"http://drools.org/drools-4.0/process drools-processes-4.0.xsd\"\n" +
+			"         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.timer\" package-name=\"org.drools\" version=\"1\" >\n" +
+			"\n" +
+			"  <header>\n" +
+			"    <globals>\n" +
+			"      <global identifier=\"myList\" type=\"java.util.List\" />\n" +
+			"    </globals>\n" +
+			"  </header>\n" +
+			"\n" +
+			"  <nodes>\n" +
+			"    <start id=\"1\" name=\"Start\" />\n" +
+			"    <milestone id=\"2\" name=\"Wait\" >\n" +
+			"      <timer id=\"1\" delay=\"300\" >\n" +
+			"        <action type=\"expression\" dialect=\"java\" >myList.add(\"Executing timer\");</action>\n" +
+			"      </timer>\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >eval(false)</constraint>\n" +
+			"    </milestone>\n" +
+			"    <end id=\"3\" name=\"End\" />\n" +
+			"  </nodes>\n" +
+			"\n" +
+			"  <connections>\n" +
+			"    <connection from=\"1\" to=\"2\" />\n" +
+			"    <connection from=\"2\" to=\"3\" />\n" +
+			"  </connections>\n" +
+			"\n" +
+			"</process>");
+		builder.addRuleFlow(source);
+		
+		Package pkg = builder.getPackage();
+		RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+		ruleBase.addPackage( pkg );
+		StatefulSession session = ruleBase.newStatefulSession();
+		List<String> myList = new ArrayList<String>();
+		session.setGlobal("myList", myList);
+        ProcessInstance processInstance =
+        	session.startProcess("org.drools.timer");
+        assertEquals(0, myList.size());
+        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
+        assertEquals(1, session.getTimerManager().getTimers().size());
+        
+        session = getSerialisedStatefulSession( session );
+        myList = (List<String>) session.getGlobal( "myList" );
+        processInstance = session.getProcessInstance( processInstance.getId() );
+        
+        assertEquals(1, session.getTimerManager().getTimers().size());
+
+        try {
+            Thread.sleep(400);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+        assertEquals(1, myList.size());
+	}
+
+	@SuppressWarnings("unchecked")
+	public void testOnEntryTimerExecutedMultipleTimes() throws Exception {
+		PackageBuilder builder = new PackageBuilder();
+		Reader source = new StringReader(
+			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+			"<process xmlns=\"http://drools.org/drools-4.0/process\"\n" +
+			"         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+			"         xs:schemaLocation=\"http://drools.org/drools-4.0/process drools-processes-4.0.xsd\"\n" +
+			"         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.timer\" package-name=\"org.drools\" version=\"1\" >\n" +
+			"\n" +
+			"  <header>\n" +
+			"    <globals>\n" +
+			"      <global identifier=\"myList\" type=\"java.util.List\" />\n" +
+			"    </globals>\n" +
+			"  </header>\n" +
+			"\n" +
+			"  <nodes>\n" +
+			"    <start id=\"1\" name=\"Start\" />\n" +
+			"    <milestone id=\"2\" name=\"Wait\" >\n" +
+			"      <timer id=\"1\" delay=\"300\" period =\"200\" >\n" +
+			"        <action type=\"expression\" dialect=\"java\" >myList.add(\"Executing timer\");</action>\n" +
+			"      </timer>\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >eval(false)</constraint>\n" +
+			"    </milestone>\n" +
+			"    <end id=\"3\" name=\"End\" />\n" +
+			"  </nodes>\n" +
+			"\n" +
+			"  <connections>\n" +
+			"    <connection from=\"1\" to=\"2\" />\n" +
+			"    <connection from=\"2\" to=\"3\" />\n" +
+			"  </connections>\n" +
+			"\n" +
+			"</process>");
+		builder.addRuleFlow(source);
+		
+		Package pkg = builder.getPackage();
+		RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+		ruleBase.addPackage( pkg );
+		StatefulSession session = ruleBase.newStatefulSession();
+		List<String> myList = new ArrayList<String>();
+		session.setGlobal("myList", myList);
+        ProcessInstance processInstance =
+        	session.startProcess("org.drools.timer");
+        assertEquals(0, myList.size());
+        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
+        assertEquals(1, session.getTimerManager().getTimers().size());
+        
+        session = getSerialisedStatefulSession( session );
+        myList = (List<String>) session.getGlobal( "myList" );
+        processInstance = session.getProcessInstance( processInstance.getId() );
+        
+        assertEquals(1, session.getTimerManager().getTimers().size());
+
+        try {
+            Thread.sleep(600);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+        assertEquals(2, myList.size());
+	}
+	
+	@SuppressWarnings("unchecked")
+	public void testMultipleTimers() throws Exception {
+		PackageBuilder builder = new PackageBuilder();
+		Reader source = new StringReader(
+			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+			"<process xmlns=\"http://drools.org/drools-4.0/process\"\n" +
+			"         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+			"         xs:schemaLocation=\"http://drools.org/drools-4.0/process drools-processes-4.0.xsd\"\n" +
+			"         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.timer\" package-name=\"org.drools\" version=\"1\" >\n" +
+			"\n" +
+			"  <header>\n" +
+			"    <globals>\n" +
+			"      <global identifier=\"myList\" type=\"java.util.List\" />\n" +
+			"    </globals>\n" +
+			"  </header>\n" +
+			"\n" +
+			"  <nodes>\n" +
+			"    <start id=\"1\" name=\"Start\" />\n" +
+			"    <milestone id=\"2\" name=\"Wait\" >\n" +
+			"      <timer id=\"1\" delay=\"600\" >\n" +
+			"        <action type=\"expression\" dialect=\"java\" >myList.add(\"Executing timer1\");</action>\n" +
+			"      </timer>\n" +
+			"      <timer id=\"2\" delay=\"200\" >\n" +
+			"        <action type=\"expression\" dialect=\"java\" >myList.add(\"Executing timer2\");</action>\n" +
+			"      </timer>\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >eval(false)</constraint>\n" +
+			"    </milestone>\n" +
+			"    <end id=\"3\" name=\"End\" />\n" +
+			"  </nodes>\n" +
+			"\n" +
+			"  <connections>\n" +
+			"    <connection from=\"1\" to=\"2\" />\n" +
+			"    <connection from=\"2\" to=\"3\" />\n" +
+			"  </connections>\n" +
+			"\n" +
+			"</process>");
+		builder.addRuleFlow(source);
+		
+		Package pkg = builder.getPackage();
+		RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+		ruleBase.addPackage( pkg );
+		StatefulSession session = ruleBase.newStatefulSession();
+		List<String> myList = new ArrayList<String>();
+		session.setGlobal("myList", myList);
+        ProcessInstance processInstance =
+        	session.startProcess("org.drools.timer");
+        assertEquals(0, myList.size());
+        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
+        assertEquals(2, session.getTimerManager().getTimers().size());
+        
+        session = getSerialisedStatefulSession( session );
+        myList = (List<String>) session.getGlobal( "myList" );
+        assertEquals(2, session.getTimerManager().getTimers().size());
+
+        try {
+            Thread.sleep(300);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+        assertEquals(1, myList.size());
+        assertEquals("Executing timer2", myList.get(0));
+        
+        session = getSerialisedStatefulSession( session );
+        myList = (List<String>) session.getGlobal( "myList" );
+        
+        try {
+            Thread.sleep(400);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+        assertEquals(2, myList.size());
+	}
+	
+	@SuppressWarnings("unchecked")
+	public void testOnEntryTimerCancelled() throws Exception {
+		PackageBuilder builder = new PackageBuilder();
+		Reader source = new StringReader(
+			"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+			"<process xmlns=\"http://drools.org/drools-4.0/process\"\n" +
+			"         xmlns:xs=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+			"         xs:schemaLocation=\"http://drools.org/drools-4.0/process drools-processes-4.0.xsd\"\n" +
+			"         type=\"RuleFlow\" name=\"flow\" id=\"org.drools.timer\" package-name=\"org.drools\" version=\"1\" >\n" +
+			"\n" +
+			"  <header>\n" +
+			"    <globals>\n" +
+			"      <global identifier=\"myList\" type=\"java.util.List\" />\n" +
+			"    </globals>\n" +
+			"  </header>\n" +
+			"\n" +
+			"  <nodes>\n" +
+			"    <start id=\"1\" name=\"Start\" />\n" +
+			"    <milestone id=\"2\" name=\"Wait\" >\n" +
+			"      <timer id=\"1\" delay=\"2000\" >\n" +
+			"        <action type=\"expression\" dialect=\"java\" >myList.add(\"Executing timer\");</action>\n" +
+			"      </timer>\n" +
+			"      <constraint type=\"rule\" dialect=\"mvel\" >org.drools.Message( )</constraint>\n" +
+			"    </milestone>\n" +
+			"    <end id=\"3\" name=\"End\" />\n" +
+			"  </nodes>\n" +
+			"\n" +
+			"  <connections>\n" +
+			"    <connection from=\"1\" to=\"2\" />\n" +
+			"    <connection from=\"2\" to=\"3\" />\n" +
+			"  </connections>\n" +
+			"\n" +
+			"</process>");
+		builder.addRuleFlow(source);
+		
+		Package pkg = builder.getPackage();
+		RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+		ruleBase.addPackage( pkg );
+		StatefulSession session = ruleBase.newStatefulSession();
+		List<String> myList = new ArrayList<String>();
+		session.setGlobal("myList", myList);
+        ProcessInstance processInstance =
+        	session.startProcess("org.drools.timer");
+        assertEquals(0, myList.size());
+        assertEquals(ProcessInstance.STATE_ACTIVE, processInstance.getState());
+        assertEquals(1, session.getTimerManager().getTimers().size());
+        
+        session = getSerialisedStatefulSession( session );
+        myList = (List<String>) session.getGlobal( "myList" );
+        session.insert(new Message());
+        assertEquals(0, myList.size());
+        assertEquals(0, session.getTimerManager().getTimers().size());
+	}
+	
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/xml/processes/XMLPersistenceTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/xml/processes/XMLPersistenceTest.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/xml/processes/XMLPersistenceTest.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -202,6 +202,16 @@
         ruleSetNode.setMetaData("width", 3);
         ruleSetNode.setMetaData("height", 4);
         ruleSetNode.setRuleFlowGroup("ruleFlowGroup");
+        Timer timer = new Timer();
+        timer.setDelay(100);
+        timer.setPeriod(100);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        ruleSetNode.addTimer(timer, action);
+        timer = new Timer();
+        timer.setDelay(200);
+        timer.setPeriod(200);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        ruleSetNode.addTimer(timer, action);
         process.addNode(ruleSetNode);
         
         FaultNode faultNode = new FaultNode();
@@ -271,6 +281,16 @@
         milestone.setMetaData("width", 3);
         milestone.setMetaData("height", 4);
         milestone.setConstraint("constraint");
+        timer = new Timer();
+        timer.setDelay(100);
+        timer.setPeriod(100);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        milestone.addTimer(timer, action);
+        timer = new Timer();
+        timer.setDelay(200);
+        timer.setPeriod(200);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        milestone.addTimer(timer, action);
         process.addNode(milestone);
         connection = new ConnectionImpl(join, Node.CONNECTION_DEFAULT_TYPE, milestone, Node.CONNECTION_DEFAULT_TYPE);
         connection.setMetaData("bendpoints", "[10,10;20,20]");
@@ -286,6 +306,16 @@
         subProcess.setIndependent(false);
         subProcess.addInMapping("subvar1", "var1");
         subProcess.addOutMapping("subvar2", "var2");
+        timer = new Timer();
+        timer.setDelay(100);
+        timer.setPeriod(100);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        subProcess.addTimer(timer, action);
+        timer = new Timer();
+        timer.setDelay(200);
+        timer.setPeriod(200);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        subProcess.addTimer(timer, action);
         process.addNode(subProcess);
         connection = new ConnectionImpl(milestone, Node.CONNECTION_DEFAULT_TYPE, subProcess, Node.CONNECTION_DEFAULT_TYPE);
         connection.setMetaData("bendpoints", "[10,10]");
@@ -306,6 +336,16 @@
         workItemNode.setWaitForCompletion(false);
         workItemNode.addInMapping("param1", "var1");
         workItemNode.addOutMapping("param2", "var2");
+        timer = new Timer();
+        timer.setDelay(100);
+        timer.setPeriod(100);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        workItemNode.addTimer(timer, action);
+        timer = new Timer();
+        timer.setDelay(200);
+        timer.setPeriod(200);
+        action = new DroolsConsequenceAction("dialect", "consequence");
+        workItemNode.addTimer(timer, action);
         process.addNode(workItemNode);
         connection = new ConnectionImpl(subProcess, Node.CONNECTION_DEFAULT_TYPE, workItemNode, Node.CONNECTION_DEFAULT_TYPE);
         connection.setMetaData("bendpoints", "[]");
@@ -335,7 +375,7 @@
         timerNode.setMetaData("y", 2);
         timerNode.setMetaData("width", 3);
         timerNode.setMetaData("height", 4);
-        Timer timer = new Timer();
+        timer = new Timer();
         timer.setDelay(1000);
         timer.setPeriod(1000);
         timerNode.setTimer(timer);

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/InputMarshaller.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/InputMarshaller.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/InputMarshaller.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -3,8 +3,10 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 
@@ -28,12 +30,12 @@
 import org.drools.concurrent.ExecutorService;
 import org.drools.process.core.context.swimlane.SwimlaneContext;
 import org.drools.process.core.context.variable.VariableScope;
-import org.drools.process.core.timer.Timer;
 import org.drools.process.instance.ProcessInstance;
 import org.drools.process.instance.WorkItem;
 import org.drools.process.instance.context.swimlane.SwimlaneContextInstance;
 import org.drools.process.instance.context.variable.VariableScopeInstance;
 import org.drools.process.instance.impl.WorkItemImpl;
+import org.drools.process.instance.timer.TimerInstance;
 import org.drools.process.instance.timer.TimerManager;
 import org.drools.reteoo.BetaMemory;
 import org.drools.reteoo.BetaNode;
@@ -824,6 +826,14 @@
                 break;
             case PersisterEnums.MILESTONE_NODE_INSTANCE :
                 nodeInstance = new MilestoneNodeInstance();
+                int nbTimerInstances = stream.readInt();
+                if (nbTimerInstances > 0) {
+                	List<Long> timerInstances = new ArrayList<Long>();
+                	for (int i = 0; i < nbTimerInstances; i++) {
+                		timerInstances.add(stream.readLong());
+                	}
+                	((MilestoneNodeInstance) nodeInstance).internalSetTimerInstances(timerInstances);
+                }
                 break;
             case PersisterEnums.TIMER_NODE_INSTANCE :
                 nodeInstance = new TimerNodeInstance();
@@ -933,16 +943,17 @@
         timerManager.internalSetTimerId( stream.readLong() );
 
         while ( stream.readShort() == PersisterEnums.TIMER ) {
-            Timer timer = readTimer( context );
+            TimerInstance timer = readTimer( context );
             timerManager.internalAddTimer( timer );
         }
     }
 
-    public static Timer readTimer(MarshallerReaderContext context) throws IOException {
+    public static TimerInstance readTimer(MarshallerReaderContext context) throws IOException {
         ObjectInputStream stream = context.stream;
 
-        Timer timer = new Timer();
+        TimerInstance timer = new TimerInstance();
         timer.setId( stream.readLong() );
+        timer.setTimerId( stream.readLong() );
         timer.setDelay( stream.readLong() );
         timer.setPeriod( stream.readLong() );
         timer.setProcessInstanceId( stream.readLong() );

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/OutputMarshaller.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/OutputMarshaller.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/marshalling/OutputMarshaller.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,9 +1,7 @@
 package org.drools.marshalling;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -30,11 +28,11 @@
 import org.drools.common.WorkingMemoryAction;
 import org.drools.process.core.context.swimlane.SwimlaneContext;
 import org.drools.process.core.context.variable.VariableScope;
-import org.drools.process.core.timer.Timer;
 import org.drools.process.instance.ProcessInstance;
 import org.drools.process.instance.WorkItem;
 import org.drools.process.instance.context.swimlane.SwimlaneContextInstance;
 import org.drools.process.instance.context.variable.VariableScopeInstance;
+import org.drools.process.instance.timer.TimerInstance;
 import org.drools.process.instance.timer.TimerManager;
 import org.drools.reteoo.BetaNode;
 import org.drools.reteoo.LeftTuple;
@@ -70,13 +68,11 @@
 
 public class OutputMarshaller {
     public static void writeSession(MarshallerWriteContext context) throws IOException {
-        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-        PrintWriter out = new PrintWriter( buffer );
         ReteooWorkingMemory wm = (ReteooWorkingMemory) context.wm;
 
         context.writeInt( wm.getFactHandleFactory().getId() );
         context.writeLong( wm.getFactHandleFactory().getRecency() );
-        out.println( "FactHandleFactory int:" + wm.getFactHandleFactory().getId() + " long:" + wm.getFactHandleFactory().getRecency() );
+        context.out.println( "FactHandleFactory int:" + wm.getFactHandleFactory().getId() + " long:" + wm.getFactHandleFactory().getRecency() );
 
         InternalFactHandle handle = context.wm.getInitialFactHandle();
         context.writeInt( handle.getId() );
@@ -84,7 +80,7 @@
         context.out.println( "InitialFact int:" + handle.getId() + " long:" + handle.getRecency() );
 
         context.writeLong( wm.getPropagationIdCounter() );
-        out.println( "PropagationCounter long:" + wm.getPropagationIdCounter() );
+        context.out.println( "PropagationCounter long:" + wm.getPropagationIdCounter() );
 
         writeAgenda( context );
 
@@ -781,6 +777,16 @@
             stream.writeLong( ((SubProcessNodeInstance) nodeInstance).getProcessInstanceId() );
         } else if ( nodeInstance instanceof MilestoneNodeInstance ) {
             stream.writeShort( PersisterEnums.MILESTONE_NODE_INSTANCE );
+            List<Long> timerInstances = 
+            	((MilestoneNodeInstance) nodeInstance).getTimerInstances();
+            if (timerInstances != null) {
+            	stream.writeInt(timerInstances.size());
+            	for (Long id: timerInstances) {
+            		stream.writeLong(id);
+            	}
+            } else {
+            	stream.writeInt(0);
+            }
         } else if ( nodeInstance instanceof TimerNodeInstance ) {
             stream.writeShort( PersisterEnums.TIMER_NODE_INSTANCE );
             stream.writeLong( ((TimerNodeInstance) nodeInstance).getTimerId() );
@@ -896,17 +902,18 @@
         ObjectOutputStream stream = context.stream;
 
         TimerManager timerManager = context.wm.getTimerManager();
-        stream.writeLong( timerManager.internalGetTimerId() );
-
-        List<Timer> timers = new ArrayList<Timer>( timerManager.getTimers() );
+        long timerId = timerManager.internalGetTimerId();
+        stream.writeLong( timerId );
+        
+        List<TimerInstance> timers = new ArrayList<TimerInstance>( timerManager.getTimers() );
         Collections.sort( timers,
-                          new Comparator<Timer>() {
-                              public int compare(Timer o1,
-                                                 Timer o2) {
+                          new Comparator<TimerInstance>() {
+                              public int compare(TimerInstance o1,
+                                                 TimerInstance o2) {
                                   return (int) (o2.getId() - o1.getId());
                               }
                           } );
-        for ( Timer timer : timers ) {
+        for ( TimerInstance timer : timers ) {
             stream.writeShort( PersisterEnums.TIMER );
             writeTimer( context,
                         timer );
@@ -915,9 +922,10 @@
     }
 
     public static void writeTimer(MarshallerWriteContext context,
-                                  Timer timer) throws IOException {
+                                  TimerInstance timer) throws IOException {
         ObjectOutputStream stream = context.stream;
         stream.writeLong( timer.getId() );
+        stream.writeLong( timer.getTimerId() );
         stream.writeLong( timer.getDelay() );
         stream.writeLong( timer.getPeriod() );
         stream.writeLong( timer.getProcessInstanceId() );

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/timer/Timer.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/timer/Timer.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/core/timer/Timer.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,19 +1,14 @@
 package org.drools.process.core.timer;
 
-import java.util.Date;
-
-import org.drools.time.JobHandle;
-
+/**
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
 public class Timer {
 
     private long id;
     private long delay;
     private long period;
-    // TODO separate in Timer and TimerInstance
-    private JobHandle jobHandle;
-    private Date activated;
-    private Date lastTriggered;
-    private long processInstanceId;
     
     public long getId() {
         return id;
@@ -38,37 +33,23 @@
     public void setPeriod(long period) {
         this.period = period;
     }
-
-    public JobHandle getJobHandle() {
-        return jobHandle;
-    }
-
-    public void setJobHandle(JobHandle jobHandle) {
-        this.jobHandle = jobHandle;
-    }
     
-    public Date getActivated() {
-		return activated;
-	}
-
-	public void setActivated(Date activated) {
-		this.activated = activated;
-	}
-
-	public void setLastTriggered(Date lastTriggered) {
-    	this.lastTriggered = lastTriggered;
+    public String toString() {
+    	String result =  "Timer";
+    	if (delay != 0 || period != 0) {
+    		result += "[";
+    		if (delay != 0) {
+    			result += "delay=" + delay;
+    			if (period != 0) {
+    				result += ", ";
+    			}
+    		}
+    		if (period != 0) {
+    			result += "period=" + period;
+    		}
+    		result += "]";
+    	}
+    	return result;
     }
-    
-    public Date getLastTriggered() {
-    	return lastTriggered;
-    }
 
-	public long getProcessInstanceId() {
-		return processInstanceId;
-	}
-
-	public void setProcessInstanceId(long processInstanceId) {
-		this.processInstanceId = processInstanceId;
-	}
-    
 }

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerInstance.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,86 @@
+package org.drools.process.instance.timer;
+
+import java.util.Date;
+
+import org.drools.time.JobHandle;
+
+/**
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class TimerInstance {
+
+    private long id;
+    private long timerId;
+    private long delay;
+    private long period;
+    private JobHandle jobHandle;
+    private Date activated;
+    private Date lastTriggered;
+    private long processInstanceId;
+    
+    public long getId() {
+        return id;
+    }
+    
+    public void setId(long id) {
+        this.id = id;
+    }
+    
+    public long getTimerId() {
+		return timerId;
+	}
+
+	public void setTimerId(long timerId) {
+		this.timerId = timerId;
+	}
+
+	public long getDelay() {
+        return delay;
+    }
+    
+    public void setDelay(long delay) {
+        this.delay = delay;
+    }
+    
+    public long getPeriod() {
+        return period;
+    }
+    
+    public void setPeriod(long period) {
+        this.period = period;
+    }
+
+    public JobHandle getJobHandle() {
+        return jobHandle;
+    }
+
+    public void setJobHandle(JobHandle jobHandle) {
+        this.jobHandle = jobHandle;
+    }
+    
+    public Date getActivated() {
+		return activated;
+	}
+
+	public void setActivated(Date activated) {
+		this.activated = activated;
+	}
+
+	public void setLastTriggered(Date lastTriggered) {
+    	this.lastTriggered = lastTriggered;
+    }
+    
+    public Date getLastTriggered() {
+    	return lastTriggered;
+    }
+
+	public long getProcessInstanceId() {
+		return processInstanceId;
+	}
+
+	public void setProcessInstanceId(long processInstanceId) {
+		this.processInstanceId = processInstanceId;
+	}
+    
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerListener.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerListener.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerListener.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,9 +1,11 @@
 package org.drools.process.instance.timer;
 
-import org.drools.process.core.timer.Timer;
-
+/**
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
 public interface TimerListener {
     
-    void timerTriggered(Timer timer);
+    void timerTriggered(TimerInstance timer);
     
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerManager.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerManager.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/process/instance/timer/TimerManager.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -9,7 +9,6 @@
 import java.util.Map;
 
 import org.drools.WorkingMemory;
-import org.drools.process.core.timer.Timer;
 import org.drools.process.instance.ProcessInstance;
 import org.drools.time.Job;
 import org.drools.time.JobContext;
@@ -17,19 +16,24 @@
 import org.drools.time.TimerService;
 import org.drools.time.Trigger;
 
+/**
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
 public class TimerManager {
     private long          timerId = 0;
 
     private WorkingMemory workingMemory;
     private TimerService  timerService;
-    private Map<Long, Timer> timers = new HashMap<Long, Timer>();
+    private Map<Long, TimerInstance> timers = new HashMap<Long, TimerInstance>();
+    private Job processJob = new ProcessJob();
 
     public TimerManager(WorkingMemory workingMemory, TimerService timerService) {
         this.workingMemory = workingMemory;
         this.timerService = timerService;
     }
 
-    public void registerTimer(final Timer timer,
+    public void registerTimer(final TimerInstance timer,
                               ProcessInstance processInstance) {
         timer.setId( ++timerId );
         timer.setProcessInstanceId(processInstance.getId());
@@ -39,15 +43,15 @@
                                                        processInstance.getId(),
                                                        this.workingMemory );
 
-        JobHandle jobHandle = this.timerService.scheduleJob( ProcessJob.instance,
+        JobHandle jobHandle = this.timerService.scheduleJob( processJob,
                                                              ctx,
                                                              new TimerTrigger( timer.getDelay(),
                                                                                timer.getPeriod() ) );
         timer.setJobHandle( jobHandle );
-        timers.put(timerId, timer);
+        timers.put(timer.getId(), timer);
     }
 
-    public void internalAddTimer(final Timer timer) {
+    public void internalAddTimer(final TimerInstance timer) {
 		ProcessJobContext ctx = new ProcessJobContext(
 			timer, timer.getProcessInstanceId(), this.workingMemory);
 
@@ -70,20 +74,20 @@
 			}
 		}
 		JobHandle jobHandle = this.timerService.scheduleJob(
-			ProcessJob.instance, ctx, new TimerTrigger(delay, timer.getPeriod()));
+			processJob, ctx, new TimerTrigger(delay, timer.getPeriod()));
 		timer.setJobHandle(jobHandle);
-		timers.put(timerId, timer);
+		timers.put(timer.getId(), timer);
 	}
 
     public void cancelTimer(long timerId) {
-    	Timer timer = timers.get(timerId);
+    	TimerInstance timer = timers.remove(timerId);
     	if (timer != null) {
     		timerService.removeJob( timer.getJobHandle() );
     	}
     }
     
     public void dispose() {
-    	for (Timer timer: timers.values()) {
+    	for (TimerInstance timer: timers.values()) {
     		timerService.removeJob( timer.getJobHandle() );
     	}
     }
@@ -92,7 +96,7 @@
         return this.timerService;
     }
     
-    public Collection<Timer> getTimers() {
+    public Collection<TimerInstance> getTimers() {
     	return timers.values();
     }
     
@@ -104,11 +108,8 @@
     	this.timerId = timerId;
     }
 
-    public static class ProcessJob
-        implements
-        Job {
-        public final static ProcessJob instance = new ProcessJob();
-
+    public class ProcessJob implements Job {
+    	
         public void execute(JobContext c) {
             ProcessJobContext ctx = (ProcessJobContext) c;
 
@@ -126,6 +127,10 @@
             if ( processInstance != null ) {
                 processInstance.signalEvent( "timerTriggered", ctx.getTimer() );
             }
+            
+            if (ctx.getTimer().getPeriod() == 0) {
+            	TimerManager.this.timers.remove(ctx.getTimer().getId());
+            }
         }
 
     }
@@ -160,8 +165,7 @@
             return date;
         }
 
-        public void readExternal(ObjectInput in) throws IOException,
-                                                ClassNotFoundException {
+        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
             this.delay = in.readLong();
             this.period = in.readLong();
             this.count = in.readInt();
@@ -171,7 +175,6 @@
             out.writeLong( this.delay );
             out.writeLong( this.period );
             out.writeInt(  this.count );
-            
         }
 
     }
@@ -181,11 +184,11 @@
         JobContext {
         private Long          processInstanceId;
         private WorkingMemory workingMemory;
-        private Timer         timer;
+        private TimerInstance timer;
 
         private JobHandle     jobHandle;
 
-        public ProcessJobContext(final Timer timer,
+        public ProcessJobContext(final TimerInstance timer,
                                  final Long processInstanceId,
                                  final WorkingMemory workingMemory) {
             this.timer = timer;
@@ -209,7 +212,7 @@
             this.jobHandle = jobHandle;
         }
 
-        public Timer getTimer() {
+        public TimerInstance getTimer() {
             return timer;
         }
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/impl/ExtendedNodeImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/impl/ExtendedNodeImpl.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/impl/ExtendedNodeImpl.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -7,6 +7,9 @@
 import org.drools.workflow.core.DroolsAction;
 
 public class ExtendedNodeImpl extends NodeImpl {
+	
+	// TODO: not all sequence nodes need entry/exit actions or timers,
+	// could this be added in a more modular way ?
 
 	public static final String EVENT_NODE_ENTER = "onEntry";
 	public static final String EVENT_NODE_EXIT = "onExit";
@@ -30,5 +33,5 @@
 	public String[] getActionTypes() {
 		return EVENT_TYPES;
 	}
-
+	
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/EventBasedNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/EventBasedNode.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/core/node/EventBasedNode.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,7 +1,39 @@
 package org.drools.workflow.core.node;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import org.drools.process.core.timer.Timer;
+import org.drools.workflow.core.DroolsAction;
+
 public class EventBasedNode extends SequenceNode {
 
     private static final long serialVersionUID = 400L;
 
+	private Map<Timer, DroolsAction> timers;
+	
+	public Map<Timer, DroolsAction> getTimers() {
+		return timers;
+	}
+	
+	public void addTimer(Timer timer, DroolsAction action) {
+		if (timers == null) {
+			timers = new HashMap<Timer, DroolsAction>();
+		}
+		if (timer.getId() == 0) {
+			long id = 0;
+	        for (Timer t: timers.keySet()) {
+	            if (t.getId() > id) {
+	                id = t.getId();
+	            }
+	        }
+	        timer.setId(++id);
+		}
+		timers.put(timer, action);
+	}
+	
+	public void internalSetTimers(Map<Timer, DroolsAction> timers) {
+		this.timers = timers;
+	}
+
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/impl/ExtendedNodeInstanceImpl.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -9,14 +9,17 @@
 import org.drools.process.core.context.exception.ExceptionScope;
 import org.drools.process.instance.context.exception.ExceptionScopeInstance;
 import org.drools.spi.Action;
+import org.drools.spi.KnowledgeHelper;
 import org.drools.spi.ProcessContext;
-import org.drools.spi.KnowledgeHelper;
 import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.Node;
 import org.drools.workflow.core.impl.ExtendedNodeImpl;
 import org.drools.workflow.instance.NodeInstance;
 
 public abstract class ExtendedNodeInstanceImpl extends NodeInstanceImpl {
 
+	private static final long serialVersionUID = 4L;
+	
 	public ExtendedNodeImpl getExtendedNode() {
 		return (ExtendedNodeImpl) getNode();
 	}
@@ -25,6 +28,10 @@
 		triggerEvent(ExtendedNodeImpl.EVENT_NODE_ENTER);
 	}
 	
+    public void triggerCompleted(boolean remove) {
+        triggerCompleted(Node.CONNECTION_DEFAULT_TYPE, remove);
+    }
+    
 	protected void triggerCompleted(String type, boolean remove) {
 		triggerEvent(ExtendedNodeImpl.EVENT_NODE_EXIT);
 		super.triggerCompleted(type, remove);
@@ -33,32 +40,41 @@
 	protected void triggerEvent(String type) {
 		List<DroolsAction> actions = getExtendedNode().getActions(type);
 		if (actions != null) {
-			WorkingMemory workingMemory = getProcessInstance().getWorkingMemory();
-			KnowledgeHelper knowledgeHelper = null;
-			if (((InternalRuleBase) workingMemory.getRuleBase()).getConfiguration().isSequential()) {
-				knowledgeHelper = new SequentialKnowledgeHelper(workingMemory);
-	        } else {
-	        	knowledgeHelper = new DefaultKnowledgeHelper(workingMemory);
-	        }
+			KnowledgeHelper knowledgeHelper = createKnowledgeHelper();
 			for (DroolsAction droolsAction: actions) {
-				Action action = (Action) droolsAction.getMetaData("Action");
-				ProcessContext context = new ProcessContext();
-				context.setNodeInstance(this);
-				try {
-					action.execute(knowledgeHelper, workingMemory, context);
-				} catch (Exception exception) {
-					String exceptionName = exception.getClass().getName();
-					ExceptionScopeInstance exceptionScopeInstance = (ExceptionScopeInstance)
-						resolveContextInstance(ExceptionScope.EXCEPTION_SCOPE, exceptionName);
-					if (exceptionScopeInstance == null) {
-						exception.printStackTrace();
-						throw new IllegalArgumentException(
-							"Could not find exception handler for " + exceptionName + " while executing node " + getNodeId());
-					}
-					exceptionScopeInstance.handleException(exceptionName, exception);
-				}
+				executeAction(droolsAction, knowledgeHelper);
 			}
 		}
 	}
 	
+	protected KnowledgeHelper createKnowledgeHelper() {
+		KnowledgeHelper knowledgeHelper = null;
+		WorkingMemory workingMemory = getProcessInstance().getWorkingMemory();
+		if (((InternalRuleBase) workingMemory.getRuleBase()).getConfiguration().isSequential()) {
+			knowledgeHelper = new SequentialKnowledgeHelper(workingMemory);
+        } else {
+        	knowledgeHelper = new DefaultKnowledgeHelper(workingMemory);
+        }
+		return knowledgeHelper;
+	}
+	
+	protected void executeAction(DroolsAction droolsAction, KnowledgeHelper knowledgeHelper) {
+		Action action = (Action) droolsAction.getMetaData("Action");
+		ProcessContext context = new ProcessContext();
+		context.setNodeInstance(this);
+		try {
+			action.execute(knowledgeHelper, getProcessInstance().getWorkingMemory(), context);
+		} catch (Exception exception) {
+			String exceptionName = exception.getClass().getName();
+			ExceptionScopeInstance exceptionScopeInstance = (ExceptionScopeInstance)
+				resolveContextInstance(ExceptionScope.EXCEPTION_SCOPE, exceptionName);
+			if (exceptionScopeInstance == null) {
+				exception.printStackTrace();
+				throw new IllegalArgumentException(
+					"Could not find exception handler for " + exceptionName + " while executing node " + getNodeId());
+			}
+			exceptionScopeInstance.handleException(exceptionName, exception);
+		}
+	}
+	
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/EventBasedNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/EventBasedNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/EventBasedNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,28 +1,123 @@
 package org.drools.workflow.instance.node;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.drools.process.core.timer.Timer;
+import org.drools.process.instance.EventListener;
+import org.drools.process.instance.timer.TimerInstance;
+import org.drools.process.instance.timer.TimerManager;
+import org.drools.spi.KnowledgeHelper;
+import org.drools.workflow.core.DroolsAction;
 import org.drools.workflow.core.Node;
+import org.drools.workflow.core.impl.ExtendedNodeImpl;
 import org.drools.workflow.core.node.EventBasedNode;
+import org.drools.workflow.instance.NodeInstance;
 import org.drools.workflow.instance.impl.ExtendedNodeInstanceImpl;
 
-public abstract class EventBasedNodeInstance extends ExtendedNodeInstanceImpl implements EventBasedNodeInstanceInterface {
+public abstract class EventBasedNodeInstance extends ExtendedNodeInstanceImpl implements EventBasedNodeInstanceInterface, EventListener {
+	
+	private static final long serialVersionUID = 4L;
 
-    public EventBasedNode getEventNode() {
+	private List<Long> timerInstances;
+
+	public EventBasedNode getEventBasedNode() {
         return (EventBasedNode) getNode();
     }
     
+	public void internalTrigger(NodeInstance from, String type) {
+		super.internalTrigger(from, type);
+		// activate timers
+		Map<Timer, DroolsAction> timers = getEventBasedNode().getTimers();
+		if (timers != null) {
+			addTimerListener();
+			timerInstances = new ArrayList<Long>(timers.size());
+			TimerManager timerManager = getProcessInstance().getWorkingMemory().getTimerManager();
+			for (Timer timer: timers.keySet()) {
+				TimerInstance timerInstance = createTimerInstance(timer); 
+				timerManager.registerTimer(timerInstance, getProcessInstance());
+				timerInstances.add(timerInstance.getId());
+			}
+		}
+	}
+	
+    protected TimerInstance createTimerInstance(Timer timer) {
+    	TimerInstance timerInstance = new TimerInstance();
+    	timerInstance.setDelay(timer.getDelay());
+    	timerInstance.setPeriod(timer.getPeriod());
+    	timerInstance.setTimerId(timer.getId());
+    	return timerInstance;
+    }
+
+    public void signalEvent(String type, Object event) {
+    	if ("timerTriggered".equals(type)) {
+    		TimerInstance timerInstance = (TimerInstance) event;
+            if (timerInstances.contains(timerInstance.getId())) {
+                triggerTimer(timerInstance);
+            }
+    	}
+    }
+    
+    private void triggerTimer(TimerInstance timerInstance) {
+    	for (Map.Entry<Timer, DroolsAction> entry: getEventBasedNode().getTimers().entrySet()) {
+    		if (entry.getKey().getId() == timerInstance.getTimerId()) {
+    			KnowledgeHelper knowledgeHelper = createKnowledgeHelper();
+    			executeAction(entry.getValue(), knowledgeHelper);
+    			return;
+    		}
+    	}
+    }
+    
+    public String[] getEventTypes() {
+    	return new String[] { "timerTriggered" };
+    }
+    
     public void triggerCompleted() {
         triggerCompleted(Node.CONNECTION_DEFAULT_TYPE, true);
     }
     
-    public void cancel() {
-        super.cancel();
-        removeEventListeners();
+    public void addEventListeners() {
+    	if (timerInstances != null && timerInstances.size() > 0) {
+    		addTimerListener();
+    	}
     }
     
-    public void addEventListeners() {
+    protected void addTimerListener() {
+    	getProcessInstance().addEventListener("timerTriggered", this);
     }
     
     public void removeEventListeners() {
+        getProcessInstance().removeEventListener("timerTriggered", this);
     }
+
+	protected void triggerCompleted(String type, boolean remove) {
+		cancelTimers();
+		super.triggerCompleted(type, remove);
+	}
+	
+	public List<Long> getTimerInstances() {
+		return timerInstances;
+	}
+	
+	public void internalSetTimerInstances(List<Long> timerInstances) {
+		this.timerInstances = timerInstances;
+	}
+
+    public void cancel() {
+        cancelTimers();
+        removeEventListeners();
+        super.cancel();
+    }
     
+	private void cancelTimers() {
+		// deactivate still active timers
+		if (timerInstances != null) {
+			TimerManager timerManager = getProcessInstance().getWorkingMemory().getTimerManager();
+			for (Long id: timerInstances) {
+				timerManager.cancelTimer(id);
+			}
+		}
+	}
+	
 }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/MilestoneNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/MilestoneNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/MilestoneNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -43,6 +43,7 @@
     }
 
     public void internalTrigger(final NodeInstance from, String type) {
+    	super.internalTrigger(from, type);
         if (!Node.CONNECTION_DEFAULT_TYPE.equals(type)) {
             throw new IllegalArgumentException(
                 "A MilestoneNode only accepts default incoming connections!");
@@ -53,12 +54,16 @@
         if( ((InternalAgenda)getProcessInstance().getAgenda()).isRuleActiveInRuleFlowGroup( "DROOLS_SYSTEM", rule ) ) {
             triggerCompleted();
         } else {
-            addEventListeners();
+            addActivationListener();
         }
     }
     
     public void addEventListeners() {
         super.addEventListeners();
+        addActivationListener();
+    }
+    
+    private void addActivationListener() {
         getProcessInstance().getWorkingMemory().addEventListener(this);
     }
 

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/RuleSetNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -42,12 +42,16 @@
         if ( !Node.CONNECTION_DEFAULT_TYPE.equals( type ) ) {
             throw new IllegalArgumentException( "A RuleSetNode only accepts default incoming connections!" );
         }
-        addEventListeners();
+        addRuleSetListener();
         getProcessInstance().getAgenda().activateRuleFlowGroup( getRuleSetNode().getRuleFlowGroup() );
     }
 
     public void addEventListeners() {
         super.addEventListeners();
+        addRuleSetListener();
+    }
+    
+    private void addRuleSetListener() {
         ((InternalAgenda) getProcessInstance().getWorkingMemory().getAgenda()).addRuleFlowGroupListener( getRuleSetNode().getRuleFlowGroup(),
                                                                                                          this );
     }

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/SubProcessNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -19,6 +19,8 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.drools.common.InternalRuleBase;
+import org.drools.process.core.Process;
 import org.drools.process.core.context.variable.VariableScope;
 import org.drools.process.instance.EventListener;
 import org.drools.process.instance.ProcessInstance;
@@ -43,6 +45,7 @@
     }
 
     public void internalTrigger(final NodeInstance from, String type) {
+    	super.internalTrigger(from, type);
         if (!Node.CONNECTION_DEFAULT_TYPE.equals(type)) {
             throw new IllegalArgumentException(
                 "A SubProcess node only accepts default incoming connections!");
@@ -59,15 +62,23 @@
                 System.err.println("Continuing without setting parameter.");
             }
         }
-    	ProcessInstance processInstance = 
-    		getProcessInstance().getWorkingMemory().startProcess(getSubProcessNode().getProcessId(), parameters);
-    	if (!getSubProcessNode().isWaitForCompletion()
-    	        || processInstance.getState() == ProcessInstance.STATE_COMPLETED) {
-    		triggerCompleted();
-    	} else {
-    		this.processInstanceId = processInstance.getId();
-    	    addEventListeners();
-    	}
+        String processId = getSubProcessNode().getProcessId();
+        Process process = ((InternalRuleBase) getProcessInstance().getWorkingMemory().getRuleBase()).getProcess(processId);
+        if (process == null) {
+        	System.err.println("Could not find process " + processId);
+        	System.err.println("Aborting process");
+        	getProcessInstance().setState(ProcessInstance.STATE_ABORTED);
+        } else {
+	    	ProcessInstance processInstance = 
+	    		getProcessInstance().getWorkingMemory().startProcess(processId, parameters);
+	    	if (!getSubProcessNode().isWaitForCompletion()
+	    	        || processInstance.getState() == ProcessInstance.STATE_COMPLETED) {
+	    		triggerCompleted();
+	    	} else {
+	    		this.processInstanceId = processInstance.getId();
+	    	    addProcessListener();
+	    	}
+        }
     }
     
     public void cancel() {
@@ -90,6 +101,10 @@
 
     public void addEventListeners() {
         super.addEventListeners();
+        addProcessListener();
+    }
+    
+    private void addProcessListener() {
         getProcessInstance().addEventListener("processInstanceCompleted:" + processInstanceId, this);
     }
 
@@ -99,7 +114,11 @@
     }
 
 	public void signalEvent(String type, Object event) {
-		processInstanceCompleted((ProcessInstance) event);
+		if (("processInstanceCompleted:" + processInstanceId).equals(type)) {
+			processInstanceCompleted((ProcessInstance) event);
+		} else {
+			super.signalEvent(type, event);
+		}
 	}
     
     public String[] getEventTypes() {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/TimerNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/TimerNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/TimerNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -2,6 +2,7 @@
 
 import org.drools.process.core.timer.Timer;
 import org.drools.process.instance.EventListener;
+import org.drools.process.instance.timer.TimerInstance;
 import org.drools.workflow.core.Node;
 import org.drools.workflow.core.node.TimerNode;
 import org.drools.workflow.instance.NodeInstance;
@@ -29,24 +30,27 @@
             throw new IllegalArgumentException(
                 "A TimerNode only accepts default incoming connections!");
         }
-        Timer timer = createTimer();
-        addEventListeners();
+        TimerInstance timer = createTimerInstance();
+        if (getTimerInstances() == null) {
+        	addTimerListener();
+        }
         getProcessInstance().getWorkingMemory().getTimerManager()
             .registerTimer(timer, getProcessInstance());
         timerId = timer.getId();
     }
     
-    protected Timer createTimer() {
-    	Timer timerDef = getTimerNode().getTimer(); 
-    	Timer timer = new Timer();
-    	timer.setDelay(timerDef.getDelay());
-    	timer.setPeriod(timerDef.getPeriod());
-    	return timer;
+    protected TimerInstance createTimerInstance() {
+    	Timer timer = getTimerNode().getTimer(); 
+    	TimerInstance timerInstance = new TimerInstance();
+    	timerInstance.setDelay(timer.getDelay());
+    	timerInstance.setPeriod(timer.getPeriod());
+    	timerInstance.setTimerId(timer.getId());
+    	return timerInstance;
     }
 
     public void signalEvent(String type, Object event) {
     	if ("timerTriggered".equals(type)) {
-    		Timer timer = (Timer) event;
+    		TimerInstance timer = (TimerInstance) event;
             if (timer.getId() == timerId) {
                 triggerCompleted(timer.getPeriod() == 0);
             }
@@ -68,7 +72,9 @@
     
     public void addEventListeners() {
         super.addEventListeners();
-        getProcessInstance().addEventListener("timerTriggered", this);
+        if (getTimerInstances() == null) {
+        	getProcessInstance().addEventListener("timerTriggered", this);
+        }
     }
     
     public void removeEventListeners() {

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/workflow/instance/node/WorkItemNodeInstance.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -80,7 +80,7 @@
         WorkItemNode workItemNode = getWorkItemNode();
         createWorkItem(workItemNode);
 		if (workItemNode.isWaitForCompletion()) {
-		    addEventListeners();
+		    addWorkItemListener();
         }
 		if (isInversionOfControl()) {
 		    getProcessInstance().getWorkingMemory().update(getProcessInstance().getWorkingMemory().getFactHandle(this), this);
@@ -172,6 +172,10 @@
     
     public void addEventListeners() {
         super.addEventListeners();
+        addWorkItemListener();
+    }
+    
+    private void addWorkItemListener() {
         getProcessInstance().addEventListener("workItemCompleted", this);
         getProcessInstance().addEventListener("workItemAborted", this);
     }
@@ -187,7 +191,9 @@
     		workItemCompleted((WorkItem) event);
     	} else if ("workItemAborted".equals(type)) {
     		workItemAborted((WorkItem) event);
-    	} 
+    	} else {
+    		super.signalEvent(type, event);
+    	}
     }
 
     public String[] getEventTypes() {

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/TimerTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/TimerTest.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/process/TimerTest.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -5,7 +5,7 @@
 import org.drools.RuleBaseFactory;
 import org.drools.common.AbstractRuleBase;
 import org.drools.common.InternalWorkingMemory;
-import org.drools.process.core.timer.Timer;
+import org.drools.process.instance.timer.TimerInstance;
 import org.drools.process.instance.timer.TimerManager;
 import org.drools.reteoo.ReteooWorkingMemory;
 import org.drools.ruleflow.instance.RuleFlowProcessInstance;
@@ -18,9 +18,10 @@
         AbstractRuleBase ruleBase = (AbstractRuleBase) RuleBaseFactory.newRuleBase();
         InternalWorkingMemory workingMemory = new ReteooWorkingMemory(1, ruleBase);
         RuleFlowProcessInstance processInstance = new RuleFlowProcessInstance() {
-        	public void signalEvent(String type, Object event) {
+			private static final long serialVersionUID = 4L;
+			public void signalEvent(String type, Object event) {
         		if ("timerTriggered".equals(type)) {
-        			Timer timer = (Timer) event;
+        			TimerInstance timer = (TimerInstance) event;
             		System.out.println("Timer " + timer.getId() + " triggered");
             		counter++;
         		}
@@ -29,7 +30,7 @@
         processInstance.setId(1234);
         workingMemory.getProcessInstanceManager().internalAddProcessInstance(processInstance);
         TimerManager timerManager = workingMemory.getTimerManager();
-        Timer timer = new Timer();
+        TimerInstance timer = new TimerInstance();
         timerManager.registerTimer(timer, processInstance);
         try {
         	Thread.sleep(1000);
@@ -39,7 +40,7 @@
         assertEquals(1, counter);
         
         counter = 0;
-        timer = new Timer();
+        timer = new TimerInstance();
         timer.setDelay(500);
         timerManager.registerTimer(timer, processInstance);
         assertEquals(0, counter);
@@ -51,7 +52,7 @@
         assertEquals(1, counter);
         
         counter = 0;
-        timer = new Timer();
+        timer = new TimerInstance();
         timer.setDelay(500);
         timer.setPeriod(300);
         timerManager.registerTimer(timer, processInstance);

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditBeanDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditBeanDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditBeanDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -15,7 +15,11 @@
  * limitations under the License.
  */
 
+import org.drools.eclipse.DroolsEclipsePlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Shell;
@@ -54,6 +58,7 @@
             value = updateValue(value);
             super.okPressed();
         } catch (IllegalArgumentException e) {
+        	showError(e.getMessage());
             // value could not be set, ignoring ok
         }
     }
@@ -63,4 +68,10 @@
     public void setValue(T value) {
         this.value = value;
     }
+    
+    protected void showError(String error) {
+        ErrorDialog.openError(getShell(), "Error", error, new Status(
+            IStatus.ERROR, DroolsEclipsePlugin.getDefault().getBundle().getSymbolicName(),
+            IStatus.ERROR, error, null));
+    }
 }

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditMapDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditMapDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/EditMapDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -39,10 +39,10 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public abstract class EditMapDialog<T> extends EditBeanDialog<Map<String, T>> {
+public abstract class EditMapDialog<S, T> extends EditBeanDialog<Map<S, T>> {
     
     private Class<? extends EditBeanDialog<T>> editItemDialogClass;
-    private Map<String, T> newMap;
+    private Map<S, T> newMap;
     private ListViewer listViewer;
     private Button removeButton;
     private Button editButton;
@@ -114,24 +114,25 @@
         return composite;
     }
     
-	public void setValue(Map<String, T> value) {
+	public void setValue(Map<S, T> value) {
         super.setValue(value);
         if (value == null) {
-        	this.newMap = new HashMap<String, T>();
+        	this.newMap = new HashMap<S, T>();
         } else {
-        	this.newMap = new HashMap<String, T>((Map<String, T>) value);
+        	this.newMap = new HashMap<S, T>((Map<S, T>) value);
         }
     }
     
-    protected Map<String, T> updateValue(Map<String, T> value) {
+    protected Map<S, T> updateValue(Map<S, T> value) {
         return newMap;
     }
 
-    private void addItem() {
+    @SuppressWarnings("unchecked")
+	private void addItem() {
         EditBeanDialog<T> dialog = createEditItemDialog();
         dialog.setValue(createItem());
         int code = dialog.open();
-        String key = ((MapItemDialog) dialog).getKey();
+        S key = ((MapItemDialog<S>) dialog).getKey();
         T result = dialog.getValue();
         if (code != CANCEL) {
             T object = newMap.put(key, result);
@@ -146,10 +147,10 @@
     @SuppressWarnings("unchecked")
 	private void editItem() {
         EditBeanDialog<T> dialog = createEditItemDialog();
-        Iterator<String> iterator = ((StructuredSelection) listViewer.getSelection()).iterator();
+        Iterator<S> iterator = ((StructuredSelection) listViewer.getSelection()).iterator();
         if (iterator.hasNext()) {
-        	String key = iterator.next();
-            ((MapItemDialog) dialog).setKey(key);
+        	S key = iterator.next();
+            ((MapItemDialog<S>) dialog).setKey(key);
             dialog.setValue(newMap.get(key));
             int code = dialog.open();
             T result = dialog.getValue();
@@ -161,10 +162,10 @@
     
     @SuppressWarnings("unchecked")
 	private void removeItem() {
-        Iterator<String> iterator = ((StructuredSelection) listViewer.getSelection()).iterator();
+        Iterator<S> iterator = ((StructuredSelection) listViewer.getSelection()).iterator();
         // single selection only allowed
         if (iterator.hasNext()) {
-            String key = iterator.next();
+            S key = iterator.next();
             newMap.remove(key);
             listViewer.remove(key);
         }

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/MapItemDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/MapItemDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/common/view/property/MapItemDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -1,9 +1,9 @@
 package org.drools.eclipse.flow.common.view.property;
 
-public interface MapItemDialog {
+public interface MapItemDialog<S> {
 	
-	String getKey();
+	S getKey();
 	
-	void setKey(String key);
+	void setKey(S key);
 
 }

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/AbstractNodeWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/AbstractNodeWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/AbstractNodeWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -28,7 +28,9 @@
  */
 public abstract class AbstractNodeWrapper extends DefaultElementWrapper implements NodeWrapper {
 	
-    public void setNode(Node node) {
+	private static final long serialVersionUID = 4L;
+
+	public void setNode(Node node) {
         setElement(node);
     }
     

Added: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/EventBasedNodeWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/EventBasedNodeWrapper.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/EventBasedNodeWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,64 @@
+package org.drools.eclipse.flow.ruleflow.core;
+
+import java.util.Map;
+
+import org.drools.eclipse.flow.common.editor.core.DefaultElementWrapper;
+import org.drools.eclipse.flow.ruleflow.view.property.timers.TimersPropertyDescriptor;
+import org.drools.process.core.timer.Timer;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.WorkflowProcess;
+import org.drools.workflow.core.node.EventBasedNode;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+
+public class EventBasedNodeWrapper extends ExtendedNodeWrapper {
+
+    public static final String TIMERS = "Timers";
+
+	private static final long serialVersionUID = 1L;
+	
+    protected IPropertyDescriptor[] descriptors;
+    
+    public EventBasedNode getEventBasedNode() {
+    	return (EventBasedNode) getNode();
+    }
+
+    protected void initDescriptors() {
+    	descriptors = new IPropertyDescriptor[DefaultElementWrapper.descriptors.length + 1];
+        System.arraycopy(DefaultElementWrapper.descriptors, 0, descriptors, 0, DefaultElementWrapper.descriptors.length);
+        descriptors[descriptors.length - 1] = 
+            new TimersPropertyDescriptor(TIMERS, "Timers", getEventBasedNode(),
+        		(WorkflowProcess) getParent().getProcessWrapper().getProcess());
+    }
+
+    public IPropertyDescriptor[] getPropertyDescriptors() {
+    	if (descriptors == null) {
+    		initDescriptors();
+    	}
+        return descriptors;
+    }
+
+    public Object getPropertyValue(Object id) {
+        if (TIMERS.equals(id)) {
+            return getEventBasedNode().getTimers();
+        }
+        return super.getPropertyValue(id);
+    }
+
+    public void resetPropertyValue(Object id) {
+        if (TIMERS.equals(id)) {
+        	getEventBasedNode().internalSetTimers(null);
+        } else {
+            super.resetPropertyValue(id);
+        }
+    }
+
+	@SuppressWarnings("unchecked")
+	public void setPropertyValue(Object id, Object value) {
+        if (TIMERS.equals(id)) {
+        	getEventBasedNode().internalSetTimers((Map<Timer, DroolsAction>) value);
+        } else {
+            super.setPropertyValue(id, value);
+        }
+    }
+    
+}

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/ExtendedNodeWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/ExtendedNodeWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/ExtendedNodeWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -52,7 +52,8 @@
         }
     }
 
-    public void setPropertyValue(Object id, Object value) {
+    @SuppressWarnings("unchecked")
+	public void setPropertyValue(Object id, Object value) {
         if (ON_ENTRY_ACTIONS.equals(id)) {
         	getExtendedNode().setActions(ExtendedNodeImpl.EVENT_NODE_ENTER, (List<DroolsAction>) value);
         } else if (ON_EXIT_ACTIONS.equals(id)) {

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/HumanTaskNodeWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/HumanTaskNodeWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/HumanTaskNodeWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -59,13 +59,13 @@
         setWorkDefinition(WORK_DEFINITION);
     }
     
-    protected IPropertyDescriptor[] createPropertyDescriptors() {
-        IPropertyDescriptor[] parentDescriptors = super.createPropertyDescriptors();
+    protected void initDescriptors() {
+    	super.initDescriptors();
+        IPropertyDescriptor[] parentDescriptors = descriptors;
         IPropertyDescriptor[] descriptors = new IPropertyDescriptor[parentDescriptors.length + 1];
         System.arraycopy(parentDescriptors, 0, descriptors, 0, parentDescriptors.length);
         descriptors[descriptors.length - 1] = 
             new TextPropertyDescriptor(SWIMLANE, "Swimlane");
-        return descriptors;
     }
     
     public HumanTaskNode getHumanTaskNode() {

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/MilestoneWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/MilestoneWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/MilestoneWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-import org.drools.eclipse.flow.common.editor.core.DefaultElementWrapper;
 import org.drools.eclipse.flow.common.editor.core.ElementConnection;
 import org.drools.eclipse.flow.common.editor.core.ElementWrapper;
 import org.drools.eclipse.flow.ruleflow.view.property.constraint.MilestoneConstraintPropertyDescriptor;
@@ -28,36 +27,31 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class MilestoneWrapper extends AbstractNodeWrapper {
+public class MilestoneWrapper extends EventBasedNodeWrapper {
 
-	private static final long serialVersionUID = -5976489437109982927L;
-	private IPropertyDescriptor[] descriptors;
-
     public static final String CONSTRAINT = "Constraint";
 
+	private static final long serialVersionUID = 4L;
+
     public MilestoneWrapper() {
         setNode(new MilestoneNode());
         getMilestoneNode().setName("Event Wait");
     }
     
-    private void setDescriptors() {
-        descriptors = new IPropertyDescriptor[DefaultElementWrapper.descriptors.length + 1];
-        System.arraycopy(DefaultElementWrapper.descriptors, 0, descriptors, 0, DefaultElementWrapper.descriptors.length);
+    protected void initDescriptors() {
+    	super.initDescriptors();
+    	IPropertyDescriptor[] oldDescriptors = descriptors; 
+        descriptors = new IPropertyDescriptor[oldDescriptors.length + 1];
+        System.arraycopy(oldDescriptors, 0, descriptors, 0, oldDescriptors.length);
         descriptors[descriptors.length - 1] = 
-            new MilestoneConstraintPropertyDescriptor(CONSTRAINT, "Constraint", getMilestoneNode(), (WorkflowProcess) getParent().getProcessWrapper().getProcess());
+            new MilestoneConstraintPropertyDescriptor(CONSTRAINT, "Constraint",
+        		getMilestoneNode(), (WorkflowProcess) getParent().getProcessWrapper().getProcess());
     }
     
     public MilestoneNode getMilestoneNode() {
         return (MilestoneNode) getNode();
     }
     
-    public IPropertyDescriptor[] getPropertyDescriptors() {
-    	if (descriptors == null) {
-    		setDescriptors();
-    	}
-        return descriptors;
-    }
-
     public boolean acceptsIncomingConnection(ElementConnection connection, ElementWrapper source) {
         return super.acceptsIncomingConnection(connection, source)
         	&& getIncomingConnections().isEmpty();

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/RuleSetNodeWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/RuleSetNodeWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/RuleSetNodeWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-import org.drools.eclipse.flow.common.editor.core.DefaultElementWrapper;
 import org.drools.eclipse.flow.common.editor.core.ElementConnection;
 import org.drools.eclipse.flow.common.editor.core.ElementWrapper;
 import org.drools.workflow.core.node.RuleSetNode;
@@ -27,15 +26,19 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class RuleSetNodeWrapper extends AbstractNodeWrapper {
+public class RuleSetNodeWrapper extends EventBasedNodeWrapper {
 
     private static final long serialVersionUID = 400L;
-    private static IPropertyDescriptor[] descriptors;
 
     public static final String RULE_FLOW_GROUP = "RuleFlowGroup";
-    static {
-        descriptors = new IPropertyDescriptor[DefaultElementWrapper.descriptors.length + 1];
-        System.arraycopy(DefaultElementWrapper.descriptors, 0, descriptors, 0, DefaultElementWrapper.descriptors.length);
+
+    protected void initDescriptors() {
+    	super.initDescriptors();
+    	IPropertyDescriptor[] oldDescriptors = descriptors; 
+        descriptors = new IPropertyDescriptor[oldDescriptors.length + 1];
+        System.arraycopy(oldDescriptors, 0, descriptors, 0, oldDescriptors.length);
+//        descriptors[descriptors.length - 3] = getOnEntryPropertyDescriptor();
+//        descriptors[descriptors.length - 2] = getOnExitPropertyDescriptor();
         descriptors[descriptors.length - 1] = 
             new TextPropertyDescriptor(RULE_FLOW_GROUP, "RuleFlowGroup");
     }
@@ -50,10 +53,6 @@
         return (RuleSetNode) getNode();
     }
     
-    public IPropertyDescriptor[] getPropertyDescriptors() {
-        return descriptors;
-    }
-
     public boolean acceptsIncomingConnection(ElementConnection connection, ElementWrapper source) {
         return super.acceptsIncomingConnection(connection, source)
         	&& getIncomingConnections().isEmpty();

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SplitWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SplitWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SplitWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -105,7 +105,8 @@
         }
     }
 
-    public void setPropertyValue(Object id, Object value) {
+    @SuppressWarnings("unchecked")
+	public void setPropertyValue(Object id, Object value) {
         if (TYPE.equals(id)) {
             getSplit().setType(((Integer) value).intValue());
         } else if (CONSTRAINTS.equals(id)) {

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SubProcessWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SubProcessWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/SubProcessWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -18,7 +18,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import org.drools.eclipse.flow.common.editor.core.DefaultElementWrapper;
 import org.drools.eclipse.flow.common.editor.core.ElementConnection;
 import org.drools.eclipse.flow.common.editor.core.ElementWrapper;
 import org.drools.eclipse.flow.ruleflow.view.property.subprocess.SubProcessParameterInMappingPropertyDescriptor;
@@ -33,10 +32,9 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class SubProcessWrapper extends ExtendedNodeWrapper {
+public class SubProcessWrapper extends EventBasedNodeWrapper {
 
 	private static final long serialVersionUID = 3668348577732020324L;
-    private static IPropertyDescriptor[] descriptors;
     
     public static final String PROCESS_ID = "ProcessId";
     public static final String WAIT_FOR_COMPLETION = "WaitForCompletion";
@@ -44,9 +42,16 @@
     public static final String PARAMETER_IN_MAPPING = "ParameterInMapping";
     public static final String PARAMETER_OUT_MAPPING = "ParameterOutMapping";
 
-    private void setDescriptors() {
-        descriptors = new IPropertyDescriptor[DefaultElementWrapper.descriptors.length + 7];
-        System.arraycopy(DefaultElementWrapper.descriptors, 0, descriptors, 0, DefaultElementWrapper.descriptors.length);
+    public SubProcessWrapper() {
+        setNode(new SubProcessNode());
+        getSubProcessNode().setName("SubProcess");
+    }
+    
+	protected void initDescriptors() {
+    	super.initDescriptors();
+    	IPropertyDescriptor[] oldDescriptors = descriptors; 
+        descriptors = new IPropertyDescriptor[oldDescriptors.length + 7];
+        System.arraycopy(oldDescriptors, 0, descriptors, 0, oldDescriptors.length);
         descriptors[descriptors.length - 7] = getOnEntryPropertyDescriptor();
         descriptors[descriptors.length - 6] = getOnExitPropertyDescriptor();
         descriptors[descriptors.length - 5] = 
@@ -61,22 +66,10 @@
             new ComboBoxPropertyDescriptor(WAIT_FOR_COMPLETION, "Wait for completion", new String[] {"true", "false"});
     }
     
-    public SubProcessWrapper() {
-        setNode(new SubProcessNode());
-        getSubProcessNode().setName("SubProcess");
-    }
-    
     public SubProcessNode getSubProcessNode() {
         return (SubProcessNode) getNode();
     }
     
-    public IPropertyDescriptor[] getPropertyDescriptors() {
-        if (descriptors == null) {
-            setDescriptors();
-        }
-        return descriptors;
-    }
-
     public boolean acceptsIncomingConnection(ElementConnection connection, ElementWrapper source) {
         return super.acceptsIncomingConnection(connection, source)
         	&& getIncomingConnections().isEmpty();
@@ -123,7 +116,8 @@
         }
     }
 
-    public void setPropertyValue(Object id, Object value) {
+    @SuppressWarnings("unchecked")
+	public void setPropertyValue(Object id, Object value) {
         if (PROCESS_ID.equals(id)) {
         	getSubProcessNode().setProcessId((String) value);
         } else if (WAIT_FOR_COMPLETION.equals(id)) {

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/WorkItemWrapper.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/WorkItemWrapper.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/core/WorkItemWrapper.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -19,7 +19,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.drools.eclipse.flow.common.editor.core.DefaultElementWrapper;
 import org.drools.eclipse.flow.common.editor.core.ElementConnection;
 import org.drools.eclipse.flow.common.editor.core.ElementWrapper;
 import org.drools.eclipse.flow.ruleflow.view.property.workitem.WorkItemParameterMappingPropertyDescriptor;
@@ -40,7 +39,7 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class WorkItemWrapper extends ExtendedNodeWrapper {
+public class WorkItemWrapper extends EventBasedNodeWrapper {
 
     public static final String WAIT_FOR_COMPLETION = "WaitForCompletion";
     public static final String RESULT_MAPPING = "ResultMapping";
@@ -49,7 +48,6 @@
 	private static final long serialVersionUID = 400L;
 
 	private WorkDefinition workDefinition;
-	private IPropertyDescriptor[] descriptors;
 
     public WorkItemWrapper() {
         setNode(new WorkItemNode());
@@ -94,22 +92,15 @@
         return false;
     }
     
-    private void setDescriptors() {
-        if (workDefinition != null) {
-            descriptors = createPropertyDescriptors();
-        }
-        if (descriptors == null) {
-            descriptors = DefaultElementWrapper.descriptors;
-        }
-    }
-    
-    protected IPropertyDescriptor[] createPropertyDescriptors() {
+	protected void initDescriptors() {
+    	super.initDescriptors();
         Set<ParameterDefinition> parameters = workDefinition.getParameters();
-            descriptors = new IPropertyDescriptor[DefaultElementWrapper.descriptors.length + parameters.size() + 5];
-        System.arraycopy(DefaultElementWrapper.descriptors, 0, descriptors, 0, DefaultElementWrapper.descriptors.length);
+    	IPropertyDescriptor[] oldDescriptors = descriptors; 
+        descriptors = new IPropertyDescriptor[oldDescriptors.length + parameters.size() + 5];
+        System.arraycopy(oldDescriptors, 0, descriptors, 0, oldDescriptors.length);
         int i = 0;
         for (ParameterDefinition def: parameters) {
-            descriptors[DefaultElementWrapper.descriptors.length + (i++)] = 
+            descriptors[oldDescriptors.length + (i++)] = 
                 new TextPropertyDescriptor(def.getName(), def.getName());
         }
         descriptors[descriptors.length - 5] = getOnEntryPropertyDescriptor();
@@ -120,16 +111,8 @@
             new WorkItemParameterMappingPropertyDescriptor(PARAMETER_MAPPING, "Parameter Mapping", getWorkItemNode());
         descriptors[descriptors.length - 1] = 
             new WorkItemResultMappingPropertyDescriptor(RESULT_MAPPING, "Result Mapping", getWorkItemNode());
-        return descriptors;
     }
     
-    public IPropertyDescriptor[] getPropertyDescriptors() {
-        if (descriptors == null) {
-            setDescriptors();
-        }
-    	return descriptors;
-    }
-
     public boolean acceptsIncomingConnection(ElementConnection connection, ElementWrapper source) {
         return super.acceptsIncomingConnection(connection, source)
         	&& getIncomingConnections().isEmpty();
@@ -175,7 +158,8 @@
         }
     }
 
-    public void setPropertyValue(Object id, Object value) {
+    @SuppressWarnings("unchecked")
+	public void setPropertyValue(Object id, Object value) {
         if (WAIT_FOR_COMPLETION.equals(id)) {
             getWorkItemNode().setWaitForCompletion(((Integer) value).intValue() == 0);
         } else if (PARAMETER_MAPPING.equals(id)) {

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlerDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlerDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlerDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -64,7 +64,7 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class ExceptionHandlerDialog extends EditBeanDialog<ActionExceptionHandler> implements MapItemDialog {
+public class ExceptionHandlerDialog extends EditBeanDialog<ActionExceptionHandler> implements MapItemDialog<String> {
     
     private static final String[] DIALECTS = new String[] { "mvel", "java" };
     

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlersDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlersDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/exceptionHandler/ExceptionHandlersDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -27,7 +27,7 @@
  * 
  * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
  */
-public class ExceptionHandlersDialog extends EditMapDialog<ActionExceptionHandler> {
+public class ExceptionHandlersDialog extends EditMapDialog<String, ActionExceptionHandler> {
     
 	private Process process;
 	

Added: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimerDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimerDialog.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimerDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,312 @@
+package org.drools.eclipse.flow.ruleflow.view.property.timers;
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.List;
+import java.util.Map;
+
+import org.drools.eclipse.editors.DRLSourceViewerConfig;
+import org.drools.eclipse.editors.scanners.DRLPartionScanner;
+import org.drools.eclipse.flow.common.view.property.EditBeanDialog;
+import org.drools.eclipse.flow.common.view.property.MapItemDialog;
+import org.drools.eclipse.flow.ruleflow.view.property.action.ActionCompletionProcessor;
+import org.drools.eclipse.flow.ruleflow.view.property.constraint.RuleFlowGlobalsDialog;
+import org.drools.eclipse.flow.ruleflow.view.property.constraint.RuleFlowImportsDialog;
+import org.drools.process.core.timer.Timer;
+import org.drools.util.ArrayUtils;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.WorkflowProcess;
+import org.drools.workflow.core.impl.DroolsConsequenceAction;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentPartitioner;
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.reconciler.IReconciler;
+import org.eclipse.jface.text.rules.FastPartitioner;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Dialog for editing exception handlers.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class TimerDialog extends EditBeanDialog<DroolsAction> implements MapItemDialog<Timer> {
+    
+    private static final String[] DIALECTS = new String[] { "mvel", "java" };
+    
+    private Timer key;
+    private Text delayText;
+    private Text periodText;
+	private WorkflowProcess process;
+	private TabFolder tabFolder;
+	private SourceViewer actionViewer;
+	private Combo dialectCombo;
+	private ActionCompletionProcessor completionProcessor;
+
+    public TimerDialog(Shell parentShell, WorkflowProcess process) {
+        super(parentShell, "Edit Timer");
+        this.process = process;
+    }
+    
+    protected Point getInitialSize() {
+        return new Point(400, 500);
+    }
+    
+    protected Control createDialogArea(Composite parent) {
+        final Composite composite = (Composite) super.createDialogArea(parent);
+        GridLayout gridLayout = new GridLayout();
+        gridLayout.numColumns = 2;
+        composite.setLayout(gridLayout);
+        
+        Label label = new Label(composite, SWT.NONE);
+        label.setText("Timer delay: ");
+        delayText = new Text(composite, SWT.NONE);
+        GridData gridData = new GridData();
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.horizontalAlignment = GridData.FILL;
+        delayText.setLayoutData(gridData);
+        if (key != null) {
+        	delayText.setText(key.getDelay() + "");
+        }
+        label = new Label(composite, SWT.NONE);
+        label.setText("Timer period: ");
+        periodText = new Text(composite, SWT.NONE);
+        gridData = new GridData();
+        gridData.grabExcessHorizontalSpace = true;
+        gridData.horizontalAlignment = GridData.FILL;
+        periodText.setLayoutData(gridData);
+        if (key != null) {
+        	periodText.setText(key.getPeriod() + "");
+        }
+        
+        		Composite top = new Composite(composite, SWT.NONE);
+		GridData gd = new GridData();
+		gd.horizontalSpan = 2;
+		gd.grabExcessHorizontalSpace = true;
+		top.setLayoutData(gd);
+
+		gridLayout = new GridLayout();
+		gridLayout.numColumns = 4;
+		top.setLayout(gridLayout);
+		
+		label = new Label(top, SWT.NONE);
+        label.setText("Dialect:");
+        createDialectCombo(top);
+		
+		Button importButton = new Button(top, SWT.PUSH);
+		importButton.setText("Imports ...");
+		importButton.setFont(JFaceResources.getDialogFont());
+		importButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent event) {
+				importButtonPressed();
+			}
+		});
+		
+		Button globalButton = new Button(top, SWT.PUSH);
+		globalButton.setText("Globals ...");
+		globalButton.setFont(JFaceResources.getDialogFont());
+		globalButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent event) {
+				globalButtonPressed();
+			}
+		});
+		
+		tabFolder = new TabFolder(composite, SWT.NONE);
+		gd = new GridData();
+		gd.horizontalSpan = 3;
+		gd.grabExcessHorizontalSpace = true;
+		gd.grabExcessVerticalSpace = true;
+		gd.verticalAlignment = GridData.FILL;
+		gd.horizontalAlignment = GridData.FILL;
+		tabFolder.setLayoutData(gd);
+		TabItem textEditorTab = new TabItem(tabFolder, SWT.NONE);
+		textEditorTab.setText("Textual Editor");
+
+		textEditorTab.setControl(createTextualEditor(tabFolder));
+        return composite;
+    }
+    
+	private Control createTextualEditor(Composite parent) {
+		actionViewer = new SourceViewer(parent, null, SWT.BORDER);
+		actionViewer.configure(new DRLSourceViewerConfig(null) {
+			public IReconciler getReconciler(ISourceViewer sourceViewer) {
+				return null;
+			}
+			public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
+				ContentAssistant assistant = new ContentAssistant();
+				completionProcessor = new ActionCompletionProcessor(process);
+				assistant.setContentAssistProcessor(
+					completionProcessor, IDocument.DEFAULT_CONTENT_TYPE);
+				assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
+				return assistant;
+			}
+		});
+		completionProcessor.setDialect(
+            dialectCombo.getItem(dialectCombo.getSelectionIndex()));
+		DroolsAction action = getValue();
+		String value = null;
+		if (action instanceof DroolsConsequenceAction) {
+			value = ((DroolsConsequenceAction) action).getConsequence();
+		}
+		if (value == null) {
+			value = "";
+		}
+		IDocument document = new Document(value);
+		actionViewer.setDocument(document);
+		IDocumentPartitioner partitioner =
+            new FastPartitioner(
+                new DRLPartionScanner(),
+                DRLPartionScanner.LEGAL_CONTENT_TYPES);
+        partitioner.connect(document);
+        document.setDocumentPartitioner(partitioner);
+        actionViewer.getControl().addKeyListener(new KeyListener() {
+			public void keyPressed(KeyEvent e) {
+				if (e.character == ' ' && e.stateMask == SWT.CTRL) {
+					actionViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
+				}
+			}
+			public void keyReleased(KeyEvent e) {
+			}
+        });
+		return actionViewer.getControl();
+	}
+	
+	private Control createDialectCombo(Composite parent) {
+	    dialectCombo = new Combo(parent, SWT.DROP_DOWN | SWT.READ_ONLY);
+	    dialectCombo.setItems(DIALECTS);
+	    DroolsAction action = getValue();
+	    int index = 0;
+        if (action instanceof DroolsConsequenceAction) {
+            String dialect = ((DroolsConsequenceAction) action).getDialect();
+            int found = ArrayUtils.indexOf(DIALECTS, dialect);
+            if (found >= 0) {
+                index = found;
+            }
+        }
+        dialectCombo.select(index);
+        dialectCombo.addSelectionListener(new SelectionListener() {
+            public void widgetDefaultSelected(SelectionEvent e) {
+                completionProcessor.setDialect(
+                    dialectCombo.getItem(dialectCombo.getSelectionIndex()));
+            }
+            public void widgetSelected(SelectionEvent e) {
+                completionProcessor.setDialect(
+                    dialectCombo.getItem(dialectCombo.getSelectionIndex()));
+            }
+        });
+        return dialectCombo;
+	}
+	
+	private DroolsConsequenceAction getAction() {
+		return new DroolsConsequenceAction(
+	        dialectCombo.getItem(dialectCombo.getSelectionIndex()),
+	        actionViewer.getDocument().get());
+	}
+	
+	private void importButtonPressed() {
+		final Runnable r = new Runnable() {
+			public void run() {
+				RuleFlowImportsDialog dialog =
+					new RuleFlowImportsDialog(getShell(), process);
+				dialog.create();
+				int code = dialog.open();
+				if (code != CANCEL) {
+					List<String> imports = dialog.getImports();
+					process.setImports(imports);
+					completionProcessor.reset();
+				}
+			}
+		};
+		r.run();
+	}
+	
+	private void globalButtonPressed() {
+		final Runnable r = new Runnable() {
+			public void run() {
+				RuleFlowGlobalsDialog dialog =
+					new RuleFlowGlobalsDialog(getShell(), process);
+				dialog.create();
+				int code = dialog.open();
+				if (code != CANCEL) {
+					Map<String, String> globals = dialog.getGlobals();
+					process.setGlobals(globals);
+					completionProcessor.reset();
+				}
+			}
+		};
+		r.run();
+	}
+
+	protected DroolsAction updateValue(DroolsAction value) {
+		if (key == null) {
+			key = new Timer();
+		}
+		try {
+			String delayString = delayText.getText().trim();
+			long delay = 0;
+			if (delayString.length() > 0) {
+				delay = new Long(delayString);
+			}
+			key.setDelay(delay);
+		} catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Delay should be a long value");
+		}
+		try {
+			String periodString = periodText.getText().trim();
+			long period = 0;
+			if (periodString.length() > 0) {
+				period = new Long(periodString);
+			}
+			key.setPeriod(period);
+		} catch (NumberFormatException e) {
+			throw new IllegalArgumentException("Period should be a long value");
+		}
+        if (tabFolder.getSelectionIndex() == 0) {
+            return getAction();
+		}
+        return null;
+    }
+    
+    public void setKey(Timer key) {
+    	this.key = key;
+    }
+
+	public Timer getKey() {
+		return key;
+	}
+    
+}
\ No newline at end of file

Added: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersCellEditor.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersCellEditor.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersCellEditor.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,55 @@
+package org.drools.eclipse.flow.ruleflow.view.property.timers;
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Map;
+
+import org.drools.eclipse.flow.common.view.property.BeanDialogCellEditor;
+import org.drools.eclipse.flow.common.view.property.EditBeanDialog;
+import org.drools.process.core.timer.Timer;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.WorkflowProcess;
+import org.drools.workflow.core.node.EventBasedNode;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Cell editor for timers.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class TimersCellEditor extends BeanDialogCellEditor<Map<Timer, DroolsAction>> {
+
+    private WorkflowProcess process;
+    private EventBasedNode eventBasedNode;
+    
+    public TimersCellEditor(Composite parent, WorkflowProcess process, EventBasedNode eventBasedNode) {
+        super(parent);
+        this.process = process;
+        this.eventBasedNode = eventBasedNode;
+    }
+
+    protected EditBeanDialog<Map<Timer, DroolsAction>> createDialog(Shell shell) {
+        TimersDialog dialog = new TimersDialog(shell, process);
+        dialog.setValue(eventBasedNode.getTimers());
+        return dialog;
+    }
+    
+    protected String getLabelText(Object value) {
+    	return "";
+    }
+
+}
\ No newline at end of file

Added: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersDialog.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,47 @@
+package org.drools.eclipse.flow.ruleflow.view.property.timers;
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.drools.eclipse.flow.common.view.property.EditBeanDialog;
+import org.drools.eclipse.flow.common.view.property.EditMapDialog;
+import org.drools.process.core.timer.Timer;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.WorkflowProcess;
+import org.drools.workflow.core.impl.DroolsConsequenceAction;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Dialog for editing a list of timers.
+ * 
+ * @author <a href="mailto:kris_verlaenen at hotmail.com">Kris Verlaenen</a>
+ */
+public class TimersDialog extends EditMapDialog<Timer, DroolsAction> {
+	
+	private WorkflowProcess process;
+
+    protected TimersDialog(Shell parentShell, WorkflowProcess process) {
+		super(parentShell, "Edit Timers", TimerDialog.class);
+		this.process = process;
+	}
+
+    protected DroolsAction createItem() {
+        return new DroolsConsequenceAction();
+    }
+
+    protected EditBeanDialog<DroolsAction> createEditItemDialog() {
+    	return new TimerDialog(getShell(), process);
+    }
+}

Added: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersPropertyDescriptor.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersPropertyDescriptor.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/timers/TimersPropertyDescriptor.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -0,0 +1,27 @@
+package org.drools.eclipse.flow.ruleflow.view.property.timers;
+
+import org.drools.workflow.core.WorkflowProcess;
+import org.drools.workflow.core.node.EventBasedNode;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.views.properties.PropertyDescriptor;
+
+public class TimersPropertyDescriptor extends PropertyDescriptor {
+	
+	private WorkflowProcess process;
+	private EventBasedNode eventBasedNode;
+
+	public TimersPropertyDescriptor(Object id, String displayName, EventBasedNode eventBasedNode, WorkflowProcess process) {
+        super(id, displayName);
+        this.eventBasedNode = eventBasedNode;
+        this.process = process;
+    }
+
+    public CellEditor createPropertyEditor(Composite parent) {
+    	TimersCellEditor editor = new TimersCellEditor(parent, process, eventBasedNode);
+        if (getValidator() != null) {
+            editor.setValidator(getValidator());
+        }
+        return editor;
+    }
+}

Modified: labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/variable/VariableDialog.java
===================================================================
--- labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/variable/VariableDialog.java	2008-09-18 19:40:11 UTC (rev 22896)
+++ labs/jbossrules/trunk/drools-eclipse/drools-eclipse-plugin/src/main/java/org/drools/eclipse/flow/ruleflow/view/property/variable/VariableDialog.java	2008-09-18 22:50:23 UTC (rev 22897)
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 
-import org.drools.eclipse.DroolsEclipsePlugin;
 import org.drools.eclipse.flow.common.datatype.DefaultDataTypeRegistry;
 import org.drools.eclipse.flow.common.view.datatype.editor.DataTypeEditor;
 import org.drools.eclipse.flow.common.view.datatype.editor.impl.DataTypeCombo;
@@ -24,9 +23,6 @@
 import org.drools.eclipse.flow.common.view.property.EditBeanDialog;
 import org.drools.process.core.context.variable.Variable;
 import org.drools.process.core.datatype.DataType;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.swt.SWT;
@@ -129,29 +125,12 @@
         Variable variable = (Variable) getValue();
         String name = nameText.getText();
         if ("".equals(name)) {
-        	String message = "Name should not be empty";
-        	showError(message);
-        	throw new IllegalArgumentException(message);
+        	throw new IllegalArgumentException("Name should not be empty");
         }
         variable.setName(name);
-        try {
-            variable.setType(dataTypeEditorComposite.getDataType());
-        } catch (IllegalArgumentException e) {
-            showError(e.getMessage());
-            throw e;
-        }
-        try {
-            variable.setValue(editorComposite.getValue());
-        } catch (IllegalArgumentException e) {
-            showError(e.getMessage());
-            throw e;
-        }
+        variable.setType(dataTypeEditorComposite.getDataType());
+        variable.setValue(editorComposite.getValue());
         return variable;
     }
     
-    private void showError(String error) {
-        ErrorDialog.openError(getShell(), "Error", error, new Status(
-            IStatus.ERROR, DroolsEclipsePlugin.getDefault().getBundle().getSymbolicName(),
-            IStatus.ERROR, error, null));
-    }
 }
\ No newline at end of file




More information about the jboss-svn-commits mailing list