INT-3859: Fix NPE in the ImapMailReceiver

JIRA: https://jira.spring.io/browse/INT-3859

The Java Mail `MessageCache.getMessageBySeqnum()` has the code:
````java
if (msgnum < 0) {		// XXX - < 1 ?
    if (logger.isLoggable(Level.FINE))
	logger.fine("no message seqnum " + seqnum);
        return null;
}
````
about which the `IMAPFolder.search` doesn't care:
````java
matchMsgs[i] = getMessageBySeqNumber(matches[i]);
````
therefore pops `null`s to the top for the `ImapMailReceiver`

* Fix `NPE` filtering the `Message[]` from `null` items

Note: its enough difficult to reproduce it because it isn't clear how we can end up with:
````java
if (seqnums[msgnum-1] > seqnum)
		break;		// message doesn't exist
````

in the `MessageCache`.
That's why there is no test-cases on the matter.

**Cherry-pick to 4.1.x**

Polishing

- Only create a new array if needed.
- Add a test case
This commit is contained in:
Artem Bilan
2015-10-21 21:47:06 -04:00
committed by Gary Russell
parent df85b87d5b
commit 9039a1b4c5
2 changed files with 74 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -16,7 +16,9 @@
package org.springframework.integration.mail;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ScheduledFuture;
@@ -197,11 +199,34 @@ public class ImapMailReceiver extends AbstractMailReceiver {
SearchTerm searchTerm = this.compileSearchTerms(supportedFlags);
Folder folder = this.getFolder();
if (folder.isOpen()) {
return searchTerm != null ? folder.search(searchTerm) : folder.getMessages();
return nullSafeMessages(searchTerm != null ? folder.search(searchTerm) : folder.getMessages());
}
throw new MessagingException("Folder is closed");
}
// INT-3859
private Message[] nullSafeMessages(Message[] messageArray) {
boolean hasNulls = false;
for (Message message : messageArray) {
if (message == null) {
hasNulls = true;
break;
}
}
if (!hasNulls) {
return messageArray;
}
else {
List<Message> messages = new ArrayList<Message>();
for (Message message : messageArray) {
if (message != null) {
messages.add(message);
}
}
return messages.toArray(new Message[messages.size()]);
}
}
private SearchTerm compileSearchTerms(Flags supportedFlags) {
return this.searchTermStrategy.generateSearchTerm(supportedFlags, this.getFolder());
}

View File

@@ -870,6 +870,53 @@ public class ImapMailReceiverTests {
assertTrue(exec.isShutdown());
}
@Test
public void testNullMessages() throws Exception {
Message message1 = mock(Message.class);
Message message2 = mock(Message.class);
final Message[] messages1 = new Message[] { null, null, message1 };
final Message[] messages2 = new Message[] { message2 };
final SearchTermStrategy searchTermStrategy = mock(SearchTermStrategy.class);
class TestReceiver extends ImapMailReceiver {
private boolean firstDone;
public TestReceiver() {
setSearchTermStrategy(searchTermStrategy);
}
@Override
protected Folder getFolder() {
Folder folder = mock(Folder.class);
when(folder.isOpen()).thenReturn(true);
try {
when(folder.getMessages())
.thenReturn(!this.firstDone ? messages1 : messages2);
}
catch (MessagingException e) {
}
return folder;
}
@Override
public Message[] receive() throws MessagingException {
Message[] messages = searchForNewMessages();
this.firstDone = true;
return messages;
}
};
ImapMailReceiver receiver = new TestReceiver();
Message[] received = receiver.receive();
assertEquals(1, received.length);
assertSame(message1, received[0]);
received = receiver.receive();
assertEquals(1, received.length);
assertSame(messages2, received);
assertSame(message2, received[0]);
}
private void setUpScheduler(ImapMailReceiver mailReceiver, ThreadPoolTaskScheduler taskScheduler) {
taskScheduler.setPoolSize(5);
taskScheduler.initialize();