Project

General

Profile

1 4951 daigle
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles scheduling tasks
4
 *  Copyright: 2009 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Michael Daigle
7
 *
8
 *   '$Author: daigle $'
9
 *     '$Date: 2009-03-25 13:41:15 -0800 (Wed, 25 Mar 2009) $'
10
 * '$Revision: 4861 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26
27
package edu.ucsb.nceas.metacat.scheduler;
28
29
import java.util.Calendar;
30 4959 daigle
import java.util.HashMap;
31 4951 daigle
import java.util.Vector;
32
33
import org.apache.log4j.Logger;
34
35
import org.quartz.Job;
36 4959 daigle
import org.quartz.JobDataMap;
37 4951 daigle
import org.quartz.JobDetail;
38
import org.quartz.Scheduler;
39
import org.quartz.SchedulerException;
40
import org.quartz.SchedulerFactory;
41
import org.quartz.Trigger;
42
import org.quartz.TriggerUtils;
43
44 5015 daigle
import edu.ucsb.nceas.metacat.shared.AccessException;
45
import edu.ucsb.nceas.metacat.shared.BaseService;
46
import edu.ucsb.nceas.metacat.shared.ServiceException;
47 5005 daigle
import edu.ucsb.nceas.utilities.DateUtil;
48 4959 daigle
import edu.ucsb.nceas.utilities.StatusUtil;
49 5005 daigle
import edu.ucsb.nceas.utilities.UtilException;
50 4951 daigle
51
public class SchedulerService extends BaseService {
52
53
	private static SchedulerService schedulerService = null;
54
55
	private static Logger logMetacat = Logger.getLogger(SchedulerService.class);
56
57
	private static Scheduler sched = null;
58
59
	/**
60
	 * private constructor since this is a singleton
61
	 */
62 4959 daigle
	private SchedulerService() throws ServiceException {
63
		start();
64
	}
65 4951 daigle
66
	/**
67
	 * Get the single instance of SchedulerService.
68
	 *
69
	 * @return the single instance of SchedulerService
70
	 */
71
	public static SchedulerService getInstance() throws ServiceException {
72
		if (schedulerService == null) {
73
			schedulerService = new SchedulerService();
74
		}
75
		return schedulerService;
76
	}
77
78 4971 daigle
	// this is a refreshable class
79 4951 daigle
	public boolean refreshable() {
80
		return true;
81
	}
82 4971 daigle
83
	// do the refresh
84 4981 daigle
	public void doRefresh() throws ServiceException {
85 4951 daigle
		stop();
86 4971 daigle
		start();
87 4951 daigle
	}
88
89 4971 daigle
	// initialize the service
90 4981 daigle
	public void start() throws ServiceException {
91 4951 daigle
		try {
92 4971 daigle
			// get the Quartz scheduler factory
93 4951 daigle
			SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
94
95 4971 daigle
			// get the scheduler
96 4951 daigle
			sched = schedFact.getScheduler();
97
			sched.start();
98 4967 daigle
99 4971 daigle
			// get all existing jobs from the database
100 4967 daigle
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
101
			HashMap<Long, ScheduledJobDAO> allJobsMap = jobAccess.getAllJobs(null);
102
103 4971 daigle
			// reschedule each job that is in a SCHEDULED state.
104 4967 daigle
			for (Long jobId : allJobsMap.keySet()) {
105
				ScheduledJobDAO jobDAO = allJobsMap.get(jobId);
106
				String[] groups = {"scheduler_group"};
107
				if (jobDAO.getStatus().equals(StatusUtil.SCHEDULED)) {
108 4971 daigle
					// send false as the last param so the reschedule method will not
109
					// complain that the job is already in a SCHEDULED state.
110 4967 daigle
					rescheduleJob(jobDAO, "scheduler_user", groups, false);
111
				}
112
			}
113
114
		} catch (AccessException ae) {
115 4971 daigle
			throw new ServiceException("SchedulerService.start - DB Access issue when starting scheduler: ", ae);
116 4951 daigle
		} catch (SchedulerException se) {
117 4971 daigle
			throw new ServiceException("SchedulerService.start - Scheduler engine issue when starting scheduler: " + se.getMessage());
118 4951 daigle
		}
119
	}
120
121 4971 daigle
	// Stop the scheduler
122 4981 daigle
	public void stop() throws ServiceException {
123 4951 daigle
		try {
124
			sched.shutdown(true);
125
			sched = null;
126
		} catch (SchedulerException se) {
127 4971 daigle
			throw new ServiceException("SchedulerService.stop - Could not shut down scheduler: " + se.getMessage());
128 4951 daigle
		}
129
	}
130
131 4971 daigle
	// this will eventually return the scheduler status
132 4951 daigle
	protected Vector<String> getStatus() throws ServiceException {
133
		return new Vector<String>();
134
	}
135
136 4971 daigle
	/**
137
	 * Schedule a job
138
	 *
139
	 * @param jobDAO
140
	 *            the job data object to schedule
141
	 * @param username
142
	 *            the user that we will use to schedule
143
	 * @param groups
144
	 *            the user group that we will use to schedule
145
	 * @return a message saying that the job was scheduled
146
	 */
147 4967 daigle
	public String scheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups) throws ServiceException {
148 4951 daigle
149 4971 daigle
		// convert the start time to a calendar object
150 4967 daigle
		Calendar startTimeCal = Calendar.getInstance();
151
        startTimeCal.setTime(jobDAO.getStartTime());
152
153 5012 daigle
		// convert the start time to a calendar object
154
		Calendar endTimeCal = Calendar.getInstance();
155
        endTimeCal.setTime(jobDAO.getEndTime());
156
157 4971 daigle
        // extract the job parameters from their data objects and put into a string map
158 4967 daigle
        HashMap<String, String> jobParams = new HashMap<String, String>();
159
        HashMap<String, ScheduledJobParamDAO> jobParamDAOs = jobDAO.getAllJobParams();
160
        for (String paramName : jobParamDAOs.keySet()) {
161
        	jobParams.put(paramName, jobParamDAOs.get(paramName).getValue());
162
        }
163
164 4971 daigle
        // schedule the job
165 5012 daigle
		return scheduleJob(jobDAO.getName(), startTimeCal, endTimeCal, jobDAO.getIntervalValue(),
166
				jobDAO.getIntervalUnit(), jobDAO.getClassName(), jobDAO.getGroupName(),
167
				jobParams, username, groups);
168 4967 daigle
	}
