Mercurial > 510Connectbot
diff app/src/main/java/ch/ethz/ssh2/util/TimeoutService.java @ 438:d29cce60f393
migrate from Eclipse to Android Studio
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 03 Dec 2015 11:23:55 -0800 |
parents | src/ch/ethz/ssh2/util/TimeoutService.java@071eccdff8ea |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/src/main/java/ch/ethz/ssh2/util/TimeoutService.java Thu Dec 03 11:23:55 2015 -0800 @@ -0,0 +1,133 @@ +/* + * 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. + * <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 + * @version $Id: TimeoutService.java 89 2014-04-07 14:36:24Z dkocher@sudo.ch $ + */ +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<TimeoutToken> todolist = new LinkedList<TimeoutService.TimeoutToken>(); + + 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<TimeoutToken>() { + 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(); + } + } + +}