INT-1929 Custom Mail SearchTerms
Add support for overriding default SeatchTerms in ImapMailReceiver INT-1929 PR comments Polish Docs
This commit is contained in:
committed by
Gary Russell
parent
14f78509ea
commit
7207bb1840
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user