169
170 4971 daigle
	/**
171
	 * schedule a job
172
	 *
173
	 * @param jobName
174
	 *            the name of the job
175
	 * @param startCal
176
	 *            a calendar holding the start date of the job
177
	 * @param intervalValue
178
	 *            the run interval for the job
179
	 * @param intervalUnit
180
	 *            the unit of the run interval for the job
181
	 * @param jobClassName
182
	 *            the job class name
183
	 * @param jobGroup
184
	 *            the job group name
185
	 * @param jobParams
186
	 *            a map of additional job parameters
187
	 * @param username
188
	 *            the user name
189
	 * @param groups
190
	 *            the user's group name
191
	 * @return a message saying that the job was scheduled
192
	 */
193 5012 daigle
	public String scheduleJob(String jobName, Calendar startCal, Calendar endCal, int intervalValue,
194
			String intervalUnit, String jobClassName, String jobGroup, HashMap<String, String> jobParams,
195 4967 daigle
			String username, String[] groups) throws ServiceException {
196
197 4951 daigle
        Class<Job> jobClass = null;
198 5005 daigle
        try {
199
			jobClass = (Class<Job>) Class.forName(jobClassName);
200
201 5013 daigle
			String startTimeStr = DateUtil.getHumanReadable(startCal);
202 5005 daigle
			logMetacat.info("SchedulerService.scheduleJob - Scheduling job -- name: "
203
					+ jobName + ", class: " + jobClassName + ", start time: "
204
					+ startTimeStr + ", interval value: " + intervalValue
205
					+ ", interval unit: " + intervalUnit);
206
207
			// start the job in the job scheduler
208 5012 daigle
			startJob(jobName, startCal, endCal, intervalValue, intervalUnit, jobClass, jobGroup,
209 5005 daigle
					jobParams);
210
211
			// get a database access object and create the job in the database
212
213 4951 daigle
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
214 5012 daigle
			jobAccess.createJob(jobName, jobName, jobGroup, jobClass, startCal, endCal,
215 5005 daigle
					intervalValue, intervalUnit, jobParams);
216 4951 daigle
		} catch (AccessException ae) {
217
			try {
218 4967 daigle
				deleteJob(jobName, username, groups);
219 4959 daigle
			} catch (Exception e) {
220 4951 daigle
				// Not much we can do here but log this
221 5005 daigle
				logMetacat.error("SchedulerService.scheduleJob - An access exception was thrown when writing job: "
222
						+ jobName + "to the db, and another exception was thrown when trying to remove the "
223 4959 daigle
						+ "job from the scheduler.  The db and scheduler may be out of sync: " + e.getMessage());
224 4951 daigle
			}
225 4959 daigle
			throw new ServiceException("SchedulerService.scheduleJob - Error accessing db: ", ae);
226 5005 daigle
		} catch (ClassNotFoundException cnfe) {
227
			throw new ServiceException("SchedulerService.scheduleJob - Could not find class with name: "
228
							+ jobClassName + " : " + cnfe.getMessage());
229
		} catch (UtilException ue) {
230
			throw new ServiceException("SchedulerService.scheduleJob - Could not schedule "
231
							+ "job due to a utility issue: " + ue.getMessage());
232 4951 daigle
		}
233
234 4967 daigle
		return "Scheduled: " + jobName;
235 4951 daigle
	}
