1 package org.apache.maven.surefire.junitcore.pc;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.junit.runner.Description;
23 import org.junit.runners.model.RunnerScheduler;
24
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Set;
28 import java.util.concurrent.CopyOnWriteArraySet;
29 import java.util.concurrent.RejectedExecutionException;
30 import java.util.concurrent.RejectedExecutionHandler;
31 import java.util.concurrent.ThreadPoolExecutor;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class Scheduler implements RunnerScheduler {
47 private final Balancer balancer;
48 private final SchedulingStrategy strategy;
49 private final Set<Controller> slaves = new CopyOnWriteArraySet<Controller>();
50 private final Description description;
51 private volatile boolean shutdown = false;
52 private volatile boolean started = false;
53 private volatile Controller masterController;
54
55
56
57
58
59
60
61 public Scheduler(Description description, SchedulingStrategy strategy) {
62 this(description, strategy, -1);
63 }
64
65
66
67
68
69
70
71
72
73
74
75
76
77 public Scheduler(Description description, SchedulingStrategy strategy, int concurrency) {
78 this(description, strategy, BalancerFactory.createBalancer(concurrency));
79 }
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public Scheduler(Description description, SchedulingStrategy strategy, Balancer balancer) {
95 strategy.setDefaultShutdownHandler(newShutdownHandler());
96 this.description = description;
97 this.strategy = strategy;
98 this.balancer = balancer;
99 masterController = null;
100 }
101
102
103
104
105
106
107
108
109
110
111 public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy, Balancer balancer) {
112 this(description, strategy, balancer);
113 strategy.setDefaultShutdownHandler(newShutdownHandler());
114 masterScheduler.register(this);
115 }
116
117
118
119
120
121
122
123 public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy, int concurrency) {
124 this(description, strategy, concurrency);
125 strategy.setDefaultShutdownHandler(newShutdownHandler());
126 masterScheduler.register(this);
127 }
128
129
130
131
132
133
134
135 public Scheduler(Description description, Scheduler masterScheduler, SchedulingStrategy strategy) {
136 this(description, masterScheduler, strategy, 0);
137 }
138
139 private void setController(Controller masterController) {
140 if (masterController == null) {
141 throw new NullPointerException("null ExecutionController");
142 }
143 this.masterController = masterController;
144 }
145
146
147
148
149
150 private boolean register(Scheduler slave) {
151 boolean canRegister = slave != null && slave != this;
152 if (canRegister) {
153 Controller controller = new Controller(slave);
154 canRegister = !slaves.contains(controller);
155 if (canRegister) {
156 slaves.add(controller);
157 slave.setController(controller);
158 }
159 }
160 return canRegister;
161 }
162
163
164
165
166 private boolean canSchedule() {
167 return !shutdown && (masterController == null || masterController.canSchedule());
168 }
169
170 protected void logQuietly(Throwable t) {
171 t.printStackTrace(System.err);
172 }
173
174 protected void logQuietly(String msg) {
175 System.err.println(msg);
176 }
177
178
179
180
181
182
183
184
185
186
187
188 public Collection<Description> shutdown(boolean shutdownNow) {
189 shutdown = true;
190 ArrayList<Description> activeChildren = new ArrayList<Description>();
191
192 if (started && description != null) {
193 activeChildren.add(description);
194 }
195
196 for (Controller slave : slaves) {
197 try {
198 activeChildren.addAll(slave.shutdown(shutdownNow));
199 } catch (Throwable t) {
200 logQuietly(t);
201 }
202 }
203
204 try {
205 balancer.releaseAllPermits();
206 } finally {
207 if (shutdownNow) {
208 strategy.stopNow();
209 } else {
210 strategy.stop();
211 }
212 }
213
214 return activeChildren;
215 }
216
217 protected void beforeExecute() {
218 }
219
220 protected void afterExecute() {
221 }
222
223 public void schedule(Runnable childStatement) {
224 if (childStatement == null) {
225 logQuietly("cannot schedule null");
226 } else if (canSchedule() && strategy.canSchedule()) {
227 try {
228 balancer.acquirePermit();
229 Runnable task = wrapTask(childStatement);
230 strategy.schedule(task);
231 started = true;
232 } catch (RejectedExecutionException e) {
233 shutdown(false);
234 } catch (Throwable t) {
235 balancer.releasePermit();
236 logQuietly(t);
237 }
238 }
239 }
240
241 public void finished() {
242 try {
243 strategy.finished();
244 } catch (InterruptedException e) {
245 logQuietly(e);
246 } finally {
247 for (Controller slave : slaves) {
248 slave.awaitFinishedQuietly();
249 }
250 }
251 }
252
253 private Runnable wrapTask(final Runnable task) {
254 return new Runnable() {
255 public void run() {
256 try {
257 beforeExecute();
258 task.run();
259 } finally {
260 try {
261 afterExecute();
262 } finally {
263 balancer.releasePermit();
264 }
265 }
266 }
267 };
268 }
269
270 protected ShutdownHandler newShutdownHandler() {
271 return new ShutdownHandler();
272 }
273
274
275
276
277 private final class Controller {
278 private final Scheduler slave;
279
280 private Controller(Scheduler slave) {
281 this.slave = slave;
282 }
283
284
285
286
287 boolean canSchedule() {
288 return Scheduler.this.canSchedule();
289 }
290
291 void awaitFinishedQuietly() {
292 try {
293 slave.finished();
294 } catch(Throwable t) {
295 slave.logQuietly(t);
296 }
297 }
298
299 Collection<Description> shutdown(boolean shutdownNow) {
300 return slave.shutdown(shutdownNow);
301 }
302
303 @Override
304 public int hashCode() {
305 return slave.hashCode();
306 }
307
308 @Override
309 public boolean equals(Object o) {
310 return o == this || (o instanceof Controller) && slave.equals(((Controller) o).slave);
311 }
312 }
313
314 public class ShutdownHandler implements RejectedExecutionHandler {
315 private volatile RejectedExecutionHandler poolHandler;
316
317 protected ShutdownHandler() {
318 poolHandler = null;
319 }
320
321 public void setRejectedExecutionHandler(RejectedExecutionHandler poolHandler) {
322 this.poolHandler = poolHandler;
323 }
324
325 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
326 if (executor.isShutdown()) {
327 shutdown(false);
328 }
329 final RejectedExecutionHandler poolHandler = this.poolHandler;
330 if (poolHandler != null) {
331 poolHandler.rejectedExecution(r, executor);
332 }
333 }
334 }
335 }