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; - } -}