236
237 4971 daigle
	/**
238
	 * Unschedule a job. This removed it from the scheduler in memory and
239
	 * changed it's status to unscheduled in the database.
240
	 *
241
	 * @param jobName
242
	 *            the name of the job to unschedule
243
	 * @param username
244
	 *            the user name
245
	 * @param groups
246
	 *            the user's group name
247
	 * @return a message saying the job was unscheduled
248
	 */
249 4967 daigle
	public String unScheduleJob(String jobName, String username,
250
			String[] groups) throws ServiceException {
251 5013 daigle
252
		ScheduledJobDAO jobDAO = null;
253 4951 daigle
		try {
254
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
255 5013 daigle
			jobDAO = jobAccess.getJobByName(jobName);
256 4967 daigle
			if (jobDAO == null) {
257
				throw new ServiceException("SchedulerService.unscheduleJob - Could "
258
						+ "not find job with name: " + jobName);
259
			}
260 4951 daigle
261 4971 daigle
			// remove the job from the scheduler
262 4967 daigle
			sched.deleteJob(jobDAO.getName(), jobDAO.getGroupName());
263 4951 daigle
264 4971 daigle
			// change the status of the job to unscheduled in the database.
265 4967 daigle
			jobDAO.setStatus(StatusUtil.UNSCHEDULED);
266 4951 daigle
			jobAccess.updateJobStatus(jobDAO);
267
		} catch (SchedulerException se) {
268
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
269
							+ "scheduled job because of service issue: " + se.getMessage());
270
		} catch (AccessException ae) {
271
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
272 5013 daigle
							+ "scheduled job : " + jobDAO.getName() + " because of db access issue: ", ae);
273 4951 daigle
		}
274 4967 daigle
275
		return "Unscheduled: " + jobName;
276 4951 daigle
	}
277
278 4971 daigle
	/**
279
	 * Reschedule a job. This call will always check to make sure the status is not SCHEDULED
280
	 * @param jobDAO the job data object holding the information about the job to reschedule
281
	 * @param username
282
	 *            the user name
283
	 * @param groups
284
	 *            the user's group name
285
	 * @return a message saying that the job was rescheduled
286
	 */
287 4967 daigle
	public String rescheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups) throws ServiceException {
288
		return rescheduleJob(jobDAO, username, groups, true);
289
	}
290
291 4971 daigle
	/**
292
	 * Reschedule a job.
293
	 *
294
	 * @param jobDAO
295
	 *            the job data object holding the information about the job to
296
	 *            reschedule
297
	 * @param username
298
	 *            the user name
299
	 * @param groups
300
	 *            the user's group name
301
	 * @param checkStatus
302
	 *            if set to true, the method will check to make sure the status
303
	 *            is UNSCHEDULED before restarting. Otherwise, the method will
304
	 *            not check. This is so that we can restart a service at startup
305
	 *            that was running when metacat was shut down.
306
	 * @return a message saying that the job was rescheduled
307
	 */
