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