001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2004 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: WaitTool.java,v 1.5 2006/12/04 15:08:17 drmlipp Exp $
021: *
022: * $Log: WaitTool.java,v $
023: * Revision 1.5 2006/12/04 15:08:17 drmlipp
024: * Added invocation with time to wait.
025: *
026: * Revision 1.4 2006/09/29 12:32:10 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.3 2004/10/20 20:40:32 drmlipp
030: * Made simple WaitTool terminatable.
031: *
032: * Revision 1.2 2004/10/19 21:06:32 drmlipp
033: * Fixed indentation.
034: *
035: * Revision 1.1.1.1 2004/08/18 15:17:39 drmlipp
036: * Update to 1.2
037: *
038: * Revision 1.5 2004/04/13 14:33:38 lipp
039: * Cleanup.
040: *
041: * Revision 1.4 2004/04/12 19:33:52 lipp
042: * Clarified application invocation interface.
043: *
044: * Revision 1.3 2004/02/27 18:09:31 lipp
045: * Removed overlooked hard-coding of result parameter.
046: *
047: * Revision 1.2 2004/02/23 13:59:31 lipp
048: * Added simple waittool invocation.
049: *
050: * Revision 1.1 2004/02/20 18:56:35 lipp
051: * Renamed package waittool to timing (much better ;-)).
052: *
053: * Revision 1.2 2004/02/20 15:58:22 lipp
054: * Several WaitTool fixes.
055: *
056: * Revision 1.1 2004/02/19 17:55:55 lipp
057: * Initial version of waittool.
058: *
059: */
060: package de.danet.an.workflow.tools.timing;
061:
062: import java.util.Date;
063: import java.util.Map;
064:
065: import java.rmi.RemoteException;
066:
067: import de.danet.an.workflow.omgcore.CannotCompleteException;
068: import de.danet.an.workflow.omgcore.InvalidDataException;
069: import de.danet.an.workflow.omgcore.ProcessData;
070:
071: import de.danet.an.workflow.api.Activity;
072: import de.danet.an.workflow.api.ActivityUniqueKey;
073: import de.danet.an.workflow.api.DefaultProcessData;
074: import de.danet.an.workflow.api.FormalParameter;
075: import de.danet.an.workflow.api.InvalidKeyException;
076:
077: import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
078: import de.danet.an.workflow.spis.aii.CannotExecuteException;
079: import de.danet.an.workflow.tools.util.SimpleApplicationInfo;
080:
081: /**
082: * This class provides a tool agent that cancels a timer.
083: *
084: * @author <a href="mailto:lipp@danet.de">Michael Lipp</a>
085: * @version $Revision: 1.5 $
086: */
087: public class WaitTool extends ToolAgentBase {
088:
089: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
090: .getLog(WaitTool.class);
091:
092: /**
093: * Creates an instance of <code>WaitTool</code>
094: * with all attributes initialized to default values.
095: */
096: public WaitTool() {
097: }
098:
099: /**
100: * Executes the tool.
101: *
102: * @param activity an <code>Activity</code> value
103: * @param fps the formal parameters
104: * @param map a <code>Map</code> value
105: * @exception CannotExecuteException if an error occurs
106: * @exception RemoteException if an error occurs
107: */
108: public void invoke(Activity activity, FormalParameter[] fps, Map map)
109: throws CannotExecuteException, RemoteException {
110: Object arg0 = map.get(fps[0].id());
111: if ((arg0 instanceof Date) || (arg0 instanceof Number)
112: && fps.length == 1) {
113: try {
114: // uncancalable wait, simply create timer and wait
115: long applId = applicationDirectory()
116: .registerInstance(WaitTool.class.getName(),
117: activity, null, false);
118: if (logger.isDebugEnabled()) {
119: logger.debug("Application " + applId
120: + " created for " + activity);
121: }
122: Object timer = timerHandler()
123: .createTimer(
124: applId,
125: (arg0 instanceof Date) ? (Date) arg0
126: : new Date(
127: Math
128: .round(System
129: .currentTimeMillis()
130: + (((Number) arg0)
131: .doubleValue() * 1000))));
132: applicationDirectory().updateState(applId,
133: new Object[] { timer, null });
134: } catch (InvalidKeyException invKey) {
135: if (logger.isDebugEnabled()) {
136: logger.debug("Timer expired immediately");
137: }
138: }
139: return;
140: }
141: // cancalable wait, update associates timer application
142: long applId = ((Long) arg0).longValue();
143: try {
144: if (logger.isDebugEnabled()) {
145: logger.debug("Waiting for timer application " + applId);
146: }
147: applicationDirectory().updateInvokingActivity(applId,
148: activity.uniqueKey());
149: if (logger.isDebugEnabled()) {
150: logger.debug("Application " + applId + " updated to "
151: + activity);
152: }
153: SimpleApplicationInfo info = applicationDirectory()
154: .instanceInfo(applId);
155: Object[] data = (Object[]) info.state();
156: data[1] = fps[1].id();
157: applicationDirectory().updateState(applId, data);
158: return;
159: } catch (InvalidKeyException invKey) {
160: if (logger.isDebugEnabled()) {
161: logger.debug("Timer application " + applId
162: + " has already expired, completing");
163: }
164: }
165: ProcessData res = new DefaultProcessData();
166: res.put(fps[1].id(), "EXPIRED");
167: try {
168: activity.setResult(res);
169: activity.complete();
170: } catch (CannotCompleteException e) {
171: logger
172: .error(activity + " waiting for timer "
173: + "but cannot be completed?!: "
174: + e.getMessage(), e);
175: throw new CannotExecuteException(
176: "Receiving activity cannot be completed");
177: } catch (InvalidDataException e) {
178: logger.error("Cannot set \"status\" out parameter of "
179: + "wait tool. Propably wrong declaration. "
180: + activity + " will be terminated.");
181: throw new CannotExecuteException(e.getMessage());
182: }
183: }
184:
185: /**
186: * Terminate the tool agent.
187: *
188: * @param activity the activity to be canceled
189: * @throws ApplicationNotStoppedException if execution cannot be
190: * terminated (see {@link ApplicationNotStoppedException
191: * <code>ApplicationNotStoppedException</code>}).
192: * @throws RemoteException if a temporary problem occurs and the
193: * workflow engine should retry the tool invocation
194: */
195: public void terminate(Activity activity)
196: throws ApplicationNotStoppedException, RemoteException {
197: ActivityUniqueKey auk = null;
198: try {
199: auk = activity.uniqueKey();
200: SimpleApplicationInfo info = applicationDirectory()
201: .infoByActivity(auk);
202: if (logger.isDebugEnabled()) {
203: logger.debug("Terminating application " + info.id()
204: + " invoked by " + auk);
205: }
206: applicationDirectory().removeInstance(info.id());
207: timerHandler().removeTimer(((Object[]) info.state())[0]);
208: } catch (InvalidKeyException e) {
209: // terminate is called by engine "to make sure"
210: logger.debug("Terminate called for " + auk
211: + " but application " + "already removed (is OK): "
212: + e.getMessage());
213: }
214: }
215:
216: }
|