308 4967 daigle
	public String rescheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups, boolean checkStatus) throws ServiceException {
309
310
		try {
311
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
312
313
			if (jobDAO == null) {
314
				throw new ServiceException("SchedulerService.reScheduleJob - Cannot reschedule nonexistant job.");
315
			}
316
317 4971 daigle
			// if we are checking status, make sure the job is in an UNSCHEDULED state in the db
318 4967 daigle
			if (checkStatus && !jobDAO.getStatus().equals(StatusUtil.UNSCHEDULED)) {
319
				throw new ServiceException("SchedulerService.reScheduleJob - Cannot reschedule a job with status: "
320
						+ jobDAO.getStatus() + ". Status must be 'unscheduled'.");
321
			}
322
323
			Calendar startCal = Calendar.getInstance();
324
	        startCal.setTime(jobDAO.getStartTime());
325
326 5012 daigle
			Calendar endCal = Calendar.getInstance();
327
	        endCal.setTime(jobDAO.getEndTime());
328
329 4967 daigle
	        HashMap<String, String> jobParams = new HashMap<String, String>();
330
	        HashMap<String, ScheduledJobParamDAO> jobParamDAOs = jobDAO.getAllJobParams();
331
	        for (String paramName : jobParamDAOs.keySet()) {
332
	        	jobParams.put(paramName, jobParamDAOs.get(paramName).getValue());
333
	        }
334
335
	        Class<Job> jobClass = null;
336
	        String jobClassName = jobDAO.getClassName();
337
	        try {
338
	        	jobClass = (Class<Job>)Class.forName(jobClassName);
339
	        } catch (ClassNotFoundException cnfe) {
340
	        	throw new ServiceException("SchedulerService.scheduleJob - Could not find class with name: "
341
	        			+ jobDAO.getClassName() + " : " + cnfe.getMessage());
342
	        }
343
344 5013 daigle
	        String startTimeStr = DateUtil.getHumanReadable(startCal);
345 4967 daigle
	        logMetacat.info("SchedulerService.rescheduleJob - name: " + jobDAO.getName() + ", class: " + jobClassName
346 5005 daigle
	        		+ ", start time: " + startTimeStr + ", interval value: " + jobDAO.getIntervalValue()
347 4967 daigle
	        		+ ", interval unit: " + jobDAO.getIntervalUnit());
348
349 4971 daigle
	        // start the job in the scheduler
350 5012 daigle
			startJob(jobDAO.getName(), startCal, endCal, jobDAO.getIntervalValue(), jobDAO.getIntervalUnit(), jobClass, jobDAO.getGroupName(), jobParams);
351 4967 daigle
352 4971 daigle
			// update the status in the database
353 4967 daigle
			jobDAO.setStatus(StatusUtil.SCHEDULED);
354
			jobAccess.updateJobStatus(jobDAO);
355
356
		} catch (AccessException ae) {
357
			throw new ServiceException("SchedulerService.reScheduleJob - Could not reschedule "
358 5013 daigle
					+ "job : " + jobDAO.getName() + " because of db access issue: ", ae);
359 5005 daigle
		} catch (UtilException ue) {
360
			throw new ServiceException("SchedulerService.reScheduleJob - Could not reschedule "
361 5013 daigle
					+ "job : " + jobDAO.getName() + " due to a utility issue: " + ue.getMessage());
362 4967 daigle
		}
363
364
		return "Resheduled: " + jobDAO.getName();
365
	}
366 5013 daigle
367
	/**
368
	 * Remove the job from the scheduler and set the job status to deleted in the database
369
	 * @param jobName
370
	 *            the string holding the name of the job to delete
371
	 * @param username
372
	 *            the user name
373
	 * @param groups
374
	 *            the user's group name
375
	 * @return a message saying that the job was deleted
376
	 */
377
	public String deleteJob(String jobName, String username,
378
			String[] groups) throws ServiceException {
379
380
		ScheduledJobDAO jobDAO = null;
381
		try {
382
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
383
			jobDAO = jobAccess.getJobByName(jobName);
384
		} catch (AccessException ae) {
385
			throw new ServiceException("SchedulerService.deleteJob - Could not delete "
386
					+ "scheduled job : " + jobDAO.getName() + " because of db access issue: ", ae);
387
		}
388
389
		return deleteJob(jobDAO, username, groups);
390
	}
391 4967 daigle
392 4971 daigle
	/**
393
	 * Remove the job from the scheduler and set the job status to deleted in the database
394
	 * @param jobDAO
395 5013 daigle
	 *            the job data object holding the information about the job to delete
396 4971 daigle
	 * @param username
397
	 *            the user name
398
	 * @param groups
399
	 *            the user's group name
400
	 * @return a message saying that the job was deleted
401
	 */
