/* Copyright 1999-2008 Acelet.org. All rights reserved. GPL v2 license */
/** @author Wei Jiang */
package com.acelet.s.scheduler;
import java.io.*;
import java.net.*;
import java.text.*;
import java.util.*;
import com.acelet.lib.Common;
import com.acelet.lib.Externals;
import com.acelet.lib.JavaVersionException;
import com.acelet.lib.Phrase;
import com.acelet.s.MailServerData;
import com.acelet.s.PrintInfo;
import com.acelet.s.job.MemberTaskInUseException;
import com.acelet.s.job.RetryObject;
import com.acelet.s.task.BusinessCalendar;
import com.acelet.s.task.CandidateTask;
import com.acelet.s.task.Task;
import com.acelet.s.task.TaskText;
import com.acelet.s.task.WorkingTask;
public class Scheduling {
//public static String version = "6.00";
public static String version = "6.10";
public static String releaseDate = "2009-01-16";
public static String NO_PERIODIC_PROMPT = "NoPeriodicPrompt";
public static int SCHEDULING_MODE_IMMEDIATELY = 1;
public static int SCHEDULING_MODE_BEGIN_AT_NEXT_MINUTE = 2;
protected static final int WORKING_TASK_DISPLAY_MIN = 20;
protected static int interval = 2000;
protected static boolean logIncludesResult = false;
protected static int workingTaskDisplayMax = WORKING_TASK_DISPLAY_MIN;
protected static long workingTaskRetireTime = System.currentTimeMillis() - 48*60*60*1000;
protected static int queryTimeout = 15;
protected static int logAgentTimeout = 15000;
protected static int schedulingMode = SCHEDULING_MODE_BEGIN_AT_NEXT_MINUTE;
protected static long minimumDuration = 3000;
protected static int maxHeartbeatMiss = 3;
protected static int heartbeatMiss = -1;
protected static long taskRefreshTime = 0;
protected static long workingTaskRefreshTime = 0;
protected static long holidayRefreshTime = 0;
protected static long preferencesRefreshTime = 0;
protected static long candidateRefreshTime = 0;
protected static long oldTaskRefreshTime = -1;
protected static long oldWorkingTaskRefreshTime = -1;
protected static long oldHolidayRefreshTime = -1;
protected static long oldPreferencesRefreshTime = -1;
protected static long oldCandidateRefreshTime = -1;
protected static long displayStartTimeForWorkingTask = -1;
protected static long superSchedulerStartTime;
protected static boolean isDoer;
protected static boolean isStartUp = true;
protected static boolean isFirstTime = true;
protected static boolean isLicenseValid = false;
protected static String licenseType;
protected static String licenseString;
protected static boolean busy = false;
protected static String doertalkerName;
protected static boolean noPeriodicPrompt = false;
protected static boolean initialized = false;
protected Scheduling() {
}
protected static void checkDurations() throws Exception {
if (CommonTimerTask.isShutdown)
return;
long now = System.currentTimeMillis();
Enumeration enumeration = Registry.taskHashtable.elements();
while (enumeration.hasMoreElements()) {
Task task = (Task) enumeration.nextElement();
long duration = task.duration;
WorkingTask workingTask = null;
if (task.duration > 0) {
for (int i = 0; i < Registry.workingTaskVector.size(); i++) {
workingTask = (WorkingTask) Registry.workingTaskVector.elementAt(i);
if (task.getId() == workingTask.getId0()) {
if (workingTask.status == WorkingTask.STATUS_STARTED) {
if (workingTask.modifiedAt + duration < now) {
ForemanTimerTask.reportExceedingDuration(task, workingTask);
}
}
}
}
}
}
}
public static void executeNow(long id) throws Exception {
Task task = Delegate.selectTask(id);
Task tmpTask = task.createTemporaryCopyForNow();
CreateTimerTask.create(tmpTask);
}
public static void executeNow(String name) throws Exception {
Task task = Delegate.selectTask(name);
Task tmpTask = task.createTemporaryCopyForNow();
CreateTimerTask.create(tmpTask);
}
protected static void iAmAlive() {
DateFormat dateFormat = DateFormat.getDateInstance();
System.out.println("\nScheduling: " + Phrase.get("TX_WORKING") + ": " +
new Date(System.currentTimeMillis()));
}
public static void init(boolean isDoer, int runningMode) throws Exception {
superSchedulerStartTime = System.currentTimeMillis();
String info = "SuperScheduler: version=" + version + " isDoer=" + isDoer +
" runningMode=" + runningMode + " starting at: " + new Date().toString();
System.out.println(info);
new SchedulerProperties().printInfo();
Scheduling.isDoer = isDoer;
Externals.runningMode = runningMode;
Scheduling.isStartUp = true;
CommonTimerTask.isShutdown = false;
oldTaskRefreshTime = -1;
oldWorkingTaskRefreshTime = -1;
oldHolidayRefreshTime = -1;
oldPreferencesRefreshTime = -1;
oldCandidateRefreshTime = -1;
doertalkerName = InetAddress.getLocalHost().getHostName() + " " +
Phrase.get("TX_SUPER_SCHEDULER") + " " +
(isDoer? Phrase.get("TX_DOER"): Phrase.get("TX_TALKER"));
Registry.taskHashtable = new Hashtable();
readFromDatabase();
long officialNextMinute = Common.getOfficialTime() + BossTimerTask.INTERVAL;
Date startDate = new Date();
if (schedulingMode == SCHEDULING_MODE_BEGIN_AT_NEXT_MINUTE)
startDate = new Date(officialNextMinute);
BossTimerTask.bossTimerTask = new BossTimerTask();
BossTimerTask.bossTimer = new Timer();
BossTimerTask.bossTimer.schedule(BossTimerTask.bossTimerTask, startDate);
initialized = true;
}
public static void initBusinessCalendar() throws Exception {
readBusinessCalendar(true);
}
public static boolean isInitialized() {
return initialized;
}
protected static void readBusinessCalendar(boolean forceToRead) throws Exception {
if (forceToRead == false) {
if (holidayRefreshTime == oldHolidayRefreshTime)
return;
}
Vector rawHolidayVector = Delegate.selectAllHolidays();
BusinessCalendar.reset(rawHolidayVector);
}
protected static void readFromDatabase() throws Exception {
if (CommonTimerTask.isShutdown)
return;
if (busy) {
if (isFirstTime == false) {
String error = Phrase.get("ER_SUPER_SCHEDULER_INTERVAL_IS_TOO_SMALL") + ". " +
Phrase.get("TX_SEE") + " Errors.html#ER_SUPER_SCHEDULER_INTERVAL_IS_TOO_SMALL";
System.out.println(error);
}
return;
}
try {
busy = true;
Hashtable tmpTaskHashtable = new Hashtable();
Hashtable tmpNameToTaskHashtable = new Hashtable();
long now = System.currentTimeMillis();
try {
readPreference();
readBusinessCalendar(false);
if (isDoer) {
runRequestedTasks();
}
} catch (Exception e) {
e.printStackTrace();
}
if (taskRefreshTime == oldTaskRefreshTime)
return;
Vector allComingTasks = Delegate.selectAllTasks();
int taskSize = allComingTasks.size();
for (int i = 0; i < taskSize; i++) {
Task comingTask = (Task) allComingTasks.elementAt(i);
Long comingTaskId = new Long(comingTask.getId());
if (isStartUp) {
if (comingTask.getRepeating() == Task.REPEATING_SUPER_SCHEDULER_STARTUP) {
if (comingTask.status != Task.STATUS_SUSPENDED) {
executeNow(comingTask.getId());
}
continue;
}
}
if (comingTask.isFutureRunnable()) {
for (int j = 0; j < 10; j++) {
if (comingTask.getNextRunTime() == comingTask.lastRunTime) {
System.out.println("!0401301455: " + comingTask.name + " " + comingTask.lastRunTime);
Thread.currentThread().sleep(100);
comingTask.reCalculate();
} else
break;
}
}
tmpTaskHashtable.put(comingTaskId, comingTask);
tmpNameToTaskHashtable.put(comingTask.name, comingTask);
}
isStartUp = false;
Registry.taskHashtable = tmpTaskHashtable;
Registry.nameToTaskHashtable = tmpNameToTaskHashtable;
Registry.cleanup();
if (SchedulerProperties.getIsDebugging())
System.out.println(new Date().toString() + "> " + Registry.toDebugInfo() + "\n");
} catch (Exception ex) {
try {
String subject = "SuperScheduler" + " " + Phrase.get("ER_DATABASE");
String msg = subject + "\n" + ex.getMessage();
Delegate.sendAlertEmail(subject, msg);
} catch (Exception exception) {
exception.printStackTrace();
}
throw ex;
} finally {
busy = false;
isFirstTime = false;
}
}
protected static void readPreference() throws Exception {
if (preferencesRefreshTime == oldPreferencesRefreshTime)
return;
Properties properties = Delegate.selectSchedulerPreference();
interval = Integer.parseInt(properties.getProperty("interval"));
logIncludesResult = new Boolean(properties.getProperty("logIncludesResult")).booleanValue();
workingTaskDisplayMax = Integer.parseInt(properties.getProperty("workingTaskDisplayMax"));
workingTaskRetireTime = Long.parseLong(properties.getProperty("workingTaskRetireTime"));
queryTimeout = Integer.parseInt(properties.getProperty("queryTimeout"));
logAgentTimeout = Integer.parseInt(properties.getProperty("logAgentTimeout"));
schedulingMode = Integer.parseInt(properties.getProperty("schedulingMode"));
minimumDuration = Integer.parseInt(properties.getProperty("minimumDuration"));
Delegate.resetTaskProcess();
if (workingTaskDisplayMax < WORKING_TASK_DISPLAY_MIN)
workingTaskDisplayMax = WORKING_TASK_DISPLAY_MIN;
workingTaskRetireTime = System.currentTimeMillis() - workingTaskRetireTime;
}
protected static boolean readRefreshTime() throws Exception {
if (CommonTimerTask.isShutdown)
return false;
try {
long tmpTaskRefreshTime = taskRefreshTime;
long tmpWorkingTaskRefreshTime = workingTaskRefreshTime;
long tmpHolidayRefreshTime = holidayRefreshTime;
long tmpPreferencesRefreshTime = preferencesRefreshTime;
long tmpCandidateRefreshTime = candidateRefreshTime;
String refreshTimeString = Delegate.getRefreshTime(doertalkerName);
StringTokenizer st = new StringTokenizer(refreshTimeString, " ");
taskRefreshTime = Long.parseLong(st.nextToken());
workingTaskRefreshTime = Long.parseLong(st.nextToken());
holidayRefreshTime = Long.parseLong(st.nextToken());
preferencesRefreshTime = Long.parseLong(st.nextToken());
candidateRefreshTime = Long.parseLong(st.nextToken());
oldTaskRefreshTime = tmpTaskRefreshTime;
oldWorkingTaskRefreshTime = tmpWorkingTaskRefreshTime;
oldHolidayRefreshTime = tmpHolidayRefreshTime;
oldPreferencesRefreshTime = tmpPreferencesRefreshTime;
oldCandidateRefreshTime = tmpCandidateRefreshTime;
heartbeatMiss = -1;
if (taskRefreshTime > oldTaskRefreshTime ||
workingTaskRefreshTime > oldWorkingTaskRefreshTime)
return true;
else
return false;
} catch (Exception ex) {
heartbeatMiss++;
if (heartbeatMiss == maxHeartbeatMiss) {
try {
String subject = "SuperScheduler" + " " + Phrase.get("ER_DATABASE");
String msg = subject + "\n" + ex.getMessage();
Delegate.sendAlertEmail(subject, msg);
} catch (Exception exception) {
exception.printStackTrace();
}
throw ex;
} else
return false;
}
}
protected static void readWorkingTasks() throws Exception {
if (CommonTimerTask.isShutdown)
return;
if (workingTaskRefreshTime == oldWorkingTaskRefreshTime)
return;
if (busy)
return;
try {
busy = true;
try {
new DatabaseMaintenance().deleteOldWorking(workingTaskRetireTime);
} catch (Exception e) {
e.printStackTrace();
}
Registry.workingTaskVector =
Delegate.selectAllWorkingTasks(displayStartTimeForWorkingTask,
Long.MAX_VALUE, workingTaskDisplayMax + 1);
int workingTaskSize = Registry.workingTaskVector.size();
if (workingTaskSize > workingTaskDisplayMax) {
WorkingTask wt =
(WorkingTask) Registry.workingTaskVector.elementAt(workingTaskDisplayMax - 1);
displayStartTimeForWorkingTask = wt.modifiedAt;
}
} finally {
busy = false;
}
}
protected static void runRequestedTasks() throws Exception {
if (candidateRefreshTime == oldCandidateRefreshTime)
return;
Vector allCandidateTasks = Delegate.selectAllCandidateTasks();
for (int i = 0; i < allCandidateTasks.size(); i++) {
try {
CandidateTask candidateTask =
(CandidateTask) allCandidateTasks.elementAt(i);
Task originalTask = Delegate.selectTask(candidateTask.name);
if (originalTask == null) {
Delegate.deleteCandidateTask(candidateTask.id);
String message = Phrase.get("ER_CANNOT_FIND_TASK") + ": " + candidateTask.name +
". " + Phrase.get("TX_REQUEST_IS_DELETED");
Delegate.sendAlarmEmailForTaskError(originalTask.alarmEmail, candidateTask.name, message);
continue;
}
if (CreateTimerTask.eligible(originalTask)) {
if (Delegate.deleteCandidateTask(candidateTask.id) == 1) {
executeNow(originalTask.name);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}