001: package org.jbpm.job;
002:
003: import java.text.DateFormat;
004: import java.text.SimpleDateFormat;
005:
006: import org.apache.commons.logging.Log;
007: import org.apache.commons.logging.LogFactory;
008: import org.jbpm.JbpmContext;
009: import org.jbpm.calendar.BusinessCalendar;
010: import org.jbpm.calendar.Duration;
011: import org.jbpm.graph.def.Action;
012: import org.jbpm.graph.def.Event;
013: import org.jbpm.graph.def.GraphElement;
014: import org.jbpm.graph.exe.ExecutionContext;
015: import org.jbpm.graph.exe.Token;
016:
017: public class Timer extends Job {
018:
019: private static final long serialVersionUID = 1L;
020:
021: static BusinessCalendar businessCalendar = new BusinessCalendar();
022:
023: String name;
024: String repeat;
025: String transitionName = null;
026: Action action = null;
027: GraphElement graphElement = null;
028:
029: public Timer() {
030: }
031:
032: public Timer(Token token) {
033: super (token);
034: }
035:
036: public boolean execute(JbpmContext jbpmContext) throws Exception {
037: boolean deleteThisJob = true;
038:
039: ExecutionContext executionContext = new ExecutionContext(token);
040: executionContext.setTimer(this );
041:
042: if (taskInstance != null) {
043: executionContext.setTaskInstance(taskInstance);
044: }
045:
046: // first fire the event if there is a graph element specified
047: if (graphElement != null) {
048: graphElement.fireAndPropagateEvent(Event.EVENTTYPE_TIMER,
049: executionContext);
050: }
051:
052: // then execute the action if there is one
053: if (action != null) {
054: try {
055: log.debug("executing timer '" + this + "'");
056: if (graphElement != null) {
057: graphElement
058: .executeAction(action, executionContext);
059: } else {
060: action.execute(executionContext);
061: }
062: } catch (Exception actionException) {
063: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
064: log.warn("timer action threw exception",
065: actionException);
066:
067: // we put the exception in t
068: Exception t = actionException;
069: try {
070: // if there is a graphElement connected to this timer...
071: if (graphElement != null) {
072: // we give that graphElement a chance to catch the exception
073: graphElement.raiseException(actionException,
074: executionContext);
075: log.debug("timer exception got handled by '"
076: + graphElement + "'");
077: t = null;
078: }
079: } catch (Exception rethrowOrDelegationException) {
080: // NOTE that Error's are not caught because that might halt the JVM and mask the original Error.
081: // if the exception handler rethrows or the original exception results in a DelegationException...
082: t = rethrowOrDelegationException;
083: }
084:
085: if (t != null) {
086: // This is either the original exception wrapped as a delegation exception
087: // or an exception that was throws from an exception handler
088: throw t;
089: }
090: }
091: }
092:
093: // then take a transition if one is specified
094: if ((transitionName != null) && (exception == null) // and if no unhandled exception occurred during the action
095: ) {
096: if (token.getNode().hasLeavingTransition(transitionName)) {
097: token.signal(transitionName);
098: }
099: }
100:
101: // save the token
102: jbpmContext.save(processInstance);
103:
104: // if repeat is specified, reschedule the job
105: if (repeat != null) {
106: deleteThisJob = false;
107:
108: // suppose that it took the timer runner thread a
109: // very long time to execute the timers.
110: // then the repeat action dueDate could already have passed.
111: while (dueDate.getTime() <= System.currentTimeMillis()) {
112: dueDate = businessCalendar.add(dueDate, new Duration(
113: repeat));
114: }
115: log.debug("updated timer for repetition '" + this
116: + "' in '"
117: + (dueDate.getTime() - System.currentTimeMillis())
118: + "' millis");
119: }
120:
121: return deleteThisJob;
122: }
123:
124: static DateFormat dateFormat = new SimpleDateFormat(
125: "yy-MM-dd HH:mm:ss,SSS");
126:
127: public String toString() {
128: StringBuffer buffer = new StringBuffer();
129: buffer.append("timer");
130: if ((name != null) || (dueDate != null)) {
131:
132: buffer.append("(");
133: if (name != null) {
134: buffer.append(name).append(",");
135: }
136: if (dueDate != null) {
137: buffer.append(dateFormat.format(dueDate)).append(",");
138: }
139: if (taskInstance != null)
140: buffer.append("TaskInstance: ").append(
141: taskInstance.getId()).append(",");
142: if (token != null)
143: buffer.append("Token: ").append(token.getId());
144: else if (processInstance != null)
145: buffer.append("ProcessInstance: ").append(
146: processInstance.getId());
147:
148: buffer.append(")");
149: }
150: return buffer.toString();
151: }
152:
153: public String getRepeat() {
154: return repeat;
155: }
156:
157: public void setRepeat(String repeat) {
158: this .repeat = repeat;
159: }
160:
161: public String getName() {
162: return name;
163: }
164:
165: public void setName(String name) {
166: this .name = name;
167: }
168:
169: public String getTransitionName() {
170: return transitionName;
171: }
172:
173: public void setTransitionName(String transitionName) {
174: this .transitionName = transitionName;
175: }
176:
177: public GraphElement getGraphElement() {
178: return graphElement;
179: }
180:
181: public void setGraphElement(GraphElement graphElement) {
182: this .graphElement = graphElement;
183: }
184:
185: public Action getAction() {
186: return action;
187: }
188:
189: public void setAction(Action action) {
190: this .action = action;
191: }
192:
193: private static Log log = LogFactory.getLog(Timer.class);
194: }
|