402 5013 daigle
	public String deleteJob(ScheduledJobDAO jobDAO, String username,
403 4967 daigle
			String[] groups) throws ServiceException {
404
405 4951 daigle
		String groupName = "";
406
		try {
407 4959 daigle
408 5013 daigle
			sched.deleteJob(jobDAO.getName(), groupName);
409 4967 daigle
410
			jobDAO.setStatus(StatusUtil.DELETED);
411 5013 daigle
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
412 4967 daigle
			jobAccess.updateJobStatus(jobDAO);
413 4951 daigle
		} catch (SchedulerException se) {
414 5013 daigle
			throw new ServiceException("SchedulerService.deleteJob - Could not delete job: " + jobDAO.getName()
415 4959 daigle
							+ " for group: " + groupName + " : " + se.getMessage());
416 4951 daigle
		} catch (AccessException ae) {
417
			throw new ServiceException("SchedulerService.deleteJob - Could not delete "
418 5013 daigle
					+ "scheduled job: " + jobDAO.getName() + " because of db access issue: ", ae);
419 4959 daigle
		}
420 4951 daigle
421 5013 daigle
		return "Deleted: " + jobDAO.getName();
422 4951 daigle
	}
423
424 4971 daigle
	/**
425
	 * Get information about the job in XML format
426
	 *
427
	 * @param jobId
428
	 *            the job for which we want the information
429
	 * @return an XML representation of the job
430
	 */
431 4959 daigle
	public String getJobInfoXML(Long jobId) throws ServiceException {
432
		String jobInfoXML = "";
433
434
		try {
435
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
436
			ScheduledJobDAO scheduledJobDAO = jobAccess.getJob(jobId);
437
438
			jobInfoXML +=
439
				"<scheduledJobs>" + jobToXML(scheduledJobDAO) + "</scheduledJobs>";
440
441
		} catch (AccessException ae) {
442
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get job info for job: "
443
					+ jobId, ae);
444
		}
445
446
		return jobInfoXML;
447
	}
448
449 4971 daigle
	/**
450
	 * Get the information for jobs in a group in an xml format. A parameter
451
	 * key/value pair can be provided as well to limit the jobs returned.
452
	 *
453
	 * @param groupName
454
	 *            the job group that we are searching for
455
	 * @param paramName
456
	 *            the parameter name that we are looking for. this is ignored if
457
	 *            null
458
	 * @param paramValue
459
	 *            the parameter value that we are looking for. this is ignored
460
	 *            if null
461
	 * @return an XML representation of the jobs.
462
	 */
463 4967 daigle
	public String getJobsInfoXML(String groupName, String paramName, String paramValue) throws ServiceException {
464 4959 daigle
		String jobInfoXML = "";
465
466
		try {
467
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
468 4967 daigle
			HashMap<Long, ScheduledJobDAO> JobDAOMap = jobAccess.getJobsWithParameter(groupName, paramName, paramValue);
469 4959 daigle
470 4967 daigle
			jobInfoXML += "<scheduledWorkflowResultset>";
471 4959 daigle
			for (Long jobDAOId : JobDAOMap.keySet()) {
472 4967 daigle
				ScheduledJobDAO jobDAO = JobDAOMap.get(jobDAOId);
473
				if (paramValue != null && paramName != null) {
474
					ScheduledJobParamDAO jobParamDAO = jobDAO.getJobParam(paramName);
475
					if(jobParamDAO != null && jobParamDAO.getValue().equals(paramValue)) {
476
						jobInfoXML +=  jobToXML(JobDAOMap.get(jobDAOId));
477
					}
478
				}
479 4959 daigle
			}
480 4967 daigle
			jobInfoXML += "</scheduledWorkflowResultset>";
481 4959 daigle
482
		} catch (AccessException ae) {
483
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get jobs info for group: "
484
					+ groupName, ae);
485
		}
486
487
		return jobInfoXML;
488
	}
489
490 4971 daigle
	/**
491
	 * Convert a single job to XML
492
	 * @param scheduledJobDAO the job we want to convert
493
	 * @return an XML representation of the job
494
	 */
