1
2
3
4
5
6
7
8
9
10
11 package org.mule.util.concurrent;
12
13 import org.mule.tck.AbstractMuleTestCase;
14 import org.mule.util.StringUtils;
15
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Iterator;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.Map;
22
23 import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
24 import edu.emory.mathcs.backport.java.util.concurrent.RejectedExecutionException;
25 import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
26 import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
27 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
28 import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
29
30 public class WaitPolicyTestCase extends AbstractMuleTestCase
31 {
32 private ExceptionCollectingThreadGroup threadGroup;
33 private ThreadPoolExecutor executor;
34 private ReentrantLock executorLock;
35
36
37 protected void doSetUp() throws Exception
38 {
39 super.doSetUp();
40
41
42 executor = new ThreadPoolExecutor(1, 1, 10000L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(1));
43 executor.prestartAllCoreThreads();
44
45
46
47 executorLock = new ReentrantLock(true);
48
49
50
51 threadGroup = new ExceptionCollectingThreadGroup();
52
53
54 SleepyTask.activeTasks.set(0);
55 }
56
57
58 protected void doTearDown() throws Exception
59 {
60 executor.shutdown();
61 threadGroup.destroy();
62 super.doTearDown();
63 }
64
65
66
67
68
69
70
71
72 protected LinkedList
73 {
74 if (tasks == null || tasks.isEmpty())
75 {
76 throw new IllegalArgumentException("List<Runnable> must not be empty");
77 }
78
79 LinkedList submitters = new LinkedList();
80
81 executorLock.lock();
82
83 for (Iterator i = tasks.iterator(); i.hasNext();)
84 {
85 final Runnable task = (Runnable)i.next();
86
87 Runnable submitterAction = new Runnable()
88 {
89 public void run()
90 {
91
92
93
94 try
95 {
96 executorLock.lock();
97 executor.execute(task);
98 }
99 finally
100 {
101 executorLock.unlock();
102 }
103 }
104 };
105
106 Thread submitter = new Thread(threadGroup, submitterAction);
107 submitter.setDaemon(true);
108 submitters.add(submitter);
109 submitter.start();
110
111
112 while (submitter.isAlive() && !executorLock.hasQueuedThread(submitter))
113 {
114 Thread.sleep(10);
115 }
116 }
117
118 executorLock.unlock();
119 return submitters;
120 }
121
122 public void testWaitPolicyWithShutdownExecutor() throws Exception
123 {
124 assertEquals(0, SleepyTask.activeTasks.get());
125
126
127 executor.setRejectedExecutionHandler(new LastRejectedWaitPolicy());
128 executor.shutdown();
129
130
131 List tasks = new ArrayList();
132 tasks.add(new SleepyTask("rejected", 1000));
133
134
135 LinkedList submitters = this.execute(tasks);
136 assertFalse(submitters.isEmpty());
137
138
139 Thread.sleep(1000);
140
141 LinkedList exceptions = threadGroup.collectedExceptions();
142 assertEquals(1, exceptions.size());
143
144 Map.Entry threadFailure = (Map.Entry)((Map)(exceptions.getFirst())).entrySet().iterator().next();
145 assertEquals(submitters.getFirst(), threadFailure.getKey());
146 assertEquals(RejectedExecutionException.class, threadFailure.getValue().getClass());
147 assertEquals(0, SleepyTask.activeTasks.get());
148 }
149
150 public void testWaitPolicyForever() throws Exception
151 {
152 assertEquals(0, SleepyTask.activeTasks.get());
153
154
155 LastRejectedWaitPolicy policy = new LastRejectedWaitPolicy(-1, TimeUnit.SECONDS);
156 executor.setRejectedExecutionHandler(policy);
157
158
159 List tasks = new ArrayList();
160
161 tasks.add(new SleepyTask("hans", 1000));
162
163 tasks.add(new SleepyTask("franz", 1000));
164
165 Runnable t3 = new SleepyTask("beavis", 1000);
166 tasks.add(t3);
167
168
169 LinkedList submitters = this.execute(tasks);
170 assertFalse(submitters.isEmpty());
171
172
173 assertFalse(executor.awaitTermination(4000, TimeUnit.MILLISECONDS));
174 assertSame(t3, policy.lastRejectedRunnable());
175 assertEquals(0, SleepyTask.activeTasks.get());
176 }
177
178 public void testWaitPolicyWithTimeout() throws Exception
179 {
180 assertEquals(0, SleepyTask.activeTasks.get());
181
182
183 LastRejectedWaitPolicy policy = new LastRejectedWaitPolicy(2500, TimeUnit.MILLISECONDS);
184 executor.setRejectedExecutionHandler(policy);
185
186
187 List tasks = new ArrayList();
188
189 tasks.add(new SleepyTask("hans", 1000));
190
191 tasks.add(new SleepyTask("franz", 1000));
192
193 Runnable t3 = new SleepyTask("tweety", 1000);
194 tasks.add(t3);
195
196
197 LinkedList submitters = this.execute(tasks);
198 assertFalse(submitters.isEmpty());
199
200 assertFalse(executor.awaitTermination(5000, TimeUnit.MILLISECONDS));
201 assertSame(t3, policy.lastRejectedRunnable());
202 assertEquals(0, SleepyTask.activeTasks.get());
203 }
204
205 public void testWaitPolicyWithTimeoutFailure() throws Exception
206 {
207 assertEquals(0, SleepyTask.activeTasks.get());
208
209
210 long failureInterval = 100L;
211 LastRejectedWaitPolicy policy = new LastRejectedWaitPolicy(failureInterval, TimeUnit.MILLISECONDS);
212 executor.setRejectedExecutionHandler(policy);
213
214
215 List tasks = new ArrayList();
216
217 tasks.add(new SleepyTask("hans", 1000));
218
219 tasks.add(new SleepyTask("franz", 1000));
220
221 Runnable failedTask = new SleepyTask("tweety", 1000);
222 tasks.add(failedTask);
223
224
225 LinkedList submitters = this.execute(tasks);
226 assertFalse(submitters.isEmpty());
227
228
229 Thread.sleep(failureInterval * 2);
230
231 LinkedList exceptions = threadGroup.collectedExceptions();
232 assertEquals(1, exceptions.size());
233
234 Map.Entry threadFailure = (Map.Entry)((Map)(exceptions.getFirst())).entrySet().iterator().next();
235 assertEquals(submitters.getLast(), threadFailure.getKey());
236 assertEquals(RejectedExecutionException.class, threadFailure.getValue().getClass());
237
238 executor.shutdown();
239 assertTrue(executor.awaitTermination(2500, TimeUnit.MILLISECONDS));
240 assertSame(failedTask, policy.lastRejectedRunnable());
241 assertEquals(0, SleepyTask.activeTasks.get());
242 }
243
244 }
245
246 class LastRejectedWaitPolicy extends WaitPolicy
247 {
248
249 private volatile Runnable _rejected;
250
251 public LastRejectedWaitPolicy()
252 {
253 super();
254 }
255
256 public LastRejectedWaitPolicy(long time, TimeUnit timeUnit)
257 {
258 super(time, timeUnit);
259 }
260
261 public Runnable lastRejectedRunnable()
262 {
263 return _rejected;
264 }
265
266
267 public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
268 {
269 _rejected = r;
270 super.rejectedExecution(r, e);
271 }
272 }
273
274
275 class SleepyTask extends Object implements Runnable
276 {
277 public static final AtomicInteger activeTasks = new AtomicInteger(0);
278
279 private final String name;
280 private final long sleepTime;
281
282 public SleepyTask(String name, long sleepTime)
283 {
284 if (StringUtils.isEmpty(name))
285 {
286 throw new IllegalArgumentException("SleepyTask needs a name!");
287 }
288
289 this.name = name;
290 this.sleepTime = sleepTime;
291 }
292
293 public String toString()
294 {
295 return this.getClass().getName() + '{' + name + ", " + sleepTime + '}';
296 }
297
298 public void run()
299 {
300 activeTasks.incrementAndGet();
301
302 try
303 {
304 Thread.sleep(sleepTime);
305 }
306 catch (InterruptedException iex)
307 {
308 Thread.currentThread().interrupt();
309 }
310 finally
311 {
312 activeTasks.decrementAndGet();
313 }
314 }
315
316 }
317
318
319 class ExceptionCollectingThreadGroup extends ThreadGroup
320 {
321 private final LinkedList
322
323 public ExceptionCollectingThreadGroup()
324 {
325 super("ExceptionCollectingThreadGroup");
326 }
327
328
329 public LinkedList collectedExceptions()
330 {
331 return exceptions;
332 }
333
334
335
336 public void uncaughtException(Thread t, Throwable e)
337 {
338 synchronized (exceptions)
339 {
340 exceptions.add(Collections.singletonMap(t, e));
341 }
342 }
343 }