001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2003 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064: package com.jcorporate.expresso.services.controller;
065:
066: import com.jcorporate.expresso.core.controller.Block;
067: import com.jcorporate.expresso.core.controller.ControllerException;
068: import com.jcorporate.expresso.core.controller.ControllerRequest;
069: import com.jcorporate.expresso.core.controller.ControllerResponse;
070: import com.jcorporate.expresso.core.controller.ErrorCollection;
071: import com.jcorporate.expresso.core.controller.Input;
072: import com.jcorporate.expresso.core.controller.NonHandleableException;
073: import com.jcorporate.expresso.core.controller.Output;
074: import com.jcorporate.expresso.core.controller.State;
075: import com.jcorporate.expresso.core.controller.Transition;
076: import com.jcorporate.expresso.core.dbobj.ValidValue;
077: import com.jcorporate.expresso.core.misc.ConfigManager;
078: import com.jcorporate.expresso.core.utility.JobHandler;
079: import com.jcorporate.expresso.services.crontab.CronException;
080: import com.jcorporate.expresso.services.crontab.Crontab;
081: import com.jcorporate.expresso.services.crontab.CrontabEntry;
082: import org.apache.log4j.Logger;
083:
084: import java.text.SimpleDateFormat;
085: import java.util.Calendar;
086: import java.util.Date;
087: import java.util.Iterator;
088: import java.util.List;
089: import java.util.Vector;
090:
091: /**
092: * Crontab Controller allows for basic insight into the currently running
093: * crontabs on the system. It also allows for basic editing and removal of
094: * existing crontabs. It does not create new crontabs yet.
095: *
096: * @author Michael Rimov
097: * @version 1.0
098: * @since Expresso 5.3
099: */
100: public class CronController extends
101: com.jcorporate.expresso.core.controller.DBController {
102: /**
103: * the Log4j Logger
104: */
105: public static final transient Logger log = Logger
106: .getLogger(CronController.class);
107:
108: /**
109: * Creates an instance of CronController. Call setRequestingUid() and
110: * setDataContext() before using.
111: *
112: * @throws ControllerException upon initialization exception.
113: * @see com.jcorporate.expresso.core.dbobj.SecuredDBObject#SecuredDBObject
114: */
115: public CronController() throws ControllerException {
116: super ();
117:
118: State s = new State("list", "List Cron Jobs");
119: this .addState(s);
120: this .setInitialState("list");
121:
122: s = new State("delete", "Delete");
123: s.addRequiredParameter("CronId");
124: this .addState(s);
125:
126: s = new State("edit", "Edit");
127: s.addRequiredParameter("CronId");
128: this .addState(s);
129:
130: s = new State("editUpdate", "Update Execution Time");
131: s.addRequiredParameter("CronId");
132: s.addRequiredParameter("minute");
133: s.addRequiredParameter("hour");
134: s.addRequiredParameter("day");
135: s.addRequiredParameter("dayofWeek");
136: s.addRequiredParameter("month");
137: s.addRequiredParameter("year");
138: this .addState(s);
139: }
140:
141: /**
142: * Retrieve the title of the controller
143: *
144: * @return java.lang.String
145: */
146: public String getTitle() {
147: return "Cron Manager";
148: }
149:
150: /**
151: * Build day of week valid values
152: *
153: * @param request ControllerRequest from which we grab the user's locale
154: * @return Vector of ValidValue objects for each day of the week
155: */
156: protected Vector buildDayOfWeekValidValues(ControllerRequest request) {
157: Vector returnValue = new Vector(8);
158: returnValue.add(new ValidValue("-1", "Unspecified"));
159:
160: SimpleDateFormat df = new SimpleDateFormat("EEEE");
161: Calendar cal = Calendar.getInstance(request.getLocale());
162: cal.clear();
163:
164: for (int i = 1; i < 8; i++) {
165: cal.set(Calendar.DAY_OF_WEEK, i);
166: returnValue.add(new ValidValue(Integer.toString(i), df
167: .format(cal.getTime())));
168: }
169:
170: return returnValue;
171: }
172:
173: /**
174: * Build the crontab day valid values
175: *
176: * @return Vector of ValidValue objects 1-31
177: */
178: protected Vector buildDayValidValues() {
179: Vector returnValue = new Vector(32);
180: returnValue.add(new ValidValue("-1", "Unspecified"));
181:
182: for (int i = 1; i < 32; i++) {
183: returnValue.add(new ValidValue(Integer.toString(i), Integer
184: .toString(i)));
185: }
186:
187: return returnValue;
188: }
189:
190: /**
191: * Build the crontab hour valid values
192: *
193: * @return Vector of ValidValue objects: 1-24
194: */
195: protected Vector buildHourValidValues() {
196: Vector returnValue = new Vector(24);
197:
198: for (int i = 0; i < 24; i++) {
199: returnValue.add(new ValidValue(Integer.toString(i), Integer
200: .toString(i)));
201: }
202:
203: return returnValue;
204: }
205:
206: /**
207: * Build the crontab minute valid values
208: *
209: * @return Vector of minute valid values
210: */
211: protected Vector buildMinuteValidValue() {
212: Vector returnValue = new Vector(60);
213:
214: for (int i = 0; i < 60; i++) {
215: returnValue.add(new ValidValue(Integer.toString(i), Integer
216: .toString(i)));
217: }
218:
219: return returnValue;
220: }
221:
222: /**
223: * Build month valid values
224: *
225: * @param request ControllerRequest from which we grab the user's locale
226: * @return Vector of valid values for each month in the year
227: */
228: protected Vector buildMonthValidValues(ControllerRequest request) {
229: Vector returnValue = new Vector(8);
230: returnValue.add(new ValidValue("-1", "Unspecified"));
231:
232: SimpleDateFormat df = new SimpleDateFormat("MMMM");
233: Calendar cal = Calendar.getInstance(request.getLocale());
234: cal.clear();
235:
236: for (int i = 0; i < 12; i++) {
237: cal.set(Calendar.MONTH, i);
238: returnValue.add(new ValidValue(Integer.toString(i), df
239: .format(cal.getTime())));
240: }
241:
242: return returnValue;
243: }
244:
245: /**
246: * Build the year valid values
247: *
248: * @param request ControllerRequest from which we grab the user's locale
249: * @return Vector of ValidValues for a 50 year span
250: */
251: protected Vector buildYearValidValues(ControllerRequest request) {
252: Vector returnValue = new Vector(51);
253: returnValue.add(new ValidValue("-1", "Unspecified"));
254:
255: Calendar cal = Calendar.getInstance(request.getLocale());
256:
257: for (int i = cal.get(Calendar.YEAR); i < (cal
258: .get(Calendar.YEAR) + 50); i++) {
259: returnValue.add(new ValidValue(Integer.toString(i), Integer
260: .toString(i)));
261: }
262:
263: return returnValue;
264: }
265:
266: /**
267: * Make sure Cron Manager is synchronized before calling this function!
268: *
269: * @param crontab the crontab to search
270: * @param id the crontab incrementing id
271: * @return CrontabEntry or null if it cannot be found.
272: */
273: protected CrontabEntry findCronById(Crontab crontab, long id) {
274: List l = crontab.getAllEntries();
275:
276: if (l.size() == 0) {
277: return null;
278: }
279:
280: for (Iterator i = l.iterator(); i.hasNext();) {
281: CrontabEntry entry = (CrontabEntry) i.next();
282:
283: if (entry.getCounter() == id) {
284: return entry;
285: }
286: }
287:
288: return null;
289: }
290:
291: /**
292: * Deletes a specified crontab
293: *
294: * @param request The <code>ControllerRequest</code> object handed to us by
295: * the framework.
296: * @param response The <code>ControllerResponse</code> object handed to us
297: * by the framework.
298: * @throws ControllerException upon error
299: * @throws NonHandleableException upon fatal error
300: */
301: protected void runDeleteState(ControllerRequest request,
302: ControllerResponse response) throws ControllerException,
303: NonHandleableException {
304: ErrorCollection ec = request.getErrorCollection();
305:
306: if (ec != null) {
307: response.saveErrors(ec);
308: transition("list", request, response);
309:
310: return;
311: }
312:
313: response.setTitle("Delete Crontab");
314:
315: JobHandler jh = ConfigManager.getJobHandler(request
316: .getDataContext());
317: Crontab crontab = jh.getCronManager();
318: String cronId = request.getParameter("CronId");
319: long cronNumber = Long.parseLong(cronId);
320: response.setTitle("Edit Cron Parameters");
321:
322: CrontabEntry entry = null;
323:
324: synchronized (crontab) {
325: entry = findCronById(crontab, cronNumber);
326:
327: if (entry != null) {
328: crontab.removeCrontabEntry(entry);
329: response.add(new Output("result",
330: "Deleted Entry Labelled: " + entry.getLabel()));
331:
332: Transition t = new Transition("list", this );
333: response.add(t);
334: }
335: }
336:
337: //We transition down here after synchronize is released so we don't
338: //hold crontab for too long.
339: if (entry == null) {
340: ec = new ErrorCollection();
341: ec.addError("Unable to find cron id of: " + cronId
342: + ". it may have been removed from the queue");
343: transition("list", request, response);
344:
345: return;
346: }
347: }
348:
349: /**
350: * Prompts for editing a crontab entry.
351: *
352: * @param request The <code>ControllerRequest</code> object handed to us by
353: * the framework.
354: * @param response The <code>ControllerResponse</code> object handed to us
355: * by the framework.
356: * @throws ControllerException upon error
357: * @throws NonHandleableException upon fatal error
358: */
359: protected void runEditState(ControllerRequest request,
360: ControllerResponse response) throws ControllerException,
361: NonHandleableException {
362: ErrorCollection ec = request.getErrorCollection();
363:
364: if (ec != null) {
365: response.saveErrors(ec);
366: transition("list", request, response);
367:
368: return;
369: }
370:
371: Vector minValidValue = buildMinuteValidValue();
372: Vector hourValidValue = buildHourValidValues();
373: Vector dayValidValue = buildDayValidValues();
374: Vector dayofWeekValidValue = buildDayOfWeekValidValues(request);
375: Vector monthValidValue = buildMonthValidValues(request);
376: Vector yearValidValue = buildYearValidValues(request);
377:
378: JobHandler jh = ConfigManager.getJobHandler(request
379: .getDataContext());
380: Crontab crontab = jh.getCronManager();
381: String cronId = request.getParameter("CronId");
382: long cronNumber = Long.parseLong(cronId);
383: response.setTitle("Edit Cron Parameters");
384:
385: CrontabEntry entry = null;
386:
387: synchronized (crontab) {
388: entry = findCronById(crontab, cronNumber);
389:
390: if (entry != null) {
391: response.add(new Output("subtitle",
392: "Editing Entry Labelled: " + entry.getLabel()));
393:
394: Input i = new Input("minute", "Minute");
395: i.setValidValues(minValidValue);
396: i.setDefaultValue(Integer.toString(entry.getMinute()));
397: response.add(i);
398:
399: i = new Input("hour", "Hour");
400: i.setValidValues(hourValidValue);
401: i.setDefaultValue(Integer.toString(entry.getHour()));
402: response.add(i);
403:
404: i = new Input("day", "Day of Month");
405: i.setValidValues(dayValidValue);
406: i.setDefaultValue(Integer.toString(entry
407: .getDayOfMonth()));
408: response.add(i);
409:
410: i = new Input("dayofWeek", "Day of Week");
411: i.setValidValues(dayofWeekValidValue);
412: i.setDefaultValue(Integer
413: .toString(entry.getDayOfWeek()));
414: response.add(i);
415:
416: i = new Input("month", "Month");
417: i.setValidValues(monthValidValue);
418: i.setDefaultValue(Integer.toString(entry.getMonth()));
419: response.add(i);
420:
421: i = new Input("year", "Year");
422: i.setValidValues(yearValidValue);
423: i.setDefaultValue(Integer.toString(entry.getYear()));
424: response.add(i);
425:
426: Transition t = new Transition("list", this );
427: response.add(t);
428:
429: t = new Transition("editUpdate", this );
430: t.addParam("CronId", cronId);
431: response.add(t);
432: }
433: }
434:
435: //We transition down here after synchronize is released so we don't
436: //hold crontab for too long.
437: if (entry == null) {
438: ec = new ErrorCollection();
439: ec.addError("Unable to find cron id of: " + cronId
440: + ". it may have been removed from the queue");
441: transition("list", request, response);
442:
443: return;
444: }
445: }
446:
447: /**
448: * Runs the processing of the edit state
449: *
450: * @param request The <code>ControllerRequest</code> object handed to us by
451: * the framework.
452: * @param response The <code>ControllerResponse</code> object handed to us
453: * by the framework.
454: * @throws ControllerException upon error
455: * @throws NonHandleableException upon fatal error
456: */
457: protected void runEditUpdateState(ControllerRequest request,
458: ControllerResponse response) throws ControllerException,
459: NonHandleableException {
460: ErrorCollection ec = request.getErrorCollection();
461:
462: if (ec != null) {
463: response.saveErrors(ec);
464: transition("list", request, response);
465:
466: return;
467: }
468:
469: JobHandler jh = ConfigManager.getJobHandler(request
470: .getDataContext());
471: Crontab crontab = jh.getCronManager();
472: String cronId = request.getParameter("CronId");
473: long cronNumber = Long.parseLong(cronId);
474: response.setTitle("Cron Execution Time Result");
475:
476: int minute = Integer.parseInt(request.getParameter("minute"));
477: int hour = Integer.parseInt(request.getParameter("hour"));
478: int day = Integer.parseInt(request.getParameter("day"));
479: int dayofWeek = Integer.parseInt(request
480: .getParameter("dayofWeek"));
481: int month = Integer.parseInt(request.getParameter("month"));
482: int year = Integer.parseInt(request.getParameter("year"));
483:
484: CrontabEntry entry = null;
485:
486: synchronized (crontab) {
487: entry = findCronById(crontab, cronNumber);
488:
489: if (entry != null) {
490: response.add(new Output("result",
491: "Edited Entry Labelled: " + entry.getLabel()));
492:
493: CrontabEntry newEntry;
494:
495: try {
496: newEntry = new CrontabEntry(minute, hour, day,
497: dayofWeek, month, year, entry.getLabel(),
498: entry.getListener());
499: crontab.addCrontabEntry(newEntry);
500: } catch (CronException ex) {
501: throw new ControllerException(
502: "Unable to construct and add new crontab entry. Old entry still exists in crontab.",
503: ex);
504: }
505:
506: crontab.removeCrontabEntry(entry);
507:
508: Transition t = new Transition("list", this );
509: response.add(t);
510: }
511: }
512:
513: //We transition down here after synchronize is released so we don't
514: //hold crontab for too long.
515: if (entry == null) {
516: ec = new ErrorCollection();
517: ec.addError("Unable to find cron id of: " + cronId
518: + ". it may have been removed from the crontab");
519: transition("list", request, response);
520:
521: return;
522: }
523: }
524:
525: /**
526: * Runs the List state. Displays all currently running crontabs
527: *
528: * @param request The <code>ControllerRequest</code> object handed to us by
529: * the framework.
530: * @param response The <code>ControllerResponse</code> object handed to us
531: * by the framework.
532: * @throws ControllerException upon error
533: * @throws NonHandleableException upon fatal error
534: */
535: protected void runListState(ControllerRequest request,
536: ControllerResponse response) throws ControllerException,
537: NonHandleableException {
538: JobHandler jh = ConfigManager.getJobHandler(request
539: .getDataContext());
540: if (jh == null) {
541: throw new ControllerException(
542: "The job handler could not be retrieved. Either an error occurred, or it is disabled.");
543: }
544: Crontab crontab = jh.getCronManager();
545: Block records = new Block("records");
546: response.setTitle("Running Crontabs");
547: response.add(records);
548:
549: synchronized (crontab) {
550: List l = crontab.getAllEntries();
551:
552: if (l.size() == 0) {
553: response.add(new Output("noCrontabs",
554: "No crontabs are currently running"));
555: }
556:
557: for (Iterator i = l.iterator(); i.hasNext();) {
558: CrontabEntry entry = (CrontabEntry) i.next();
559:
560: long key = entry.getCounter();
561: String paramString = Long.toString(key);
562: Block oneEntry = new Block(paramString);
563: oneEntry.add(new Output("label", entry.getLabel()));
564: oneEntry.add(new Output("minute", Integer
565: .toString(entry.getMinute())));
566: oneEntry.add(new Output("hour", Integer.toString(entry
567: .getHour())));
568: oneEntry.add(new Output("dayofweek", Integer
569: .toString(entry.getDayOfWeek())));
570: oneEntry.add(new Output("dayofmonth", Integer
571: .toString(entry.getDayOfMonth())));
572: oneEntry.add(new Output("month", Integer.toString(entry
573: .getMonth())));
574: oneEntry.add(new Output("year", Integer.toString(entry
575: .getYear())));
576: oneEntry.add(new Output("alarmTime", new Date(entry
577: .getAlarmTime()).toString()));
578: oneEntry.add(new Output("isRepetitive", ""
579: + entry.isIsRepetitive()));
580:
581: Transition t = new Transition("edit", this );
582: t.addParam("CronId", paramString);
583: oneEntry.add(t);
584:
585: t = new Transition("delete", this );
586: t.addParam("CronId", paramString);
587: oneEntry.add(t);
588: records.add(oneEntry);
589: }
590:
591: Transition refresh = new Transition("list", this );
592: refresh.setName("refresh");
593: refresh.setLabel("Refresh List");
594: response.add(refresh);
595: }
596: }
597: }
|