001: /**********************************************************************************
002: * $URL$
003: * $Id$
004: **********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005 The Regents of the University of Michigan, Trustees of Indiana University,
007: * Board of Trustees of the Leland Stanford, Jr., University, and The MIT Corporation
008: *
009: * Licensed under the Educational Community License Version 1.0 (the "License");
010: * By obtaining, using and/or copying this Original Work, you agree that you have read,
011: * understand, and will comply with the terms and conditions of the Educational Community License.
012: * You may obtain a copy of the License at:
013: *
014: * http://cvs.sakaiproject.org/licenses/license_1_0.html
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
017: * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
018: * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
019: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
020: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
021: *
022: **********************************************************************************/package org.sakaiproject.tool.app.scheduler;
023:
024: import java.text.ParseException;
025: import java.util.*;
026:
027: import javax.faces.application.FacesMessage;
028: import javax.faces.component.UIComponent;
029: import javax.faces.context.FacesContext;
030: import javax.faces.event.ActionEvent;
031: import javax.faces.validator.ValidatorException;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.quartz.CronTrigger;
036: import org.quartz.JobDetail;
037: import org.quartz.Scheduler;
038: import org.quartz.SchedulerException;
039: import org.quartz.Trigger;
040: import org.quartz.JobExecutionContext;
041: import org.sakaiproject.api.app.scheduler.JobDetailWrapper;
042: import org.sakaiproject.api.app.scheduler.SchedulerManager;
043: import org.sakaiproject.api.app.scheduler.TriggerWrapper;
044: import org.sakaiproject.api.app.scheduler.JobBeanWrapper;
045: import org.sakaiproject.component.app.scheduler.JobDetailWrapperImpl;
046: import org.sakaiproject.component.app.scheduler.TriggerWrapperImpl;
047:
048: public class SchedulerTool {
049:
050: private static final Log LOG = LogFactory
051: .getLog(SchedulerTool.class);
052:
053: private static final String CRON_CHECK_ASTERISK = "**";
054: private static final String CRON_CHECK_QUESTION_MARK = "??";
055:
056: private SchedulerManager schedulerManager;
057: private Set jobClasses;
058: private String jobName;
059: private String triggerName;
060: private String triggerExpression;
061: private String selectedClass;
062:
063: private List jobDetailWrapperList;
064: private List filteredJobDetailWrapperList;
065: private JobDetailWrapper selectedJobDetailWrapper;
066: private boolean isSelectAllJobsSelected = false;
067: private boolean isSelectAllTriggersSelected = false;
068:
069: private List filteredTriggersWrapperList;
070:
071: public SchedulerTool() {
072: }
073:
074: /**
075: * @return Returns the filteredTriggersWrapperList.
076: */
077: public List getFilteredTriggersWrapperList() {
078: return filteredTriggersWrapperList;
079: }
080:
081: /**
082: * @param filteredTriggerWrapperList The filteredTriggersWrapperList to set.
083: */
084: public void setFilteredTriggersWrapperList(
085: List filteredTriggersWrapperList) {
086: this .filteredTriggersWrapperList = filteredTriggersWrapperList;
087: }
088:
089: /**
090: * @return Returns the isSelectAllJobsSelected.
091: */
092: public boolean isSelectAllJobsSelected() {
093: return isSelectAllJobsSelected;
094: }
095:
096: /**
097: * @param isSelectAllJobsSelected
098: * The isSelectAllJobsSelected to set.
099: */
100: public void setSelectAllJobsSelected(boolean isSelectAllJobsSelected) {
101: this .isSelectAllJobsSelected = isSelectAllJobsSelected;
102: }
103:
104: /**
105: * @return Returns the selectedClass.
106: */
107: public String getSelectedClass() {
108: return selectedClass;
109: }
110:
111: /**
112: * @param selectedClass
113: * The selectedClass to set.
114: */
115: public void setSelectedClass(String selectedClass) {
116: this .selectedClass = selectedClass;
117: }
118:
119: /**
120: * @return Returns the jobName.
121: */
122: public String getJobName() {
123: return jobName;
124: }
125:
126: /**
127: * @param jobName
128: * The jobName to set.
129: */
130: public void setJobName(String jobName) {
131: this .jobName = jobName;
132: }
133:
134: /**
135: * @return Returns the triggerName.
136: */
137: public String getTriggerName() {
138: return triggerName;
139: }
140:
141: /**
142: * @param triggerName The triggerName to set.
143: */
144: public void setTriggerName(String triggerName) {
145: this .triggerName = triggerName;
146: }
147:
148: /**
149: * @return Returns the triggerExpression.
150: */
151: public String getTriggerExpression() {
152: return triggerExpression;
153: }
154:
155: /**
156: * @param triggerExpression The triggerExpression to set.
157: */
158: public void setTriggerExpression(String triggerExpression) {
159: this .triggerExpression = triggerExpression;
160: }
161:
162: /**
163: * @return Returns the jobClasses.
164: */
165: public Map getJobClasses() {
166: return schedulerManager.getQrtzQualifiedJobs();
167: }
168:
169: /**
170: * @return Returns the schedulerManager.
171: */
172: public SchedulerManager getSchedulerManager() {
173: return schedulerManager;
174: }
175:
176: /**
177: * @param schedulerManager
178: * The schedulerManager to set.
179: */
180: public void setSchedulerManager(SchedulerManager schedulerManager) {
181: this .schedulerManager = schedulerManager;
182: }
183:
184: /**
185: * @return Returns the jobDetailWrapperList.
186: */
187: public List getJobDetailWrapperList() {
188: return jobDetailWrapperList;
189: }
190:
191: /**
192: * @param jobDetailWrapperList
193: * The jobDetailWrapperList to set.
194: */
195: public void setJobDetailWrapperList(List jobDetailWrapperList) {
196: this .jobDetailWrapperList = jobDetailWrapperList;
197: }
198:
199: /**
200: * @return Returns the filteredJobDetailWrapperList.
201: */
202: public List getFilteredJobDetailWrapperList() {
203: return filteredJobDetailWrapperList;
204: }
205:
206: /**
207: * @param filteredJobDetailWrapperList
208: * The filteredJobDetailWrapperList to set.
209: */
210: public void setFilteredJobDetailWrapperList(
211: List filteredJobDetailWrapperList) {
212: this .filteredJobDetailWrapperList = filteredJobDetailWrapperList;
213: }
214:
215: /**
216: * @return Returns the selectedJobDetailWrapper.
217: */
218: public JobDetailWrapper getSelectedJobDetailWrapper() {
219: return selectedJobDetailWrapper;
220: }
221:
222: /**
223: * @param selectedJobDetailWrapper
224: * The selectedJobDetailWrapper to set.
225: */
226: public void setSelectedJobDetailWrapper(
227: JobDetailWrapper selectedJobDetailWrapper) {
228: this .selectedJobDetailWrapper = selectedJobDetailWrapper;
229: }
230:
231: /**
232: * This method runs the current job only once, right now
233: * @return int 0 if it's not running, 1 if it is, 2 if there is an error
234: */
235: public int getSelectedJobRunning() {
236: Scheduler scheduler = schedulerManager.getScheduler();
237: if (scheduler == null) {
238: LOG.error("Scheduler is down!");
239: return 2;
240: }
241: try {
242: List executingJobs = scheduler.getCurrentlyExecutingJobs();
243:
244: for (Iterator i = executingJobs.iterator(); i.hasNext();) {
245: JobExecutionContext jobExecContext = (JobExecutionContext) i
246: .next();
247: if (selectedJobDetailWrapper.getJobDetail()
248: .getFullName().equals(
249: jobExecContext.getJobDetail()
250: .getFullName()))
251: return 1;
252: }
253: return 0;
254: } catch (Exception e) {
255: LOG.error("Failed to trigger job now");
256: return 2;
257: }
258: }
259:
260: public String processCreateJob() {
261: Scheduler scheduler = schedulerManager.getScheduler();
262: if (scheduler == null) {
263: LOG.error("Scheduler is down!");
264: return "error";
265: }
266: try {
267: JobDetail jd = null;
268: JobBeanWrapper job = getSchedulerManager()
269: .getJobBeanWrapper(selectedClass);
270: if (job != null) {
271: jd = new JobDetail(jobName, Scheduler.DEFAULT_GROUP,
272: job.getJobClass(), false, true, true);
273: jd.getJobDataMap().put(JobBeanWrapper.SPRING_BEAN_NAME,
274: job.getBeanId());
275: jd.getJobDataMap().put(JobBeanWrapper.JOB_TYPE,
276: job.getJobType());
277: } else {
278: jd = new JobDetail(jobName, Scheduler.DEFAULT_GROUP,
279: Class.forName(selectedClass.toString()), false,
280: true, true);
281: }
282: scheduler.addJob(jd, false);
283: processRefreshJobs();
284: return "jobs";
285: } catch (Exception e) {
286: LOG.error("Failed to create job");
287: return "error";
288: }
289: }
290:
291: public String processCreateTrigger() {
292: Scheduler scheduler = schedulerManager.getScheduler();
293: if (scheduler == null) {
294: LOG.error("Scheduler is down!");
295: return "error";
296: }
297: try {
298: Trigger trigger = new CronTrigger(triggerName,
299: Scheduler.DEFAULT_GROUP, selectedJobDetailWrapper
300: .getJobDetail().getName(),
301: Scheduler.DEFAULT_GROUP, triggerExpression);
302: scheduler.scheduleJob(trigger);
303: TriggerWrapper tempTriggerWrapper = new TriggerWrapperImpl();
304: tempTriggerWrapper.setTrigger(trigger);
305: selectedJobDetailWrapper.getTriggerWrapperList().add(
306: tempTriggerWrapper);
307: int currentTriggerCount = selectedJobDetailWrapper
308: .getTriggerCount().intValue();
309: selectedJobDetailWrapper.setTriggerCount(new Integer(
310: currentTriggerCount + 1));
311:
312: triggerName = null;
313: triggerExpression = null;
314: return "edit_triggers";
315: } catch (Exception e) {
316: triggerName = null;
317: triggerExpression = null;
318: LOG.error("Failed to create trigger");
319: return "error";
320: }
321: }
322:
323: public String processSelectAllJobs() {
324:
325: isSelectAllJobsSelected = !isSelectAllJobsSelected;
326: processRefreshJobs();
327: return "jobs";
328: }
329:
330: public String processSelectAllTriggers() {
331:
332: isSelectAllTriggersSelected = !isSelectAllTriggersSelected;
333: for (Iterator i = selectedJobDetailWrapper
334: .getTriggerWrapperList().iterator(); i.hasNext();) {
335: if (isSelectAllTriggersSelected) {
336: ((TriggerWrapper) i.next()).setIsSelected(true);
337: } else {
338: ((TriggerWrapper) i.next()).setIsSelected(false);
339: }
340: }
341: return "edit_triggers";
342: }
343:
344: public String processDeleteJobs() {
345: try {
346: for (Iterator i = filteredJobDetailWrapperList.iterator(); i
347: .hasNext();) {
348: JobDetailWrapper jobDetailWrapper = (JobDetailWrapper) i
349: .next();
350: schedulerManager.getScheduler().deleteJob(
351: jobDetailWrapper.getJobDetail().getName(),
352: Scheduler.DEFAULT_GROUP);
353: }
354: } catch (SchedulerException e) {
355: LOG.error("Scheduler Down");
356: }
357: processRefreshJobs();
358: return "jobs";
359: }
360:
361: public String processDeleteTriggers() {
362: try {
363: TriggerWrapper triggerWrapper;
364: for (Iterator i = filteredTriggersWrapperList.iterator(); i
365: .hasNext();) {
366: triggerWrapper = (TriggerWrapper) i.next();
367: schedulerManager.getScheduler().unscheduleJob(
368: triggerWrapper.getTrigger().getName(),
369: Scheduler.DEFAULT_GROUP);
370: selectedJobDetailWrapper.getTriggerWrapperList()
371: .remove(triggerWrapper);
372: }
373: } catch (SchedulerException e) {
374: LOG.error("Scheduler Down");
375: }
376: return "edit_triggers";
377: }
378:
379: public String processRefreshJobs() {
380: try {
381: Scheduler scheduler = schedulerManager.getScheduler();
382: String[] jobNames = scheduler
383: .getJobNames(Scheduler.DEFAULT_GROUP);
384: jobDetailWrapperList = new ArrayList();
385: for (int i = 0; i < jobNames.length; i++) {
386: JobDetailWrapper jobDetailWrapper = new JobDetailWrapperImpl();
387: jobDetailWrapper.setJobDetail(scheduler.getJobDetail(
388: jobNames[i], Scheduler.DEFAULT_GROUP));
389: Trigger[] triggerArr = scheduler.getTriggersOfJob(
390: jobNames[i], Scheduler.DEFAULT_GROUP);
391: List triggerWrapperList = new ArrayList();
392: TriggerWrapper tw;
393: for (int j = 0; j < triggerArr.length; j++) {
394: tw = new TriggerWrapperImpl();
395: tw.setTrigger(triggerArr[j]);
396: triggerWrapperList.add(tw);
397: }
398:
399: jobDetailWrapper
400: .setTriggerWrapperList(triggerWrapperList);
401: jobDetailWrapperList.add(jobDetailWrapper);
402: }
403: } catch (SchedulerException e) {
404: LOG.error("scheduler error while getting job detail");
405: }
406:
407: // test for select all
408: if (isSelectAllJobsSelected) {
409: for (Iterator i = jobDetailWrapperList.iterator(); i
410: .hasNext();) {
411: if (isSelectAllJobsSelected) {
412: ((JobDetailWrapper) i.next()).setIsSelected(true);
413: } else {
414: ((JobDetailWrapper) i.next()).setIsSelected(false);
415: }
416: }
417: }
418: return "jobs";
419: }
420:
421: /**
422: * This method runs the current job only once, right now
423: * @return String
424: */
425: public String processRunJobNow() {
426: Scheduler scheduler = schedulerManager.getScheduler();
427: if (scheduler == null) {
428: LOG.error("Scheduler is down!");
429: return "error";
430: }
431: try {
432:
433: scheduler.triggerJob(selectedJobDetailWrapper
434: .getJobDetail().getName(), selectedJobDetailWrapper
435: .getJobDetail().getGroup());
436:
437: return "success";
438: } catch (Exception e) {
439: LOG.error("Failed to trigger job now");
440: return "error";
441: }
442: }
443:
444: public String processRefreshFilteredJobs() {
445: filteredJobDetailWrapperList = new ArrayList();
446: for (Iterator i = jobDetailWrapperList.iterator(); i.hasNext();) {
447: JobDetailWrapper jobDetailWrapper = (JobDetailWrapper) i
448: .next();
449: if (jobDetailWrapper.getIsSelected()) {
450: filteredJobDetailWrapperList.add(jobDetailWrapper);
451: }
452: }
453: return "delete_jobs";
454: }
455:
456: public String processRefreshFilteredTriggers() {
457: filteredTriggersWrapperList = new ArrayList();
458: for (Iterator i = selectedJobDetailWrapper
459: .getTriggerWrapperList().iterator(); i.hasNext();) {
460: TriggerWrapper triggerWrapper = (TriggerWrapper) i.next();
461: if (triggerWrapper.getIsSelected()) {
462: filteredTriggersWrapperList.add(triggerWrapper);
463: }
464: }
465: return "delete_triggers";
466: }
467:
468: public void validateJobName(FacesContext context,
469: UIComponent component, Object value) {
470: if (value != null) {
471: try {
472: JobDetail jd = schedulerManager.getScheduler()
473: .getJobDetail((String) value,
474: Scheduler.DEFAULT_GROUP);
475: if (jd != null) {
476: FacesMessage message = new FacesMessage(
477: "Existing Job Name");
478: message.setSeverity(FacesMessage.SEVERITY_WARN);
479: throw new ValidatorException(message);
480: }
481: } catch (SchedulerException e) {
482: LOG.error("Scheduler down!");
483: }
484: }
485: }
486:
487: public void validateTriggerName(FacesContext context,
488: UIComponent component, Object value) {
489: if (value != null) {
490: try {
491: Trigger trigger = schedulerManager.getScheduler()
492: .getTrigger((String) value,
493: Scheduler.DEFAULT_GROUP);
494: if (trigger != null) {
495: FacesMessage message = new FacesMessage(
496: "Existing Trigger Name");
497: message.setSeverity(FacesMessage.SEVERITY_WARN);
498: throw new ValidatorException(message);
499: }
500: } catch (SchedulerException e) {
501: LOG.error("Scheduler down!");
502: }
503: }
504: }
505:
506: public void validateTriggerExpression(FacesContext context,
507: UIComponent component, Object value) {
508: if (value != null) {
509: try {
510: String expression = (String) value;
511: CronTrigger trigger = new CronTrigger();
512: trigger.setCronExpression(expression);
513:
514: // additional checks
515: // quartz does not check for more than 7 tokens in expression
516: String[] arr = expression.split("\\s");
517: if (arr.length > 7) {
518: throw new ParseException(
519: "Expression has more than 7 tokens", 7);
520: }
521:
522: //(check that last 2 entries are not both * or ?
523: String trimmed_expression = expression.replaceAll(
524: "\\s", ""); // remove whitespace
525: if (trimmed_expression.endsWith(CRON_CHECK_ASTERISK)
526: || trimmed_expression
527: .endsWith(CRON_CHECK_QUESTION_MARK)) {
528: throw new ParseException(
529: "Cannot End in * * or ? ?", 1);
530: }
531: } catch (ParseException e) {
532: // not giving a detailed message to prevent line wraps
533: FacesMessage message = new FacesMessage(
534: "Parse Exception");
535: message.setSeverity(FacesMessage.SEVERITY_WARN);
536: throw new ValidatorException(message);
537: }
538: }
539: }
540:
541: public void editTriggersListener(ActionEvent e) {
542: FacesContext context = FacesContext.getCurrentInstance();
543: Map requestParams = context.getExternalContext()
544: .getRequestParameterMap();
545: String jobName = (String) requestParams.get("jobName");
546:
547: //loop through jobDetailWrapperList finding the one selected by user.
548: for (Iterator i = jobDetailWrapperList.iterator(); i.hasNext();) {
549: JobDetailWrapper jobDetailWrapper = (JobDetailWrapper) i
550: .next();
551: if (jobDetailWrapper.getJobDetail().getName().equals(
552: jobName)) {
553: selectedJobDetailWrapper = jobDetailWrapper;
554: break;
555: }
556: }
557: }
558:
559: public Map getBeanJobs() {
560: Map beanJobs = new Hashtable();
561: Map serverJobs = getSchedulerManager().getBeanJobs();
562: for (Iterator i = serverJobs.keySet().iterator(); i.hasNext();) {
563: Object job = i.next();
564: beanJobs.put(job, job);
565: }
566: return beanJobs;
567: }
568:
569: }
|