001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019:
020: package org.openharmonise.rm.tasks;
021:
022: import java.io.*;
023: import java.util.*;
024: import java.util.Vector;
025: import java.util.logging.*;
026: import java.util.logging.Logger;
027:
028: import org.openharmonise.commons.dsi.*;
029: import org.openharmonise.commons.net.*;
030: import org.openharmonise.rm.HarmoniseExceptionHandler;
031: import org.openharmonise.rm.config.ConfigSettings;
032:
033: /**
034: * Handles the running of scheduled tasks.
035: *
036: * @author Michael Bell
037: * @version $Revision: 1.2 $
038: *
039: */
040: public class Scheduler implements Runnable {
041: static final String PNAME_SITE_URL = "SITE_URL";
042: static final String PNAME_SCHEDULE_PERIOD = "SCHEDULE_PERIOD";
043:
044: /** Instance of this class
045: */
046: private static Scheduler m_instance = null;
047:
048: /** Variable to control running of thread
049: */
050: private boolean m_bKeepRunning = true;
051:
052: /** Interface to database
053: */
054: private AbstractDataStoreInterface m_dbinterf = null;
055:
056: /** Counter for number of iterations
057: */
058: private int m_nCounter = 0;
059:
060: /** Vector of Exceptions, for use in collecting info on running of tasks
061: */
062: private Vector m_Exceptions = null;
063:
064: /**
065: * Vector containing ids of tasks that have thrown an exception, will not be run again and need fixing
066: */
067: private Vector m_RogueTasks = null;
068:
069: /**
070: * Period, in seconds, of scheduler
071: */
072: private int m_schedule_period = 30 * 1000;
073:
074: /**
075: * Logger for this class
076: */
077: private static final Logger m_logger = Logger
078: .getLogger(Scheduler.class.getName());
079:
080: /**
081: * Contructs new Scheduler object
082: *
083: * @param dbinterf Interface to database
084: */
085: public Scheduler(AbstractDataStoreInterface dbinterf) {
086: m_dbinterf = dbinterf;
087: }
088:
089: /* (non-Javadoc)
090: * @see java.lang.Runnable#run()
091: */
092: /**
093: * Run method. Executes pending tasks and updates next run time for each task.
094: */
095: public void run() {
096: m_bKeepRunning = true;
097:
098: while (m_bKeepRunning == true) {
099: int nTaskId = -1;
100:
101: if (m_logger.isLoggable(Level.FINE)) {
102: m_logger.log(Level.FINE, "Checking tasks....");
103: }
104:
105: try {
106: List tasks = TaskCache.getInstance().getPendingTasks();
107:
108: for (Iterator iter = tasks.iterator(); iter.hasNext();) {
109: Task tsk = (Task) iter.next();
110:
111: nTaskId = tsk.getId();
112:
113: if ((m_RogueTasks == null)
114: || (m_RogueTasks.contains(String
115: .valueOf(nTaskId)) == false)) {
116: tsk.execute();
117: tsk.updateNextRuntime();
118: }
119: }
120:
121: Thread.sleep(m_schedule_period);
122: m_nCounter++;
123: } catch (Exception e) {
124: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
125:
126: if (m_Exceptions == null) {
127: m_Exceptions = new Vector(16);
128: m_RogueTasks = new Vector(16);
129: }
130:
131: m_Exceptions.add(new TaskExecutionException("Task id: "
132: + nTaskId, e));
133:
134: m_RogueTasks.add(String.valueOf(nTaskId));
135:
136: try {
137: HarmoniseExceptionHandler eHandler = new HarmoniseExceptionHandler();
138:
139: eHandler.setImportance(Email.IMPORTANCE_HIGH);
140:
141: eHandler.emailError(
142: "TASK ERROR - TASK ERROR - TASK ERROR - TASK ERROR - TASK ERROR - URL:"
143: + ConfigSettings
144: .getProperty(
145: PNAME_SITE_URL,
146: "Not known"),
147: eHandler.describeException(e), e);
148: } catch (Exception e2) {
149: m_logger.log(Level.WARNING, e2
150: .getLocalizedMessage(), e2);
151: }
152:
153: if (m_Exceptions.size() > 10) {
154: m_bKeepRunning = false;
155: }
156:
157: }
158: }
159: }
160:
161: /**
162: * Returns number of iterations complete so far
163: *
164: * @return number of interations
165: */
166: public int getCounterValue() {
167: return m_nCounter;
168: }
169:
170: public void setPeriod(int nSeconds) {
171: this .m_schedule_period = nSeconds * 1000;
172: }
173:
174: /**
175: * Returns an instance of scheduler. Fits singleton design pattern.
176: *
177: * @param dbinterf Interface to database
178: * @return instance of scheduler class
179: */
180: public static synchronized Scheduler instance(
181: AbstractDataStoreInterface dbinterf) {
182: if (m_instance == null) {
183: m_instance = new Scheduler(dbinterf);
184:
185: try {
186: String sPeriod = ConfigSettings.getProperty(
187: PNAME_SCHEDULE_PERIOD, "1");
188:
189: m_instance.setPeriod(Integer.parseInt(sPeriod));
190: } catch (Exception e) {
191: //make do with the default period then
192: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
193: }
194: }
195:
196: return m_instance;
197: }
198:
199: /**
200: * Test whether scheduler is running or not.
201: *
202: * @return is scheduler running
203: */
204: public boolean isRunning() {
205: return m_bKeepRunning;
206: }
207:
208: /**
209: * Sets m_bKeepRunning to stop thread running.
210: */
211: public void stopRunning() {
212: m_bKeepRunning = false;
213: }
214:
215: /**
216: * Returns Report on status of Scheduler, including list of exceptions thrown.
217: *
218: * @param bVerbose Has report to be verbose
219: * @return Status report
220: */
221: public String getStatusReport(boolean bVerbose) {
222: StringBuffer sBuf = new StringBuffer();
223:
224: if (m_bKeepRunning) {
225: sBuf.append("<p>Scheduler running</p>");
226: } else {
227: sBuf.append("<p>Scheduler not running</p>");
228: }
229:
230: sBuf.append("<p>No. of iterations:").append(m_nCounter).append(
231: "</p>");
232:
233: if ((m_Exceptions == null) || (m_Exceptions.size() == 0)) {
234: sBuf.append("No Exceptions thrown.");
235: } else {
236: sBuf.append("<p>").append(m_Exceptions.size()).append(
237: " Exceptions thrown.</p><hr>");
238:
239: for (int i = 0; i < m_Exceptions.size(); i++) {
240: sBuf.append("<p>").append(
241: ((Exception) m_Exceptions.elementAt(i))
242: .getMessage()).append("</p>");
243:
244: if (bVerbose) {
245: String str = "";
246: StringWriter swriter = new StringWriter();
247: PrintWriter out = new PrintWriter(swriter);
248: ((TaskExecutionException) m_Exceptions.elementAt(i))
249: .printOriginalStackTrace(out);
250: out.close();
251: sBuf.append("<p>").append(swriter.toString())
252: .append("</p>");
253: }
254:
255: sBuf.append("<hr>");
256: }
257: }
258:
259: return (sBuf.toString());
260: }
261:
262: /**
263: * Clears list of exceptions thrown.
264: */
265: public void clearExceptionHistory() {
266: m_Exceptions.setSize(0);
267: }
268: }
|