001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: /*
006: * Created by IntelliJ IDEA.
007: * User: plightbo
008: * Date: May 22, 2002
009: * Time: 4:05:53 PM
010: */
011: package com.opensymphony.workflow.util;
012:
013: import com.opensymphony.module.propertyset.PropertySet;
014:
015: import com.opensymphony.util.TextUtils;
016:
017: import com.opensymphony.workflow.FunctionProvider;
018: import com.opensymphony.workflow.WorkflowContext;
019: import com.opensymphony.workflow.spi.WorkflowEntry;
020: import com.opensymphony.workflow.timer.LocalWorkflowJob;
021: import com.opensymphony.workflow.timer.WorkflowJob;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import org.quartz.*;
027:
028: import org.quartz.impl.StdSchedulerFactory;
029:
030: import java.util.Date;
031: import java.util.Map;
032:
033: /**
034: * Schedules a job in the Quartz job scheduler to be executed one or more times in the future.
035: * The following arguments are required:
036: *
037: * <ul>
038: * <li> triggerId - the id of the trigger function defined in the XML workflow
039: * <li> jobName - the name to be given to the job
040: * <li> triggerName - the name to be given to the trigger
041: * <li> groupName - the group given to both the job and the trigger
042: * </ul>
043: *
044: * The following arguments are optional:
045: * <ul>
046: * <li> username - the system account's username that will execute the function in the future.
047: * If this is not specified value from WorkflowContext.getCaller() is used
048: * <li> password - the system account's password
049: * <li> local - if set to the true, a LocalWorkflowJob is used, bypassing the need for SOAP support.
050: * Will be ignored if "workflowClass" is specified.
051: * <li> jobClass - the class implementing 'Job' to run, defaults to WorkflowJob. If not specified,
052: * defaults to either a WorkflowJob or a LocalWorkflowJob if "local" is set to true.
053: * <li>schedulerName - the name of an existing scheduler to use</li>
054: * <li>schdulerStart - if "true", start the scheduler if it hasn't been started already</li>
055: * <li>txHack - set this to true if you are getting lockups while running with transactions (defaults to false)</li>
056: * </ul>
057: *
058: * If you are using a cron trigger, the following is required:
059: * <ul>
060: * <li> cronExpression - the Cron expression
061: * </ul>
062: *
063: * If you are using a simple trigger, the follow are all optional:
064: * <ul>
065: * <li> startOffset - the offset, in milliseconds, from the current time. (default is 0)
066: * <li> endOffset - the offset, in milliseconds, from the current time. (default is infinity)
067: * <li> repeat - the repeat count (default is 0). Can also be REPEAT_INDEFINITELY
068: * <li> repeatDelay - the time delay, in milliseconds, between repeats (default is 0)
069: * </ul>
070: *
071: * @author <a href="mike.g.slack@usahq.unitedspacealliance.com ">Michael G. Slack</a>
072: * @author <a href="mailto:plightbo@hotmail.com">Pat Lightbody</a>
073: */
074: public class ScheduleJob implements FunctionProvider {
075: //~ Static fields/initializers /////////////////////////////////////////////
076:
077: private static final Log log = LogFactory.getLog(ScheduleJob.class);
078:
079: //~ Methods ////////////////////////////////////////////////////////////////
080:
081: public void execute(Map transientVars, Map args, PropertySet ps) {
082: try {
083: WorkflowEntry entry = (WorkflowEntry) transientVars
084: .get("entry");
085: WorkflowContext context = (WorkflowContext) transientVars
086: .get("context");
087:
088: log
089: .info("Starting to schdule job for WF #"
090: + entry.getId());
091:
092: int triggerId = TextUtils.parseInt((String) args
093: .get("triggerId"));
094: String jobName = (String) args.get("jobName");
095: String triggerName = (String) args.get("triggerName");
096: String groupName = (String) args.get("groupName");
097:
098: String username = (String) args.get("username");
099: String password = (String) args.get("password");
100:
101: boolean txHack = TextUtils.parseBoolean((String) args
102: .get("txHack"));
103:
104: if (username == null) {
105: username = context.getCaller();
106: }
107:
108: String cronExpression = (String) args.get("cronExpression");
109:
110: jobName = jobName + ":" + entry.getId();
111: triggerName = triggerName + ":" + entry.getId();
112: groupName = groupName + ":" + entry.getId();
113:
114: String schedulerName = (String) args.get("schedulerName");
115: Scheduler s;
116:
117: SchedulerFactory factory = new StdSchedulerFactory();
118:
119: if ((schedulerName == null)
120: || "".equals(schedulerName.trim())) {
121: s = factory.getScheduler();
122: } else {
123: s = factory.getScheduler(schedulerName);
124: }
125:
126: if (TextUtils.parseBoolean((String) args
127: .get("schedulerStart"))) {
128: log.info("Starting Quartz Job Scheduler");
129: s.start();
130: }
131:
132: Class jobClass;
133: String jobClassArg = (String) args.get("jobClass");
134:
135: if (jobClassArg != null) {
136: jobClass = Class.forName(jobClassArg);
137: } else if (TextUtils.parseBoolean((String) args
138: .get("local"))) {
139: jobClass = LocalWorkflowJob.class;
140: } else {
141: jobClass = WorkflowJob.class;
142: }
143:
144: JobDetail jobDetail = new JobDetail(jobName, groupName,
145: jobClass);
146: Trigger trigger;
147:
148: if (cronExpression == null) {
149: long now = System.currentTimeMillis();
150:
151: // get start date - default is now
152: Date startDate = null;
153:
154: try {
155: String start = (String) args.get("startOffset");
156:
157: if (s != null) {
158: startDate = new Date(now
159: + Long.parseLong(start));
160: }
161: } catch (NumberFormatException e) {
162: }
163:
164: if (startDate == null) {
165: startDate = new Date(now);
166: }
167:
168: // get end date - default is null
169: Date endDate = null;
170:
171: try {
172: String end = (String) args.get("endOffset");
173:
174: if (s != null) {
175: startDate = new Date(now + Long.parseLong(end));
176: }
177: } catch (NumberFormatException e) {
178: }
179:
180: // get the repeat amount - default is 0
181: int repeat = 0;
182:
183: try {
184: String r = (String) args.get("repeat");
185:
186: if (r != null) {
187: if (r.equalsIgnoreCase("REPEAT_INDEFINITELY")) {
188: repeat = SimpleTrigger.REPEAT_INDEFINITELY;
189: } else {
190: repeat = TextUtils.parseInt(r);
191: }
192: }
193: } catch (NumberFormatException e) {
194: }
195:
196: // get repeat delay - default is 0
197: long delay = 0;
198:
199: try {
200: String rd = (String) args.get("repeatDelay");
201:
202: if (rd != null) {
203: delay = Long.parseLong(rd);
204: }
205: } catch (NumberFormatException e) {
206: }
207:
208: trigger = new SimpleTrigger(triggerName, groupName,
209: jobName, groupName, startDate, endDate, repeat,
210: delay);
211: } else {
212: trigger = new CronTrigger(triggerName, groupName,
213: jobName, groupName, cronExpression);
214: }
215:
216: JobDataMap dataMap = new JobDataMap();
217: dataMap.put("triggerId", triggerId);
218: dataMap.put("entryId", entry.getId());
219: dataMap.put("username", username);
220: dataMap.put("password", password);
221:
222: if (TextUtils.parseBoolean((String) args.get("local"))) {
223: dataMap.put("configuration", transientVars
224: .get("configuration"));
225: }
226:
227: jobDetail.setJobDataMap(dataMap);
228: jobDetail.setDurability(true);
229:
230: trigger.setJobName(jobDetail.getName());
231: trigger.setJobGroup(jobDetail.getGroup());
232:
233: if (txHack && !s.isPaused() && !s.isShutdown()) {
234: s.pause();
235:
236: try {
237: s.addJob(jobDetail, true);
238: s.scheduleJob(trigger);
239: } catch (SchedulerException e) {
240: throw e;
241: } finally {
242: s.start();
243: }
244: } else {
245: s.addJob(jobDetail, true);
246: s.scheduleJob(trigger);
247: }
248:
249: log.info("Job scheduled");
250: } catch (Exception e) {
251: log.error("Error scheduling job", e);
252: }
253: }
254: }
|