From cb87246d47b2e15434eccf941cb17a9fcf2f7b77 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Mon, 19 Nov 2012 19:50:03 -0500 Subject: [PATCH] INT-2820 Shutdown Default Idle Executor The default executor for sending messages from the IMAP IDLE channel adapter is a single threaded thread pool. If the default executor is used (no executor injected), shut it down when the adapter is stopped. INT-2820 Polishing If using the default sendingTaskExecutor, create a new one when restarted. Add test to restart adapter after stop. INT-2820 Polishing Review comments; protect for null sendingTaskExecutor. --- .../mail/ImapIdleChannelAdapter.java | 22 +++++++++++++++++- .../mail/ImapMailReceiverTests.java | 23 +++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapIdleChannelAdapter.java b/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapIdleChannelAdapter.java index dc4e6fca74..4d982fe7de 100755 --- a/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapIdleChannelAdapter.java +++ b/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapIdleChannelAdapter.java @@ -19,6 +19,7 @@ package org.springframework.integration.mail; import java.util.Date; import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledFuture; @@ -57,7 +58,9 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be private final IdleTask idleTask = new IdleTask(); - private volatile Executor sendingTaskExecutor = Executors.newFixedThreadPool(1); + private volatile Executor sendingTaskExecutor; + + private volatile boolean sendingTaskExecutorSet; private volatile boolean shouldReconnectAutomatically = true; @@ -102,6 +105,7 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be public void setSendingTaskExecutor(Executor sendingTaskExecutor) { Assert.notNull(sendingTaskExecutor, "'sendingTaskExecutor' must not be null"); this.sendingTaskExecutor = sendingTaskExecutor; + this.sendingTaskExecutorSet = true; } /** @@ -130,6 +134,9 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be protected void doStart() { final TaskScheduler scheduler = this.getTaskScheduler(); Assert.notNull(scheduler, "'taskScheduler' must not be null" ); + if (this.sendingTaskExecutor == null) { + this.sendingTaskExecutor = Executors.newFixedThreadPool(1); + } this.receivingTask = scheduler.schedule(new ReceivingTask(), this.receivingTaskTrigger); this.pingTask = scheduler.scheduleAtFixedRate(new PingTask(), this.connectionPingInterval); } @@ -146,6 +153,13 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be throw new IllegalStateException( "Failure during the destruction of Mail receiver: " + mailReceiver, e); } + /* + * If we're running with the default executor, shut it down. + */ + if (!this.sendingTaskExecutorSet && this.sendingTaskExecutor != null) { + ((ExecutorService) sendingTaskExecutor).shutdown(); + this.sendingTaskExecutor = null; + } } @@ -170,6 +184,12 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be public void run() { final TaskScheduler scheduler = getTaskScheduler(); Assert.notNull(scheduler, "'taskScheduler' must not be null" ); + /* + * The following shouldn't be necessary because doStart() will have ensured we have + * one. But, just in case... + */ + Assert.state(sendingTaskExecutor != null, "'sendingTaskExecutor' must not be null"); + try { if (logger.isDebugEnabled()) { logger.debug("waiting for mail"); diff --git a/spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java b/spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java index 704e73fcf8..185d32b323 100644 --- a/spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java +++ b/spring-integration-mail/src/test/java/org/springframework/integration/mail/ImapMailReceiverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.mail; import static org.junit.Assert.assertEquals; @@ -33,6 +34,7 @@ import java.lang.reflect.Field; import java.util.Properties; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -63,6 +65,7 @@ import org.springframework.integration.handler.AbstractReplyProducingMessageHand import org.springframework.integration.history.MessageHistory; import org.springframework.integration.mail.config.ImapIdleChannelAdapterParserTests; import org.springframework.integration.test.util.TestUtils; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.FileCopyUtils; import com.sun.mail.imap.IMAPFolder; @@ -71,7 +74,6 @@ import com.sun.mail.imap.IMAPMessage; /** * @author Oleg Zhurakousky * @author Gary Russell - * */ public class ImapMailReceiverTests { @@ -663,4 +665,21 @@ public class ImapMailReceiverTests { assertSame(folder, messages[0].getFolder()); } + + @Test + public void testExecShutdown() { + ImapIdleChannelAdapter adapter = new ImapIdleChannelAdapter(new ImapMailReceiver()); + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.initialize(); + adapter.setTaskScheduler(taskScheduler); + adapter.start(); + ExecutorService exec = TestUtils.getPropertyValue(adapter, "sendingTaskExecutor", ExecutorService.class); + adapter.stop(); + assertTrue(exec.isShutdown()); + adapter.start(); + exec = TestUtils.getPropertyValue(adapter, "sendingTaskExecutor", ExecutorService.class); + adapter.stop(); + assertTrue(exec.isShutdown()); + } + }