Project

General

Profile

1 5039 daigle
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that handles scheduling workflow jobs
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.workflowscheduler;
28
29
import java.io.IOException;
30
import java.io.PrintWriter;
31 5057 daigle
import java.io.StringReader;
32 5039 daigle
import java.util.Calendar;
33
import java.util.Hashtable;
34
import java.util.HashMap;
35
36
import javax.servlet.http.HttpServletRequest;
37
import javax.servlet.http.HttpServletResponse;
38 5057 daigle
import javax.xml.xpath.XPath;
39
import javax.xml.xpath.XPathFactory;
40 5039 daigle
41
import org.apache.log4j.Logger;
42
43 5057 daigle
import org.xml.sax.InputSource;
44
45
import org.ecoinformatics.ecogrid.client.AuthenticationServiceClient;
46
47 5039 daigle
import edu.ucsb.nceas.metacat.scheduler.BaseScheduler;
48
import edu.ucsb.nceas.metacat.scheduler.ScheduledJobAccess;
49
import edu.ucsb.nceas.metacat.scheduler.ScheduledJobDAO;
50
import edu.ucsb.nceas.metacat.scheduler.SchedulerService;
51
import edu.ucsb.nceas.metacat.scheduler.MetacatSchedulerException;
52 5057 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
53 5039 daigle
import edu.ucsb.nceas.metacat.shared.AccessException;
54
import edu.ucsb.nceas.metacat.shared.ServiceException;
55
import edu.ucsb.nceas.metacat.util.ErrorSendingErrorException;
56
import edu.ucsb.nceas.metacat.util.ResponseUtil;
57
import edu.ucsb.nceas.utilities.DateUtil;
58 5057 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
59 5039 daigle
import edu.ucsb.nceas.utilities.UtilException;
60
61
/**
62
 * @author daigle
63
 *
64
 */
65
public class WorkflowScheduler extends BaseScheduler {
66
67
	private static WorkflowScheduler workflowScheduler = null;
68
69
	private static Logger logMetacat = Logger.getLogger(WorkflowScheduler.class);
70
71
	private static String WORKFLOW_JOB_GROUP = "workflow";
72
	private static String WORKFLOW_JOB_CLASS = "edu.ucsb.nceas.workflowscheduler.WorkflowJob";
73
74
	/**
75
	 * private constructor since this is a singleton
76
	 */
77
	private WorkflowScheduler()  {}
78
79
	/**
80
	 * Get the single instance of SchedulerService.
81
	 *
82
	 * @return the single instance of SchedulerService
83
	 */
84
	public static WorkflowScheduler getInstance() {
85
		if (workflowScheduler == null) {
86
			workflowScheduler = new WorkflowScheduler();
87
		}
88
		return workflowScheduler;
89
	}
90
91
	/**
92
	 * Scheduling a workflow
93
	 *
94
	 * @param request
95
	 *            the servlet request object
96
	 * @param response
97
	 *            the servlet response object
98
	 * @param params
99
	 *            the request parameters
100
	 * @param username
101
	 *            the user
102
	 * @param groups
103
	 *            the user's group
104
	 */
105
	public void scheduleJob(HttpServletRequest request, HttpServletResponse response,
106 5057 daigle
			Hashtable<String, String[]> params) throws MetacatSchedulerException {
107
108
		String sessionIds[] = params.get("sessionid");
109 5039 daigle
		String delays[] = params.get("delay");
110
		String startTimes[] = params.get("starttime");
111
		String endTimes[] = params.get("endtime");
112
		HashMap<String, String> jobParams = new HashMap<String, String>();
113
		Calendar startCal = null;
114
		Calendar endCal = null;
115 5057 daigle
116
		if (sessionIds == null) {
117
			throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - sessionid field must be populated "
118
							+ "in scheduler parameters when scheduling job.");
119
		}
120
121
		String sessionStatus = validateRemoteSession(sessionIds[0]);
122
		logMetacat.debug("WorkflowScheduler.scheduleJob - session status: " + sessionStatus);
123
124
		if (!sessionStatus.equals("valid")) {
125
			throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - session "
126 5072 daigle
					+ request.getSession().getId() + " is not valid.");
127 5057 daigle
		}
