TimeoutService.java :  » Net » Ganymed-SSH-2 » ch » ethz » ssh2 » util » Java Open Source

Java Open Source » Net » Ganymed SSH 2 
Ganymed SSH 2 » ch » ethz » ssh2 » util » TimeoutService.java

package ch.ethz.ssh2.util;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.LinkedList;

import ch.ethz.ssh2.log.Logger;

/**
 * TimeoutService (beta). Here you can register a timeout.
 * <p>
 * Implemented having large scale programs in mind: if you open many concurrent SSH connections
 * that rely on timeouts, then there will be only one timeout thread. Once all timeouts
 * have expired/are cancelled, the thread will (sooner or later) exit.
 * Only after new timeouts arrive a new thread (singleton) will be instantiated.
 * 
 * @author Christian Plattner, plattner@inf.ethz.ch
 * @version $Id: TimeoutService.java,v 1.2 2006/07/30 21:59:29 cplattne Exp $
 */
public class TimeoutService
{
  private static final Logger log = Logger.getLogger(TimeoutService.class);

  public static class TimeoutToken implements Comparable
  {
    private long runTime;
    private Runnable handler;

    private TimeoutToken(long runTime, Runnable handler)
    {
      this.runTime = runTime;
      this.handler = handler;
    }

    public int compareTo(Object o)
    {
      TimeoutToken t = (TimeoutToken) o;
      if (runTime > t.runTime)
        return 1;
      if (runTime == t.runTime)
        return 0;
      return -1;
    }
  }

  private static class TimeoutThread extends Thread
  {
    public void run()
    {
      synchronized (todolist)
      {
        while (true)
        {
          if (todolist.size() == 0)
          {
            timeoutThread = null;
            return;
          }

          long now = System.currentTimeMillis();

          TimeoutToken tt = (TimeoutToken) todolist.getFirst();

          if (tt.runTime > now)
          {
            /* Not ready yet, sleep a little bit */

            try
            {
              todolist.wait(tt.runTime - now);
            }
            catch (InterruptedException e)
            {
            }

            /* We cannot simply go on, since it could be that the token
             * was removed (cancelled) or another one has been inserted in
             * the meantime.
             */

            continue;
          }

          todolist.removeFirst();

          try
          {
            tt.handler.run();
          }
          catch (Exception e)
          {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.log(20, "Exeception in Timeout handler:" + e.getMessage() + "(" + sw.toString() + ")");
          }
        }
      }
    }
  }

  /* The list object is also used for locking purposes */
  private static final LinkedList todolist = new LinkedList();

  private static Thread timeoutThread = null;

  /**
   * It is assumed that the passed handler will not execute for a long time.
   * 
   * @param runTime
   * @param handler
   * @return a TimeoutToken that can be used to cancel the timeout.
   */
  public static final TimeoutToken addTimeoutHandler(long runTime, Runnable handler)
  {
    TimeoutToken token = new TimeoutToken(runTime, handler);

    synchronized (todolist)
    {
      todolist.add(token);
      Collections.sort(todolist);

      if (timeoutThread != null)
        timeoutThread.interrupt();
      else
      {
        timeoutThread = new TimeoutThread();
        timeoutThread.setDaemon(true);
        timeoutThread.start();
      }
    }

    return token;
  }

  public static final void cancelTimeoutHandler(TimeoutToken token)
  {
    synchronized (todolist)
    {
      todolist.remove(token);

      if (timeoutThread != null)
        timeoutThread.interrupt();
    }
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.