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();
+        }
+    }
+
+}