ch.ethz.ssh2.util.TimeoutService Maven / Gradle / Ivy
Show all versions of ganymed-ssh2 Show documentation
/*
* Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
* Please refer to the LICENSE.txt for licensing details.
*/
package ch.ethz.ssh2.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import ch.ethz.ssh2.log.Logger;
/**
* TimeoutService (beta). Here you can register a timeout.
*
* 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
* @version $Id: TimeoutService.java 89 2014-04-07 14:36:24Z [email protected] $
*/
public class TimeoutService
{
private static final Logger log = Logger.getLogger(TimeoutService.class);
public static class TimeoutToken
{
private long runTime;
private Runnable handler;
private TimeoutToken(long runTime, Runnable handler)
{
this.runTime = runTime;
this.handler = handler;
}
}
private static class TimeoutThread extends Thread
{
@Override
public void run()
{
synchronized (todolist)
{
while (true)
{
if (todolist.size() == 0)
{
timeoutThread = null;
return;
}
long now = System.currentTimeMillis();
TimeoutToken tt = todolist.getFirst();
if (tt.runTime > now)
{
/* Not ready yet, sleep a little bit */
try
{
todolist.wait(tt.runTime - now);
}
catch (InterruptedException ignored)
{
}
/* 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.warning("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 TimeoutToken addTimeoutHandler(long runTime, Runnable handler)
{
TimeoutToken token = new TimeoutToken(runTime, handler);
synchronized (todolist)
{
todolist.add(token);
Collections.sort(todolist, new Comparator()
{
public int compare(TimeoutToken o1, TimeoutToken o2)
{
if (o1.runTime > o2.runTime)
return 1;
if (o1.runTime == o2.runTime)
return 0;
return -1;
}
});
if (timeoutThread != null)
timeoutThread.interrupt();
else
{
timeoutThread = new TimeoutThread();
timeoutThread.setDaemon(true);
timeoutThread.start();
}
}
return token;
}
public static void cancelTimeoutHandler(TimeoutToken token)
{
synchronized (todolist)
{
todolist.remove(token);
if (timeoutThread != null)
timeoutThread.interrupt();
}
}
}