495 4967 daigle
	public String jobToXML(ScheduledJobDAO scheduledJobDAO) throws ServiceException {
496 4959 daigle
		String jobXML = "";
497 4951 daigle
498 4959 daigle
		if (scheduledJobDAO != null) {
499
			jobXML += "<scheduledJob>";
500
			jobXML += "<id>" + scheduledJobDAO.getId() + "</id>";
501
			jobXML += "<createTime>" + scheduledJobDAO.getCreateTime() + "</createTime>";
502
			jobXML += "<modTime>" + scheduledJobDAO.getModTime() + "</modTime>";
503
			jobXML += "<status>" + scheduledJobDAO.getStatus() + "</status>";
504
			jobXML += "<name>" + scheduledJobDAO.getName() + "</name>";
505
			jobXML += "<triggerName>" + scheduledJobDAO.getName() + "</triggerName>";
506
			jobXML += "<groupName>" + scheduledJobDAO.getGroupName() + "</groupName>";
507 4967 daigle
			jobXML += "<className>" + scheduledJobDAO.getClassName() + "</className>";
508 5005 daigle
			String startTimeString = null;
509
			try {
510
				startTimeString =
511 5013 daigle
					DateUtil.getHumanReadable(scheduledJobDAO.getStartTime());
512 5005 daigle
			} catch (UtilException ue) {
513
				throw new ServiceException("SchedulerService.jobToXML - error getting human readable date for job: "
514
						+ scheduledJobDAO.getId() + " ; " + ue.getMessage());
515
			}
516 5013 daigle
			jobXML += "<startTime>" + startTimeString + "</startTime>";
517
518
			String endTimeString = null;
519
			try {
520
				if (scheduledJobDAO.getEndTime() != null) {
521
					endTimeString = DateUtil.getHumanReadable(scheduledJobDAO.getEndTime());
522
				}
523
			} catch (UtilException ue) {
524
				throw new ServiceException("SchedulerService.jobToXML - error getting human readable date for job: "
525
						+ scheduledJobDAO.getId() + " ; " + ue.getMessage());
526
			}
527
			jobXML += "<endTime>" + endTimeString + "</endTime>";
528
			jobXML += "<intervalValue>" + scheduledJobDAO.getIntervalValue() + "</intervalValue>";
529
			jobXML += "<intervalUnit>" + scheduledJobDAO.getIntervalUnit() + "</intervalUnit>";
530 4959 daigle
531
			HashMap<String, ScheduledJobParamDAO> jobParams = scheduledJobDAO
532
					.getAllJobParams();
533
			for (String jobParamKey : jobParams.keySet()) {
534 4967 daigle
				jobXML += "<jobParam name='" + jobParams.get(jobParamKey).getKey() + "'>";
535 4959 daigle
				jobXML += "<id>" + jobParams.get(jobParamKey).getId() + "</id>";
536
				jobXML += "<createTime>" + jobParams.get(jobParamKey).getCreateTime()
537
						+ "</createTime>";
538
				jobXML += "<modTime>" + jobParams.get(jobParamKey).getModTime()
539
						+ "</modTime>";
540
				jobXML += "<status>" + jobParams.get(jobParamKey).getStatus()
541
						+ "</status>";
542
				jobXML += "<jobId>" + jobParams.get(jobParamKey).getJobId() + "</jobId>";
543
				jobXML += "<key>" + jobParams.get(jobParamKey).getKey() + "</key>";
544
				jobXML += "<value>" + jobParams.get(jobParamKey).getValue() + "</value>";
545
				jobXML += "</jobParam>";
546
			}
547
			jobXML += "</scheduledJob>";
548
		}
549
550
		return jobXML;
551
	}
552
553 4971 daigle
	/**
554
	 * Start a job in the scheduler
555
	 *
556
	 * @param jobName
557
	 *            the name of the job
558
	 * @param startCal
559
	 *            a calendar holding the start date of the job
560
	 * @param intervalValue
561
	 *            the run interval for the job
562
	 * @param intervalUnit
563
	 *            the unit of the run interval for the job
564
	 * @param jobClassName
565
	 *            the job class name
566
	 * @param jobGroup
567
	 *            the job group name
568
	 * @param jobParams
569
	 *            a map of additional job parameters
570
	 * @param username
571
	 *            the user name
572
	 * @param groups
573
	 *            the user's group name
574
	 */
