diff --git a/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java b/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java index 05b9799c42..d8f24d146b 100755 --- a/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java +++ b/spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 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. @@ -41,7 +41,7 @@ import com.sun.mail.imap.IMAPMessage; * the option of blocking until new messages are available prior to calling * {@link #receive()}. That option is only available if the server supports * the {@link IMAPFolder#idle() idle} command. - * + * * @author Arjen Poutsma * @author Mark Fisher * @author Oleg Zhurakousky @@ -50,6 +50,8 @@ public class ImapMailReceiver extends AbstractMailReceiver { private volatile boolean shouldMarkMessagesAsRead = true; + private volatile SearchTermStrategy searchTermStrategy = new DefaultSearchTermStrategy(); + private final MessageCountListener messageCountListener = new SimpleMessageCountListener(); public ImapMailReceiver() { @@ -76,6 +78,17 @@ public class ImapMailReceiver extends AbstractMailReceiver { return shouldMarkMessagesAsRead; } + /** + * Provides a way to set custom {@link SearchTermStrategy} to compile a {@link SearchTerm} + * to be applied when retrieving mail + * + * @param searchTermStrategy + */ + public void setSearchTermStrategy(SearchTermStrategy searchTermStrategy) { + Assert.notNull(searchTermStrategy, "'searchTermStrategy' must not be null"); + this.searchTermStrategy = searchTermStrategy; + } + /** * Specify if messages should be marked as read. */ @@ -131,66 +144,10 @@ public class ImapMailReceiver extends AbstractMailReceiver { } private SearchTerm compileSearchTerms(Flags supportedFlags) { - SearchTerm searchTerm = null; - boolean recentFlagSupported = false; - if (supportedFlags != null) { - recentFlagSupported = supportedFlags.contains(Flags.Flag.RECENT); - if (recentFlagSupported) { - searchTerm = new FlagTerm(new Flags(Flags.Flag.RECENT), true); - } - if (supportedFlags.contains(Flags.Flag.ANSWERED)) { - NotTerm notAnswered = new NotTerm(new FlagTerm(new Flags(Flags.Flag.ANSWERED), true)); - if (searchTerm == null) { - searchTerm = notAnswered; - } - else { - searchTerm = new AndTerm(searchTerm, notAnswered); - } - } - if (supportedFlags.contains(Flags.Flag.DELETED)) { - NotTerm notDeleted = new NotTerm(new FlagTerm(new Flags(Flags.Flag.DELETED), true)); - if (searchTerm == null) { - searchTerm = notDeleted; - } - else { - searchTerm = new AndTerm(searchTerm, notDeleted); - } - } - if (supportedFlags.contains(Flags.Flag.SEEN)) { - NotTerm notSeen = new NotTerm(new FlagTerm(new Flags(Flags.Flag.SEEN), true)); - if (searchTerm == null) { - searchTerm = notSeen; - } - else { - searchTerm = new AndTerm(searchTerm, notSeen); - } - } - } - - if (!recentFlagSupported) { - NotTerm notFlagged = null; - if (this.getFolder().getPermanentFlags().contains(Flags.Flag.USER)) { - logger.debug("This email server does not support RECENT flag, but it does support " + - "USER flags which will be used to prevent duplicates during email fetch."); - Flags siFlags = new Flags(); - siFlags.add(SI_USER_FLAG); - notFlagged = new NotTerm(new FlagTerm(siFlags, true)); - } - else { - logger.debug("This email server does not support RECENT or USER flags. " + - "System flag 'Flag.FLAGGED' will be used to prevent duplicates during email fetch."); - notFlagged = new NotTerm(new FlagTerm(new Flags(Flags.Flag.FLAGGED), true)); - } - if (searchTerm == null) { - searchTerm = notFlagged; - } - else { - searchTerm = new AndTerm(searchTerm, notFlagged); - } - } - return searchTerm; + return this.searchTermStrategy.generateSearchTerm(supportedFlags, this.getFolder()); } + @Override protected void setAdditionalFlags(Message message) throws MessagingException { super.setAdditionalFlags(message); if (this.shouldMarkMessagesAsRead) { @@ -204,6 +161,7 @@ public class ImapMailReceiver extends AbstractMailReceiver { */ private static class SimpleMessageCountListener extends MessageCountAdapter { + @Override public void messagesAdded(MessageCountEvent event) { Message[] messages = event.getMessages(); for (Message message : messages) { @@ -218,4 +176,70 @@ public class ImapMailReceiver extends AbstractMailReceiver { } } + private class DefaultSearchTermStrategy implements SearchTermStrategy { + + public SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder) { + SearchTerm searchTerm = null; + boolean recentFlagSupported = false; + if (supportedFlags != null) { + recentFlagSupported = supportedFlags.contains(Flags.Flag.RECENT); + if (recentFlagSupported) { + searchTerm = new FlagTerm(new Flags(Flags.Flag.RECENT), true); + } + if (supportedFlags.contains(Flags.Flag.ANSWERED)) { + NotTerm notAnswered = new NotTerm(new FlagTerm(new Flags(Flags.Flag.ANSWERED), true)); + if (searchTerm == null) { + searchTerm = notAnswered; + } + else { + searchTerm = new AndTerm(searchTerm, notAnswered); + } + } + if (supportedFlags.contains(Flags.Flag.DELETED)) { + NotTerm notDeleted = new NotTerm(new FlagTerm(new Flags(Flags.Flag.DELETED), true)); + if (searchTerm == null) { + searchTerm = notDeleted; + } + else { + searchTerm = new AndTerm(searchTerm, notDeleted); + } + } + if (supportedFlags.contains(Flags.Flag.SEEN)) { + NotTerm notSeen = new NotTerm(new FlagTerm(new Flags(Flags.Flag.SEEN), true)); + if (searchTerm == null) { + searchTerm = notSeen; + } + else { + searchTerm = new AndTerm(searchTerm, notSeen); + } + } + } + + if (!recentFlagSupported) { + NotTerm notFlagged = null; + if (folder.getPermanentFlags().contains(Flags.Flag.USER)) { + logger.debug("This email server does not support RECENT flag, but it does support " + + "USER flags which will be used to prevent duplicates during email fetch."); + Flags siFlags = new Flags(); + siFlags.add(AbstractMailReceiver.SI_USER_FLAG); + notFlagged = new NotTerm(new FlagTerm(siFlags, true)); + } + else { + logger.debug("This email server does not support RECENT or USER flags. " + + "System flag 'Flag.FLAGGED' will be used to prevent duplicates during email fetch."); + notFlagged = new NotTerm(new FlagTerm(new Flags(Flags.Flag.FLAGGED), true)); + } + if (searchTerm == null) { + searchTerm = notFlagged; + } + else { + searchTerm = new AndTerm(searchTerm, notFlagged); + } + } + return searchTerm; + } + + } + + } diff --git a/spring-integration-mail/src/main/java/org/springframework/integration/mail/SearchTermStrategy.java b/spring-integration-mail/src/main/java/org/springframework/integration/mail/SearchTermStrategy.java new file mode 100644 index 0000000000..a2edcdb294 --- /dev/null +++ b/spring-integration-mail/src/main/java/org/springframework/integration/mail/SearchTermStrategy.java @@ -0,0 +1,42 @@ +/* + * 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. + * 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.springframework.integration.mail; + +import javax.mail.Flags; +import javax.mail.Folder; +import javax.mail.search.SearchTerm; + +/** + * Strategy to be used to generate a {@link SearchTerm} + * + * See {@link ImapMailReceiver} + * + * @author Oleg Zhurakousky + * @since 2.2 + * + */ +public interface SearchTermStrategy { + + /** + * Will generate an instance of the {@link SearchTerm} + * + * @param supportedFlags + * @param folder + * @return + */ + SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder); + +} diff --git a/spring-integration-mail/src/main/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParser.java b/spring-integration-mail/src/main/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParser.java index ac8b83b003..b8d3778edb 100644 --- a/spring-integration-mail/src/main/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParser.java +++ b/spring-integration-mail/src/main/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParser.java @@ -16,6 +16,8 @@ package org.springframework.integration.mail.config; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -26,11 +28,10 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.mail.ImapIdleChannelAdapter; import org.springframework.integration.mail.ImapMailReceiver; import org.springframework.util.StringUtils; -import org.w3c.dom.Element; /** * Parser for the <imap-idle-channel-adapter> element in the 'mail' namespace. - * + * * @author Jonas Partner * @author Mark Fisher * @author Oleg Zhurakousky @@ -38,6 +39,7 @@ import org.w3c.dom.Element; */ public class ImapIdleChannelAdapterParser extends AbstractChannelAdapterParser { + @Override protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ImapIdleChannelAdapter.class); builder.addConstructorArgValue(this.parseImapMailReceiver(element, parserContext)); @@ -49,6 +51,7 @@ public class ImapIdleChannelAdapterParser extends AbstractChannelAdapterParser { private BeanDefinition parseImapMailReceiver(Element element, ParserContext parserContext) { BeanDefinitionBuilder receiverBuilder = BeanDefinitionBuilder.genericBeanDefinition(ImapMailReceiver.class); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "search-term-strategy"); Object source = parserContext.extractSource(element); String uri = element.getAttribute("store-uri"); if (StringUtils.hasText(uri)) { @@ -72,16 +75,16 @@ public class ImapIdleChannelAdapterParser extends AbstractChannelAdapterParser { if (StringUtils.hasText(markAsRead)){ receiverBuilder.addPropertyValue("shouldMarkMessagesAsRead", markAsRead); } - + String selectorExpression = element.getAttribute("mail-filter-expression"); - + RootBeanDefinition expressionDef = null; if (StringUtils.hasText(selectorExpression)){ expressionDef = new RootBeanDefinition("org.springframework.integration.config.ExpressionFactoryBean"); expressionDef.getConstructorArgumentValues().addGenericArgumentValue(selectorExpression); receiverBuilder.addPropertyValue("selectorExpression", expressionDef); } - - return receiverBuilder.getBeanDefinition(); + + return receiverBuilder.getBeanDefinition(); } } diff --git a/spring-integration-mail/src/main/resources/org/springframework/integration/mail/config/spring-integration-mail-2.2.xsd b/spring-integration-mail/src/main/resources/org/springframework/integration/mail/config/spring-integration-mail-2.2.xsd index 5f9b4eed18..63006186a5 100644 --- a/spring-integration-mail/src/main/resources/org/springframework/integration/mail/config/spring-integration-mail-2.2.xsd +++ b/spring-integration-mail/src/main/resources/org/springframework/integration/mail/config/spring-integration-mail-2.2.xsd @@ -122,6 +122,23 @@ + + + + + + + + + Reference to a custom implementation of org.springframework.integration.mail.SearchTermStrategy + to use when retrieving email. + By default ImapMailReceiver will search for Messages based in the default SearchTerm + which is "All mails that are RECENT (if supported), that are NOT ANSWERED, that are NOT DELETED, that are NOT SEEN and have not + been processed by this mail receiver (enabled by the use of the custom USER flag or simply NOT FLAGGED if not supported)". + + + 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 962518e4b0..8a3792eb8e 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 @@ -62,9 +62,9 @@ import com.sun.mail.imap.IMAPFolder; * */ public class ImapMailReceiverTests { - - private AtomicInteger failed = new AtomicInteger(0); - + + private final AtomicInteger failed = new AtomicInteger(0); + @Test public void receiveAndMarkAsReadDontDelete() throws Exception{ AbstractMailReceiver receiver = new ImapMailReceiver(); @@ -80,7 +80,7 @@ public class ImapMailReceiverTests { Message msg1 = mock(MimeMessage.class); Message msg2 = mock(MimeMessage.class); final Message[] messages = new Message[]{msg1, msg2}; - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { DirectFieldAccessor accessor = new DirectFieldAccessor(invocation.getMock()); @@ -88,17 +88,17 @@ public class ImapMailReceiverTests { if (folderOpenMode != Folder.READ_WRITE){ throw new IllegalArgumentException("Folder had to be open in READ_WRITE mode"); } - + return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; @@ -116,13 +116,13 @@ public class ImapMailReceiverTests { receiver.setShouldDeleteMessages(true); receiver = spy(receiver); receiver.afterPropertiesSet(); - + Field folderField = AbstractMailReceiver.class.getDeclaredField("folder"); folderField.setAccessible(true); Folder folder = mock(Folder.class); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); folderField.set(receiver, folder); - + Message msg1 = mock(MimeMessage.class); Message msg2 = mock(MimeMessage.class); final Message[] messages = new Message[]{msg1, msg2}; @@ -136,13 +136,13 @@ public class ImapMailReceiverTests { return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; @@ -159,14 +159,14 @@ public class ImapMailReceiverTests { ((ImapMailReceiver)receiver).setShouldMarkMessagesAsRead(false); receiver = spy(receiver); receiver.afterPropertiesSet(); - + Field folderField = AbstractMailReceiver.class.getDeclaredField("folder"); folderField.setAccessible(true); Folder folder = mock(Folder.class); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); folderField.set(receiver, folder); - - + + Message msg1 = mock(MimeMessage.class); Message msg2 = mock(MimeMessage.class); final Message[] messages = new Message[]{msg1, msg2}; @@ -175,13 +175,13 @@ public class ImapMailReceiverTests { return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; @@ -199,13 +199,13 @@ public class ImapMailReceiverTests { ((ImapMailReceiver)receiver).setShouldMarkMessagesAsRead(false); receiver = spy(receiver); receiver.afterPropertiesSet(); - + Field folderField = AbstractMailReceiver.class.getDeclaredField("folder"); folderField.setAccessible(true); Folder folder = mock(Folder.class); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); folderField.set(receiver, folder); - + Message msg1 = mock(MimeMessage.class); Message msg2 = mock(MimeMessage.class); final Message[] messages = new Message[]{msg1, msg2}; @@ -219,13 +219,13 @@ public class ImapMailReceiverTests { return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; @@ -243,13 +243,13 @@ public class ImapMailReceiverTests { AbstractMailReceiver receiver = new ImapMailReceiver(); receiver = spy(receiver); receiver.afterPropertiesSet(); - + Field folderField = AbstractMailReceiver.class.getDeclaredField("folder"); folderField.setAccessible(true); Folder folder = mock(Folder.class); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); folderField.set(receiver, folder); - + Message msg1 = mock(MimeMessage.class); Message msg2 = mock(MimeMessage.class); final Message[] messages = new Message[]{msg1, msg2}; @@ -263,13 +263,13 @@ public class ImapMailReceiverTests { return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; @@ -283,22 +283,22 @@ public class ImapMailReceiverTests { @Test @Ignore public void testMessageHistory() throws Exception{ - ApplicationContext context = + ApplicationContext context = new ClassPathXmlApplicationContext("ImapIdleChannelAdapterParserTests-context.xml", ImapIdleChannelAdapterParserTests.class); ImapIdleChannelAdapter adapter = context.getBean("simpleAdapter", ImapIdleChannelAdapter.class); - + AbstractMailReceiver receiver = new ImapMailReceiver(); receiver = spy(receiver); receiver.afterPropertiesSet(); - + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); adapterAccessor.setPropertyValue("mailReceiver", receiver); - + MimeMessage mailMessage = mock(MimeMessage.class); Flags flags = mock(Flags.class); when(mailMessage.getFlags()).thenReturn(flags); final Message[] messages = new Message[]{mailMessage}; - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { DirectFieldAccessor accesor = new DirectFieldAccessor((invocation.getMock())); @@ -308,19 +308,19 @@ public class ImapMailReceiverTests { return null; } }).when(receiver).openFolder(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; } }).when(receiver).fetchMessages(messages); - + PollableChannel channel = context.getBean("channel", PollableChannel.class); adapter.start(); @@ -334,16 +334,17 @@ public class ImapMailReceiverTests { @Test public void testIdleChannelAdapterException() throws Exception{ - ApplicationContext context = + ApplicationContext context = new ClassPathXmlApplicationContext("ImapIdleChannelAdapterParserTests-context.xml", ImapIdleChannelAdapterParserTests.class); ImapIdleChannelAdapter adapter = context.getBean("simpleAdapter", ImapIdleChannelAdapter.class); //ImapMailReceiver receiver = (ImapMailReceiver) TestUtils.getPropertyValue(adapter, "mailReceiver"); - - - + + + DirectChannel channel = new DirectChannel(); channel.subscribe(new AbstractReplyProducingMessageHandler() { + @Override protected Object handleRequestMessage(org.springframework.integration.Message requestMessage) { throw new RuntimeException("Failed"); } @@ -351,58 +352,58 @@ public class ImapMailReceiverTests { adapter.setOutputChannel(channel); QueueChannel errorChannel = new QueueChannel(); adapter.setErrorChannel(errorChannel); - + AbstractMailReceiver receiver = new ImapMailReceiver(); receiver = spy(receiver); receiver.afterPropertiesSet(); - + Field folderField = AbstractMailReceiver.class.getDeclaredField("folder"); folderField.setAccessible(true); Folder folder = mock(IMAPFolder.class); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); folderField.set(receiver, folder); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return true; } }).when(folder).isOpen(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; } }).when(receiver).openFolder(); - + DirectFieldAccessor adapterAccessor = new DirectFieldAccessor(adapter); adapterAccessor.setPropertyValue("mailReceiver", receiver); - + MimeMessage mailMessage = mock(MimeMessage.class); Flags flags = mock(Flags.class); when(mailMessage.getFlags()).thenReturn(flags); final Message[] messages = new Message[]{mailMessage}; - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return messages; } }).when(receiver).searchForNewMessages(); - + doAnswer(new Answer() { public Object answer(InvocationOnMock invocation) throws Throwable { return null; } }).when(receiver).fetchMessages(messages); - + adapter.start(); org.springframework.integration.Message replMessage = errorChannel.receive(10000); assertNotNull(replMessage); assertEquals("Failed", ((Exception) replMessage.getPayload()).getCause().getMessage()); } - + @Test // see INT-1801 public void testImapLifecycleForRaceCondition() throws Exception{ - + for (int i = 0; i < 1000; i++) { final ImapMailReceiver receiver = new ImapMailReceiver("imap://foo"); Store store = mock(Store.class); @@ -412,12 +413,12 @@ public class ImapMailReceiverTests { when(folder.search((SearchTerm) Mockito.any())).thenReturn(new Message[]{}); when(store.getFolder(Mockito.any(URLName.class))).thenReturn(folder); when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER)); - - + + DirectFieldAccessor df = new DirectFieldAccessor(receiver); df.setPropertyValue("store", store); receiver.afterPropertiesSet(); - + new Thread(new Runnable() { public void run(){ try { @@ -428,10 +429,10 @@ public class ImapMailReceiverTests { failed.getAndIncrement(); } } - + } }).start(); - + new Thread(new Runnable() { public void run(){ try { @@ -445,4 +446,13 @@ public class ImapMailReceiverTests { } assertEquals(0, failed.get()); } + + @Test + public void testCustomSearchTermStrategy() throws Exception{ + ImapMailReceiver receiver = new ImapMailReceiver(); + SearchTermStrategy stStrategy = mock(SearchTermStrategy.class); + + receiver.setSearchTermStrategy(stStrategy); + assertEquals(stStrategy, TestUtils.getPropertyValue(receiver, "searchTermStrategy")); + } } diff --git a/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests-context.xml b/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests-context.xml index 02dc65116f..a8b12caff5 100644 --- a/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests-context.xml +++ b/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests-context.xml @@ -63,7 +63,10 @@ channel="channel" auto-startup="false" java-mail-properties="javaMailProperties" - should-delete-messages="${mail.delete}"/> + should-delete-messages="${mail.delete}" + search-term-strategy="searchTermStrategy"/> + + bar diff --git a/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests.java b/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests.java index 33721cb21b..47188a20db 100644 --- a/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests.java +++ b/spring-integration-mail/src/test/java/org/springframework/integration/mail/config/ImapIdleChannelAdapterParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 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. @@ -22,10 +22,14 @@ import static org.junit.Assert.assertSame; import java.util.Properties; +import javax.mail.Flags; +import javax.mail.Folder; import javax.mail.URLName; +import javax.mail.search.SearchTerm; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -33,6 +37,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.integration.MessageChannel; import org.springframework.integration.mail.ImapIdleChannelAdapter; import org.springframework.integration.mail.ImapMailReceiver; +import org.springframework.integration.mail.SearchTermStrategy; import org.springframework.integration.test.util.TestUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -111,7 +116,7 @@ public class ImapIdleChannelAdapterParserTests { assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("shouldDeleteMessages")); assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("shouldMarkMessagesAsRead")); } - + @Test public void simpleAdapterWithMarkeMessagesAsReadFalse() { Object adapter = context.getBean("simpleAdapterMarkAsReadFalse"); @@ -147,10 +152,20 @@ public class ImapIdleChannelAdapterParserTests { Properties properties = (Properties) receiverAccessor.getPropertyValue("javaMailProperties"); assertEquals("bar", properties.getProperty("foo")); assertEquals(Boolean.FALSE, receiverAccessor.getPropertyValue("shouldDeleteMessages")); + SearchTermStrategy stStrategy = context.getBean("searchTermStrategy", SearchTermStrategy.class); + assertEquals(stStrategy, TestUtils.getPropertyValue(adapter, "mailReceiver.searchTermStrategy")); } @Test public void testAutoChannel() { assertSame(autoChannel, TestUtils.getPropertyValue(autoChannelAdapter, "outputChannel")); } + + public static class TestSearchTermStrategy implements SearchTermStrategy { + + public SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder) { + return null; + } + + } } diff --git a/src/reference/docbook/mail.xml b/src/reference/docbook/mail.xml index 27f8d4e577..9cddae3e84 100644 --- a/src/reference/docbook/mail.xml +++ b/src/reference/docbook/mail.xml @@ -125,6 +125,34 @@ ]]> + + By default, the ImapMailReceiver will search for Messages based on the default SearchTerm + which is All mails that are RECENT (if supported), that are NOT ANSWERED, that are NOT DELETED, that are NOT SEEN and have not + been processed by this mail receiver (enabled by the use of the custom USER flag or simply NOT FLAGGED if not supported). + Since version 2.2, the SearchTerm used by the ImapMailReceiver is fully configurable + via the SearchTermStrategy which you can inject via the search-term-strategy attribute. + SearchTermStrategy is a simple strategy interface with a single method that allows you to create an + instance of the SearchTerm that will be used by the ImapMailReceiver. + + + +For example: + + + +]]> + +In the above example instead of relying on the default SearchTermStrategy the +TestSearchTermStrategy will be used instead + + IMAP IDLE and lost connection