comparison src/com/trilead/ssh2/util/TimeoutService.java @ 0:0ce5cc452d02

initial version
author Carl Byington <carl@five-ten-sg.com>
date Thu, 22 May 2014 10:41:19 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:0ce5cc452d02
1
2 package com.trilead.ssh2.util;
3
4 import java.io.PrintWriter;
5 import java.io.StringWriter;
6 import java.util.Collections;
7 import java.util.LinkedList;
8
9 import com.trilead.ssh2.log.Logger;
10
11
12 /**
13 * TimeoutService (beta). Here you can register a timeout.
14 * <p>
15 * Implemented having large scale programs in mind: if you open many concurrent SSH connections
16 * that rely on timeouts, then there will be only one timeout thread. Once all timeouts
17 * have expired/are cancelled, the thread will (sooner or later) exit.
18 * Only after new timeouts arrive a new thread (singleton) will be instantiated.
19 *
20 * @author Christian Plattner, plattner@trilead.com
21 * @version $Id: TimeoutService.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
22 */
23 public class TimeoutService {
24 private static final Logger log = Logger.getLogger(TimeoutService.class);
25
26 public static class TimeoutToken implements Comparable {
27 private long runTime;
28 private Runnable handler;
29
30 private TimeoutToken(long runTime, Runnable handler) {
31 this.runTime = runTime;
32 this.handler = handler;
33 }
34
35 public int compareTo(Object o) {
36 TimeoutToken t = (TimeoutToken) o;
37
38 if (runTime > t.runTime)
39 return 1;
40
41 if (runTime == t.runTime)
42 return 0;
43
44 return -1;
45 }
46 }
47
48 private static class TimeoutThread extends Thread {
49 public void run() {
50 synchronized (todolist) {
51 while (true) {
52 if (todolist.size() == 0) {
53 timeoutThread = null;
54 return;
55 }
56
57 long now = System.currentTimeMillis();
58 TimeoutToken tt = (TimeoutToken) todolist.getFirst();
59
60 if (tt.runTime > now) {
61 /* Not ready yet, sleep a little bit */
62 try {
63 todolist.wait(tt.runTime - now);
64 }
65 catch (InterruptedException e) {
66 }
67
68 /* We cannot simply go on, since it could be that the token
69 * was removed (cancelled) or another one has been inserted in
70 * the meantime.
71 */
72 continue;
73 }
74
75 todolist.removeFirst();
76
77 try {
78 tt.handler.run();
79 }
80 catch (Exception e) {
81 StringWriter sw = new StringWriter();
82 e.printStackTrace(new PrintWriter(sw));
83 log.log(20, "Exeception in Timeout handler:" + e.getMessage() + "(" + sw.toString() + ")");
84 }
85 }
86 }
87 }
88 }
89
90 /* The list object is also used for locking purposes */
91 private static final LinkedList todolist = new LinkedList();
92
93 private static Thread timeoutThread = null;
94
95 /**
96 * It is assumed that the passed handler will not execute for a long time.
97 *
98 * @param runTime
99 * @param handler
100 * @return a TimeoutToken that can be used to cancel the timeout.
101 */
102 public static final TimeoutToken addTimeoutHandler(long runTime, Runnable handler) {
103 TimeoutToken token = new TimeoutToken(runTime, handler);
104
105 synchronized (todolist) {
106 todolist.add(token);
107 Collections.sort(todolist);
108
109 if (timeoutThread != null)
110 timeoutThread.interrupt();
111 else {
112 timeoutThread = new TimeoutThread();
113 timeoutThread.setDaemon(true);
114 timeoutThread.start();
115 }
116 }
117
118 return token;
119 }
120
121 public static final void cancelTimeoutHandler(TimeoutToken token) {
122 synchronized (todolist) {
123 todolist.remove(token);
124
125 if (timeoutThread != null)
126 timeoutThread.interrupt();
127 }
128 }
129
130 }