schedule.java
来自「这是一个以JAVA编写的程序,本人还没有试过,是一个简单的温度控制系统」· Java 代码 · 共 667 行 · 第 1/2 页
JAVA
667 行
package net.sf.dz.scheduler;import java.io.File;import java.io.FileNotFoundException;import java.net.URL;import java.util.Calendar;import java.util.GregorianCalendar;import java.util.Date;import java.util.Iterator;import java.util.List;import java.util.SortedSet;import java.util.StringTokenizer;import java.util.TreeSet;import java.util.Comparator;import org.freehold.jukebox.conf.Configuration;import org.freehold.jukebox.conf.ConfigurationFactory;import org.freehold.jukebox.conf.TextConfiguration;import org.freehold.jukebox.logger.LogChannel;import org.freehold.jukebox.scheduler.Scheduler;import org.freehold.jukebox.scheduler.TaskListener;import org.freehold.jukebox.service.PassiveService;import org.freehold.jukebox.scheduler.Task;import org.freehold.jukebox.scheduler.TaskDescriptor;import org.freehold.jukebox.scheduler.RecurringTaskDescriptor;import net.sf.dz.device.model.Thermostat;/** * Coordinates the {@link ScheduleEvent schedule events} comprising the * schedule. */public class Schedule extends PassiveService { public static final LogChannel CH_SCHEDULE = new LogChannel("Schedule"); /** * Two-letter abbreviations for days of week, just in case. */ public static final String days[] = { "SU", "MO", "TU", "WE", "TH", "FR", "SA" }; /** * Event set for this schedule. */ private SortedSet eventSet[] = new SortedSet[7]; /** * The actual scheduler. */ private Scheduler scheduler; /** * Thermostat to control. */ private Thermostat ts; /** * URL to get the configuration from. */ private URL scheduleURL; /** * Persistent configuration. * * While the original (global) configuration defines the initial state, * this object stores all the changes so there's no need to touch the * global configuration. */ private Configuration persistentConf; public Schedule(Thermostat ts) { this.ts = ts; } protected void configure() throws Throwable { scheduler = new Scheduler(); scheduler.setLogger(getLogger()); String cfroot = getConfigurationRoot(); Configuration conf = getConfiguration(); String persistentDirName = conf.getString("dz.persistent_schedule"); File persistentDir = new File(persistentDirName); if ( !persistentDir.exists() ) { persistentDir.mkdirs(); if ( !persistentDir.exists() ) { throw new IllegalArgumentException(persistentDirName + ": unable to create"); } } File scheduleName = new File(persistentDir, ts.getName() + ".conf"); scheduleURL = new URL("file:" + scheduleName); Configuration cf = null; try { persistentConf = new ConfigurationFactory().getConfiguration(scheduleURL); complain(LOG_NOTICE, CH_SCHEDULE, "Reading persistent data from " + scheduleURL); } catch ( FileNotFoundException fnfex ) { complain(LOG_WARNING, CH_SCHEDULE, "Persistent data not found in " + scheduleURL + ", will store later"); persistentConf = new TextConfiguration(); } complain(LOG_DEBUG, CH_SCHEDULE, "Persistent configuration for " + ts.getName() + ":"); for ( Iterator ci = persistentConf.keySet().iterator(); ci.hasNext(); ) { String key = ci.next().toString(); complain(LOG_DEBUG, CH_SCHEDULE, "" + key + ": " + persistentConf.getString(key)); } persistentConf.setDefaultConfiguration(getConfiguration()); for ( int idx = 0; idx < 7; idx++ ) { String day = days[idx]; String dayRoot = cfroot + ".day." + day + ".period"; eventSet[idx] = new TreeSet(new EventComparator()); List eventNameList = persistentConf.getList(dayRoot); complain(LOG_DEBUG, CH_SCHEDULE, "Event list at " + dayRoot + ": " + eventNameList); for ( Iterator i = eventNameList.iterator(); i.hasNext(); ) { String eventName = i.next().toString(); try { TaskDescriptor td = createEvent(idx, day, eventName); eventSet[idx].add(td); Task t = new Command(ts, td, eventName); try { // VT: NOTE: Running a late task results in a mess // when the periods from the different days overlap. scheduler.schedule(t); } catch ( Throwable x ) { complain(LOG_ERR, CH_SCHEDULE, x.getMessage()); } } catch ( Throwable x2 ) { complain(LOG_ERR, CH_SCHEDULE, "Failed to create " + day + "/" + eventName + ", cause:", x2); } } } // Now that we know what exactly the schedule looks like, we can // just run the current event without hurry: ScheduleEvent current = getCurrentEvent(); if ( current != null ) { current.run(ts); } } /** * Create the event. * * Read the configuration values for the given set of arguments and try * to create the event out of them. * * @param dayOffset Day number (0 is Monday). * * @param dayName Weekday name. * * @param periodName Period name. */ private ScheduleEvent createEvent(int dayOffset, String dayName, String periodName) { String cfroot = getConfigurationRoot() + ".day." + dayName + ".period." + periodName; Configuration conf = getConfiguration(); // VT: NOTE: Configuration segment looks like this: // // <start_time> // XX // </start_time> // <setpoint enabled="true"> // XX // </setpoint> // <voting enabled="true"/> // <dump_priority> // XX // </dump_priority> String startTime = persistentConf.getString(cfroot + ".start_time", "00:00"); double setpoint = persistentConf.getDouble(cfroot + ".setpoint", 22); boolean enabled = persistentConf.getBoolean(cfroot + ".setpoint.enabled", true); boolean voting = persistentConf.getBoolean(cfroot + ".voting.enabled", true); int dumpPriority = persistentConf.getInteger(cfroot + ".dump_priority", 0); ScheduleEvent e = new ScheduleEvent(dayOffset, periodName, parseTime(startTime), setpoint, enabled, voting, dumpPriority); complain(LOG_DEBUG, CH_SCHEDULE, dayName + "/" + e); return e; } /** * @param time Time in HH:MM or NNNN format. * * @return Absolute value of that time for today in milliseconds. */ private long parseTime(String time) { long result = 0; // Find out if there's a semicolon if ( time.indexOf(":") == -1 ) { // No semicolon, treat it as a literal result = Long.parseLong(time); } else { // Full parse, expect 24 hour HH:MM StringTokenizer st = new StringTokenizer(time, ":"); String hours = st.nextToken(); String minutes = st.nextToken(); result = Long.parseLong(hours) * 60 + Long.parseLong(minutes); } // Now, figure out the milliseconds // Find the milliseconds value of the start of the day Calendar c = new GregorianCalendar(); c.set(Calendar.MILLISECOND, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); Date d = c.getTime(); //complain(LOG_WARNING, CH_SCHEDULE, "Day: " + d); //complain(LOG_WARNING, CH_SCHEDULE, "Today: " + new Date(d.getTime() + (result * 60 * 1000))); return d.getTime() + (result * 60 * 1000); } protected void startup() throws Throwable { scheduler.start(); } protected void shutdown(Throwable cause) throws Throwable { } /** * Return the set of events for the requested day. * * @param day Day of week, 0 being Monday. */ public SortedSet getEvents(int day) { return eventSet[day]; } /** * Get the currently running event. * * @return The event that is supposed to be run[ning] right now. */ public ScheduleEvent getCurrentEvent() { int today = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY; SortedSet s = getEvents(today); long currentOffset = RecurringTaskDescriptor.getOffset(System.currentTimeMillis()); ScheduleEvent current = null; //complain(LOG_NOTICE, CH_SCHEDULE, ts.getName() + ": current offset: " + currentOffset); try { ScheduleEvent first = (ScheduleEvent)s.first(); for ( Iterator i = s.iterator(); i.hasNext(); ) { ScheduleEvent e = (ScheduleEvent)i.next(); long offset = e.getStartOffset(); //complain(LOG_NOTICE, CH_SCHEDULE, ts.getName() + ": offset: " + offset + " " + e.getName()); if ( currentOffset > offset ) { current = e; } else { // We've reached the wrong one //complain(LOG_NOTICE, CH_SCHEDULE, ts.getName() + ": stepped beyond"); if ( e == first ) { // VT: NOTE: OK, the first period is already in the // future. This means that there was no period today // yet, and the one we're looking for is the last // one for yesterday.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?