Project

General

Profile

« Previous | Next » 

Revision 4959

Added by daigle about 15 years ago

Added generic scheduler and workflow scheduling functionality.

View differences:

SchedulerService.java
26 26

  
27 27
package edu.ucsb.nceas.metacat.scheduler;
28 28

  
29
import java.text.DateFormat;
30
import java.text.ParseException;
31 29
import java.util.Arrays;
32 30
import java.util.Calendar;
33
import java.util.Date;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
31
import java.util.HashMap;
36 32
import java.util.Vector;
37 33

  
38
import javax.servlet.http.HttpServletRequest;
39
import javax.servlet.http.HttpServletResponse;
40

  
41 34
import org.apache.log4j.Logger;
42 35

  
43 36
import org.quartz.Job;
37
import org.quartz.JobDataMap;
44 38
import org.quartz.JobDetail;
45 39
import org.quartz.Scheduler;
46 40
import org.quartz.SchedulerException;
......
51 45
import edu.ucsb.nceas.metacat.service.BaseService;
52 46
import edu.ucsb.nceas.metacat.service.ServiceException;
53 47
import edu.ucsb.nceas.shared.AccessException;
48
import edu.ucsb.nceas.utilities.StatusUtil;
54 49

  
55 50
public class SchedulerService extends BaseService {
56 51
	
......
59 54
	private static Logger logMetacat = Logger.getLogger(SchedulerService.class);
60 55
	
61 56
	private static Scheduler sched = null;
62
	
63
	static Hashtable<String, String> jobClassNames = new Hashtable<String, String>();
64
	static {
65
		jobClassNames.put("workflow", "edu.ucsb.nceas.metacat.workflow.WorkflowJob");
66
	}
67 57

  
68 58
	/**
69 59
	 * private constructor since this is a singleton
70 60
	 */
71
	private SchedulerService() throws ServiceException {}
61
	private SchedulerService() throws ServiceException {
62
		start();
63
	}
72 64
	
73 65
	/**
74 66
	 * Get the single instance of SchedulerService.
......
116 108
		return new Vector<String>();
117 109
	}
118 110
	
119
	public String scheduleHandler(Hashtable<String, String[]> params,
120
            HttpServletRequest request, HttpServletResponse response,
121
            String username, String[] groups) throws ServiceException {
111
	public String scheduleJob(String jobName, Calendar startCal, String interval,
112
			String jobClassName, String jobGroup, HashMap<String, String> jobParams) throws ServiceException {
122 113
        
123
		String returnString = "";
124
        String[] categories = params.get("category");
125
        if (categories == null || categories.length == 0) {
126
        	throw new ServiceException("SchedulerService.scheduleHandler - Category field " 
127
        			+ "must be populated in scheduler parameters");
128
        }
129
        
130
        String category = categories[0];
131
        
132
        if (category.equals("schedule")) {
133
    		Calendar startCal = null;
134
            Hashtable<String, String> jobParams = new Hashtable<String, String>();
135
        	
136
    		String jobTypes[] = params.get("type");
137
            if (jobTypes == null || jobTypes.length == 0) {
138
            	throw new ServiceException("SchedulerService.scheduleJob - Type field must be populated " 
139
            			+ "in scheduler parameters when scheduling job.");
140
            }
141
    		
142
            String delays[] = params.get("delay");
143
    		String startTimes[] = params.get("starttime");       
144
            try {
145
    			if (delays != null && delays.length > 0) {
146
    				startCal = getStartDateFromDelay(delays[0]);
147
    			} else if (startTimes != null && startTimes.length > 0) {
148
    				Date startDate = DateFormat.getInstance().parse(startTimes[0]);
149
    				startCal = Calendar.getInstance();
150
    				startCal.setTime(startDate);
151
    			} else {
152
    				throw new ServiceException("SchedulerService.scheduleJob -  Either delay or starttime  " 
153
    						+ "field must be populated in scheduler parameters when scheduling job.");
154
    			}
155
    		} catch (ParseException pe) {
156
    			throw new ServiceException("SchedulerService.scheduleJob - Could not parse start time " 
157
    					+ startTimes[0] + " : " + pe.getMessage());
158
    		}
159
            
160
            String intervals[] = params.get("interval"); 
161
            if (intervals == null || intervals.length == 0) {
162
            	throw new ServiceException("SchedulerService.scheduleJob - Interval field must be populated " 
163
            			+ "in scheduler parameters when scheduling job.");
164
            } 
165
            String interval = intervals[0];
166
            
167
            Enumeration<String> paramNames = params.keys();
168
            while (paramNames.hasMoreElements()) {
169
            	String paramName = paramNames.nextElement();
170
            	if (paramName.startsWith("jobparam_")) {
171
            		jobParams.put(paramName.substring(8), params.get(paramName)[0]);
172
            	}
173
            }
174
                   
175
            String jobType = jobTypes[0];
176
            String jobName = jobType + Calendar.getInstance().getTimeInMillis();
177
        	
178
        	returnString = scheduleJob(jobName, startCal, interval, jobType, jobParams);
179
        } else if (category.equals("unschedule")) {
180
        	String jobNames[] = params.get("jobName");
181
        	if (jobNames == null || jobNames.length == 0) {
182
        		throw new ServiceException("SchedulerService.scheduleJob - Job ID field must be populated " 
183
            			+ "in scheduler parameters when unscheduling job.");
184
        	}
185
        	        	
186
        	unscheduleJob(jobNames[0]);
187
        } else if (category.equals("delete")) {
188
//        	deleteJob(params);
189
        }
190
        
191
        return returnString;
192
	}
193
	
194
	public String scheduleJob(String jobName, Calendar startCal, String interval,
195
			String jobType, Hashtable<String, String> jobParams) throws ServiceException {
196

  
197 114
        Class<Job> jobClass = null;
198
       
199
        String className = jobClassNames.get(jobType);
200
        if (className == null) {
201
        	throw new ServiceException("SchedulerService.scheduleJob - Type: " + jobType 
202
        			+ " is not registered as a valid job type");
203
        }
204
        
205
        logMetacat.info("Scheduling job -- name: " + jobName + ", class: " + className 
206
        		+ ", start time: " + startCal.toString() + ", interval: " + interval);
207
       	 
208 115
        try {        	
209
        	jobClass = (Class<Job>)Class.forName(jobType + "Job");     	
116
        	jobClass = (Class<Job>)Class.forName(jobClassName);     	
210 117
        } catch (ClassNotFoundException cnfe) {
211 118
        	throw new ServiceException("SchedulerService.scheduleJob - Could not find class with name: " 
212
        			+ jobType + "Job");
213
        }    
119
        			+ jobClassName + " : " + cnfe.getMessage());
120
        } 
214 121
        
215
		char intervalUnit = interval.trim().charAt(interval.length());
122
        logMetacat.info("Scheduling job -- name: " + jobName + ", class: " + jobClassName 
123
        		+ ", start time: " + startCal.toString() + ", interval: " + interval);  
124
        
125
		char intervalUnit = interval.trim().charAt(interval.length() - 1);
216 126
		String intervalStrValue = interval.trim().substring(0, interval.length() - 1);
217 127
		int intervalValue;
218 128
		try {
219 129
			intervalValue = Integer.parseInt(intervalStrValue);
220 130
		} catch (NumberFormatException nfe) {
221 131
			throw new ServiceException("SchedulerService.scheduleJob - Could not parse interval value " 
222
					+ "into an integer: " + intervalStrValue);
132
					+ "into an integer: " + intervalStrValue + " : " + nfe.getMessage());
223 133
		}
224 134
		
225
		switch (intervalUnit) {
226
		case 's':
227
		case 'S':
228
			scheduleSecondlyJob(jobName, jobClass, startCal, intervalValue, jobType);
229
			break;
230
		case 'm':
231
		case 'M':
232
			scheduleMinutelyJob(jobName, jobClass, startCal, intervalValue, jobType);
233
			break;
234
		case 'h':
235
		case 'H':
236
			scheduleHourlyJob(jobName, jobClass, startCal, intervalValue, jobType);
237
			break;
238
		case 'd':
239
		case 'D':
240
			scheduleDailyJob(jobName, jobClass, startCal, intervalValue, jobType);
241
			break;
242
		default:
243
			throw new ServiceException("SchedulerService.scheduleJob - Could not interpret interval unit: " 
244
					+ intervalUnit + ". Unit must be s, m, h or d");	
245
		}	
135
		startJob(jobName, startCal, intervalValue, intervalUnit, jobClass, jobGroup, jobParams);
246 136
		
247 137
		try {
248 138
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
249
			jobAccess.createJob(jobName, jobClass, startCal, intervalValue, jobParams);
139
			jobAccess.createJob(jobName, jobName, jobGroup, jobClass, startCal, intervalValue, Character.toString(intervalUnit), jobParams);
250 140
		} catch (AccessException ae) {
251 141
			try {
252 142
				deleteJob(jobName);
253
			} catch (ServiceException se) {
143
			} catch (Exception e) {
254 144
				// Not much we can do here but log this
255 145
				logMetacat.error("An access exception was thrown when writing job: " + jobName 
256 146
						+ "to the db, and another exception was thrown when trying to remove the " 
257
						+ "job from the scheduler.  The db and scheduler may be out of sync");
147
						+ "job from the scheduler.  The db and scheduler may be out of sync: " + e.getMessage());
258 148
			}
259
			throw new ServiceException("SchedulerService.scheduleJob - Error accessing db: " 
260
					+ ae.getMessage());
149
			throw new ServiceException("SchedulerService.scheduleJob - Error accessing db: ", ae);
261 150
		}
262 151
		
263 152
		return jobName;
......
270 159

  
271 160
			sched.unscheduleJob(jobDAO.getName(), jobDAO.getGroupName());
272 161

  
273
			jobDAO.setStatus(ScheduledJobInterface.STATE_UNSHCEDULED);
162
			jobDAO.setStatus(StatusUtil.UNSHCEDULED);
274 163
			jobAccess.updateJobStatus(jobDAO);
275 164
		} catch (SchedulerException se) {
276 165
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
277 166
							+ "scheduled job because of service issue: " + se.getMessage());
278 167
		} catch (AccessException ae) {
279 168
			throw new ServiceException("SchedulerService.unscheduleJob - Could not create "
280
							+ "scheduled job because of db access issue: " + ae.getMessage());
169
							+ "scheduled job because of db access issue: ", ae);
281 170
		}
282 171
	}
283 172
	
284 173
	public void deleteJob(String jobName) throws ServiceException {
285 174
		String groupName = "";
286
		
175

  
287 176
		try {
288 177
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
289 178
			ScheduledJobDAO jobDAO = jobAccess.getJobByName(jobName);
290 179
			groupName = jobDAO.getGroupName();
291
			
180

  
292 181
			sched.deleteJob(jobName, groupName);
293 182
		} catch (SchedulerException se) {
294
			throw new ServiceException("SchedulerService.deleteJob - Could not delete job: " 
295
					+ jobName + " for group: " + groupName + " : " + se.getMessage());
183
			throw new ServiceException("SchedulerService.deleteJob - Could not delete job: " + jobName
184
							+ " for group: " + groupName + " : " + se.getMessage());
296 185
		} catch (AccessException ae) {
297 186
			throw new ServiceException("SchedulerService.deleteJob - Could not delete "
298
					+ "scheduled job because of db access issue: " + ae.getMessage());
299
}
187
					+ "scheduled job because of db access issue: ", ae);
188
		}
300 189
	}
301 190
	
302 191
	public Vector<String> getJobInfo(String groupName) throws ServiceException {
......
319 208
		return returnVector;
320 209
	}
321 210
	
322
	private void scheduleSecondlyJob(String name, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup) throws ServiceException {
323
		JobDetail jobDetail = new JobDetail(name, jobGroup, jobClass);
211
	public String getJobInfoXML(Long jobId) throws ServiceException {
212
		String jobInfoXML = "";
213
		
214
		try {
215
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
216
			ScheduledJobDAO scheduledJobDAO = jobAccess.getJob(jobId);
217
			
218
			jobInfoXML += 
219
				"<scheduledJobs>" + jobToXML(scheduledJobDAO) + "</scheduledJobs>";
220
			
221
		} catch (AccessException ae) {
222
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get job info for job: " 
223
					+ jobId, ae);
224
		}
225
		
226
		return jobInfoXML;
227
	}
228
	
229
	public String getJobsInfoXML(String groupName) throws ServiceException {
230
		String jobInfoXML = "";
231
		
232
		try {
233
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
234
			HashMap<Long, ScheduledJobDAO> JobDAOMap = jobAccess.getAllJobs(groupName);
235
			
236
			jobInfoXML += "<scheduledJobs>";
237
			for (Long jobDAOId : JobDAOMap.keySet()) {
238
				jobInfoXML +=  jobToXML(JobDAOMap.get(jobDAOId)); 
239
			}				
240
			jobInfoXML += "</scheduledJobs>";
241
			
242
		} catch (AccessException ae) {
243
			throw new ServiceException("SchedulerService.getJobInfoXML - Could not get jobs info for group: " 
244
					+ groupName, ae);
245
		}
246
		
247
		return jobInfoXML;
248
	}
249
	
250
	private String jobToXML(ScheduledJobDAO scheduledJobDAO) {
251
		String jobXML = "";
324 252

  
253
		if (scheduledJobDAO != null) {
254
			jobXML += "<scheduledJob>";
255
			jobXML += "<id>" + scheduledJobDAO.getId() + "</id>";
256
			jobXML += "<createTime>" + scheduledJobDAO.getCreateTime() + "</createTime>";
257
			jobXML += "<modTime>" + scheduledJobDAO.getModTime() + "</modTime>";
258
			jobXML += "<status>" + scheduledJobDAO.getStatus() + "</status>";
259
			jobXML += "<name>" + scheduledJobDAO.getName() + "</name>";
260
			jobXML += "<triggerName>" + scheduledJobDAO.getName() + "</triggerName>";
261
			jobXML += "<groupName>" + scheduledJobDAO.getGroupName() + "</groupName>";
262
			jobXML += "<className>" + scheduledJobDAO.getName() + "</className>";
263
			jobXML += "<startTime>" + scheduledJobDAO.getStartTime().toString()
264
					+ "</startTime>";
265
			jobXML += "<intervalValue>" + scheduledJobDAO.getIntervalValue()
266
					+ "</intervalValue>";
267
			jobXML += "<intervalUnit>" + scheduledJobDAO.getIntervalUnit()
268
					+ "</intervalUnit>";
269

  
270
			HashMap<String, ScheduledJobParamDAO> jobParams = scheduledJobDAO
271
					.getAllJobParams();
272
			for (String jobParamKey : jobParams.keySet()) {
273
				jobXML += "<jobParam>";
274
				jobXML += "<id>" + jobParams.get(jobParamKey).getId() + "</id>";
275
				jobXML += "<createTime>" + jobParams.get(jobParamKey).getCreateTime()
276
						+ "</createTime>";
277
				jobXML += "<modTime>" + jobParams.get(jobParamKey).getModTime()
278
						+ "</modTime>";
279
				jobXML += "<status>" + jobParams.get(jobParamKey).getStatus()
280
						+ "</status>";
281
				jobXML += "<jobId>" + jobParams.get(jobParamKey).getJobId() + "</jobId>";
282
				jobXML += "<key>" + jobParams.get(jobParamKey).getKey() + "</key>";
283
				jobXML += "<value>" + jobParams.get(jobParamKey).getValue() + "</value>";
284
				jobXML += "</jobParam>";
285
			}
286
			jobXML += "</scheduledJob>";
287
		}
288

  
289
		return jobXML;
290
	}
291
	
292
	
293
	private void startJob(String jobName, Calendar startCal, int intervalValue, char intervalUnit,
294
			Class<Job> jobClass, String jobGroup, HashMap<String, String> jobParams) throws ServiceException { 
295
		
296
		JobDetail jobDetail = new JobDetail(jobName, jobGroup, jobClass);
297
		jobDetail.setJobDataMap(new JobDataMap(jobParams));
298
		
299
		switch (intervalUnit) {
300
		case 's':
301
		case 'S':
302
			scheduleSecondlyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
303
			break;
304
		case 'm':
305
		case 'M':
306
			scheduleMinutelyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
307
			break;
308
		case 'h':
309
		case 'H':
310
			scheduleHourlyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
311
			break;
312
		case 'd':
313
		case 'D':
314
			scheduleDailyJob(jobName, jobClass, startCal, intervalValue, jobGroup, jobDetail);
315
			break;
316
		default:
317
			throw new ServiceException("SchedulerService.scheduleJob - Could not interpret interval unit: " 
318
					+ intervalUnit + ". Unit must be s, m, h or d");	
319
		}	
320
	}
321
	
322
	private void scheduleSecondlyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
323

  
325 324
		Trigger trigger = TriggerUtils.makeSecondlyTrigger(interval);
326
		trigger.setName(name);
325
		trigger.setName(jobName);
327 326
		trigger.setStartTime(startTime.getTime());
328 327

  
329 328
		try {
......
334 333
		}
335 334
	}
336 335
	
337
	private void scheduleMinutelyJob(String name, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup) throws ServiceException {
338
		JobDetail jobDetail = new JobDetail(name, jobGroup, jobClass);
336
	private void scheduleMinutelyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
339 337

  
340 338
		Trigger trigger = TriggerUtils.makeMinutelyTrigger(interval);
341
		trigger.setName(name);
339
		trigger.setName(jobName);
342 340
		trigger.setStartTime(startTime.getTime());
343 341

  
344 342
		try {
......
349 347
		}
350 348
	}
351 349
	
352
	private void scheduleHourlyJob(String name, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup) throws ServiceException {
353
		JobDetail jobDetail = new JobDetail(name, jobGroup, jobClass);
350
	private void scheduleHourlyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
354 351

  
355 352
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval);
356
		trigger.setName(name);
353
		trigger.setName(jobName);
357 354
		trigger.setStartTime(startTime.getTime());
358 355

  
359 356
		try {
......
364 361
		}
365 362
	}
366 363
	
367
	private void scheduleDailyJob(String name, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup) throws ServiceException {
364
	private void scheduleDailyJob(String jobName, Class<Job> jobClass, Calendar startTime, int interval, String jobGroup, JobDetail jobDetail) throws ServiceException {
368 365

  
369
		JobDetail jobDetail = new JobDetail(name, jobGroup, jobClass);
370

  
371 366
		Trigger trigger = TriggerUtils.makeHourlyTrigger(interval * 24);
372
		trigger.setName(name);
367
		trigger.setName(jobName);
373 368
		trigger.setStartTime(startTime.getTime());
374 369

  
375 370
		try {
......
382 377
	
383 378

  
384 379
	
385
	private Calendar getStartDateFromDelay(String delay) throws ServiceException {
380
	public Calendar getStartDateFromDelay(String delay) throws ServiceException {
386 381
		Calendar cal = Calendar.getInstance();
387 382
	
388
		char delayUnit = delay.trim().charAt(delay.length());
383
		char delayUnit = delay.trim().charAt(delay.length() - 1);
389 384
		String delayStrValue = delay.trim().substring(0, delay.length() - 1);
390 385
		int delayValue;
391 386
		try {
392 387
			delayValue = Integer.parseInt(delayStrValue);
393 388
		} catch (NumberFormatException nfe) {
394 389
			throw new ServiceException("SchedulerService.getStartDateFromDelay - Could not " 
395
					+ "parse delay value into an integer: " + delayStrValue);
390
					+ "parse delay value into an integer: " + delayStrValue + " : " + nfe.getMessage());
396 391
		}
397 392
		
398 393
		switch (delayUnit) {

Also available in: Unified diff