/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.camel.util.concurrent.RejectableThreadPoolExecutor;
public class ThreadPoolRejectedPolicyTest extends TestSupport {
public void testAbortAsRejectedExecutionHandler() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.Abort.asRejectedExecutionHandler());
final MockCallable<String> task1 = new MockCallable<String>();
final Future<?> result1 = executorService.submit(task1);
final MockRunnable task2 = new MockRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockCallable<String> task3 = new MockCallable<String>();
try {
executorService.submit(task3);
fail("Third task should have been rejected by a threadpool is full with 1 task and queue is full with 1 task.");
} catch (RejectedExecutionException e) {
}
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertRejected(task3, null);
}
public void testAbortAsRejectedExecutionHandlerWithRejectableTasks() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.Abort.asRejectedExecutionHandler());
final MockRejectableRunnable task1 = new MockRejectableRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRejectableCallable<String> task2 = new MockRejectableCallable<String>();
final Future<?> result2 = executorService.submit(task2);
final MockRejectableRunnable task3 = new MockRejectableRunnable();
final Future<?> result3 = executorService.submit(task3);
final MockRejectableCallable<String> task4 = new MockRejectableCallable<String>();
final Future<?> result4 = executorService.submit(task4);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertRejected(task3, result3);
assertRejected(task4, result4);
}
public void testCallerRunsAsRejectedExecutionHandler() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.CallerRuns.asRejectedExecutionHandler());
final MockRunnable task1 = new MockRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRunnable task2 = new MockRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRunnable task3 = new MockRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertInvoked(task3, result3);
}
public void testCallerRunsAsRejectedExecutionHandlerWithRejectableTasks() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.CallerRuns.asRejectedExecutionHandler());
final MockRejectableRunnable task1 = new MockRejectableRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRejectableRunnable task2 = new MockRejectableRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRejectableRunnable task3 = new MockRejectableRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertInvoked(task3, result3);
}
public void testDiscardAsRejectedExecutionHandler() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.Discard.asRejectedExecutionHandler());
final MockRunnable task1 = new MockRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRunnable task2 = new MockRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRunnable task3 = new MockRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertRejected(task3, result3);
}
public void testDiscardAsRejectedExecutionHandlerWithRejectableTasks() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.Discard.asRejectedExecutionHandler());
final MockRejectableRunnable task1 = new MockRejectableRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRejectableRunnable task2 = new MockRejectableRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRejectableRunnable task3 = new MockRejectableRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertInvoked(task2, result2);
assertRejected(task3, result3);
}
public void testDiscardOldestAsRejectedExecutionHandler() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.DiscardOldest.asRejectedExecutionHandler());
final MockRunnable task1 = new MockRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRunnable task2 = new MockRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRunnable task3 = new MockRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertRejected(task2, result2);
assertInvoked(task3, result3);
}
public void testDiscardOldestAsRejectedExecutionHandlerWithRejectableTasks() throws InterruptedException {
final ExecutorService executorService = createTestExecutorService(ThreadPoolRejectedPolicy.DiscardOldest.asRejectedExecutionHandler());
final MockRejectableRunnable task1 = new MockRejectableRunnable();
final Future<?> result1 = executorService.submit(task1);
final MockRejectableRunnable task2 = new MockRejectableRunnable();
final Future<?> result2 = executorService.submit(task2);
final MockRejectableRunnable task3 = new MockRejectableRunnable();
final Future<?> result3 = executorService.submit(task3);
shutdownAndAwait(executorService);
assertInvoked(task1, result1);
assertRejected(task2, result2);
assertInvoked(task3, result3);
}
private ExecutorService createTestExecutorService(final RejectedExecutionHandler rejectedExecutionHandler) {
return new RejectableThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(1), rejectedExecutionHandler);
}
private void shutdownAndAwait(final ExecutorService executorService) {
executorService.shutdown();
try {
assertTrue("Test ExecutorService shutdown is not expected to take longer than 10 seconds.", executorService.awaitTermination(10, TimeUnit.SECONDS));
} catch (InterruptedException e) {
fail("Test ExecutorService shutdown is not expected to be interrupted.");
}
}
private void assertInvoked(MockTask task, Future<?> result) {
assertTrue(result.isDone());
assertEquals(1, task.getInvocationCount());
if (task instanceof Rejectable) {
assertEquals(0, task.getRejectionCount());
}
}
private void assertRejected(MockTask task, Future<?> result) {
if (result != null) {
assertFalse(result.isDone());
}
assertEquals(0, task.getInvocationCount());
if (task instanceof Rejectable) {
assertEquals(1, task.getRejectionCount());
}
}
private abstract static class MockTask {
private final AtomicInteger invocationCount = new AtomicInteger();
private final AtomicInteger rejectionCount = new AtomicInteger();
public int getInvocationCount() {
return invocationCount.get();
}
protected void countInvocation() {
invocationCount.incrementAndGet();
}
public int getRejectionCount() {
return rejectionCount.get();
}
protected void countRejection() {
rejectionCount.incrementAndGet();
}
}
private static class MockRunnable extends MockTask implements Runnable {
@Override
public void run() {
countInvocation();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
fail("MockRunnable task is not expected to be interrupted.");
}
}
}
private static class MockRejectableRunnable extends MockRunnable implements Rejectable {
@Override
public void reject() {
countRejection();
}
}
private static class MockCallable<T> extends MockTask implements Callable<T> {
@Override
public T call() throws Exception {
countInvocation();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
fail("MockCallable task is not expected to be interrupted.");
}
return null;
}
}
private static class MockRejectableCallable<T> extends MockCallable<T> implements Rejectable {
@Override
public void reject() {
countRejection();
}
}
}