[jbpm-commits] JBoss JBPM SVN: r6135 - in jbpm4/trunk/modules: bpmn/src/main/java/org/jbpm/bpmn/flownodes and 15 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Tue Jan 26 13:44:05 EST 2010
Author: jbarrez
Date: 2010-01-26 13:44:04 -0500 (Tue, 26 Jan 2010)
New Revision: 6135
Added:
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEventActivity.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteJobCmd.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java
jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/util/
jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/util/DateUtils.java
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java
Removed:
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEvent.java
Modified:
jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ManagementService.java
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java
jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java
jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/TaskActivity.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/CronExpression.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/TimerImpl.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/jobexecutor/JobExecutorTimerSession.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/ManagementServiceImpl.java
jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/intermediatecatch/IntermediateCatchTimerEventTest.java
Log:
JBPM-2722: impl of timer start event + basic test coverage
Modified: jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ManagementService.java
===================================================================
--- jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ManagementService.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/api/src/main/java/org/jbpm/api/ManagementService.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -39,4 +39,10 @@
/** search for jobs */
JobQuery createJobQuery();
+
+ /**
+ * Deletes the job with the given id.
+ * @return True if the deletion was succesful.
+ */
+ boolean deleteJob(long jobId);
}
Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/StartEventBinding.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -23,7 +23,7 @@
import org.jbpm.bpmn.model.BpmnProcessDefinition;
import org.jbpm.bpmn.parser.BpmnParser;
-import org.jbpm.pvm.internal.job.JobImpl;
+import org.jbpm.pvm.internal.job.PeriodicStartProcessTimer;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.TimerDefinitionImpl;
import org.jbpm.pvm.internal.util.XmlUtil;
@@ -50,10 +50,10 @@
parse.addProblem("multiple start events not yet supported", element);
}
- String id = XmlUtil.attribute(element, "id");
+ String id = XmlUtil.attribute(element, "id", true, parse);
Element eventDefinition = XmlUtil.element(element);
if (eventDefinition != null && "timerEventDefinition".equals(eventDefinition.getNodeName())) {
- return createTimerStartEvent((BpmnParser) parser, parse, id);
+ return createTimerStartEvent(processDefinition, eventDefinition, id, (BpmnParser) parser, parse);
} else if (eventDefinition != null){
parse.addProblem("Invalid eventDefinition type : " + eventDefinition.getNodeName());
}
@@ -61,13 +61,28 @@
return new NoneStartEventActivity(); // default
}
- protected TimerStartEvent createTimerStartEvent(BpmnParser parser, Parse parse, String eventId) {
- TimerStartEvent timerStartEvent = new TimerStartEvent();
+ protected TimerStartEventActivity createTimerStartEvent(BpmnProcessDefinition processDefinition,
+ Element timerEventDefinition, String eventId, BpmnParser parser, Parse parse) {
- TimerDefinitionImpl timerDefinition = parser.parseTimerEventDefinition(null, parse, eventId);
+ TimerStartEventActivity timerStartEvent = new TimerStartEventActivity();
+ TimerDefinitionImpl timerDefinition = parser.parseTimerEventDefinition(timerEventDefinition, parse, eventId);
- // schedule job
+ if (timerDefinition == null) { // problem explanation will already be added to parse, no need to do it here
+ return null;
+ }
+ PeriodicStartProcessTimer startProcessTimer = new PeriodicStartProcessTimer();
+ startProcessTimer.setProcessDefinitionName(processDefinition.getName());
+
+ if (timerDefinition.getDueDate() != null) {
+ startProcessTimer.setDuedate(timerDefinition.getDueDate());
+ } else if (timerDefinition.getDueDateDescription() != null) {
+ startProcessTimer.setIntervalExpression(timerDefinition.getDueDateDescription());
+ } else if (timerDefinition.getCronExpression() != null) {
+ startProcessTimer.setIntervalExpression(timerDefinition.getCronExpression());
+ }
+
+ startProcessTimer.schedule();
return timerStartEvent;
}
Deleted: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEvent.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEvent.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEvent.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -1,45 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2005, JBoss Inc., and individual contributors as indicated
- * by the @authors tag. See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jbpm.bpmn.flownodes;
-
-import org.jbpm.api.activity.ActivityExecution;
-import org.jbpm.pvm.internal.model.ExecutionImpl;
-
-
-/**
- * @author Joram Barrez
- */
-public class TimerStartEvent extends BpmnActivity {
-
- private static final long serialVersionUID = 1L;
-
- public void execute(ActivityExecution execution) {
-
- }
-
- public void execute(ExecutionImpl execution) {
-
- }
-
-
-
-}
Copied: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEventActivity.java (from rev 6124, jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEvent.java)
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEventActivity.java (rev 0)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/flownodes/TimerStartEventActivity.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.bpmn.flownodes;
+
+
+
+/**
+ * @author Joram Barrez
+ */
+public class TimerStartEventActivity extends NoneStartEventActivity {
+
+ private static final long serialVersionUID = 1L;
+
+ // At the moment no difference with a none start event. Could change in the future.
+
+}
Modified: jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java
===================================================================
--- jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/bpmn/src/main/java/org/jbpm/bpmn/parser/BpmnParser.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -111,7 +111,7 @@
parse.contextStackPush(processDefinition);
try {
- String id = XmlUtil.attribute(processElement, "id", false, parse);
+ String id = XmlUtil.attribute(processElement, "id", true, parse);
String name = XmlUtil.attribute(processElement, "name", false, parse);
if (id != null && !"".equals(id)) {
@@ -335,6 +335,11 @@
}
/**
+ * Parses a <timerEventDefinition> element:
+ * * sets dueDate if 'timeDate' is used
+ * * sets duedateDescription if a duration expression is used
+ * * set cronExpression if a cron expression is used
+ *
* @param timerEventDefinitionElement The XML element that defines the timer definition
* @param activity The activity on which the timer definition must be created
* @param eventId The id of the event on which the timer is defined
@@ -346,7 +351,7 @@
if ( (timeDate != null && timeCycle != null)
|| (timeDate == null && timeCycle == null) ) {
- parse.addProblem("Intermediate catch event '" + eventId +
+ parse.addProblem("timerEventDefinition for event '" + eventId +
"' requires either a timeDate or a timeCycle definition (but not both)");
return null;
}
@@ -363,18 +368,6 @@
return timerDefinition;
}
-
- protected void parseTimeCycle(String catchEventId, Parse parse, Element timeCycle, TimerDefinitionImpl timerDefinition) {
- String cycleExpression = timeCycle.getTextContent();
- if (Duration.isValidExpression(cycleExpression)) {
- timerDefinition.setDueDateDescription(cycleExpression);
- } else if (CronExpression.isValidExpression(cycleExpression)) {
- timerDefinition.setCronExpression(cycleExpression);
- } else {
- parse.addProblem("couldn't parse timeDate duration '"+ cycleExpression
- + "' on intermediate catch timer event " + catchEventId);
- }
- }
protected void parseTimeDate(String catchEventId, Parse parse, Element timeDate, TimerDefinitionImpl timerDefinition) {
String dueDateTime = timeDate.getTextContent();
@@ -391,6 +384,18 @@
+ "' on intermediate catch timer event " + catchEventId, e);
}
}
+
+ protected void parseTimeCycle(String catchEventId, Parse parse, Element timeCycle, TimerDefinitionImpl timerDefinition) {
+ String cycleExpression = timeCycle.getTextContent();
+ if (Duration.isValidExpression(cycleExpression)) {
+ timerDefinition.setDueDateDescription(cycleExpression);
+ } else if (CronExpression.isValidExpression(cycleExpression)) {
+ timerDefinition.setCronExpression(cycleExpression);
+ } else {
+ parse.addProblem("couldn't parse timeDate duration '"+ cycleExpression
+ + "' on intermediate catch timer event " + catchEventId);
+ }
+ }
public void parseResources(Element documentElement, Parse parse, BpmnProcessDefinition processDefinition) {
Modified: jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml
===================================================================
--- jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/devguide/src/main/docbook/en/modules/ch03-Bpmn2.xml 2010-01-26 18:44:04 UTC (rev 6135)
@@ -242,8 +242,9 @@
If a name is defined for the process element, it is be used as <emphasis role="bold">key</emphasis>
for that process (ie. starting a process can be done by calling executionService.startProcessInstanceByKey("myBusinessProcess").
If no name is defined, the id will be used as key. So having only an id defined, will allow
- to start a process instance using that id. Note that for a key the same rules apply as with
- JPDL: whitespace and non alpha-numeric characters are replace by an underscore.
+ to start a process instance using that id. So basically, name and key are of equivalent
+ in usage, for example to search process definitions. Note that for a key the same rules apply as with
+ JPDL: whitespace and non alpha-numeric characters are replaced by an underscore.
</para>
</section>
Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/TaskActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/TaskActivity.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/TaskActivity.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -27,10 +27,10 @@
import org.jbpm.api.JbpmException;
import org.jbpm.api.activity.ActivityExecution;
import org.jbpm.api.model.Transition;
+import org.jbpm.pvm.internal.cal.Duration;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.history.HistoryEvent;
import org.jbpm.pvm.internal.history.events.TaskActivityStart;
-import org.jbpm.pvm.internal.job.TimerImpl;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.script.ScriptManager;
@@ -85,7 +85,7 @@
// calculate the due date of the task based on the due date duration
String dueDateDescription = taskDefinition.getDueDateDescription();
if (dueDateDescription != null) {
- task.setDuedate(TimerImpl.calculateDueDate(dueDateDescription));
+ task.setDuedate(Duration.calculateDueDate(dueDateDescription));
}
// save task so that TaskDbSession.findTaskByExecution works for assign event listeners
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/CronExpression.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/CronExpression.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/CronExpression.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -360,7 +360,7 @@
try {
new CronExpression(cronExpression);
- } catch (ParseException pe) {
+ } catch (Exception pe) {
return false;
}
@@ -746,7 +746,7 @@
return i;
}
- public String getCronExpression() {
+ public String getCronExpressionString() {
return cronExpression;
}
@@ -1502,7 +1502,7 @@
public Object clone() {
CronExpression copy = null;
try {
- copy = new CronExpression(getCronExpression());
+ copy = new CronExpression(getCronExpressionString());
copy.setTimeZone(getTimeZone());
} catch (ParseException ex) { // never happens since the source is valid...
throw new IncompatibleClassChangeError("Not Cloneable.");
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cal/Duration.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -22,12 +22,21 @@
package org.jbpm.pvm.internal.cal;
import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.jbpm.api.JbpmException;
+import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.script.ScriptManager;
+import org.jbpm.pvm.internal.util.Clock;
/**
* represents a time duration.
@@ -59,6 +68,14 @@
protected int weeks;
protected int months;
protected int years;
+
+ private final static String dateFormat = "yyyy-MM-dd HH:mm:ss";
+
+ private static final Pattern dateDurationPattern = Pattern.compile("\\s*(#\\{.+\\})\\s*"
+ + "(?:(\\+|-)\\s*(\\d+\\s+(?:business\\s+)?\\w+))?\\s*");
+
+ private static final Pattern durationPattern = Pattern.compile("\\s*(\\d+\\s+(?:business\\s+)?"
+ + "\\w+)\\s*");
/** constructor for persistence. note that this type is to be immutable. */
protected Duration() {
@@ -91,7 +108,56 @@
}
return true;
}
+
+ public static Date calculateDueDate(String durationExpression) {
+ Date dueDate;
+ // is due date description in date_expression +|- fixed_duration format?
+ Matcher dateDurationMatcher = dateDurationPattern.matcher(durationExpression);
+ if (dateDurationMatcher.matches()) {
+ // evaluate date expression
+ String dateExpression = dateDurationMatcher.group(1);
+ Object result = ScriptManager.getScriptManager().evaluateExpression(dateExpression, null);
+ // convert result to Date
+ if (result instanceof Date) {
+ dueDate = (Date) result;
+ } else if (result instanceof Calendar) {
+ Calendar calendar = (Calendar) result;
+ dueDate = calendar.getTime();
+ } else if (result instanceof String) {
+ try {
+ // TODO use a locale-sensitive date format?
+ dueDate = new SimpleDateFormat(dateFormat).parse((String) result);
+ } catch (ParseException e) {
+ throw new JbpmException("invalid base date: " + result, e);
+ }
+ } else {
+ throw new JbpmException("invalid base date: " + result);
+ }
+ // fixed duration is optional
+ String operationString = dateDurationMatcher.group(2);
+ if (operationString != null) {
+ char operation = operationString.charAt(0);
+ String duration = dateDurationMatcher.group(3);
+ // add duration to base date
+ BusinessCalendar businessCalendar = EnvironmentImpl.getFromCurrent(BusinessCalendar.class);
+ dueDate = operation == '+' ? businessCalendar.add(dueDate, duration)
+ : businessCalendar.subtract(dueDate, duration);
+ }
+ } else {
+ // is due date description in fixed_duration format?
+ Matcher durationMatcher = durationPattern.matcher(durationExpression);
+ if (durationMatcher.matches()) {
+ // add duration to current date
+ dueDate = EnvironmentImpl.getFromCurrent(BusinessCalendar.class).add(
+ Clock.getTime(), durationMatcher.group(1));
+ } else {
+ throw new JbpmException("invalid due date duration: " + durationExpression);
+ }
+ }
+ return dueDate;
+ }
+
public Duration(boolean isBusinessTime, int millis, int seconds, int minutes, int hours, int days, int weeks, int months, int years) {
this.isBusinessTime = isBusinessTime;
this.millis = millis;
Added: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteJobCmd.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteJobCmd.java (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/cmd/DeleteJobCmd.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.cmd;
+
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.cmd.Environment;
+import org.jbpm.pvm.internal.job.JobImpl;
+import org.jbpm.pvm.internal.session.DbSession;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class DeleteJobCmd extends AbstractCommand<Boolean>{
+
+ private static final long serialVersionUID = 1L;
+
+ protected long jobId;
+
+ public DeleteJobCmd(long jobId) {
+ this.jobId = jobId;
+ }
+
+ public Boolean execute(Environment environment) throws Exception {
+ DbSession dbSession = environment.get(DbSession.class);
+ if (dbSession==null) {
+ throw new JbpmException("no " + DbSession.class.getName() + " found in environment");
+ }
+ JobImpl job = dbSession.get(JobImpl.class, jobId);
+ if (job != null) {
+ dbSession.delete(job);
+ return true;
+ }
+ return false;
+ }
+
+}
Added: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java (rev 0)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/PeriodicStartProcessTimer.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -0,0 +1,200 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.pvm.internal.job;
+
+import java.text.ParseException;
+
+import org.jbpm.api.ExecutionService;
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.RepositoryService;
+import org.jbpm.api.cmd.Environment;
+import org.jbpm.internal.log.Log;
+import org.jbpm.pvm.internal.cal.CronExpression;
+import org.jbpm.pvm.internal.cal.Duration;
+import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.session.DbSession;
+import org.jbpm.pvm.internal.util.Clock;
+
+
+/**
+ * Job that periodically startes a new process instance of a given process definition.
+ *
+ * @author Joram Barrez
+ */
+public class PeriodicStartProcessTimer extends TimerImpl {
+
+ private static final long serialVersionUID = 1L;
+
+ private static final Log LOG = Log.getLog(PeriodicStartProcessTimer.class.getName());
+
+ // Override execution logic of regular timer
+ public Boolean execute(Environment environment) throws Exception {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Periodic start process triggered at " + Clock.getTime());
+ }
+
+ boolean processDefinitionExists = processDefinitionExists(environment);
+ boolean newDueDateCalculated = false;
+
+ if (processDefinitionExists) {
+ startProcessInstance(environment);
+ newDueDateCalculated = calculateDueDate(environment);
+ }
+
+ if (!processDefinitionExists || !newDueDateCalculated) {
+ deleteThisJob(environment);
+ } else {
+ saveThisJob(environment);
+ }
+
+ return null;
+ }
+
+ protected boolean processDefinitionExists(Environment environment) {
+ RepositoryService repositoryService = environment.get(RepositoryService.class);
+ boolean processExists = !repositoryService.createProcessDefinitionQuery()
+ .processDefinitionName(getProcessDefinitionName()).list().isEmpty();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Process definition with name " + getProcessDefinitionName() + " still exists: " + processExists);
+ }
+
+ return processExists;
+ }
+
+ protected void startProcessInstance(Environment environment) {
+ ExecutionService executionService = environment.get(ExecutionService.class);
+ if (executionService == null) {
+ throw new JbpmException("no " + ExecutionService.class.getName() + " in environment");
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Starting a new process instance for process definition with name " + getProcessDefinitionName());
+ }
+
+ executionService.startProcessInstanceByKey(getProcessDefinitionName());
+ }
+
+ protected boolean calculateDueDate(Environment environment) throws ParseException {
+
+ if (getIntervalExpression() != null && Duration.isValidExpression(getIntervalExpression())) {
+ duedate = Duration.calculateDueDate(getIntervalExpression());
+ } else if (getIntervalExpression() != null && CronExpression.isValidExpression(getIntervalExpression())) {
+ duedate = new CronExpression(getIntervalExpression()).getNextValidTimeAfter(Clock.getTime());
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("No next duedate calculated for periodic start process job " +
+ "with intervalExpression " + getIntervalExpression());
+ }
+ return false;
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Next process start duedate: " + duedate);
+ }
+
+ return true;
+ }
+
+ protected void saveThisJob(Environment environment) {
+ DbSession dbSession = environment.get(DbSession.class);
+ if (dbSession == null) {
+ throw new JbpmException("no " + DbSession.class.getName() + " in environment");
+ }
+ dbSession.save(this);
+ }
+
+ protected void deleteThisJob(Environment environment) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Deleting periodic start job for process definition with name " + getProcessDefinitionName());
+ }
+
+ DbSession dbSession = environment.get(DbSession.class);
+ if (dbSession == null) {
+ throw new JbpmException("no " + DbSession.class.getName() + " in environment");
+ }
+ dbSession.delete(this);
+ }
+
+ @Override
+ public void schedule() {
+ if (duedate == null && getIntervalExpression() != null) {
+ try {
+ calculateDueDate(EnvironmentImpl.getCurrent());
+ } catch (ParseException e) {
+ throw new JbpmException("Cannot parse intervalExpression", e);
+ }
+ } else if (duedate == null) {
+ throw new JbpmException("Cannot schedule periodic start process timer: " +
+ "no duedate or intervalExpression set");
+ }
+ super.schedule();
+ }
+
+ @Override
+ public void validate() {
+ if (getProcessDefinitionName() == null) {
+ throw new JbpmException("No process definition name set for periodic start process timer");
+ }
+ if (duedate == null && getIntervalExpression() == null) {
+ throw new JbpmException("No duedate or intervalExpression found for periodic start process timer");
+ }
+ }
+
+ public String getProcessDefinitionName() {
+ return signalName;
+ }
+
+ public void setProcessDefinitionName(String processDefinitionName) {
+ this.signalName = processDefinitionName;
+ }
+
+ public String getIntervalExpression() {
+ return eventName;
+ }
+
+ /**
+ * Sets the expression that will define the interval between
+ * two sequential process starts by this job.
+ *
+ * Possible expression types are {@link Duration} and {@link CronExpression}.
+ */
+ public void setIntervalExpression(String intervalExpression) {
+ this.eventName = intervalExpression;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder strb = new StringBuilder();
+ strb.append("PeriodicProcessStart[");
+ if (duedate != null) {
+ strb.append(duedate);
+ }
+ if (getIntervalExpression() != null) {
+ strb.append("| " + getIntervalExpression());
+ }
+ strb.append("]");
+ return strb.toString();
+ }
+
+}
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/TimerImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/TimerImpl.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/job/TimerImpl.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -21,24 +21,19 @@
*/
package org.jbpm.pvm.internal.job;
-import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Calendar;
import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import org.jbpm.api.JbpmException;
import org.jbpm.api.cmd.Environment;
import org.jbpm.api.job.Timer;
import org.jbpm.internal.log.Log;
-import org.jbpm.pvm.internal.cal.BusinessCalendar;
+import org.jbpm.pvm.internal.cal.Duration;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.id.DbidGenerator;
import org.jbpm.pvm.internal.jobexecutor.JobAddedNotification;
import org.jbpm.pvm.internal.jobexecutor.JobExecutor;
import org.jbpm.pvm.internal.model.ObservableElement;
-import org.jbpm.pvm.internal.script.ScriptManager;
import org.jbpm.pvm.internal.session.DbSession;
import org.jbpm.pvm.internal.session.TimerSession;
import org.jbpm.pvm.internal.tx.Transaction;
@@ -58,10 +53,6 @@
private static final Log log = Log.getLog(TimerImpl.class.getName());
private final static String dateFormat = "yyyy-MM-dd HH:mm:ss";
- private static final Pattern dateDurationPattern = Pattern.compile("\\s*(#\\{.+\\})\\s*"
- + "(?:(\\+|-)\\s*(\\d+\\s+(?:business\\s+)?\\w+))?\\s*");
- private static final Pattern durationPattern = Pattern.compile("\\s*(\\d+\\s+(?:business\\s+)?"
- + "\\w+)\\s*");
protected String signalName;
protected String eventName;
@@ -80,62 +71,13 @@
public void setDueDateDescription(String dueDateDescription) {
if (dueDateDescription != null) {
- duedate = calculateDueDate(dueDateDescription);
+ duedate = Duration.calculateDueDate(dueDateDescription);
}
}
- public static Date calculateDueDate(String dueDateDescription) {
- Date dueDate;
- // is due date description in date_expression +|- fixed_duration format?
- Matcher dateDurationMatcher = dateDurationPattern.matcher(dueDateDescription);
- if (dateDurationMatcher.matches()) {
- // evaluate date expression
- String dateExpression = dateDurationMatcher.group(1);
- Object result = ScriptManager.getScriptManager().evaluateExpression(dateExpression, null);
- // convert result to Date
- if (result instanceof Date) {
- dueDate = (Date) result;
- } else if (result instanceof Calendar) {
- Calendar calendar = (Calendar) result;
- dueDate = calendar.getTime();
- } else if (result instanceof String) {
- try {
- // TODO use a locale-sensitive date format?
- dueDate = new SimpleDateFormat(dateFormat).parse((String) result);
- } catch (ParseException e) {
- throw new JbpmException("invalid base date: " + result, e);
- }
- } else {
- throw new JbpmException("invalid base date: " + result);
- }
-
- // fixed duration is optional
- String operationString = dateDurationMatcher.group(2);
- if (operationString != null) {
- char operation = operationString.charAt(0);
- String duration = dateDurationMatcher.group(3);
- // add duration to base date
- BusinessCalendar businessCalendar = EnvironmentImpl.getFromCurrent(BusinessCalendar.class);
- dueDate = operation == '+' ? businessCalendar.add(dueDate, duration)
- : businessCalendar.subtract(dueDate, duration);
- }
- } else {
- // is due date description in fixed_duration format?
- Matcher durationMatcher = durationPattern.matcher(dueDateDescription);
- if (durationMatcher.matches()) {
- // add duration to current date
- dueDate = EnvironmentImpl.getFromCurrent(BusinessCalendar.class).add(
- Clock.getTime(), durationMatcher.group(1));
- } else {
- throw new JbpmException("invalid due date duration: " + dueDateDescription);
- }
- }
- return dueDate;
- }
-
public Boolean execute(Environment environment) throws Exception {
if (log.isDebugEnabled()) log.debug("executing " + this);
-
+
if (environment==null) {
throw new JbpmException("environment is null");
}
@@ -189,6 +131,18 @@
return deleteThisJob;
}
+
+ public void validate() {
+ if (getExecution() == null) {
+ throw new JbpmException("timer has no execution specified");
+ }
+ if ((getSignalName() == null) && (getEventName() == null)) {
+ throw new JbpmException("timer has no signalName or eventName specified");
+ }
+ if (getDueDate() == null) {
+ throw new JbpmException("timer scheduled at null date");
+ }
+ }
public String toString() {
StringBuilder text = new StringBuilder();
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/jobexecutor/JobExecutorTimerSession.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/jobexecutor/JobExecutorTimerSession.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/jobexecutor/JobExecutorTimerSession.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -49,10 +49,9 @@
public void schedule(Timer timer) {
if (timer == null) throw new JbpmException("null timer scheduled");
- if (timer.getExecution() == null) throw new JbpmException("timer has no execution specified");
- if ((timer.getSignalName() == null) && (timer.getEventName() == null)) throw new JbpmException("timer has no signalName or eventName specified");
- if (timer.getDueDate() == null) throw new JbpmException("timer scheduled at null date");
-
+ TimerImpl timerImpl = (TimerImpl) timer;
+ timerImpl.validate();
+
log.debug("scheduling " + timer);
session.save(timer);
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -307,8 +307,7 @@
if (timer.getDuedate() == null && timerDefinition.getCronExpression() != null) {
try {
- timer.setDuedate(new CronExpression(timerDefinition.getCronExpression())
- .getNextValidTimeAfter(Clock.getTime()));
+ timer.setDuedate(new CronExpression(timerDefinition.getCronExpression()).getNextValidTimeAfter(Clock.getTime()));
} catch (ParseException pe) {
throw new JbpmException("Can't parse cron expression " + timerDefinition.getCronExpression(), pe);
}
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/ManagementServiceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/ManagementServiceImpl.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/svc/ManagementServiceImpl.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -24,6 +24,7 @@
import org.jbpm.api.JobQuery;
import org.jbpm.api.ManagementService;
import org.jbpm.pvm.internal.cmd.CreateJobQueryCmd;
+import org.jbpm.pvm.internal.cmd.DeleteJobCmd;
import org.jbpm.pvm.internal.cmd.ExecuteJobCmd;
import org.jbpm.pvm.internal.query.JobQueryImpl;
@@ -42,4 +43,8 @@
query.setCommandService(commandService);
return query;
}
+
+ public boolean deleteJob(long jobId) {
+ return commandService.execute(new DeleteJobCmd(jobId));
+ }
}
Modified: jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/pvm/src/main/resources/jbpm.execution.hbm.xml 2010-01-26 18:44:04 UTC (rev 6135)
@@ -247,8 +247,11 @@
<property name="signalName" column="SIGNAL_" />
<property name="eventName" column="EVENT_" />
<property name="repeat" column="REPEAT_" />
+
+ <subclass name="org.jbpm.pvm.internal.job.PeriodicStartProcessTimer" discriminator-value="PeriodicStartProcess" />
+
</subclass>
-
+
</class>
<!-- ### HibernatePvmDbSession QUERIES ################################## -->
Added: jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/util/DateUtils.java
===================================================================
--- jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/util/DateUtils.java (rev 0)
+++ jbpm4/trunk/modules/test-base/src/main/java/org/jbpm/test/util/DateUtils.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.test.util;
+
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class DateUtils {
+
+ // No need to instantiate
+ private DateUtils() {}
+
+ public static Date getDate(int day, int month, int year, int hour, int minute, int second) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.DAY_OF_MONTH, day);
+ cal.set(Calendar.MONTH, month);
+ cal.set(Calendar.YEAR, year);
+ cal.set(Calendar.HOUR_OF_DAY, hour);
+ cal.set(Calendar.MINUTE, minute);
+ cal.set(Calendar.SECOND, second);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTime();
+ }
+
+ public static Date getDateAtMidnight(int day, int month, int year) {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.DAY_OF_MONTH, day);
+ cal.set(Calendar.MONTH, month);
+ cal.set(Calendar.YEAR, year);
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTime();
+ }
+
+}
Modified: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/intermediatecatch/IntermediateCatchTimerEventTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/intermediatecatch/IntermediateCatchTimerEventTest.java 2010-01-26 18:25:52 UTC (rev 6134)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/intermediatecatch/IntermediateCatchTimerEventTest.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -30,6 +30,7 @@
import org.jbpm.pvm.internal.util.Clock;
import org.jbpm.test.JbpmTestCase;
import org.jbpm.test.assertion.CollectionAssertions;
+import org.jbpm.test.util.DateUtils;
/**
* @author Joram Barrez
@@ -65,7 +66,7 @@
" </process>" +
"</definitions>";
- private static final String TIMER_CATCH_WITH_TIMECYCLE =
+ private static final String TIMER_CATCH_WITH_TIMECYCLE_DURATION =
"<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
" <process id='timeCycleProcess'>" +
" <startEvent id='theStart' />" +
@@ -132,8 +133,7 @@
}
public void testInvalidProcess() {
- final String expectedMsg = "Intermediate catch event 'intermediateTimer' requires either a " +
- "timeDate or a timeCycle definition (but not both)";
+ final String expectedMsg = "requires either a timeDate or a timeCycle definition (but not both)";
try {
deployBpmn2XmlString(BAD_PROCESS_1);
fail();
@@ -150,7 +150,7 @@
}
public void testTimeCycleExpression() {
- deployBpmn2XmlString(TIMER_CATCH_WITH_TIMECYCLE);
+ deployBpmn2XmlString(TIMER_CATCH_WITH_TIMECYCLE_DURATION);
long processStartTime = 5000;
Clock.setExplicitTime(new Date(processStartTime));
@@ -173,7 +173,7 @@
CollectionAssertions.assertContainsSameElements(pi.findActiveActivityNames(), "intermediateTimer");
Job timerJob = managementService.createJobQuery().processInstanceId(pi.getId()).uniqueResult();
- Date expectedDueDate = getDateAtMidnight(10, Calendar.OCTOBER, 2099);
+ Date expectedDueDate = DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099);
assertEquals(expectedDueDate.getTime(), timerJob.getDuedate().getTime());
managementService.executeJob(timerJob.getId());
@@ -182,13 +182,13 @@
public void testCronExpression() {
deployBpmn2XmlString(TIMER_CATCH_WITH_CRON_EXPRESSION);
- Clock.setExplicitTime(getDate(20, Calendar.JANUARY, 2010, 0, 1, 1)); // Start on 61 seconds
+ Clock.setExplicitTime(DateUtils.getDate(20, Calendar.JANUARY, 2010, 0, 1, 1)); // Start on 61 seconds
ProcessInstance pi = executionService.startProcessInstanceByKey("timeDateProcess");
CollectionAssertions.assertContainsSameElements(pi.findActiveActivityNames(), "intermediateTimer");
Job timerJob = managementService.createJobQuery().processInstanceId(pi.getId()).uniqueResult();
- assertEquals(getDate(20, Calendar.JANUARY, 2010, 0, 2, 0).getTime(), timerJob.getDuedate().getTime());
+ assertEquals(DateUtils.getDate(20, Calendar.JANUARY, 2010, 0, 2, 0).getTime(), timerJob.getDuedate().getTime());
managementService.executeJob(timerJob.getId());
assertProcessInstanceEnded(pi);
@@ -196,41 +196,19 @@
public void testCronExpression2() {
deployBpmn2XmlString(TIMER_CATCH_WITH_CRON_EXPRESSION_2);
- Clock.setExplicitTime(getDateAtMidnight(21, Calendar.JANUARY, 2010)); // 21/01/2009 is a Thursday
+ Clock.setExplicitTime(DateUtils.getDateAtMidnight(21, Calendar.JANUARY, 2010)); // 21/01/2009 is a Thursday
ProcessInstance pi = executionService.startProcessInstanceByKey("timeDateProcess");
CollectionAssertions.assertContainsSameElements(pi.findActiveActivityNames(), "intermediateTimer");
Job timerJob = managementService.createJobQuery().processInstanceId(pi.getId()).uniqueResult();
- assertEquals(getDate(22, Calendar.JANUARY, 2010, 23, 0, 0).getTime(), timerJob.getDuedate().getTime());
+ assertEquals(DateUtils.getDate(22, Calendar.JANUARY, 2010, 23, 0, 0).getTime(), timerJob.getDuedate().getTime());
managementService.executeJob(timerJob.getId());
assertProcessInstanceEnded(pi);
}
- private Date getDateAtMidnight(int day, int month, int year) {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.DAY_OF_MONTH, day);
- cal.set(Calendar.MONTH, month);
- cal.set(Calendar.YEAR, year);
- cal.set(Calendar.HOUR_OF_DAY, 0);
- cal.set(Calendar.MINUTE, 0);
- cal.set(Calendar.SECOND, 0);
- cal.set(Calendar.MILLISECOND, 0);
- return cal.getTime();
- }
-
- private Date getDate(int day, int month, int year, int hour, int minute, int second) {
- Calendar cal = Calendar.getInstance();
- cal.set(Calendar.DAY_OF_MONTH, day);
- cal.set(Calendar.MONTH, month);
- cal.set(Calendar.YEAR, year);
- cal.set(Calendar.HOUR_OF_DAY, hour);
- cal.set(Calendar.MINUTE, minute);
- cal.set(Calendar.SECOND, second);
- cal.set(Calendar.MILLISECOND, 0);
- return cal.getTime();
- }
+
}
Added: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/bpmn/test/startevent/TimerStartEventTest.java 2010-01-26 18:44:04 UTC (rev 6135)
@@ -0,0 +1,256 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.bpmn.test.startevent;
+
+import java.util.Calendar;
+
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.ProcessInstanceQuery;
+import org.jbpm.api.job.Job;
+import org.jbpm.pvm.internal.util.Clock;
+import org.jbpm.test.JbpmTestCase;
+import org.jbpm.test.util.DateUtils;
+
+
+/**
+ * @author Joram Barrez
+ */
+public class TimerStartEventTest extends JbpmTestCase {
+
+ private static final String INVALID_PROCESS_1 =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='invalidProcess1'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition />" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String INVALID_PROCESS_2 =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='invalidProcess1'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeCycle>5 hours</timeCycle>" +
+ " <timeDate>10/10/1985</timeDate>" +
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String INVALID_PROCESS_3 =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='invalidProcess1'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeCycle>5 abcdefghijklmnop</timeCycle>" +
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String INVALID_PROCESS_4 =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='invalidProcess1'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeCycle>Z 0 22 * * ?</timeCycle>" +
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String TIMER_START_FIXED_DUEDATE =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='timerStartFixedDueDate'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeDate>10/10/2099 00:00:00</timeDate>" +
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='wait' />" +
+ " <receiveTask id='wait' />" +
+ " <sequenceFlow id='flow2' sourceRef='wait' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String TIMER_START_TIMECYCLE_DURATION =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='timerStartTimeCycleDuration'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeCycle>10 hours</timeCycle>" +
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='wait' />" +
+ " <receiveTask id='wait' />" +
+ " <sequenceFlow id='flow2' sourceRef='wait' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ private static final String TIMER_START_TIMECYCLE_CRON_EXPR =
+ "<definitions xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>" +
+ " <process id='timerStartTimeCycleCronExpression'>" +
+ " <startEvent id='theStart' >" +
+ " <timerEventDefinition >" +
+ " <timeCycle>0 0 22 * * ?</timeCycle>" + // every day at 22:00
+ " </timerEventDefinition>" +
+ " </startEvent>" +
+ " <sequenceFlow id='flow1' sourceRef='theStart' targetRef='wait' />" +
+ " <receiveTask id='wait' />" +
+ " <sequenceFlow id='flow2' sourceRef='wait' targetRef='theEnd' />" +
+ " <endEvent id='theEnd' />" +
+ " </process>" +
+ "</definitions>";
+
+ @Override
+ protected void tearDown() throws Exception {
+ Clock.setExplicitTime(null);
+ super.tearDown();
+ }
+
+ public void testInvalidProcess() {
+ testDeployInvalidProcess(INVALID_PROCESS_1);
+ testDeployInvalidProcess(INVALID_PROCESS_2);
+ testDeployInvalidProcess(INVALID_PROCESS_3);
+ testDeployInvalidProcess(INVALID_PROCESS_4);
+ }
+
+ private void testDeployInvalidProcess(String process) {
+ try {
+ deployBpmn2XmlString(process);
+ fail();
+ } catch (JbpmException e) {
+ // Exception is expected
+ }
+ }
+
+ public void testTimerStartEventWithFixedDuedate() {
+ deployBpmn2XmlString(TIMER_START_FIXED_DUEDATE);
+
+ // After deployment, there should be one job in the database that starts a new process instance
+ Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNotNull(startProcessTimer);
+ assertEquals(DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099).getTime(), startProcessTimer.getDuedate().getTime());
+
+ ProcessInstanceQuery procInstQuery = executionService.createProcessInstanceQuery()
+ .processDefinitionId(findProcessDefinitionId("timerStartFixedDueDate"));
+
+ // Triggering the job should start a new process instance of the deployed process definition
+ assertEquals(0, procInstQuery.count());
+ managementService.executeJob(startProcessTimer.getId());
+ assertEquals(1, procInstQuery.count());
+
+ // Since a fixed duedate was used, the job should have been deleted from the database
+ startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNull(startProcessTimer);
+ }
+
+ public void testTimerStartEventWithDurationAsTimeCycle() {
+ Clock.setExplicitTime(DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099));
+ deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+
+ // After deployment, there should be one job in the database that starts a new process instance
+ Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNotNull(startProcessTimer);
+ assertEquals(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 10, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+
+ // Triggering the job should start a new process instance of the deployed process definition
+ ProcessInstanceQuery procInstQuery = executionService.createProcessInstanceQuery()
+ .processDefinitionId(findProcessDefinitionId("timerStartTimeCycleDuration"));
+ assertEquals(0, procInstQuery.count());
+
+ // need to change current date to calculate the next duedate correctly
+ Clock.setExplicitTime(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 10, 0, 0));
+ managementService.executeJob(startProcessTimer.getId());
+ assertEquals(1, procInstQuery.count());
+
+ // Since a timeCycle was used, the job should have been recreated with a new duedate
+ startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertEquals(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 20, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+
+
+ // So we need to manually delete it
+ managementService.deleteJob(Long.valueOf(startProcessTimer.getId()));
+ }
+
+ public void testTimerStartEventWithCronExpressionAsTimeCycle() {
+ Clock.setExplicitTime(DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099));
+ deployBpmn2XmlString(TIMER_START_TIMECYCLE_CRON_EXPR);
+
+ // After deployment, there should be one job in the database that starts a new process instance
+ Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNotNull(startProcessTimer);
+ assertEquals(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 22, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+
+ // Triggering the job should start a new process instance of the deployed process definition
+ ProcessInstanceQuery procInstQuery = executionService.createProcessInstanceQuery()
+ .processDefinitionId(findProcessDefinitionId("timerStartTimeCycleCronExpression"));
+ assertEquals(0, procInstQuery.count());
+
+ // need to change current date to calculate the next duedate correctly
+ Clock.setExplicitTime(DateUtils.getDate(10, Calendar.OCTOBER, 2099, 22, 0, 0));
+ managementService.executeJob(startProcessTimer.getId());
+ assertEquals(1, procInstQuery.count());
+
+ // Since a timeCycle was used, the job should have been recreated with a new duedate
+ startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertEquals(DateUtils.getDate(11, Calendar.OCTOBER, 2099, 22, 0, 0).getTime(), startProcessTimer.getDuedate().getTime());
+
+ // So we need to manually delete it
+ managementService.deleteJob(Long.valueOf(startProcessTimer.getId()));
+ }
+
+ public void testDeleteProcessDefinitionBeforeTimerTriggers() {
+ Clock.setExplicitTime(DateUtils.getDateAtMidnight(10, Calendar.OCTOBER, 2099));
+ String deployId = deployBpmn2XmlString(TIMER_START_TIMECYCLE_DURATION);
+
+ // Delete the process definition
+ repositoryService.deleteDeploymentCascade(deployId);
+ registeredDeployments.remove(0);
+
+ // After process definition deletion, the timer is still in the database
+ Job startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNotNull(startProcessTimer);
+
+ // When the timer triggers, it notices that the process definition is gone and it deletes itselves
+ managementService.executeJob(startProcessTimer.getId());
+ startProcessTimer = managementService.createJobQuery().uniqueResult();
+ assertNull(startProcessTimer);
+ }
+
+ private String findProcessDefinitionId(String processDefinitionKey) {
+ return repositoryService.createProcessDefinitionQuery()
+ .processDefinitionName(processDefinitionKey).uniqueResult().getId();
+ }
+
+}
More information about the jbpm-commits
mailing list