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
46
47 @Override
48 public Watchdog get() {
49 return new Watchdog(threadFactory, timeout);
50 }
51
52
53
54
55
56
57
58 public Builder setThreadFactory(final ThreadFactory threadFactory) {
59 this.threadFactory = threadFactory;
60 return this;
61 }
62
63
64
65
66
67
68
69 public Builder setTimeout(final Duration timeout) {
70 this.timeout = timeout;
71 return this;
72 }
73
74 }
75
76
77
78
79
80
81
82 public static Builder builder() {
83 return new Builder();
84 }
85
86 private final Vector<TimeoutObserver> observers = new Vector<>(1);
87
88 private final long timeoutMillis;
89
90 private boolean stopped;
91
92
93
94
95 private final ThreadFactory threadFactory;
96
97
98
99
100
101
102
103 @Deprecated
104 public Watchdog(final long timeoutMillis) {
105 this(null, Duration.ofMillis(timeoutMillis));
106 }
107
108
109
110
111
112
113
114 private Watchdog(final ThreadFactory threadFactory, final Duration timeout) {
115 if (timeout.isNegative() || Duration.ZERO.equals(timeout)) {
116 throw new IllegalArgumentException("timeout must not be less than 1.");
117 }
118 this.timeoutMillis = timeout.toMillis();
119 this.threadFactory = threadFactory;
120 }
121
122
123
124
125
126
127 public void addTimeoutObserver(final TimeoutObserver to) {
128 observers.addElement(to);
129 }
130
131
132
133
134 protected final void fireTimeoutOccured() {
135 observers.forEach(o -> o.timeoutOccured(this));
136 }
137
138
139
140
141
142
143 public void removeTimeoutObserver(final TimeoutObserver to) {
144 observers.removeElement(to);
145 }
146
147 @Override
148 public void run() {
149 final long startTimeMillis = System.currentTimeMillis();
150 boolean isWaiting;
151 synchronized (this) {
152 long timeLeftMillis = timeoutMillis - (System.currentTimeMillis() - startTimeMillis);
153 isWaiting = timeLeftMillis > 0;
154 while (!stopped && isWaiting) {
155 try {
156 wait(timeLeftMillis);
157 } catch (final InterruptedException ignore) {
158
159 }
160 timeLeftMillis = timeoutMillis - (System.currentTimeMillis() - startTimeMillis);
161 isWaiting = timeLeftMillis > 0;
162 }
163 }
164
165
166 if (!isWaiting) {
167 fireTimeoutOccured();
168 }
169 }
170
171
172
173
174 public synchronized void start() {
175 stopped = false;
176 ThreadUtil.newThread(threadFactory, this, "CommonsExecWatchdog-", true).start();
177 }
178
179
180
181
182 public synchronized void stop() {
183 stopped = true;
184 notifyAll();
185 }
186
187 }