1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.debug.core.model;
15 
16 /**
17  * A timer notifies listeners when a specific amount of time has passed.
18  *
19  * @see ITimeoutListener
20  */
21 public class Timer {
22 
23 	/**
24 	 * Listener to notify of a timeout
25 	 */
26 	private ITimeoutListener fListener;
27 
28 	/**
29 	 * Timeout value, in milliseconds
30 	 */
31 	private int fTimeout;
32 
33 	/**
34 	 * Whether this timer's thread is alive
35 	 */
36 	private boolean fAlive = true;
37 
38 	/**
39 	 * Whether this timer has been started and has not yet timed out or been
40 	 * stopped.
41 	 */
42 	private boolean fStarted = false;
43 
44 	/**
45 	 * The single thread used for each request.
46 	 */
47 	private Thread fThread;
48 
49 	/**
50 	 * Constructs a new timer
51 	 */
Timer()52 	public Timer() {
53 		setTimeout(Integer.MAX_VALUE);
54 		Runnable r = new Runnable() {
55 			@Override
56 			public void run() {
57 				while (isAlive()) {
58 					boolean interrupted = false;
59 					try {
60 						Thread.sleep(getTimeout());
61 					} catch (InterruptedException e) {
62 						interrupted = true;
63 					}
64 					if (!interrupted) {
65 						if (getListener() != null) {
66 							setStarted(false);
67 							setTimeout(Integer.MAX_VALUE);
68 							getListener().timeout();
69 							setListener(null);
70 						}
71 					}
72 				}
73 			}
74 		};
75 		setThread(new Thread(r, "Evaluation Timer")); //$NON-NLS-1$
76 		getThread().setDaemon(true);
77 		getThread().start();
78 	}
79 
80 	/**
81 	 * Starts this timer, and notifies the given listener when the time has
82 	 * passed. A call to <code>stop</code>, before the time expires, will cancel
83 	 * the the timer and timeout callback. This method can only be called if
84 	 * this timer is idle (i.e. <code>isStarted() == false<code>).
85 	 *
86 	 * @param listener
87 	 *            The timer listener
88 	 * @param ms
89 	 *            The number of milliseconds to wait before notifying the
90 	 *            listener
91 	 */
start(ITimeoutListener listener, int ms)92 	public void start(ITimeoutListener listener, int ms) {
93 		if (isStarted()) {
94 			throw new IllegalStateException(
95 					JDIDebugModelMessages.Timer_Timer_cannot_be_started_more_than_once_1);
96 		}
97 		setListener(listener);
98 		setTimeout(ms);
99 		setStarted(true);
100 		getThread().interrupt();
101 	}
102 
103 	/**
104 	 * Stops this timer, cancelling any pending timeout notification.
105 	 */
stop()106 	public void stop() {
107 		if (isAlive()) {
108 			setStarted(false);
109 			setTimeout(Integer.MAX_VALUE);
110 			getThread().interrupt();
111 		}
112 	}
113 
114 	/**
115 	 * Disposes this timer
116 	 */
dispose()117 	public void dispose() {
118 		if (isAlive()) {
119 			setAlive(false);
120 			getThread().interrupt();
121 			setThread(null);
122 		}
123 	}
124 
125 	/**
126 	 * Returns whether this timer's thread is alive
127 	 *
128 	 * @return whether this timer's thread is alive
129 	 */
isAlive()130 	private boolean isAlive() {
131 		return fAlive;
132 	}
133 
134 	/**
135 	 * Sets whether this timer's thread is alive. When set to <code>false</code>
136 	 * this timer's thread will exit on its next iteration.
137 	 *
138 	 * @param alive
139 	 *            whether this timer's thread should be alive
140 	 * @see #dispose()
141 	 */
setAlive(boolean alive)142 	private void setAlive(boolean alive) {
143 		fAlive = alive;
144 	}
145 
146 	/**
147 	 * Returns the current timeout listener
148 	 *
149 	 * @return timeout listener
150 	 */
getListener()151 	protected ITimeoutListener getListener() {
152 		return fListener;
153 	}
154 
155 	/**
156 	 * Sets the listener to be notified if this timer times out.
157 	 *
158 	 * @param listener
159 	 *            timeout listener
160 	 */
setListener(ITimeoutListener listener)161 	private void setListener(ITimeoutListener listener) {
162 		fListener = listener;
163 	}
164 
165 	/**
166 	 * Returns whether this timer has been started, and has not yet timed out,
167 	 * or been stopped.
168 	 *
169 	 * @return whether this timer has been started, and has not yet timed out,
170 	 *         or been stopped
171 	 */
isStarted()172 	public boolean isStarted() {
173 		return fStarted;
174 	}
175 
176 	/**
177 	 * Sets whether this timer has been started, and has not yet timed out, or
178 	 * been stopped.
179 	 *
180 	 * @param started
181 	 *            whether this timer has been started, and has not yet timed
182 	 *            out, or been stopped
183 	 */
setStarted(boolean started)184 	private void setStarted(boolean started) {
185 		fStarted = started;
186 	}
187 
188 	/**
189 	 * Returns this timer's thread
190 	 *
191 	 * @return thread that waits for a timeout
192 	 */
getThread()193 	private Thread getThread() {
194 		return fThread;
195 	}
196 
197 	/**
198 	 * Sets this timer's thread used to perform timeout processing
199 	 *
200 	 * @param thread
201 	 *            thread that waits for a timeout
202 	 */
setThread(Thread thread)203 	private void setThread(Thread thread) {
204 		fThread = thread;
205 	}
206 
207 	/**
208 	 * Returns the amount of time, in milliseconds, that this timer is/was
209 	 * waiting for.
210 	 *
211 	 * @return timeout value, in milliseconds
212 	 */
getTimeout()213 	protected int getTimeout() {
214 		return fTimeout;
215 	}
216 
217 	/**
218 	 * Sets the amount of time, in milliseconds, that this timer will wait for
219 	 * before timing out.
220 	 *
221 	 * @param timeout
222 	 *            value, in milliseconds
223 	 */
setTimeout(int timeout)224 	private void setTimeout(int timeout) {
225 		fTimeout = timeout;
226 	}
227 }
228