INT-1929 Custom Mail SearchTerms

Add support for overriding default SeatchTerms in ImapMailReceiver

INT-1929 PR comments

Polish Docs
This commit is contained in:
Oleg Zhurakousky
2012-06-06 17:24:23 -04:00
committed by Gary Russell
parent 14f78509ea
commit 7207bb1840
8 changed files with 263 additions and 121 deletions

View File

@@ -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;
}
}
}

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -122,6 +122,23 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="search-term-strategy" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type
type="org.springframework.integration.mail.SearchTermStrategy" />
</tool:annotation>
</xsd:appinfo>
<xsd:documentation>
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)".
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>

View File

@@ -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<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return true;
}
}).when(folder).isOpen();
doAnswer(new Answer<Object>() {
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<Object>() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return messages;
}
}).when(receiver).searchForNewMessages();
doAnswer(new Answer<Object>() {
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"));
}
}

View File

@@ -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"/>
<bean id="searchTermStrategy" class="org.springframework.integration.mail.config.ImapIdleChannelAdapterParserTests.TestSearchTermStrategy"/>
<util:properties id="javaMailProperties">
<prop key="foo">bar</prop>

View File

@@ -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;
}
}
}

View File

@@ -125,6 +125,34 @@
</util:properties>]]></programlisting>
</para>
<para>
By default, the <classname>ImapMailReceiver</classname> will search for Messages based on the default <classname>SearchTerm</classname>
which is <emphasis>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)</emphasis>.
Since version 2.2, the <classname>SearchTerm</classname> used by the <classname>ImapMailReceiver</classname> is fully configurable
via the <code>SearchTermStrategy</code> which you can inject via the <code>search-term-strategy</code> attribute.
<classname>SearchTermStrategy</classname> is a simple strategy interface with a single method that allows you to create an
instance of the <classname>SearchTerm</classname> that will be used by the <classname>ImapMailReceiver</classname>.
</para>
<programlisting language="java"><![CDATA[public interface SearchTermStrategy {
SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder);
}]]></programlisting>
<para>
For example:
</para>
<programlisting language="xml"><![CDATA[<mail:imap-idle-channel-adapter id="customAdapter"
store-uri="imap:foo"
. . .
search-term-strategy="searchTermStrategy"/>
<bean id="searchTermStrategy" class="org.springframework.integration.mail.config.ImapIdleChannelAdapterParserTests.TestSearchTermStrategy"/>]]></programlisting>
<para>
In the above example instead of relying on the default <classname>SearchTermStrategy</classname> the
<classname>TestSearchTermStrategy</classname> will be used instead
</para>
<para><emphasis>IMAP IDLE and lost connection</emphasis></para>
<para>