Project

General

Profile

1
/**
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
import java.io.StringReader;
32
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
import javax.xml.xpath.XPath;
39
import javax.xml.xpath.XPathFactory;
40

    
41
import org.apache.log4j.Logger;
42

    
43
import org.xml.sax.InputSource;
44

    
45
import org.ecoinformatics.ecogrid.client.AuthenticationServiceClient;
46

    
47
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
import edu.ucsb.nceas.metacat.properties.PropertyService;
53
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
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
59
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
			Hashtable<String, String[]> params) throws MetacatSchedulerException {
107
		 
108
		String sessionIds[] = params.get("sessionid");
109
		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
		
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
					+ request.getSession().getId() + " is not valid.");
127
		}
128
		
129
		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
					WORKFLOW_JOB_CLASS, WORKFLOW_JOB_GROUP, jobParams);
195
			
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
	public void unscheduleJob(HttpServletRequest request, HttpServletResponse response,
225
			Hashtable<String, String[]> params, String username, String[] groups)
226
			throws MetacatSchedulerException {
227
		try {
228
			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
			// workflow job id must exist
245
			String jobNames[] = params.get("workflowjobname");
246
			if (jobNames == null || jobNames.length == 0) {
247
				throw new MetacatSchedulerException("SchedulerService.unScheduleJob - workflowjobname " 
248
						+ "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
			String xmlResult = schedulerService.unscheduleJob(jobName, username, groups);
255
			
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
	public void rescheduleJob(HttpServletRequest request, HttpServletResponse response, 
282
			Hashtable<String, String[]> params, String username,
283
			String[] groups) throws MetacatSchedulerException {
284
		 		
285
		try {
286
			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
			// workflow job id must exist
304
			String jobNames[] = params.get("workflowjobname");	
305
			if (jobNames == null || jobNames.length == 0) {
306
				throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - workflowjobname field must be populated "
307
						+ "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
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - " 
322
					+ "DB access issue when rescheduling job  : ", ae);
323
		} catch (ServiceException se) {
324
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - " 
325
					+ "Service issue rescheduling job", se);
326
		} catch (ErrorSendingErrorException esee) {
327
			throw new MetacatSchedulerException("WorkflowScheduler.rescheduleJob - " 
328
					+ "Issue sending erro when rescheduling job: " + esee.getMessage());			
329
		}
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
			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
			// workflow job id must exist
355
			String jobNames[] = params.get("workflowjobname");
356
			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
			String result = schedulerService.deleteJob(jobDAO);
369

    
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
	
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
}
(2-2/3)