575 5012 daigle
	private void startJob(String jobName, Calendar startCal, Calendar endCal, int intervalValue, String intervalUnit,
576 4959 daigle
			Class<Job> jobClass, String jobGroup, HashMap<String, String> jobParams) throws ServiceException {
577
578
		JobDetail jobDetail = new JobDetail(jobName, jobGroup, jobClass);
579
		jobDetail.setJobDataMap(new JobDataMap(jobParams));
580
581 4967 daigle
		char intervalChar = intervalUnit.charAt(0);
582
583 4971 daigle
		// call the appropriate scheduling method depending on the schedule interval unit
584 4967 daigle
		switch (intervalChar) {
585 4959 daigle
		case 's':
586
		case 'S':
587 5012 daigle
			scheduleSecondlyJob(jobName, jobClass, startCal, endCal, intervalValue, jobGroup, jobDetail);
588 4959 daigle
			break;
589
		case 'm':
590
		case 'M':
591 5012 daigle
			scheduleMinutelyJob(jobName, jobClass, startCal, endCal, intervalValue, jobGroup, jobDetail);
592 4959 daigle
			break;
593
		case 'h':
594
		case 'H':
595 5012 daigle
			scheduleHourlyJob(jobName, jobClass, startCal, endCal, intervalValue, jobGroup, jobDetail);
596 4959 daigle
			break;
597
		case 'd':
598
		case 'D':
599 5012 daigle
			scheduleDailyJob(jobName, jobClass, startCal, endCal, intervalValue, jobGroup, jobDetail);
600 4959 daigle
			break;
601
		default:
602
			throw new ServiceException("SchedulerService.scheduleJob - Could not interpret interval unit: "
603
					+ intervalUnit + ". Unit must be s, m, h or d");
604
		}
605
	}
606
607 4971 daigle
	/**
608
	 * Schedule a job in the scheduler that has an interval based in seconds
609
	 *
610
	 * @param jobName
611
	 *            the name of the job
612
	 * @param jobClass
613
	 *            the job class object
614
	 * @param startTime
615
	 *            the time of the first run
616
	 * @param interval
617
	 *            the interval in seconds between runs
618
	 * @param jobGroup
619
	 *            the group of this job
620
	 * @param jobDetail
621
	 *            the job detail object
622
	 */
623 5012 daigle
	private void scheduleSecondlyJob(String jobName, Class<Job> jobClass, Calendar startTime, Calendar endTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
624 4959 daigle
625 4951 daigle
		Trigger trigger = TriggerUtils.makeSecondlyTrigger(interval);
626 4959 daigle
		trigger.setName(jobName);
627 4951 daigle
		trigger.setStartTime(startTime.getTime());
628 5012 daigle
		if (endTime != null) {
629
			trigger.setEndTime(endTime.getTime());
630
		}
631 4951 daigle
632
		try {
633
			sched.scheduleJob(jobDetail, trigger);
634
		} catch (SchedulerException se) {
635
			throw new ServiceException("SchedulerService.scheduleSecondlyJob - Could not create "
636
					+ "scheduler: " + se.getMessage());
637
		}
638
	}
639
640 4971 daigle
	/**
641
	 * Schedule a job in the scheduler that has an interval based in minutes
642
	 *
643
	 * @param jobName
644
	 *            the name of the job
645
	 * @param jobClass
646
	 *            the job class object
647
	 * @param startTime
648
	 *            the time of the first run
649
	 * @param interval
650
	 *            the interval in minutes between runs
651
	 * @param jobGroup
652
	 *            the group of this job
653
	 * @param jobDetail
654
	 *            the job detail object
655
	 */
656 5012 daigle
	private void scheduleMinutelyJob(String jobName, Class<Job> jobClass, Calendar startTime, Calendar endTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
657 4951 daigle
658
		Trigger trigger = TriggerUtils.makeMinutelyTrigger(interval);
659 4959 daigle
		trigger.setName(jobName);
660 4951 daigle
		trigger.setStartTime(startTime.getTime());
661 5012 daigle
		if (endTime != null) {
662
			trigger.setEndTime(endTime.getTime());
663
		}
664 4951 daigle
665
		try {
666
			sched.scheduleJob(jobDetail, trigger);
667
		} catch (SchedulerException se) {
668
			throw new ServiceException("SchedulerService.scheduleMinutelyJob - Could not create "
669
					+ "scheduler: " + se.getMessage());
670
		}
671
	}
