Project

General

Profile

1
/**
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
import java.util.HashMap;
31
import java.util.Vector;
32

    
33
import org.apache.log4j.Logger;
34

    
35
import org.quartz.Job;
36
import org.quartz.JobDataMap;
37
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
import edu.ucsb.nceas.metacat.service.BaseService;
45
import edu.ucsb.nceas.metacat.service.ServiceException;
46
import edu.ucsb.nceas.shared.AccessException;
47
import edu.ucsb.nceas.utilities.StatusUtil;
48

    
49
public class SchedulerService extends BaseService {
50
	
51
	private static SchedulerService schedulerService = null;
52
	
53
	private static Logger logMetacat = Logger.getLogger(SchedulerService.class);
54
	
55
	private static Scheduler sched = null;
56

    
57
	/**
58
	 * private constructor since this is a singleton
59
	 */
60
	private SchedulerService() throws ServiceException {
61
		start();
62
	}
63
	
64
	/**
65
	 * Get the single instance of SchedulerService.
66
	 * 
67
	 * @return the single instance of SchedulerService
68
	 */
69
	public static SchedulerService getInstance() throws ServiceException {
70
		if (schedulerService == null) {
71
			schedulerService = new SchedulerService();
72
		}
73
		return schedulerService;
74
	}
75
	
76
	// this is a refreshable class
77
	public boolean refreshable() {
78
		return true;
79
	}
80

    
81
	// do the refresh
82
	protected void doRefresh() throws ServiceException {
83
		stop();
84
		start();
85
	}
86

    
87
	// initialize the service
88
	protected void start() throws ServiceException {
89
		try {
90
			// get the Quartz scheduler factory
91
			SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
92
			
93
			// get the scheduler
94
			sched = schedFact.getScheduler();
95
			sched.start();
96
			
97
			// get all existing jobs from the database
98
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
99
			HashMap<Long, ScheduledJobDAO> allJobsMap = jobAccess.getAllJobs(null);
100
			
101
			// reschedule each job that is in a SCHEDULED state.  
102
			for (Long jobId : allJobsMap.keySet()) {
103
				ScheduledJobDAO jobDAO = allJobsMap.get(jobId);
104
				String[] groups = {"scheduler_group"};
105
				if (jobDAO.getStatus().equals(StatusUtil.SCHEDULED)) {
106
					// send false as the last param so the reschedule method will not 
107
					// complain that the job is already in a SCHEDULED state.
108
					rescheduleJob(jobDAO, "scheduler_user", groups, false);
109
				}
110
			}			
111
			
112
		} catch (AccessException ae) {
113
			throw new ServiceException("SchedulerService.start - DB Access issue when starting scheduler: ", ae);
114
		} catch (SchedulerException se) {
115
			throw new ServiceException("SchedulerService.start - Scheduler engine issue when starting scheduler: " + se.getMessage());
116
		}		
117
	}
118
	
119
	// Stop the scheduler
120
	protected void stop() throws ServiceException {
121
		try {
122
			sched.shutdown(true);
123
			sched = null;
124
		} catch (SchedulerException se) {
125
			throw new ServiceException("SchedulerService.stop - Could not shut down scheduler: " + se.getMessage());
126
		}		
127
	}
128
	
129
	// this will eventually return the scheduler status
130
	protected Vector<String> getStatus() throws ServiceException {
131
		return new Vector<String>();
132
	}
133
	
134
	/**
135
	 * Schedule a job
136
	 * 
137
	 * @param jobDAO
138
	 *            the job data object to schedule
139
	 * @param username
140
	 *            the user that we will use to schedule
141
	 * @param groups
142
	 *            the user group that we will use to schedule
143
	 * @return a message saying that the job was scheduled
144
	 */
145
	public String scheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups) throws ServiceException {
146
        
147
		// convert the start time to a calendar object
148
		Calendar startTimeCal = Calendar.getInstance();
149
        startTimeCal.setTime(jobDAO.getStartTime());
150
        
151
        // extract the job parameters from their data objects and put into a string map
152
        HashMap<String, String> jobParams = new HashMap<String, String>();
153
        HashMap<String, ScheduledJobParamDAO> jobParamDAOs = jobDAO.getAllJobParams();
154
        for (String paramName : jobParamDAOs.keySet()) {
155
        	jobParams.put(paramName, jobParamDAOs.get(paramName).getValue());   	
156
        }
157
        
158
        // schedule the job
159
		return scheduleJob(jobDAO.getName(), startTimeCal, jobDAO.getIntervalValue(), jobDAO.getIntervalUnit(),
160
				jobDAO.getClassName(), jobDAO.getGroupName(), jobParams, username, groups);
161
	}
