001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.util;
023:
024: import java.util.Iterator;
025: import java.util.TreeSet;
026:
027: /**
028: * A runnable scheduler.<p>
029: *
030: * The scheduler needs to be started to do real work. To add work to the
031: * scheduler, create a SchedulableRunnable and set the scheduler. When
032: * the next run has passed the work is performed.
033: *
034: * @see SchedulableRunnable
035: *
036: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
037: * @version $Revision: 57200 $
038: */
039: public class RunnableScheduler implements Runnable {
040: // Attributes ----------------------------------------------------
041:
042: /**
043: * The runnables to schedule
044: */
045: private TreeSet runnables = new TreeSet();
046:
047: /**
048: * The thread pool used to process the runnables.
049: */
050: private ThreadPool threadPool;
051:
052: /**
053: * The controller thread.
054: */
055: private Thread controller = null;
056:
057: // Static --------------------------------------------------------
058:
059: // Constructors --------------------------------------------------
060:
061: /**
062: * Constructs a new runnable scheduler.
063: */
064: public RunnableScheduler() {
065: }
066:
067: /**
068: * Start the scheduler
069: */
070: public synchronized void start() {
071: //log.debug("start");
072: if (controller != null)
073: return;
074: controller = new Thread(this );
075: controller.setDaemon(true);
076: controller.start();
077: }
078:
079: /**
080: * Stop the scheduler
081: */
082: public synchronized void stop() {
083: //log.debug("stop");
084: if (controller == null)
085: return;
086: controller.interrupt();
087: controller = null;
088: }
089:
090: /**
091: * Run the scheduler
092: */
093: public void run() {
094: // Start the threadpool
095: threadPool = new ThreadPool();
096: threadPool.setActive(true);
097: try {
098: // Do outstanding work until stopped
099: while (true) {
100: try {
101: runOutstanding();
102: waitOutstanding();
103: } catch (InterruptedException weAreDone) {
104: //log.debug("interupted");
105: break;
106: }
107: }
108: } finally {
109: // Stop the thread pool
110: threadPool.setActive(false);
111: threadPool = null;
112: }
113: }
114:
115: // Public --------------------------------------------------------
116:
117: // X Implementation ----------------------------------------------
118:
119: // Y Overrides ---------------------------------------------------
120:
121: // Protected -----------------------------------------------------
122:
123: // Package -------------------------------------------------------
124:
125: /**
126: * Add a schedulable runnable
127: *
128: * @param runnable the runnable to add
129: */
130: synchronized void add(SchedulableRunnable runnable) {
131: runnables.add(runnable);
132: notifyAll();
133: }
134:
135: /**
136: * Remove a schedulable runnable
137: *
138: * @param runnable the runnable to add
139: */
140: synchronized void remove(SchedulableRunnable runnable) {
141: runnables.remove(runnable);
142: }
143:
144: /**
145: * Check whether the scheduler contains a runnable
146: *
147: * @param runnable the runnable to check
148: * @return true when the runnable is present, false otherwise
149: */
150: synchronized boolean contains(SchedulableRunnable runnable) {
151: return runnables.contains(runnable);
152: }
153:
154: // Private -------------------------------------------------------
155:
156: /**
157: * Run all outstanding runnables, they are in date order
158: */
159: private synchronized void runOutstanding() {
160: long current = System.currentTimeMillis();
161: Iterator iterator = runnables.iterator();
162: while (iterator.hasNext()) {
163: SchedulableRunnable next = (SchedulableRunnable) iterator
164: .next();
165: if (next.getNextRun() <= current) {
166: //log.debug("runOutstanding: " + next);
167: iterator.remove();
168: threadPool.run(next);
169: } else {
170: //log.debug("runOutstanding: break");
171: break;
172: }
173: }
174: }
175:
176: /**
177: * Wait for the next outstanding runnable
178: */
179: private synchronized void waitOutstanding()
180: throws InterruptedException {
181: // There is nothing to run
182: if (runnables.size() == 0) {
183: //log.debug("waitOutstanding_1");
184: wait();
185: //log.debug("waitOutstanding_1 - wakeup");
186: } else {
187: // Wait until the next runnable
188: SchedulableRunnable next = (SchedulableRunnable) runnables
189: .first();
190: long current = System.currentTimeMillis();
191: long wait = next.getNextRun() - current;
192: //log.debug("waitOutstanding_2 until: " + new Date(current + wait));
193: if (wait > 0)
194: wait(wait);
195: //log.debug("waitOutstanding_2 - wakeup");
196: }
197: }
198:
199: // Inner Classes -------------------------------------------------
200: }
|