1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.exec;
19
20 import java.time.Duration;
21 import java.util.Vector;
22 import java.util.concurrent.ThreadFactory;
23 import java.util.function.Supplier;
24
25
26
27
28
29
30 public class Watchdog implements Runnable {
31
32
33
34
35
36
37 public static final class Builder implements Supplier<Watchdog> {
38
39 private ThreadFactory threadFactory;
40 private Duration timeout;
41
42
43
44
45 public Builder() {
46
47 }
48
49
50
51
52
53
54 @Override
55 public Watchdog get() {
56 return new Watchdog(threadFactory, timeout);
57 }
58
59
60
61
62
63
64
65 public Builder setThreadFactory(final ThreadFactory threadFactory) {
66 this.threadFactory = threadFactory;
67 return this;
68 }
69
70
71
72
73
74
75
76 public Builder setTimeout(final Duration timeout) {
77 this.timeout = timeout;
78 return this;
79 }
80
81 }
82
83
84
85
86
87
88
89 public static Builder builder() {
90 return new Builder();
91 }
92
93 private final Vector<TimeoutObserver> observers = new Vector<>(1);
94
95 private final long timeoutMillis;
96
97 private boolean stopped;
98
99
100
101
102 private final ThreadFactory threadFactory;
103
104
105
106
107
108
109
110 @Deprecated
111 public Watchdog(final long timeoutMillis) {
112 this(null, Duration.ofMillis(timeoutMillis));
113 }
114
115
116
117
118
119
120
121 private Watchdog(final ThreadFactory threadFactory, final Duration timeout) {
122 if (timeout.isNegative() || Duration.ZERO.equals(timeout)) {
123 throw new IllegalArgumentException("timeout must not be less than 1.");
124 }
125 this.timeoutMillis = timeout.toMillis();
126 this.threadFactory = threadFactory;
127 }
128
129
130
131
132
133
134 public void addTimeoutObserver(final TimeoutObserver to) {
135 observers.addElement(to);
136 }
137
138
139
140
141 protected final void fireTimeoutOccured() {
142 observers.forEach(o -> o.timeoutOccured(this));
143 }
144
145
146
147
148
149
150 public void removeTimeoutObserver(final TimeoutObserver to) {
151 observers.removeElement(to);
152 }
153
154 @Override
155 public void run() {
156 final long startTimeMillis = System.currentTimeMillis();
157 boolean isWaiting;
158 synchronized (this) {
159 long timeLeftMillis = timeoutMillis - (System.currentTimeMillis() - startTimeMillis);
160 isWaiting = timeLeftMillis > 0;
161 while (!stopped && isWaiting) {
162 try {
163 wait(timeLeftMillis);
164 } catch (final InterruptedException ignore) {
165
166 }
167 timeLeftMillis = timeoutMillis - (System.currentTimeMillis() - startTimeMillis);
168 isWaiting = timeLeftMillis > 0;
169 }
170 }
171
172
173 if (!isWaiting) {
174 fireTimeoutOccured();
175 }
176 }
177
178
179
180
181 public synchronized void start() {
182 stopped = false;
183 ThreadUtil.newThread(threadFactory, this, "CommonsExecWatchdog-", true).start();
184 }
185
186
187
188
189 public synchronized void stop() {
190 stopped = true;
191 notifyAll();
192 }
193
194 }