162
	
163
	/**
164
	 * schedule a job
165
	 * 
166
	 * @param jobName
167
	 *            the name of the job
168
	 * @param startCal
169
	 *            a calendar holding the start date of the job
170
	 * @param intervalValue
171
	 *            the run interval for the job
172
	 * @param intervalUnit
173
	 *            the unit of the run interval for the job
174
	 * @param jobClassName
175
	 *            the job class name
176
	 * @param jobGroup
177
	 *            the job group name
178
	 * @param jobParams
179
	 *            a map of additional job parameters
180
	 * @param username
181
	 *            the user name
182
	 * @param groups
183
	 *            the user's group name
184
	 * @return a message saying that the job was scheduled
185
	 */
186
	public String scheduleJob(String jobName, Calendar startCal, int intervalValue, String intervalUnit,
187
			String jobClassName, String jobGroup, HashMap<String, String> jobParams, 
188
			String username, String[] groups) throws ServiceException {
189
        
190
        Class<Job> jobClass = null;
191
        try {        	
192
        	jobClass = (Class<Job>)Class.forName(jobClassName);     	
193
        } catch (ClassNotFoundException cnfe) {
194
        	throw new ServiceException("SchedulerService.scheduleJob - Could not find class with name: " 
195
        			+ jobClassName + " : " + cnfe.getMessage());
196
        } 
197
        
198
        logMetacat.info("SchedulerService.scheduleJob - Scheduling job -- name: " + jobName + ", class: " + jobClassName 
199
        		+ ", start time: " + startCal.toString() + ", interval value: " + intervalValue 
200
        		+ ", interval unit: " + intervalUnit);  
201
		
202
        // start the job in the job scheduler
203
		startJob(jobName, startCal, intervalValue, intervalUnit, jobClass, jobGroup, jobParams);
204
		
205
		// get a database access object and create the job in the database
206
		try {
207
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
208
			jobAccess.createJob(jobName, jobName, jobGroup, jobClass, startCal, intervalValue, intervalUnit, jobParams);
209
		} catch (AccessException ae) {
210
			try {
211
				deleteJob(jobName, username, groups);
212
			} catch (Exception e) {
213
				// Not much we can do here but log this
214
				logMetacat.error("SchedulerService.scheduleJob - An access exception was thrown when writing job: " + jobName 
215
						+ "to the db, and another exception was thrown when trying to remove the " 
216
						+ "job from the scheduler.  The db and scheduler may be out of sync: " + e.getMessage());
217
			}
218
			throw new ServiceException("SchedulerService.scheduleJob - Error accessing db: ", ae);
219
		}
220
		
221
		return "Scheduled: " + jobName;
222
	}
223
	
224
	/**
225
	 * Unschedule a job. This removed it from the scheduler in memory and
226
	 * changed it's status to unscheduled in the database.
227
	 * 
228
	 * @param jobName
229
	 *            the name of the job to unschedule
230
	 * @param username
231
	 *            the user name
232
	 * @param groups
233
	 *            the user's group name
234
	 * @return a message saying the job was unscheduled
235
	 */
236
	public String unScheduleJob(String jobName, String username,
237
			String[] groups) throws ServiceException {
238
		try {
239
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
240
			ScheduledJobDAO jobDAO = jobAccess.getJobByName(jobName);
241
			if (jobDAO == null) {
242
				throw new ServiceException("SchedulerService.unscheduleJob - Could " 
243
						+ "not find job with name: " + jobName);
244
			}
245

    
246
			// remove the job from the scheduler
247
			sched.deleteJob(jobDAO.getName(), jobDAO.getGroupName());
248

    
249
			// change the status of the job to unscheduled in the database.
250
			jobDAO.setStatus(StatusUtil.UNSCHEDULED);
251
			jobAccess.updateJobStatus(jobDAO);
252
		} catch (SchedulerException se) {
253
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
254
							+ "scheduled job because of service issue: " + se.getMessage());
255
		} catch (AccessException ae) {
256
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
257
							+ "scheduled job because of db access issue: ", ae);
258
		}
259
		
260
		return "Unscheduled: " + jobName;
261
	}
262
	
