diff --git a/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java b/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java
index e0375f75..42621e78 100644
--- a/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java
+++ b/projects/samskivert/src/java/com/samskivert/servlet/user/UserManager.java
@@ -32,7 +32,6 @@ import com.samskivert.servlet.RedirectException;
import com.samskivert.servlet.util.CookieUtil;
import com.samskivert.servlet.util.RequestUtils;
import com.samskivert.util.Interval;
-import com.samskivert.util.IntervalManager;
import com.samskivert.util.StringUtil;
/**
@@ -130,8 +129,8 @@ public class UserManager
}
// register a cron job to prune the session table every hour
- Interval pruner = new Interval() {
- public void intervalExpired (int id, Object arg)
+ _pruner = new Interval() {
+ public void expired ()
{
try {
_repository.pruneSessions();
@@ -141,8 +140,7 @@ public class UserManager
}
}
};
- _prunerid = IntervalManager.register(pruner, SESSION_PRUNE_INTERVAL,
- null, true);
+ _pruner.schedule(SESSION_PRUNE_INTERVAL, true);
}
/**
@@ -159,7 +157,7 @@ public class UserManager
public void shutdown ()
{
// cancel our session table pruning thread
- IntervalManager.remove(_prunerid);
+ _pruner.cancel();
}
/**
@@ -321,8 +319,8 @@ public class UserManager
/** The user repository. */
protected UserRepository _repository;
- /** The interval id for the user session pruning interval. */
- protected int _prunerid = -1;
+ /** The interval for user session pruning. */
+ protected Interval _pruner;
/** The URL for the user login page. */
protected String _loginURL;
diff --git a/projects/samskivert/src/java/com/samskivert/util/AuditLogger.java b/projects/samskivert/src/java/com/samskivert/util/AuditLogger.java
index aec00dd0..817a3c2e 100644
--- a/projects/samskivert/src/java/com/samskivert/util/AuditLogger.java
+++ b/projects/samskivert/src/java/com/samskivert/util/AuditLogger.java
@@ -23,7 +23,6 @@ import com.samskivert.Log;
* collection, processing and possible archiving of the logs.
*/
public class AuditLogger
- implements Interval
{
/**
* Creates an audit logger that logs to the specified file.
@@ -119,8 +118,10 @@ public class AuditLogger
}
}
- // documentation inherited from interface Interval
- public synchronized void intervalExpired (int id, Object arg)
+ /**
+ * Check to see if it's time to roll over the log file.
+ */
+ protected synchronized void checkRollOver ()
{
// check to see if we should roll over the log
String newDayStamp = _dayFormat.format(new Date());
@@ -160,7 +161,7 @@ public class AuditLogger
(59L - cal.get(Calendar.SECOND)) * 1000L +
(59L - cal.get(Calendar.MINUTE)) * (1000L * 60L);
- IntervalManager.register(this, nextCheck, null, false);
+ _rollover.schedule(nextCheck);
}
/** The path to our log file. */
@@ -169,6 +170,13 @@ public class AuditLogger
/** We actually write to this feller here. */
protected PrintWriter _logWriter;
+ /** The interval that rolls over the log file. */
+ protected Interval _rollover = new Interval() {
+ public void expired () {
+ checkRollOver();
+ }
+ };
+
/** Suppress freakouts if our log file becomes hosed. */
protected Throttle _throttle = new Throttle(2, 5*60*1000L);
diff --git a/projects/samskivert/src/java/com/samskivert/util/Interval.java b/projects/samskivert/src/java/com/samskivert/util/Interval.java
index b301b517..cbc6cc07 100644
--- a/projects/samskivert/src/java/com/samskivert/util/Interval.java
+++ b/projects/samskivert/src/java/com/samskivert/util/Interval.java
@@ -20,14 +20,163 @@
package com.samskivert.util;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.samskivert.Log;
+
/**
- * An interface for doing operations after some delay. Normally,
- * intervalExpired() should not do anything that will take
- * very long.
- *
- * @see IntervalManager
+ * An interface for doing operations after some delay.
*/
-public interface Interval
+public abstract class Interval
+ implements Runnable
{
- public void intervalExpired (int id, Object arg);
+ /**
+ * Create a simple interval that does not use a RunQueue to run
+ * the expire() method.
+ */
+ public Interval ()
+ {
+ }
+
+ /**
+ * Create an Interval that uses the specified RunQueue to run
+ * the expire() method.
+ */
+ public Interval (RunQueue runQueue)
+ {
+ if (runQueue == null) {
+ throw new NullPointerException("RunQueue cannot be null, " +
+ "use other constructor if you want a simple Interval.");
+ }
+ _runQueue = runQueue;
+ }
+
+ /**
+ *
+ * The main method where your interval should do its work.
+ *
+ */
+ public abstract void expired ();
+
+ /**
+ * Schedule the interval to execute once, after the specified delay.
+ */
+ public final void schedule (long delay)
+ {
+ schedule(delay, 0L);
+ }
+
+ /**
+ * Schedule the interval to execute repeatedly, with the same delay.
+ */
+ public final void schedule (long delay, boolean repeat)
+ {
+ schedule(delay, repeat ? delay : 0L);
+ }
+
+ /**
+ * Schedule the interval to execute repeatedly with the specified
+ * initial delay and repeat delay.
+ */
+ public final void schedule (long initialDelay, long repeatDelay)
+ {
+ cancel();
+ _task = new TimerTask() {
+ public void run () {
+ if (this != _task) {
+ return;
+ }
+
+ // if the Interval is operating in simple mode,
+ // just expire here
+ if (_runQueue == null) {
+ safelyExpire();
+ return;
+ }
+
+ // else we need to make sure we want to run
+ // and post the Runnable
+ synchronized (this) {
+ if (_fired != -1) {
+ _fired++;
+ _runQueue.postRunnable(Interval.this);
+ }
+ }
+ }
+ };
+
+ synchronized (_task) {
+ _fired = _expired = 0;
+ if (repeatDelay == 0L) {
+ _timer.schedule(_task, initialDelay);
+ } else {
+ _timer.scheduleAtFixedRate(_task, initialDelay, repeatDelay);
+ }
+ }
+ }
+
+ /**
+ * Cancel the Interval, and ensure that any expirations that are queued
+ * up but have not yet run do not run.
+ */
+ public final void cancel ()
+ {
+ if (_task != null) { // task can only be null if we were never scheduled
+ synchronized (_task) {
+ _task.cancel();
+ _fired = -1;
+ }
+ }
+ }
+
+ // documentation inherited from interface Runnable
+ public final void run ()
+ {
+ if (_expired >= _fired) {
+ // we are a dead interval. We were queued up prior to cancel()
+ // being called, but we are now running after cancel()
+ return;
+ }
+
+ // increment expired and scoot everything back if we're getting too big
+ _expired++;
+ if (_expired > Integer.MAX_VALUE/2) {
+ synchronized (_task) {
+ _expired -= Integer.MAX_VALUE/2;
+ _fired -= Integer.MAX_VALUE/2;
+ }
+ }
+
+ safelyExpire();
+ }
+
+ /**
+ * Safely expire the interval.
+ */
+ protected final void safelyExpire ()
+ {
+ try {
+ expired();
+ } catch (Throwable t) {
+ Log.warning("Interval broken in expired(): " + t);
+ Log.logStackTrace(t);
+ }
+ }
+
+ /** Counters used to guarantee that we don't fuck up. */
+ protected int _fired = -1, _expired = 0;
+
+ /** If non-null, the RunQueue used to run the expired() method for each
+ * Interval. */
+ protected RunQueue _runQueue;
+
+ /** The task that actually schedules our execution with the static Timer.
+ * Also the object that we synchronize upon when dealing with those issues.
+ */
+ protected TimerTask _task;
+
+ /** The daemon timer used to schedule all Intervals. */
+ protected static final Timer _timer =
+ new Timer(/*JDK1.5 "samskivert Interval Timer",*/ true);
}
diff --git a/projects/samskivert/src/java/com/samskivert/util/IntervalManager.java b/projects/samskivert/src/java/com/samskivert/util/IntervalManager.java
deleted file mode 100644
index d044e389..00000000
--- a/projects/samskivert/src/java/com/samskivert/util/IntervalManager.java
+++ /dev/null
@@ -1,206 +0,0 @@
-//
-// $Id: IntervalManager.java,v 1.10 2003/08/13 21:04:12 mdb Exp $
-//
-// samskivert library - useful routines for java programs
-// Copyright (C) 2001 Michael Bayne
-//
-// This library is free software; you can redistribute it and/or modify it
-// under the terms of the GNU Lesser General Public License as published
-// by the Free Software Foundation; either version 2.1 of the License, or
-// (at your option) any later version.
-//
-// This library 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
-// Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-package com.samskivert.util;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-import com.samskivert.Log;
-
-/**
- * Can be used to register an object that is to be called once or
- * repeatedly after an interval has expired. This now uses {@link Timer}
- * to do all the actual scheduling, but we keep this front end because it
- * is static (accessible anywhere), provides a single thread where
- * disparate simple intervals can all run happily, and because {@link
- * Interval} is an interface, unlike {@link TimerTask}, which is an
- * abstract class.
- */
-public class IntervalManager
-{
- /**
- * Schedules the intervaled object to get called after an interval.
- *
- * @param i the intervaled object
- * @param delay the milliseconds until the interval expires.
- * @param arg the object to be passed to the interval when the
- * interval delay expires.
- * @param recur if true, interval gets called every timeout until
- * removed.
- *
- * @return an ID number that will passed to the {@link
- * Interval#intervalExpired} method of i along with arg
- */
- public static int register (
- Interval i, long delay, Object arg, boolean recur)
- {
- IntervalTask task = new IntervalTask(i, arg, recur);
- _hash.put(task.id, task);
-
- if (recur) {
- _timer.scheduleAtFixedRate(task, delay, delay);
- } else {
- _timer.schedule(task, delay);
- }
-
- return task.id;
- }
-
- /**
- * Schedule the interval to be called repeatedly, but at a fixed delay
- * instead of fixed rate. This means that the delay between executions
- * will be the delay specified below plus the actual execution time it
- * takes to run the interval's expire method.
- */
- public static int registerAtFixedDelay (Interval i, long delay, Object arg)
- {
- IntervalTask task = new IntervalTask(i, arg, true);
- _hash.put(task.id, task);
- _timer.schedule(task, delay, delay);
- return task.id;
- }
-
- /**
- * Non-recurring intervals are removed automatically after they are
- * run! This method is only useful if you want to remove a recurring
- * {@link Interval} or if you want to remove a non-recurring {@link
- * Interval} before it gets run.
- */
- public static void remove (int id)
- {
- IntervalTask task = (IntervalTask) _hash.remove(id);
- if (task != null) {
- task.cancel();
- } else {
- Log.warning("remove() called on non-registered " +
- "interval [id=" + id + "].");
- }
- }
-
- /**
- * Turn on or off logging of all interval firings.
- */
- public static void setLogIntervals (boolean log)
- {
- _logging = log;
- }
-
- /**
- * Returns the total number of intervals registered.
- */
- public static int registeredIntervalCount ()
- {
- return _hash.size();
- }
-
- /**
- * Returns the number of intervals fired since the last call to this
- * method.
- */
- public static int getAndClearFiredIntervals ()
- {
- int fired;
- synchronized (_hash) {
- fired = _firedIntervals;
- _firedIntervals = 0;
- }
- return fired;
- }
-
- /** The timer we use to schedule everything. */
- protected static Timer _timer = new Timer(true);
-
- /** Our registered intervals, indexed by id. */
- protected static IntMap _hash =
- Collections.synchronizedIntMap(new HashIntMap());
-
- /** Whether or not we're logging interval fires. */
- protected static boolean _logging = false;
-
- /** Used by {@link #getAndClearFiredIntervals}. */
- protected static int _firedIntervals;
-
- /**
- * A class to adapt {@link TimerTask} to the smooth action of {@link
- * Interval}.
- */
- static class IntervalTask extends TimerTask
- {
- public int id;
- protected Interval _i;
- protected Object _arg;
- protected boolean _onetime;
- protected String _source;
-
- public IntervalTask (Interval i, Object arg, boolean recur)
- {
- _i = i;
- _arg = arg;
- _onetime = !recur;
- id = nextID();
- try {
- _source = new Throwable().getStackTrace()[2].toString();
- } catch (Throwable oopsie) {
- _source = "";
- }
- }
-
- /**
- * Run the interval. It's synchronized so that if we someday have
- * multiple threads, the same interval won't be called multiple
- * times.
- */
- public void run ()
- {
- if (_logging) {
- System.err.println("Interval fired [source=" + _source + "]");
- }
-
- // note that we fired another interval
- synchronized (_hash) {
- _firedIntervals++;
- }
-
- // protect our ass.
- try {
- _i.intervalExpired(id, _arg);
- } catch (Exception e) {
- Log.warning("Exception while expiring interval: " + e);
- Log.logStackTrace(e);
- }
-
- // if we're not recurring, be sure to remove from the mgr's hash
- if (_onetime) {
- _hash.remove(id);
- }
- }
-
- /**
- * Unique ids for each interval item.
- */
- private static synchronized int nextID ()
- {
- return _idseq++;
- }
-
- private static int _idseq = 0;
- }
-}