128
129 5039 daigle
		try {
130
			SchedulerService schedulerService = SchedulerService.getInstance();
131
132
			// get start time or delay.  Start time takes precedence if both exist.
133
			if (startTimes != null && startTimes.length > 0) {
134
				startCal = DateUtil.humanReadableToCalendar(startTimes[0], "MM/dd/yyyy HH:mm:ss");
135
			} else if (delays != null && delays.length > 0) {
136
				startCal = schedulerService.getStartDateFromDelay(delays[0]);
137
			} else {
138
				// if delay and starttime were not provided, set date to now.
139
				startCal = Calendar.getInstance();
140
			}
141
142
			// get end time.  null is fine.
143
			if (endTimes != null && endTimes.length > 0) {
144
				endCal = DateUtil.humanReadableToCalendar(endTimes[0], "MM/dd/yyyy HH:mm:ss");
145
			}
146
147
			// interval value must exist
148
			String intervalValues[] = params.get("intervalvalue");
149
			if (intervalValues == null || intervalValues.length == 0) {
150
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - intervalvalue field must be populated "
151
								+ "in scheduler parameters when scheduling job.");
152
			}
153
			String intervalStrValue = intervalValues[0];
154
			int intervalValue = Integer.parseInt(intervalStrValue);
155
156
			// interval unit must exist
157
			String intervalUnits[] = params.get("intervalunit");
158
			if (intervalUnits == null || intervalUnits.length == 0) {
159
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - intervalunit field must be populated "
160
								+ "in scheduler parameters when scheduling job.");
161
			}
162
			String intervalUnit = intervalUnits[0];
163
164
			// workflow id must exist.  Add to job params
165
			String workflowids[] = params.get("workflowid");
166
			if (workflowids == null || workflowids.length == 0) {
167
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - workflowid field must be populated "
168
								+ "in scheduler parameters when scheduling job.");
169
			}
170
			jobParams.put("workflowid", workflowids[0]);
171
172
			// kar id must exist.  Add to job params
173
			String karids[] = params.get("karid");
174
			if (karids == null || karids.length == 0) {
175
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - karid field must be populated "
176
								+ "in scheduler parameters when scheduling job.");
177
			}
178
			jobParams.put("karid", karids[0]);
179
180
181
			// workflow name unit must exist.  Add to job params
182
			String workflownames[] = params.get("workflowname");
183
			if (workflownames == null || workflownames.length == 0) {
184
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - workflowname field must be populated "
185
								+ "in scheduler parameters when scheduling job.");
186
			}
187
			jobParams.put("workflowname", workflownames[0]);
188
189
			String jobName = WORKFLOW_JOB_GROUP
190
					+ Calendar.getInstance().getTimeInMillis();
191
192
			// Schedule the job
193
			String xmlResult = schedulerService.scheduleJob(jobName, startCal, endCal, intervalValue, intervalUnit,
194 5057 daigle
					WORKFLOW_JOB_CLASS, WORKFLOW_JOB_GROUP, jobParams);
195 5039 daigle
196
			ResponseUtil.sendSuccessXML(response, xmlResult);
197
198
		} catch (UtilException ue) {
199
			throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - "
200
					+ "Utility issue when scheduling job: " + ue.getMessage());
201
		} catch (ServiceException se) {
202
			throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - "
203
					+ "Service issue when scheduling job", se);
204
		} catch (ErrorSendingErrorException esee) {
205
			throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - "
206
					+ "Issue sending error when scheduling job: " + esee.getMessage());
207
		}
208
	}
209
210
	/**
211
	 * Unschedule a job
212
	 *
213
	 * @param request
214
	 *            the servlet request object
215
	 * @param response
216
	 *            the servlet response object
217
	 * @param params
218
	 *            the request parameters
219
	 * @param username
220
	 *            the user
221
	 * @param groups
222
	 *            the user's group
223
	 */
224 5044 daigle
	public void unscheduleJob(HttpServletRequest request, HttpServletResponse response,
225 5039 daigle
			Hashtable<String, String[]> params, String username, String[] groups)
