1 /*-----------------------------------------------------------------------------
2 Name: Timeout.h
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Allows you be called back after a given delay.
6 -----------------------------------------------------------------------------*/
7
8 #ifndef _UTIL_TIMEOUT_H
9 #define _UTIL_TIMEOUT_H
10
11 #include <util/xmlBlasterDef.h>
12 #include <util/I_Timeout.h>
13 #include <util/Timestamp.h>
14
15 #include <string>
16 #include <map>
17 #include <util/thread/ThreadImpl.h>
18
19 namespace org { namespace xmlBlaster { namespace util {
20
21 typedef std::pair<I_Timeout*, void*> Container;
22 typedef std::map<org::xmlBlaster::util::Timestamp, Container> TimeoutMap;
23
24
25 /**
26 * Allows you be called back after a given delay.
27 * <p />
28 * Note that this class should be called Timer, but with JDK 1.3 there
29 * will be a java.util.Timer.
30 * <p />
31 * There is a single background thread that is used to execute the I_Timeout.timeout() callback.
32 * Timer callbacks should complete quickly. If a timeout() takes excessive time to complete, it "hogs" the timer's
33 * task execution thread. This can, in turn, delay the execution of subsequent tasks, which may "bunch up" and execute in
34 * rapid succession when (and if) the offending task finally completes.
35 * <p />
36 * This singleton is thread-safe.
37 * <p />
38 * This class does not offer real-time guarantees, but usually notifies you within ~ 20 milliseconds
39 * of the scheduled time.
40 * <p />
41 * Adding or removing a timer is good performing, also when huge amounts of timers (> 1000) are used.<br />
42 * Feeding of 10000: 10362 adds/sec and all updates came in 942 millis (600MHz Linux PC with Sun JDK 1.3.1)
43 * * <p />
44 * TODO: Use a thread pool to dispatch the timeout callbacks.
45 * <p />
46 * Example:<br />
47 * <pre>
48 * public class MyClass implements I_Timeout {
49 * ...
50 * Timeout timeout = new Timeout("TestTimer");
51 * org::xmlBlaster::util::Timestamp timeoutHandle = timeout.addTimeoutListener(this, 4000L, "myTimeout");
52 * ...
53 * public void timeout(Object userData) {
54 * // userData contains String "myTimeout"
55 * System.out.println("Timeout happened");
56 * ...
57 * // If you want to activate the timer again:
58 * timeoutHandle = timeout.addTimeoutListener(this, 4000L, "myTimeout");
59 * }
60 * ...
61 * // if you want to refresh the timer:
62 * timeoutHandle = timeout.refreshTimeoutListener(timeoutHandle, 1500L);
63 * ...
64 * }
65 * </pre>
66 * Or a short form:
67 * <pre>
68 * Timeout timeout = new Timeout("TestTimer");
69 * org::xmlBlaster::util::Timestamp timeoutHandle = timeout.addTimeoutListener(new I_Timeout() {
70 * public void timeout(Object userData) {
71 * System.out.println("Timeout happened");
72 * System.exit(0);
73 * }
74 * },
75 * 2000L, null);
76 * </pre>
77 *
78 *
79 * @author xmlBlaster@marcelruff.info
80 * @author laghi@swissinfo.org
81 */
82 class Dll_Export Timeout : public org::xmlBlaster::util::thread::Thread
83 {
84
85 private:
86 /** Name for logging output */
87 std::string ME; // = "Timeout";
88 std::string threadName_;
89 // boost::thread* runningThread_;
90 /** Sorted std::map */
91 TimeoutMap timeoutMap_;
92 // private TreeMap std::map = null;
93 /** Start/Stop the Timeout manager thread */
94 bool isRunning_; // = true;
95 /** On creation wait until thread started */
96 bool isReady_; // = false;
97
98 /** To protect thread gap **/
99 bool mapHasNewEntry_;
100
101 /** is set to false once the thread is finished (for cleanup) */
102 bool isActive_;
103 /** Switch on debugging output */
104 const bool isDebug_; // = false;
105
106 const bool detached_;
107
108 org::xmlBlaster::util::TimestampFactory& timestampFactory_;
109
110 org::xmlBlaster::util::Global& global_;
111 org::xmlBlaster::util::I_Log& log_;
112
113 /** The synchronization object */
114 org::xmlBlaster::util::thread::Mutex invocationMutex_;
115 org::xmlBlaster::util::thread::Mutex waitForTimeoutMutex_;
116 org::xmlBlaster::util::thread::Condition waitForTimeoutCondition_;
117
118 size_t getTimeoutMapSize();
119
120 /**
121 * Starts the thread
122 */
123 bool start(bool detached);
124
125 // friend class TimeoutRunner;
126 public:
127
128 /**
129 * Create a timer thread.
130 */
131 Timeout(org::xmlBlaster::util::Global& global);
132
133 /**
134 * Create a timer thread.
135 */
136 Timeout(org::xmlBlaster::util::Global& global, const std::string &name);
137
138 ~Timeout();
139
140 /**
141 * Used to join the thread used by this instance.
142 * Don't call this method for detached running threads.
143 */
144 void join();
145
146 /** the run method (what has to be done inside a thread */
147 // void operator()();
148
149 /**
150 * Get number of current used timers.
151 * @return The number of active timers
152 */
153 int getSize() const {
154 return (int)timeoutMap_.size();
155 }
156
157 /**
158 * Add a listener which gets informed after 'delay' milliseconds.<p />
159 *
160 * After the timeout happened, you are not registered any more. If you
161 * want to cycle timeouts, you need to register again.<p />
162 *
163 * @param listener
164 * Your callback handle (you need to implement this interface).
165 * @param delay
166 * The timeout in milliseconds.
167 * @param userData
168 * Some arbitrary data you supply, it will be routed back
169 * to you when the timeout occurs through method
170 * I_Timeout.timeout().
171 * @return A handle which you can use to unregister with
172 * removeTimeoutListener().
173 * @throws XmlBlasterException if timer is not started
174 */
175 org::xmlBlaster::util::Timestamp addTimeoutListener(I_Timeout *listener, long delay, void *userData);
176
177 /**
178 * Refresh a listener before the timeout happened.<p />
179 *
180 * NOTE: The returned timeout handle is different from the original one.<p />
181 *
182 * NOTE: If you are not sure if the key has elapsed already try this:
183 * <pre>
184 * timeout.removeTimeoutListener(timeoutHandle);
185 * timeoutHandle = timeout.addTimeoutListener(this, "1000L", "UserData");
186 * </pre>
187 * @param key
188 * The timeout handle you received by a previous
189 * addTimeoutListener() call.<br />
190 * It is invalid after this call.
191 * @param delay
192 * The timeout in milliseconds measured from now.
193 * @return A new handle which you can use to unregister with
194 * removeTimeoutListener().
195 * -1: if key is null or unknown or invalid because timer elapsed already
196 * @throws XmlBlasterException if key<0 or timer is not started
197 */
198 org::xmlBlaster::util::Timestamp refreshTimeoutListener(org::xmlBlaster::util::Timestamp key, long delay);
199
200 /**
201 * Checks if key is 0 -> addTimeoutListener else refreshTimeoutListener()
202 * in a thread save way.
203 * @param key If <= 0 we add a new timer, else lookup given key and refresh
204 * @throws XmlBlasterException if timer is not started
205 */
206 org::xmlBlaster::util::Timestamp addOrRefreshTimeoutListener(I_Timeout *listener,
207 long delay, void *userData, org::xmlBlaster::util::Timestamp key);
208 // throws org::xmlBlaster::util::XmlBlasterException
209
210 /**
211 * Remove a listener before the timeout happened.<p />
212 *
213 * @param key
214 * The timeout handle you received by a previous
215 * addTimeoutListener() call.
216 */
217 void removeTimeoutListener(org::xmlBlaster::util::Timestamp key);
218
219 /**
220 * Is this handle expired?<p />
221 *
222 * @param key
223 * The timeout handle you received by a previous
224 * addTimeoutListener() call<br />
225 * @return true/false
226 */
227 bool isExpired(org::xmlBlaster::util::Timestamp key);
228
229 /**
230 * How long to my timeout.<p />
231 *
232 * @param key
233 * The timeout handle you received by a previous
234 * addTimeoutListener() call.
235 * @return Milliseconds to timeout, or -1 if not known.
236 */
237 long spanToTimeout(org::xmlBlaster::util::Timestamp key);
238
239 /**
240 * Access the end of life span.<p />
241 *
242 * @param key
243 * The timeout handle you received by a previous
244 * addTimeoutListener() call.
245 * @return Time in milliseconds since midnight, January 1, 1970 UTC
246 * or -1 if not known.
247 */
248 long getTimeout(org::xmlBlaster::util::Timestamp key);
249
250 /**
251 * Reset all pending timeouts.<p />
252 */
253 void removeAll();
254
255 /**
256 * Reset and stop the Timeout manager thread.
257 */
258 void shutdown();
259
260 void run();
261
262 };
263
264 }}} // namespaces
265
266 #endif
syntax highlighted by Code2HTML, v. 0.9.1