Java tutorial
/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util.schedule; import java.util.ArrayList; import java.util.List; import java.util.Vector; import java.text.DateFormat; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A generic scheduler object which keeps track of events, when they should * be executed, deletion after invocation, etc. The basetime used when * doing any arithmetic with times is the epoch. The scheduler is * synchronized. * * Scheduled events have an interval property -- how often the event should * execute (in milliseconds). */ public class Schedule { private final Object _lock = new Object(); private long scheduleID; // Used for assigning unique event IDs private Vector schedule; // The actual events being scheduled, sorted // by ascending nextTime in the item private Log log = LogFactory.getLog(Schedule.class); public Schedule() { this.schedule = new Vector(); this.scheduleID = 0; } /** * Get the next global schedule identifier, and internally increment it. * * @return a globally unique identifier, for the next scheduled item. */ private long consumeNextGlobalID() { synchronized (_lock) { return this.scheduleID++; } } /** * Insert a pre-made ScheduledItem into the schedule. The item should * already have all appropriate attributes assigned (including the ID). * * @param item The item to be inserted into the schedule */ private void insertScheduledItem(ScheduledItem item) { int i, size = this.schedule.size(); long nextTime = item.getNextTime(); ScheduledItem x; for (i = 0; i < size; i++) { x = (ScheduledItem) this.schedule.get(i); if (x.getNextTime() > nextTime) { this.schedule.add(i, item); return; } } // Else add at the end of the vector (time greater than all others) this.schedule.add(item); } /** * Add an item to the internal schedule. * * @param item the object to schedule * @param interval the number of seconds between invocations of the item * @param prev true if the item should be scheduled in the past to * force immediate firing. * @param repeat true if the item should stay in the schedule even after * its time has expired * @throws UnscheduledItemException If the given schedule interval is <= 0 * * @return a global identifier for the scheduled item */ public synchronized long scheduleItem(Object item, long interval, boolean prev, boolean repeat) throws ScheduleException { long itemId; ScheduledItem newItem; if (interval <= 0) { throw new ScheduleException("Invalid schedule interval given (" + interval + ")"); } itemId = this.consumeNextGlobalID(); newItem = new ScheduledItem(item, interval, prev, repeat, itemId); this.insertScheduledItem(newItem); return itemId; } /** * Add an item to the internal schedule. * * @param item the object to schedule * @param interval the number of seconds between invocations of the item * @param repeat true if the item should stay in the schedule even after * its time has expired * * @return a global identifier for the scheduled item */ public synchronized long scheduleItem(Object item, long interval, boolean repeat) throws ScheduleException { return this.scheduleItem(item, interval, false, repeat); } /** * Add an item to the internal schedule, with the repeat flag set to true. * See the documentation for scheduleItem for more information. */ public long scheduleItem(Object item, long interval) throws ScheduleException { return this.scheduleItem(item, interval, true); } /** * Remove an item from the schedule. Scheduled items which have not * been consumed may be unscheduled by using this method. * * @param id ID returned by a call to scheduleItem of the item to remove * * @throws UnscheduledItemException indicating the ID was not found. */ public synchronized ScheduledItem unscheduleItem(long id) throws UnscheduledItemException { int i, size = this.schedule.size(); for (i = 0; i < size; i++) { ScheduledItem item = (ScheduledItem) this.schedule.get(i); if (item.getId() == id) { if (log.isDebugEnabled()) { log.debug("unscheduling " + item.getObj() + " getNextTime " + getDateStr(item.getNextTime())); } return (ScheduledItem) this.schedule.remove(i); } } throw new UnscheduledItemException("id '" + id + "' not found"); } /** * Get the time that the next scheduled item is to be executed. The * returned time is in UTC since the epoch (similar to * System.currentTimeMillis()) * * @return the absolute the the next event is to be executed * * @throws EmptyScheduleException indicating there is no next item for * which the time can be retrieved. */ public synchronized long getTimeOfNext() throws EmptyScheduleException { int size = this.schedule.size(); ScheduledItem item; if (size == 0) throw new EmptyScheduleException(); item = (ScheduledItem) this.schedule.get(0); return item.getNextTime(); } /** * Get the next item (or items) to be executed. If more than one item * is scheduled for a specific time, they are all returned. Items * returned by this function are re-inserted into the schedule, if their * repeat flag is set to true -- otherwise they are removed. * * @return a list of items to execute * * @throws EmptyScheduleException indicating there was no 'next item' */ public synchronized List consumeNextItems() throws EmptyScheduleException { int size = this.schedule.size(); ScheduledItem base; ArrayList res; long baseNextTime; if (size == 0) throw new EmptyScheduleException(); res = new ArrayList(1); // We always add the first item to the list of returned objects base = (ScheduledItem) this.schedule.get(0); baseNextTime = System.currentTimeMillis(); res.add(base); boolean debug = log.isDebugEnabled(); // Now add other items if they occur at the same time for (int i = 1; i < size; i++) { ScheduledItem other = (ScheduledItem) this.schedule.get(i); if (debug) { log.debug("checking " + other.getObj() + " baseNextTime: " + getDateStr(baseNextTime) + ", getNextTime: " + getDateStr(other.getNextTime())); } if (other.getNextTime() <= baseNextTime) { res.add(other); } else { break; } } // Finally, loop through the objects we are about to return, so // we can re-order our innards, and return the actual objects // stored instead of the ScheduledItem // XXX -- This could be MUCH more efficient, especially with respect // to re-inserting into the list, since all of the returned // objects are of the same size. for (int i = 0; i < res.size(); i++) { ScheduledItem other = (ScheduledItem) res.get(i); if (debug) { log.debug("removing " + other.getObj()); } this.schedule.remove(other); if (other.isRepeat()) { other.stepNextTime(); if (debug) { log.debug("adding " + other.getObj() + " getNextTime " + getDateStr(other.getNextTime())); } this.insertScheduledItem(other); } res.set(i, other.getObj()); } return res; } private static String getDateStr(long timems) { return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT) .format(new java.util.Date(timems)); } /** * Get the number of items in the schedule. * * @return the number of items in the schedule. */ public int getNumItems() { return this.schedule.size(); } /** * Get a list of all the currently scheduled items. * * @return the list of scheduled items. */ public ScheduledItem[] getScheduledItems() { return (ScheduledItem[]) this.schedule.toArray(new ScheduledItem[0]); } public static void main(String args[]) throws Exception { Schedule s = new Schedule(); s.scheduleItem(new Integer(30), 30 * 1000, true); s.scheduleItem(new Integer(5), 5 * 1000, true); long id_for_8 = s.scheduleItem(new Integer(8), 8 * 1000, true); s.scheduleItem(new Integer(10), 10 * 1000, false); int secondsRunning = 0; while (true) { System.out.println(System.currentTimeMillis() / 1000); if (System.currentTimeMillis() > s.getTimeOfNext()) { List items = s.consumeNextItems(); System.out.println("Consuming"); for (int i = 0; i < items.size(); i++) { System.out.println("Consumed: " + (Integer) items.get(i)); } } Thread.sleep(1000); secondsRunning++; if (secondsRunning > 10 && id_for_8 != -1) { s.unscheduleItem(id_for_8); System.out.println("Removing 8"); id_for_8 = -1; } if (secondsRunning > 20) System.exit(0); } } }