226
			throws MetacatSchedulerException {
227
		try {
228 5057 daigle
			String sessionIds[] = params.get("sessionid");
229
230
			// interval value must exist
231
			if (sessionIds == null || sessionIds.length == 0) {
232
				throw new MetacatSchedulerException("WorkflowScheduler.unscheduleJob - sessionid field must be populated "
233
								+ "in scheduler parameters when unscheduling job.");
234
			}
235
236
			String sessionStatus = validateRemoteSession(sessionIds[0]);
237
			logMetacat.debug("WorkflowScheduler.unscheduleJob - session status: " + sessionStatus);
238
239
			if (!sessionStatus.equals("valid")) {
240
				throw new MetacatSchedulerException("WorkflowScheduler.unscheduleJob - session "
241
						+ sessionIds[0] + " is not valid.");
242
			}
243
244 5039 daigle
			// workflow job id must exist
245 5044 daigle
			String jobNames[] = params.get("workflowjobname");
246 5039 daigle
			if (jobNames == null || jobNames.length == 0) {
247 5044 daigle
				throw new MetacatSchedulerException("SchedulerService.unScheduleJob - workflowjobname "
248 5039 daigle
						+ "field must be populated in scheduler parameters when unscheduling job.");
249
			}
250
			String jobName = jobNames[0];
251
252
			// unschedule the job
253
			SchedulerService schedulerService = SchedulerService.getInstance();
254 5044 daigle
			String xmlResult = schedulerService.unscheduleJob(jobName, username, groups);
255 5039 daigle
256
			ResponseUtil.sendSuccessXML(response, xmlResult);
257
258
		} catch (ServiceException se) {
259
			throw new MetacatSchedulerException("WorkflowScheduler.unScheduleJob - "
260
					+ "Service issue unscheduling job", se);
261
		} catch (Exception e) {
262
			throw new MetacatSchedulerException("WorkflowScheduler.unScheduleJob - "
263
					+ "Generic issue unscheduling job: " + e.getMessage());
264
		}
265
	}
266
267
	/**
268
	 * reschedule job
269
	 *
270
	 * @param request
271
	 *            the servlet request object
272
	 * @param response
273
	 *            the servlet response object
274
	 * @param params
275
	 *            the request parameters
276
	 * @param username
277
	 *            the user
278
	 * @param groups
279
	 *            the user's group
280
	 */
281 5044 daigle
	public void rescheduleJob(HttpServletRequest request, HttpServletResponse response,
282 5039 daigle
			Hashtable<String, String[]> params, String username,
283
			String[] groups) throws MetacatSchedulerException {
284
285
		try {
286 5057 daigle
			String sessionIds[] = params.get("sessionid");
287
288
			// interval value must exist
289
			if (sessionIds == null || sessionIds.length == 0) {
290
				throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - sessionid field must be populated "
291
								+ "in scheduler parameters when rescheduling job.");
292
			}
293
294
			String sessionStatus = validateRemoteSession(sessionIds[0]);
295
296
			logMetacat.debug("WorkflowScheduler.rescheduleJob - session status: " + sessionStatus);
297
298
			if (!sessionStatus.equals("valid")) {
299
				throw new MetacatSchedulerException("WorkflowScheduler.scheduleJob - session "
300
						+ sessionIds[0] + " is not valid.");
301
			}
302
303 5039 daigle
			// workflow job id must exist
304 5044 daigle
			String jobNames[] = params.get("workflowjobname");
305 5039 daigle
			if (jobNames == null || jobNames.length == 0) {
306 5057 daigle
				throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - workflowjobname field must be populated "
307 5039 daigle
						+ "in scheduler parameters when rescheduling job.");
308
			}
309
			String jobName = jobNames[0];
310
311
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
312
			ScheduledJobDAO jobDAO = jobAccess.getJobByName(jobName);
313
314
			// reschedule the job
315
			SchedulerService schedulerService = SchedulerService.getInstance();
316
			String result = schedulerService.rescheduleJob(jobDAO, username, groups);
317
318
			ResponseUtil.sendSuccessXML(response, result);
319
320
		} catch (AccessException ae) {
321 5057 daigle
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - "
322
					+ "DB access issue when rescheduling job  : ", ae);
323 5039 daigle
		} catch (ServiceException se) {
324 5057 daigle
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - "
325
					+ "Service issue rescheduling job", se);
326 5039 daigle
		} catch (ErrorSendingErrorException esee) {
327 5057 daigle
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - "
328
					+ "Issue sending erro when rescheduling job: " + esee.getMessage());
329 5039 daigle
		}
330
	}
331
332
	/**
333
	 * delete job - to be implemented
334
	 */