672
673 4971 daigle
	/**
674
	 * Schedule a job in the scheduler that has an interval based in hours
675
	 *
676
	 * @param jobName
677
	 *            the name of the job
678
	 * @param jobClass
679
	 *            the job class object
680
	 * @param startTime
681
	 *            the time of the first run
682
	 * @param interval
683
	 *            the interval in hours between runs
684
	 * @param jobGroup
685
	 *            the group of this job
686
	 * @param jobDetail
687
	 *            the job detail object
688
	 */
689 5012 daigle
	private void scheduleHourlyJob(String jobName, Class<Job> jobClass, Calendar startTime, Calendar endTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
690 4951 daigle
691
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval);
692 4959 daigle
		trigger.setName(jobName);
693 4951 daigle
		trigger.setStartTime(startTime.getTime());
694 5012 daigle
		if (endTime != null) {
695
			trigger.setEndTime(endTime.getTime());
696
		}
697 4951 daigle
698
		try {
699
			sched.scheduleJob(jobDetail, trigger);
700
		} catch (SchedulerException se) {
701
			throw new ServiceException("SchedulerService.scheduleHourlyJob - Could not create "
702
					+  "scheduler: " + se.getMessage());
703
		}
704
	}
705
706 4971 daigle
	/**
707
	 * Schedule a job in the scheduler that has an interval based in days
708
	 *
709
	 * @param jobName
710
	 *            the name of the job
711
	 * @param jobClass
712
	 *            the job class object
713
	 * @param startTime
714
	 *            the time of the first run
715
	 * @param interval
716
	 *            the interval in days between runs
717
	 * @param jobGroup
718
	 *            the group of this job
719
	 * @param jobDetail
720
	 *            the job detail object
721
	 */
722 5012 daigle
	private void scheduleDailyJob(String jobName, Class<Job> jobClass, Calendar startTime, Calendar endTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
723 4951 daigle
724
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval * 24);
725 4959 daigle
		trigger.setName(jobName);
726 4951 daigle
		trigger.setStartTime(startTime.getTime());
727 5012 daigle
		if (endTime != null) {
728
			trigger.setEndTime(endTime.getTime());
729
		}
730 4951 daigle
731
		try {
732
			sched.scheduleJob(jobDetail, trigger);
733
		} catch (SchedulerException se) {
734
			throw new ServiceException("SchedulerService.scheduleHourlyJob - Could not create "
735
					+ "scheduler: " + se.getMessage());
736
		}
737
	}
738
739 4971 daigle
	/**
740
	 * Extract the start date from the delay value
741
	 *
742
	 * @param delay
743
	 *            a string representing the start delay in <value><unit>
744
	 *            notation where value is an integer and unit is one of s,m,h or
745
	 *            d
746
	 * @return the calendar object holding the start date
747
	 */
748 4959 daigle
	public Calendar getStartDateFromDelay(String delay) throws ServiceException {
749 4951 daigle
		Calendar cal = Calendar.getInstance();
750
751 4959 daigle
		char delayUnit = delay.trim().charAt(delay.length() - 1);
752 4951 daigle
		String delayStrValue = delay.trim().substring(0, delay.length() - 1);
753
		int delayValue;
754
		try {
755
			delayValue = Integer.parseInt(delayStrValue);
756
		} catch (NumberFormatException nfe) {
757
			throw new ServiceException("SchedulerService.getStartDateFromDelay - Could not "
758 4959 daigle
					+ "parse delay value into an integer: " + delayStrValue + " : " + nfe.getMessage());
759 4951 daigle
		}
760
761
		switch (delayUnit) {
762
		case 's':
763
		case 'S':
764
			cal.add(Calendar.SECOND, delayValue);
765
			break;
766
		case 'm':
767
		case 'M':
768
			cal.add(Calendar.MINUTE, delayValue);
769
			break;
770
		case 'h':
771
		case 'H':
772
			cal.add(Calendar.HOUR, delayValue);
773
			break;
774
		case 'd':
775
		case 'D':
776
			cal.add(Calendar.DAY_OF_YEAR, delayValue);
777
			break;
778
		default:
779
			throw new ServiceException("SchedulerService.getStartDateFromDelay - Could not "
780
					+ "interpret delay unit: " + delayUnit + ". Unit must be s, m, h or d");
781
		}
782
783
		return cal;
784 4971 daigle
	}
785 4951 daigle
}