263
	/**
264
	 * Reschedule a job. This call will always check to make sure the status is not SCHEDULED
265
	 * @param jobDAO the job data object holding the information about the job to reschedule
266
	 * @param username
267
	 *            the user name
268
	 * @param groups
269
	 *            the user's group name
270
	 * @return a message saying that the job was rescheduled
271
	 */
272
	public String rescheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups) throws ServiceException {
273
		return rescheduleJob(jobDAO, username, groups, true);
274
	}
275
	
276
	/**
277
	 * Reschedule a job.
278
	 * 
279
	 * @param jobDAO
280
	 *            the job data object holding the information about the job to
281
	 *            reschedule
282
	 * @param username
283
	 *            the user name
284
	 * @param groups
285
	 *            the user's group name
286
	 * @param checkStatus
287
	 *            if set to true, the method will check to make sure the status
288
	 *            is UNSCHEDULED before restarting. Otherwise, the method will
289
	 *            not check. This is so that we can restart a service at startup
290
	 *            that was running when metacat was shut down.
291
	 * @return a message saying that the job was rescheduled
292
	 */
293
	public String rescheduleJob(ScheduledJobDAO jobDAO, String username, String[] groups, boolean checkStatus) throws ServiceException {
294
		
295
		try {
296
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
297
        
298
			if (jobDAO == null) {
299
				throw new ServiceException("SchedulerService.reScheduleJob - Cannot reschedule nonexistant job.");
300
			}
301
        
302
			// if we are checking status, make sure the job is in an UNSCHEDULED state in the db
303
			if (checkStatus && !jobDAO.getStatus().equals(StatusUtil.UNSCHEDULED)) {
304
				throw new ServiceException("SchedulerService.reScheduleJob - Cannot reschedule a job with status: " 
305
						+ jobDAO.getStatus() + ". Status must be 'unscheduled'.");
306
			}
307
        
308
			Calendar startCal = Calendar.getInstance();
309
	        startCal.setTime(jobDAO.getStartTime());
310
	        
311
	        HashMap<String, String> jobParams = new HashMap<String, String>();
312
	        HashMap<String, ScheduledJobParamDAO> jobParamDAOs = jobDAO.getAllJobParams();
313
	        for (String paramName : jobParamDAOs.keySet()) {
314
	        	jobParams.put(paramName, jobParamDAOs.get(paramName).getValue());   	
315
	        }
316
	        
317
	        Class<Job> jobClass = null;
318
	        String jobClassName = jobDAO.getClassName();
319
	        try {        	
320
	        	jobClass = (Class<Job>)Class.forName(jobClassName);     	
321
	        } catch (ClassNotFoundException cnfe) {
322
	        	throw new ServiceException("SchedulerService.scheduleJob - Could not find class with name: " 
323
	        			+ jobDAO.getClassName() + " : " + cnfe.getMessage());
324
	        } 
325
	        
326
	        logMetacat.info("SchedulerService.rescheduleJob - name: " + jobDAO.getName() + ", class: " + jobClassName 
327
	        		+ ", start time: " + startCal.toString() + ", interval value: " + jobDAO.getIntervalValue() 
328
	        		+ ", interval unit: " + jobDAO.getIntervalUnit());  
329
			
330
	        // start the job in the scheduler
331
			startJob(jobDAO.getName(), startCal, jobDAO.getIntervalValue(), jobDAO.getIntervalUnit(), jobClass, jobDAO.getGroupName(), jobParams);
332
	        
333
			// update the status in the database
334
			jobDAO.setStatus(StatusUtil.SCHEDULED);
335
			jobAccess.updateJobStatus(jobDAO);
336
			
337
		} catch (AccessException ae) {
338
			throw new ServiceException("SchedulerService.reScheduleJob - Could not reschedule "
339
					+ "job because of db access issue: ", ae);
340
		}
341
        		
342
		return "Resheduled: " + jobDAO.getName();
343
	}
344
	
345
	/**
346
	 * Remove the job from the scheduler and set the job status to deleted in the database
347
	 * @param jobDAO
348
	 *            the job data object holding the information about the job to
349
	 *            delete
350
	 * @param username
351
	 *            the user name
352
	 * @param groups
353
	 *            the user's group name
354
	 * @return a message saying that the job was deleted
355
	 */