335
	public void deleteJob(HttpServletRequest request, HttpServletResponse response,
336
			Hashtable<String, String[]> params, String username, String[] groups) throws MetacatSchedulerException {
337
		 try {
338 5057 daigle
			String sessionIds[] = params.get("sessionid");
339
340
			// interval value must exist
341
			if (sessionIds == null || sessionIds.length == 0) {
342
				throw new MetacatSchedulerException("WorkflowScheduler.deleteJob - sessionid field must be populated "
343
								+ "in scheduler parameters when deleting job.");
344
			}
345
346
			String sessionStatus = validateRemoteSession(sessionIds[0]);
347
			logMetacat.debug("WorkflowScheduler.rescheduleJob - session status: " + sessionStatus);
348
349
			if (!sessionStatus.equals("valid")) {
350
				throw new MetacatSchedulerException("WorkflowScheduler.deleteJob - session "
351
						+ sessionIds[0] + " is not valid.");
352
			}
353
354 5039 daigle
			// workflow job id must exist
355 5044 daigle
			String jobNames[] = params.get("workflowjobname");
356 5039 daigle
			if (jobNames == null || jobNames.length == 0) {
357
				throw new MetacatSchedulerException(
358
						"WorkflowScheduler.deleteJob - workflowname field must be populated "
359
								+ "in scheduler parameters when deleting job.");
360
			}
361
			String jobName = jobNames[0];
362
363
			ScheduledJobAccess jobAccess = new ScheduledJobAccess();
364
			ScheduledJobDAO jobDAO = jobAccess.getJobByName(jobName);
365
366
			// delete the job
367
			SchedulerService schedulerService = SchedulerService.getInstance();
368 5057 daigle
			String result = schedulerService.deleteJob(jobDAO);
369 5039 daigle
370
			ResponseUtil.sendSuccessXML(response, result);
371
372
		} catch (AccessException ae) {
373
			throw new MetacatSchedulerException("WorkflowScheduler.deleteJob - "
374
					+ "DB access issue when deleting job  : ", ae);
375
		} catch (ServiceException se) {
376
			throw new MetacatSchedulerException("WorkflowScheduler.deleteJob - "
377
					+ "Service issue deleting job", se);
378
		} catch (ErrorSendingErrorException esee) {
379
			throw new MetacatSchedulerException("WorkflowScheduler.deleteJob - "
380
					+ "Issue sending erro when deleting job: " + esee.getMessage());
381
		}
382
	}
383
384
	/**
385
	 * get job information for a given workflow in xml format
386
	 *
387
	 * @param request
388
	 *            the servlet request object
389
	 * @param response
390
	 *            the servlet response object
391
	 * @param params
392
	 *            the request parameters
393
	 * @param username
394
	 *            the user
395
	 * @param groups
396
	 *            the user's group
397
	 */
398
	public void getJobs(HttpServletRequest request, HttpServletResponse response,
399
			Hashtable<String, String[]> params, String username, String[] groups) throws MetacatSchedulerException {
400
401
		String workflowId = null;
402
403
		String workflowIds[] = params.get("workflowid");
404
		if (workflowIds != null && workflowIds.length != 0) {
405
			workflowId = workflowIds[0];
406
		}
407
408
		logMetacat.debug("WorkflowScheduler.getJobs - getting jobs for workflow:" + workflowId);
409
410
        PrintWriter out = null;
411
		try {
412
			// get the job info in xml format
413
			out = response.getWriter();
414
			SchedulerService.getInstance().getJobsInfoXML(WORKFLOW_JOB_GROUP,
415
					"workflowid", workflowId, out);
416
		} catch (ServiceException se) {
417
			throw new MetacatSchedulerException("WorkflowScheduler.getJobs - "
418
					+ "Service error when transforming XML for workflow id: "
419
					+ workflowId + " : " + se.getMessage());
420
		} catch (IOException ioe) {
421
			throw new MetacatSchedulerException("WorkflowScheduler.getJobs - "
422
					+ "I/O error when transforming XML for workflow id: "
423
					+ workflowId + " : " + ioe.getMessage());
424
		} finally {
425
			if (out != null) {
426
				out.close();
427
			}
428
		}
429
	}
430 5057 daigle
431
	private String validateRemoteSession(String sessionId) throws MetacatSchedulerException {
432
		String sessionStatus = "unknown";
433
	    XPath xpath = XPathFactory.newInstance().newXPath();
434
435
		try {
436
			String ecogridUrl = PropertyService.getProperty("workflowScheduler.authServiceUrl");
437
438
			AuthenticationServiceClient authServiceClient =
439
					new AuthenticationServiceClient(ecogridUrl);
440
441
			String sessionStatusXML = authServiceClient.validate_session_action(sessionId);
442
443
			sessionStatus =
444
				xpath.evaluate("/validateSession/status",  new InputSource(new StringReader(sessionStatusXML)));
445
446
447
		} catch (PropertyNotFoundException pnfe) {
448
			throw new MetacatSchedulerException("WorkflowScheduler.validateSession - Could not "
449
					+ "find property: " + pnfe.getMessage());
450
		} catch (Exception e) {
451
			throw new MetacatSchedulerException("WorkflowScheduler.validateSession - "
452
					+ "general error when validating Session: " + e.getMessage());
453
		}
454
455
456
		return sessionStatus;
457
	}
458 5039 daigle
}