/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: Deadline.java 2368 2007-05-03 21:58:25Z mlipp $
*
* $Log$
* Revision 1.3 2006/09/29 12:32:08 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.2 2005/01/09 21:32:42 mlipp
* Added support for debugging exceptions and deadlines.
*
* Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.10 2004/03/12 12:19:53 lipp
* Javadoc fixes.
*
* Revision 1.9 2003/09/25 12:00:05 lipp
* Avoid client dependency on rhino.
*
* Revision 1.8 2003/09/25 11:01:20 lipp
* Fixed usage of jsScope (may not be used remotely).
*
* Revision 1.7 2003/09/24 20:28:42 lipp
* Reorganized deadline/suspend handling.
*
* Revision 1.6 2003/09/24 13:46:27 lipp
* Fixed JavaScript evaluation with Date result.
*
* Revision 1.5 2003/09/23 17:04:41 lipp
* Fixed retrieval of Date return type.
*
* Revision 1.4 2003/09/22 14:56:47 lipp
* Moved code to Deadline.
*
* Revision 1.3 2003/09/15 15:43:40 lipp
* Initial version of handling exceptions in transition manager.
*
* Revision 1.2 2003/09/09 13:40:23 lipp
* Added state to deadline.
*
* Revision 1.1 2003/09/08 15:37:18 lipp
* Introduced deadline definition and suspend tracking.
*
*/
package de.danet.an.workflow.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.text.ParseException;
import org.mozilla.javascript.Context;
import de.danet.an.util.Duration;
import de.danet.an.workflow.api.Activity.DeadlineInfo;
import de.danet.an.workflow.internalapi.ExtProcessLocal;
import de.danet.an.workflow.internalapi.ScriptException;
import de.danet.an.workflow.localapi.ActivityLocal;
import de.danet.an.workflow.util.XPDLUtil;
/**
* This class represents a defined deadline with all its attributes.
*
* @author <a href="mailto:lipp@danet.de">Michael Lipp</a>
* @version $Revision: 2368 $
*/
public class Deadline implements Serializable {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog(Deadline.class);
/**
* Denotes asynchronous execution of the deadline.
*/
public static final int ASYNCHR = DeadlineInfo.ASYNCHR;
/**
* Denotes synchronous execution of the deadline.
*/
public static final int SYNCHR = DeadlineInfo.SYNCHR;
/**
* Deadline is in initial state.
*/
public static final int STATE_INITIAL = DeadlineInfo.STATE_INITIAL;
/**
* Deadline has been reached.
*/
public static final int STATE_REACHED = DeadlineInfo.STATE_REACHED;
private int execution;
private String condition;
private String exceptionName;
private int state = STATE_INITIAL;
/**
* Creates an instance of <code>Deadline</code>
* with all attributes initialized to the given values.
* @param execMode the execution mode
* @param cond the condition
* @param exception the exception to be thrown
*/
public Deadline (int execMode, String cond, String exception) {
execution = execMode;
condition = cond;
exceptionName = exception;
}
/**
* Get the value of execution.
* @return value of execution.
*/
public int getExecution() {
return execution;
}
/**
* Get the value of Condition.
* @return value of Condition.
*/
public String getCondition() {
return condition;
}
/**
* Get the value of ExceptionName.
* @return value of ExceptionName.
*/
public String getExceptionName() {
return exceptionName;
}
/**
* Get the value of state.
* @return value of state.
* @see #setState
*/
public int getState() {
return state;
}
/**
* Set the value of state.
* @param v value to assign to state.
* @see #getState
*/
public void setState(int v) {
this.state = v;
}
/**
* Evaluate the expiration date for the given deadline.
*
* @param baseTime the point in time used to resolve relative time
* specifications in the condition
* @param process used for evaluation of the deadline expiration time
* @return the expiration date
* @throws ParseException if the condition cannot be evaluated
*/
public Date expirationDate (Date baseTime, ExtProcessLocal process)
throws ParseException {
Object cond = null;
final ExtProcessLocal proc = process;
try {
cond = XPDLUtil.parseDuration
(getCondition(),
new Duration.ValueEvaluator () {
public float evaluate(String s)
throws ParseException {
try {
return Float.parseFloat (s);
} catch (NumberFormatException e) {
return evalDurationValue (proc, s);
}
}
});
} catch (ParseException ee) {
Context cx = Context.enter();
try {
Object res = process.evalScript (getCondition ());
if (res instanceof Date) {
cond = (Date)res;
} else if (res instanceof Number) {
cond = new Duration ();
((Duration)cond).setSeconds
(((Number)res).floatValue ());
} else {
throw new ParseException
("Evaluating duration \"" + getCondition()
+ "\" yields neither number nor date.", 0);
}
} catch (ScriptException e) {
throw new ParseException
("Problem evaluating duration value \""
+ getCondition() + "\": " + e.getMessage(), 0);
} finally {
cx.exit();
}
}
Date end = null;
if (cond instanceof Date) {
end = (Date)cond;
} else {
Duration dur = (Duration)cond;
end = dur.addTo (baseTime);
}
return end;
}
private float evalDurationValue (ExtProcessLocal process, String value)
throws ParseException {
try {
Object res = process.evalScript (value);
if (!(res instanceof Number)) {
throw new IllegalArgumentException
("Evaluating duration value \"" + value
+ "\" does not yield number.");
}
return ((Number)res).floatValue();
} catch (ScriptException e) {
throw new ParseException
("Problem evaluating duration value \""
+ value + "\": " + e.getMessage(), 0);
}
}
/**
* Set a timer for the given timed object as specified by this
* deadline for the given date. This method may be used if the
* expiration date has been evaluated already.
*
* @param to the <code>TimedObject</code>
* @param expirationDate the expiration date
* @param info the information to be delivered to the timed object
* on timeout
*/
public void arm (TimedObject to, Date expirationDate, Serializable info) {
if (getState() != Deadline.STATE_INITIAL) {
return;
}
if (logger.isDebugEnabled ()) {
logger.debug ("Starting timer for " + to.toString() + ", "
+ toString () + ", ends " + expirationDate + " (in "
+ ((expirationDate.getTime() - (new Date()).getTime())
/ 1000.0) + "sec).");
}
to.startTimer (expirationDate, info);
}
/**
* Set a timer for the given timed object as specified by this deadline.
*
* @param to the <code>TimedObject</code>
* @param baseTime the point in time used to resolve relative time
* specifications in the condition
* @param process used for evaluation of the deadline expiration time
* @param info the information to be delivered to the timed object
* on timeout
*/
public void arm (TimedObject to, Date baseTime,
ExtProcessLocal process, Serializable info) {
if (getState() != Deadline.STATE_INITIAL) {
return;
}
try {
Date end = expirationDate (baseTime, process);
arm (to, end, info);
} catch (ParseException e) {
logger.error (e.getMessage ());
}
}
/**
* Arms the given list of deadlines on the given object, providing
* the index in the list as info to be delivered.
*
* @param to the <code>TimedObject</code>
* @param baseTime the point in time used to resolve relative time
* specifications in the condition
* @param proc used for evaluation of the deadline expiration time
* @param dls the deadlines
*/
public static void armDeadlines
(TimedObject to, Date baseTime, ExtProcessLocal proc, List dls) {
int dlIndex = 0;
for (Iterator dli = dls.iterator (); dli.hasNext ();
dlIndex += 1) {
Deadline dl = (Deadline)dli.next ();
if (dl.getState() != Deadline.STATE_INITIAL) {
continue;
}
dl.arm (to, baseTime, proc, new Integer (dlIndex));
}
}
/**
* Return string representation for debugging purposes.
* @return a string representation.
*/
public String toString() {
return "Deadline[execution=" + execution
+ ",condition=" + condition.replace('\n', (char)0x00B6)
+ ",execeptionName=" + exceptionName + "]";
}
}