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 EDU.oswego.cs.dl.util.concurrent.SynchronizedLong;
025:
026: /**
027: * A schedulable runnable.<p>
028: *
029: * Subclasses should implement doRun() to do some real work.<p>
030: *
031: * setScheduler(RunnableScheduler) has to be invoked with a RunnableScheduler
032: * that has been started for the work to be performed. If the doRun() does
033: * not invoke setNextRun(), the link to the scheduler is removed.
034: *
035: * @see RunnableScheduler
036: *
037: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
038: * @author Scott.Stark@jboss.org
039: * @version $Revision: 57200 $
040: */
041: public abstract class SchedulableRunnable implements Comparable,
042: Runnable {
043:
044: // Attributes ----------------------------------------------------
045:
046: /**
047: * A unique identifier
048: */
049: private long id;
050:
051: /**
052: * The next run timestamp
053: */
054: private SynchronizedLong nextRun = new SynchronizedLong(0);
055:
056: /**
057: * The current scheduler
058: */
059: private RunnableScheduler scheduler;
060:
061: /**
062: * Whether we are running
063: */
064: private boolean running;
065:
066: /**
067: * Whether we should reschedule after the run
068: */
069: private boolean reschedule;
070:
071: // Static --------------------------------------------------------
072:
073: /**
074: * The next unique identifier
075: */
076: private static long nextId = 0;
077:
078: // Constructors --------------------------------------------------
079:
080: /**
081: * Constructs a new schedulable runnable.
082: */
083: public SchedulableRunnable() {
084: this .id = getNextId();
085: }
086:
087: // Public --------------------------------------------------------
088:
089: /**
090: * Gets the next run timestamp
091: *
092: * @return the next run
093: */
094: public long getNextRun() {
095: return nextRun.get();
096: }
097:
098: /**
099: * Sets the next run date<p>
100: *
101: * If it is linked to a scheduler, it is temporarily removed while the date
102: * is modified.
103: *
104: * @param nextRun the next run date
105: */
106: public synchronized void setNextRun(long nextRun) {
107: // Remove from scheduler
108: if (scheduler != null)
109: scheduler.remove(this );
110:
111: // Set the new run time
112: this .nextRun.set(nextRun);
113:
114: // If we are not running, add it to the scheduler otherwise
115: // remember we want adding back
116: if (running == false && scheduler != null) {
117: //log.debug("add to scheduler: " + this);
118: scheduler.add(this );
119: } else {
120: //log.debug("reschedule: " + this);
121: reschedule = true;
122: }
123: }
124:
125: /**
126: * Set the scheduler for this runnable
127: *
128: * @param scheduler pass null to remove the runnable from any scheduler
129: * @return the previous scheduler or null if there was no previous scheduler
130: */
131: public synchronized RunnableScheduler setScheduler(
132: RunnableScheduler scheduler) {
133: // Null operation
134: if (this .scheduler == scheduler)
135: return this .scheduler;
136:
137: // Remember the result
138: RunnableScheduler result = this .scheduler;
139:
140: // Remove from previous scheduler
141: if (this .scheduler != null)
142: this .scheduler.remove(this );
143:
144: // Set the new state
145: this .scheduler = scheduler;
146:
147: // This is a remove operation
148: if (scheduler == null)
149: reschedule = false;
150:
151: // If we are not running, add it to the scheduler otherwise
152: // remember we want adding
153: else if (running == false)
154: scheduler.add(this );
155: else
156: reschedule = true;
157:
158: // We are done
159: return result;
160: }
161:
162: /**
163: * Do the work, the scheduled runnable should do its work here
164: */
165: public abstract void doRun();
166:
167: // Runnable Implementation ---------------------------------------
168:
169: /**
170: * Runs doRun()<p>
171: *
172: * If setNextRun() is not invoked during the doRun(), the link to the
173: * scheduler is removed
174: */
175: public final void run() {
176: startRun();
177: try {
178: doRun();
179: } finally {
180: endRun();
181: }
182: }
183:
184: // Runnable Implementation ---------------------------------------
185:
186: public int compareTo(Object o) {
187: SchedulableRunnable other = (SchedulableRunnable) o;
188: long temp = this .nextRun.get() - other.nextRun.get();
189: if (temp < 0)
190: return -1;
191: if (temp > 0)
192: return +1;
193: temp = this .id - other.id;
194: if (temp < 0)
195: return -1;
196: if (temp > 0)
197: return +1;
198: return 0;
199: }
200:
201: // Object Overrides ----------------------------------------------
202:
203: public boolean equals(Object obj) {
204: return (compareTo(obj) == 0);
205: }
206:
207: // Protected -----------------------------------------------------
208:
209: // Package -------------------------------------------------------
210:
211: // Private -------------------------------------------------------
212:
213: /**
214: * Start the run
215: */
216: private synchronized void startRun() {
217: running = true;
218: }
219:
220: /**
221: * Check whether the work got rescheduled
222: */
223: private synchronized void endRun() {
224: running = false;
225: if (reschedule == true)
226: scheduler.add(this );
227: reschedule = false;
228: }
229:
230: /**
231: * Get the next identifier
232: */
233: private static synchronized long getNextId() {
234: return nextId++;
235: }
236:
237: // Inner Classes -------------------------------------------------
238: }
|