001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: Deadline.java,v 1.4 2007/05/03 21:58:18 mlipp Exp $
021: *
022: * $Log: Deadline.java,v $
023: * Revision 1.4 2007/05/03 21:58:18 mlipp
024: * Internal refactoring for making better use of local EJBs.
025: *
026: * Revision 1.3 2006/09/29 12:32:08 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.2 2005/01/09 21:32:42 mlipp
030: * Added support for debugging exceptions and deadlines.
031: *
032: * Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
033: * Update to 1.2
034: *
035: * Revision 1.10 2004/03/12 12:19:53 lipp
036: * Javadoc fixes.
037: *
038: * Revision 1.9 2003/09/25 12:00:05 lipp
039: * Avoid client dependency on rhino.
040: *
041: * Revision 1.8 2003/09/25 11:01:20 lipp
042: * Fixed usage of jsScope (may not be used remotely).
043: *
044: * Revision 1.7 2003/09/24 20:28:42 lipp
045: * Reorganized deadline/suspend handling.
046: *
047: * Revision 1.6 2003/09/24 13:46:27 lipp
048: * Fixed JavaScript evaluation with Date result.
049: *
050: * Revision 1.5 2003/09/23 17:04:41 lipp
051: * Fixed retrieval of Date return type.
052: *
053: * Revision 1.4 2003/09/22 14:56:47 lipp
054: * Moved code to Deadline.
055: *
056: * Revision 1.3 2003/09/15 15:43:40 lipp
057: * Initial version of handling exceptions in transition manager.
058: *
059: * Revision 1.2 2003/09/09 13:40:23 lipp
060: * Added state to deadline.
061: *
062: * Revision 1.1 2003/09/08 15:37:18 lipp
063: * Introduced deadline definition and suspend tracking.
064: *
065: */
066: package de.danet.an.workflow.domain;
067:
068: import java.io.Serializable;
069:
070: import java.util.Date;
071: import java.util.Iterator;
072: import java.util.List;
073:
074: import java.text.ParseException;
075:
076: import org.mozilla.javascript.Context;
077:
078: import de.danet.an.util.Duration;
079:
080: import de.danet.an.workflow.api.Activity.DeadlineInfo;
081: import de.danet.an.workflow.internalapi.ExtProcessLocal;
082: import de.danet.an.workflow.internalapi.ScriptException;
083: import de.danet.an.workflow.localapi.ActivityLocal;
084: import de.danet.an.workflow.util.XPDLUtil;
085:
086: /**
087: * This class represents a defined deadline with all its attributes.
088: *
089: * @author <a href="mailto:lipp@danet.de">Michael Lipp</a>
090: * @version $Revision: 1.4 $
091: */
092:
093: public class Deadline implements Serializable {
094:
095: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
096: .getLog(Deadline.class);
097:
098: /**
099: * Denotes asynchronous execution of the deadline.
100: */
101: public static final int ASYNCHR = DeadlineInfo.ASYNCHR;
102:
103: /**
104: * Denotes synchronous execution of the deadline.
105: */
106: public static final int SYNCHR = DeadlineInfo.SYNCHR;
107:
108: /**
109: * Deadline is in initial state.
110: */
111: public static final int STATE_INITIAL = DeadlineInfo.STATE_INITIAL;
112:
113: /**
114: * Deadline has been reached.
115: */
116: public static final int STATE_REACHED = DeadlineInfo.STATE_REACHED;
117:
118: private int execution;
119: private String condition;
120: private String exceptionName;
121: private int state = STATE_INITIAL;
122:
123: /**
124: * Creates an instance of <code>Deadline</code>
125: * with all attributes initialized to the given values.
126: * @param execMode the execution mode
127: * @param cond the condition
128: * @param exception the exception to be thrown
129: */
130: public Deadline(int execMode, String cond, String exception) {
131: execution = execMode;
132: condition = cond;
133: exceptionName = exception;
134: }
135:
136: /**
137: * Get the value of execution.
138: * @return value of execution.
139: */
140: public int getExecution() {
141: return execution;
142: }
143:
144: /**
145: * Get the value of Condition.
146: * @return value of Condition.
147: */
148: public String getCondition() {
149: return condition;
150: }
151:
152: /**
153: * Get the value of ExceptionName.
154: * @return value of ExceptionName.
155: */
156: public String getExceptionName() {
157: return exceptionName;
158: }
159:
160: /**
161: * Get the value of state.
162: * @return value of state.
163: * @see #setState
164: */
165: public int getState() {
166: return state;
167: }
168:
169: /**
170: * Set the value of state.
171: * @param v value to assign to state.
172: * @see #getState
173: */
174: public void setState(int v) {
175: this .state = v;
176: }
177:
178: /**
179: * Evaluate the expiration date for the given deadline.
180: *
181: * @param baseTime the point in time used to resolve relative time
182: * specifications in the condition
183: * @param process used for evaluation of the deadline expiration time
184: * @return the expiration date
185: * @throws ParseException if the condition cannot be evaluated
186: */
187: public Date expirationDate(Date baseTime, ExtProcessLocal process)
188: throws ParseException {
189: Object cond = null;
190: final ExtProcessLocal proc = process;
191: try {
192: cond = XPDLUtil.parseDuration(getCondition(),
193: new Duration.ValueEvaluator() {
194: public float evaluate(String s)
195: throws ParseException {
196: try {
197: return Float.parseFloat(s);
198: } catch (NumberFormatException e) {
199: return evalDurationValue(proc, s);
200: }
201: }
202: });
203: } catch (ParseException ee) {
204: Context cx = Context.enter();
205: try {
206: Object res = process.evalScript(getCondition());
207: if (res instanceof Date) {
208: cond = (Date) res;
209: } else if (res instanceof Number) {
210: cond = new Duration();
211: ((Duration) cond).setSeconds(((Number) res)
212: .floatValue());
213: } else {
214: throw new ParseException("Evaluating duration \""
215: + getCondition()
216: + "\" yields neither number nor date.", 0);
217: }
218: } catch (ScriptException e) {
219: throw new ParseException(
220: "Problem evaluating duration value \""
221: + getCondition() + "\": "
222: + e.getMessage(), 0);
223: } finally {
224: cx.exit();
225: }
226: }
227: Date end = null;
228: if (cond instanceof Date) {
229: end = (Date) cond;
230: } else {
231: Duration dur = (Duration) cond;
232: end = dur.addTo(baseTime);
233: }
234: return end;
235: }
236:
237: private float evalDurationValue(ExtProcessLocal process,
238: String value) throws ParseException {
239: try {
240: Object res = process.evalScript(value);
241: if (!(res instanceof Number)) {
242: throw new IllegalArgumentException(
243: "Evaluating duration value \"" + value
244: + "\" does not yield number.");
245: }
246: return ((Number) res).floatValue();
247: } catch (ScriptException e) {
248: throw new ParseException(
249: "Problem evaluating duration value \"" + value
250: + "\": " + e.getMessage(), 0);
251: }
252: }
253:
254: /**
255: * Set a timer for the given timed object as specified by this
256: * deadline for the given date. This method may be used if the
257: * expiration date has been evaluated already.
258: *
259: * @param to the <code>TimedObject</code>
260: * @param expirationDate the expiration date
261: * @param info the information to be delivered to the timed object
262: * on timeout
263: */
264: public void arm(TimedObject to, Date expirationDate,
265: Serializable info) {
266: if (getState() != Deadline.STATE_INITIAL) {
267: return;
268: }
269: if (logger.isDebugEnabled()) {
270: logger.debug("Starting timer for "
271: + to.toString()
272: + ", "
273: + toString()
274: + ", ends "
275: + expirationDate
276: + " (in "
277: + ((expirationDate.getTime() - (new Date())
278: .getTime()) / 1000.0) + "sec).");
279: }
280: to.startTimer(expirationDate, info);
281: }
282:
283: /**
284: * Set a timer for the given timed object as specified by this deadline.
285: *
286: * @param to the <code>TimedObject</code>
287: * @param baseTime the point in time used to resolve relative time
288: * specifications in the condition
289: * @param process used for evaluation of the deadline expiration time
290: * @param info the information to be delivered to the timed object
291: * on timeout
292: */
293: public void arm(TimedObject to, Date baseTime,
294: ExtProcessLocal process, Serializable info) {
295: if (getState() != Deadline.STATE_INITIAL) {
296: return;
297: }
298: try {
299: Date end = expirationDate(baseTime, process);
300: arm(to, end, info);
301: } catch (ParseException e) {
302: logger.error(e.getMessage());
303: }
304: }
305:
306: /**
307: * Arms the given list of deadlines on the given object, providing
308: * the index in the list as info to be delivered.
309: *
310: * @param to the <code>TimedObject</code>
311: * @param baseTime the point in time used to resolve relative time
312: * specifications in the condition
313: * @param proc used for evaluation of the deadline expiration time
314: * @param dls the deadlines
315: */
316: public static void armDeadlines(TimedObject to, Date baseTime,
317: ExtProcessLocal proc, List dls) {
318: int dlIndex = 0;
319: for (Iterator dli = dls.iterator(); dli.hasNext(); dlIndex += 1) {
320: Deadline dl = (Deadline) dli.next();
321: if (dl.getState() != Deadline.STATE_INITIAL) {
322: continue;
323: }
324: dl.arm(to, baseTime, proc, new Integer(dlIndex));
325: }
326: }
327:
328: /**
329: * Return string representation for debugging purposes.
330: * @return a string representation.
331: */
332: public String toString() {
333: return "Deadline[execution=" + execution + ",condition="
334: + condition.replace('\n', (char) 0x00B6)
335: + ",execeptionName=" + exceptionName + "]";
336: }
337:
338: }
|