356
	public String deleteJob(String jobName, String username,
357
			String[] groups) throws ServiceException {
358

    
359
		String groupName = "";
360
		try {
361
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
362
			ScheduledJobDAO jobDAO = jobAccess.getJobByName(jobName);
363
			groupName = jobDAO.getGroupName();
364

    
365
			sched.deleteJob(jobName, groupName);
366
			
367
			jobDAO.setStatus(StatusUtil.DELETED);
368
			jobAccess.updateJobStatus(jobDAO);
369
		} catch (SchedulerException se) {
370
			throw new ServiceException("SchedulerService.deleteJob - Could not delete job: " + jobName
371
							+ " for group: " + groupName + " : " + se.getMessage());
372
		} catch (AccessException ae) {
373
			throw new ServiceException("SchedulerService.deleteJob - Could not delete "
374
					+ "scheduled job because of db access issue: ", ae);
375
		}
376
		
377
		return "Deleted: " + jobName;
378
	}
379
	
380
	/**
381
	 * Get information about the job in XML format
382
	 * 
383
	 * @param jobId
384
	 *            the job for which we want the information
385
	 * @return an XML representation of the job
386
	 */
387
	public String getJobInfoXML(Long jobId) throws ServiceException {
388
		String jobInfoXML = "";
389
		
390
		try {
391
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
392
			ScheduledJobDAO scheduledJobDAO = jobAccess.getJob(jobId);
393
			
394
			jobInfoXML += 
395
				"<scheduledJobs>" + jobToXML(scheduledJobDAO) + "</scheduledJobs>";
396
			
397
		} catch (AccessException ae) {
398
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get job info for job: " 
399
					+ jobId, ae);
400
		}
401
		
402
		return jobInfoXML;
403
	}
404
	
405
	/**
406
	 * Get the information for jobs in a group in an xml format. A parameter
407
	 * key/value pair can be provided as well to limit the jobs returned.
408
	 * 
409
	 * @param groupName
410
	 *            the job group that we are searching for
411
	 * @param paramName
412
	 *            the parameter name that we are looking for. this is ignored if
413
	 *            null
414
	 * @param paramValue
415
	 *            the parameter value that we are looking for. this is ignored
416
	 *            if null
417
	 * @return an XML representation of the jobs.
418
	 */
419
	public String getJobsInfoXML(String groupName, String paramName, String paramValue) throws ServiceException {
420
		String jobInfoXML = "";
421
		
422
		try {
423
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
424
			HashMap<Long, ScheduledJobDAO> JobDAOMap = jobAccess.getJobsWithParameter(groupName, paramName, paramValue);
425
			
426
			jobInfoXML += "<scheduledWorkflowResultset>";
427
			for (Long jobDAOId : JobDAOMap.keySet()) {
428
				ScheduledJobDAO jobDAO = JobDAOMap.get(jobDAOId); 
429
				if (paramValue != null && paramName != null) {
430
					ScheduledJobParamDAO jobParamDAO = jobDAO.getJobParam(paramName);
431
					if(jobParamDAO != null && jobParamDAO.getValue().equals(paramValue)) {
432
						jobInfoXML +=  jobToXML(JobDAOMap.get(jobDAOId)); 
433
					}
434
				}
435
			}				
436
			jobInfoXML += "</scheduledWorkflowResultset>";
437
			
438
		} catch (AccessException ae) {
439
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get jobs info for group: " 
440
					+ groupName, ae);
441
		}
442
		
443
		return jobInfoXML;
444
	}
445
	
446
	/**
447
	 * Convert a single job to XML
448
	 * @param scheduledJobDAO the job we want to convert
449
	 * @return an XML representation of the job
450
	 */
451
	public String jobToXML(ScheduledJobDAO scheduledJobDAO) throws ServiceException {
452
		String jobXML = "";
453

    
454
		if (scheduledJobDAO != null) {
455
			jobXML += "<scheduledJob>";
456
			jobXML += "<id>" + scheduledJobDAO.getId() + "</id>";
457
			jobXML += "<createTime>" + scheduledJobDAO.getCreateTime() + "</createTime>";
458
			jobXML += "<modTime>" + scheduledJobDAO.getModTime() + "</modTime>";
459
			jobXML += "<status>" + scheduledJobDAO.getStatus() + "</status>";
460
			jobXML += "<name>" + scheduledJobDAO.getName() + "</name>";
461
			jobXML += "<triggerName>" + scheduledJobDAO.getName() + "</triggerName>";
462
			jobXML += "<groupName>" + scheduledJobDAO.getGroupName() + "</groupName>";
463
			jobXML += "<className>" + scheduledJobDAO.getClassName() + "</className>";
464
			jobXML += "<startTime>" + scheduledJobDAO.getStartTime().toString()
465
					+ "</startTime>";
466
			jobXML += "<intervalValue>" + scheduledJobDAO.getIntervalValue()
467
					+ "</intervalValue>";
468
			jobXML += "<intervalUnit>" + scheduledJobDAO.getIntervalUnit()
469
					+ "</intervalUnit>";
470

    
471
			HashMap<String, ScheduledJobParamDAO> jobParams = scheduledJobDAO
472
					.getAllJobParams();
473
			for (String jobParamKey : jobParams.keySet()) {
474
				jobXML += "<jobParam name='" + jobParams.get(jobParamKey).getKey() + "'>";
475
				jobXML += "<id>" + jobParams.get(jobParamKey).getId() + "</id>";
476
				jobXML += "<createTime>" + jobParams.get(jobParamKey).getCreateTime()
477
						+ "</createTime>";
478
				jobXML += "<modTime>" + jobParams.get(jobParamKey).getModTime()
479
						+ "</modTime>";
480
				jobXML += "<status>" + jobParams.get(jobParamKey).getStatus()
481
						+ "</status>";
482
				jobXML += "<jobId>" + jobParams.get(jobParamKey).getJobId() + "</jobId>";
483
				jobXML += "<key>" + jobParams.get(jobParamKey).getKey() + "</key>";
484
				jobXML += "<value>" + jobParams.get(jobParamKey).getValue() + "</value>";
485
				jobXML += "</jobParam>";
486
			}
487
			jobXML += "</scheduledJob>";
488
		}
489

    
490
		return jobXML;
491
	}
492
	
493
	/**
494
	 * Start a job in the scheduler
495
	 * 
496
	 * @param jobName
497
	 *            the name of the job
498
	 * @param startCal
499
	 *            a calendar holding the start date of the job
500
	 * @param intervalValue
501
	 *            the run interval for the job
502
	 * @param intervalUnit
503
	 *            the unit of the run interval for the job
504
	 * @param jobClassName
505
	 *            the job class name
506
	 * @param jobGroup
507
	 *            the job group name
508
	 * @param jobParams
509
	 *            a map of additional job parameters
510
	 * @param username
511
	 *            the user name
512
	 * @param groups
513
	 *            the user's group name
514
	 */
515
	private void startJob(String jobName, Calendar startCal, int intervalValue, String intervalUnit,
516
			Class<Job> jobClass, String jobGroup, HashMap<String, String> jobParams) throws ServiceException { 
517
		
518
		JobDetail jobDetail = new JobDetail(jobName, jobGroup, jobClass);
519
		jobDetail.setJobDataMap(new JobDataMap(jobParams));
520
		
521
		char intervalChar = intervalUnit.charAt(0);
522
		
523
		// call the appropriate scheduling method depending on the schedule interval unit
524
		switch (intervalChar) {
525
		case 's':
526
		case 'S':
527
			scheduleSecondlyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
528
			break;
529
		case 'm':
530
		case 'M':
531
			scheduleMinutelyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
532
			break;
533
		case 'h':
534
		case 'H':
535
			scheduleHourlyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
536
			break;
537
		case 'd':
538
		case 'D':
539
			scheduleDailyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
540
			break;
541
		default:
542
			throw new ServiceException("SchedulerService.scheduleJob - Could not interpret interval unit: " 
543
					+ intervalUnit + ". Unit must be s, m, h or d");	
544
		}	
545
	}
546
	
547
	/**
548
	 * Schedule a job in the scheduler that has an interval based in seconds
549
	 * 
550
	 * @param jobName
551
	 *            the name of the job
552
	 * @param jobClass
553
	 *            the job class object
554
	 * @param startTime
555
	 *            the time of the first run
556
	 * @param interval
557
	 *            the interval in seconds between runs
558
	 * @param jobGroup
559
	 *            the group of this job
560
	 * @param jobDetail
561
	 *            the job detail object
562
	 */
563
	private void scheduleSecondlyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
564

    
565
		Trigger trigger = TriggerUtils.makeSecondlyTrigger(interval);
566
		trigger.setName(jobName);
567
		trigger.setStartTime(startTime.getTime());
568

    
569
		try {
570
			sched.scheduleJob(jobDetail, trigger);
571
		} catch (SchedulerException se) {
572
			throw new ServiceException("SchedulerService.scheduleSecondlyJob - Could not create " 
573
					+ "scheduler: " + se.getMessage());
574
		}
575
	}
576
	
577
	/**
578
	 * Schedule a job in the scheduler that has an interval based in minutes
579
	 * 
580
	 * @param jobName
581
	 *            the name of the job
582
	 * @param jobClass
583
	 *            the job class object
584
	 * @param startTime
585
	 *            the time of the first run
586
	 * @param interval
587
	 *            the interval in minutes between runs
588
	 * @param jobGroup
589
	 *            the group of this job
590
	 * @param jobDetail
591
	 *            the job detail object
592
	 */
593
	private void scheduleMinutelyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
594

    
595
		Trigger trigger = TriggerUtils.makeMinutelyTrigger(interval);
596
		trigger.setName(jobName);
597
		trigger.setStartTime(startTime.getTime());
598

    
599
		try {
600
			sched.scheduleJob(jobDetail, trigger);
601
		} catch (SchedulerException se) {
602
			throw new ServiceException("SchedulerService.scheduleMinutelyJob - Could not create " 
603
					+ "scheduler: " + se.getMessage());
604
		}
605
	}
606
	
607
	/**
608
	 * Schedule a job in the scheduler that has an interval based in hours
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 hours between runs
618
	 * @param jobGroup
619
	 *            the group of this job
620
	 * @param jobDetail
621
	 *            the job detail object
622
	 */
623
	private void scheduleHourlyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
624

    
625
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval);
626
		trigger.setName(jobName);
627
		trigger.setStartTime(startTime.getTime());
628

    
629
		try {
630
			sched.scheduleJob(jobDetail, trigger);
631
		} catch (SchedulerException se) {
632
			throw new ServiceException("SchedulerService.scheduleHourlyJob - Could not create " 
633
					+  "scheduler: " + se.getMessage());
634
		}
635
	}
636
	
637
	/**
638
	 * Schedule a job in the scheduler that has an interval based in days
639
	 * 
640
	 * @param jobName
641
	 *            the name of the job
642
	 * @param jobClass
643
	 *            the job class object
644
	 * @param startTime
645
	 *            the time of the first run
646
	 * @param interval
647
	 *            the interval in days between runs
648
	 * @param jobGroup
649
	 *            the group of this job
650
	 * @param jobDetail
651
	 *            the job detail object
652
	 */
653
	private void scheduleDailyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
654

    
655
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval * 24);
656
		trigger.setName(jobName);
657
		trigger.setStartTime(startTime.getTime());
658

    
659
		try {
660
			sched.scheduleJob(jobDetail, trigger);
661
		} catch (SchedulerException se) {
662
			throw new ServiceException("SchedulerService.scheduleHourlyJob - Could not create " 
663
					+ "scheduler: " + se.getMessage());
664
		}
665
	}
666
	
667
	/**
668
	 * Extract the start date from the delay value
669
	 * 
670
	 * @param delay
671
	 *            a string representing the start delay in <value><unit>
672
	 *            notation where value is an integer and unit is one of s,m,h or
673
	 *            d
674
	 * @return the calendar object holding the start date
675
	 */
676
	public Calendar getStartDateFromDelay(String delay) throws ServiceException {
677
		Calendar cal = Calendar.getInstance();
678
	
679
		char delayUnit = delay.trim().charAt(delay.length() - 1);
680
		String delayStrValue = delay.trim().substring(0, delay.length() - 1);
681
		int delayValue;
682
		try {
683
			delayValue = Integer.parseInt(delayStrValue);
684
		} catch (NumberFormatException nfe) {
685
			throw new ServiceException("SchedulerService.getStartDateFromDelay - Could not " 
686
					+ "parse delay value into an integer: " + delayStrValue + " : " + nfe.getMessage());
687
		}
688
		
689
		switch (delayUnit) {
690
		case 's':
691
		case 'S':
692
			cal.add(Calendar.SECOND, delayValue);
693
			break;
694
		case 'm':
695
		case 'M':
696
			cal.add(Calendar.MINUTE, delayValue);
697
			break;
698
		case 'h':
699
		case 'H':
700
			cal.add(Calendar.HOUR, delayValue);
701
			break;
702
		case 'd':
703
		case 'D':
704
			cal.add(Calendar.DAY_OF_YEAR, delayValue);
705
			break;
706
		default:
707
			throw new ServiceException("SchedulerService.getStartDateFromDelay - Could not " 
708
					+ "interpret delay unit: " + delayUnit + ". Unit must be s, m, h or d");	
709
		}
710
		
711
		return cal;
712
	}	
713
}
(7-7/8)