MailSendException includes all messages as failed messages in case of a connect failure (SPR-7245)

This commit is contained in:
Juergen Hoeller 2010-06-10 21:06:13 +00:00
parent 2f4453a99c
commit 433b4eff8f
3 changed files with 102 additions and 41 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -55,6 +55,22 @@ public class MailSendException extends MailException {
this.failedMessages = new LinkedHashMap<Object, Exception>(); this.failedMessages = new LinkedHashMap<Object, Exception>();
} }
/**
* Constructor for registration of failed messages, with the
* messages that failed as keys, and the thrown exceptions as values.
* <p>The messages should be the same that were originally passed
* to the invoked send method.
* @param msg the detail message
* @param cause the root cause from the mail API in use
* @param failedMessages Map of failed messages as keys and thrown
* exceptions as values
*/
public MailSendException(String msg, Throwable cause, Map<Object, Exception> failedMessages) {
super(msg, cause);
this.failedMessages = new LinkedHashMap<Object, Exception>(failedMessages);
this.messageExceptions = failedMessages.values().toArray(new Exception[failedMessages.size()]);
}
/** /**
* Constructor for registration of failed messages, with the * Constructor for registration of failed messages, with the
* messages that failed as keys, and the thrown exceptions as values. * messages that failed as keys, and the thrown exceptions as values.
@ -64,9 +80,7 @@ public class MailSendException extends MailException {
* exceptions as values * exceptions as values
*/ */
public MailSendException(Map<Object, Exception> failedMessages) { public MailSendException(Map<Object, Exception> failedMessages) {
super(null); this(null, null, failedMessages);
this.failedMessages = new LinkedHashMap<Object, Exception>(failedMessages);
this.messageExceptions = failedMessages.values().toArray(new Exception[failedMessages.size()]);
} }
@ -111,7 +125,12 @@ public class MailSendException extends MailException {
return super.getMessage(); return super.getMessage();
} }
else { else {
StringBuilder sb = new StringBuilder("Failed messages: "); StringBuilder sb = new StringBuilder();
String baseMessage = super.getMessage();
if (baseMessage != null) {
sb.append(baseMessage).append(". ");
}
sb.append("Failed messages: ");
for (int i = 0; i < this.messageExceptions.length; i++) { for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i]; Exception subEx = this.messageExceptions[i];
sb.append(subEx.toString()); sb.append(subEx.toString());
@ -129,8 +148,8 @@ public class MailSendException extends MailException {
return super.toString(); return super.toString();
} }
else { else {
StringBuilder sb = new StringBuilder(getClass().getName()); StringBuilder sb = new StringBuilder(super.toString());
sb.append("; nested exceptions (").append(this.messageExceptions.length).append(") are:"); sb.append("; message exceptions (").append(this.messageExceptions.length).append(") are:");
for (int i = 0; i < this.messageExceptions.length; i++) { for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i]; Exception subEx = this.messageExceptions[i];
sb.append('\n').append("Failed message ").append(i + 1).append(": "); sb.append('\n').append("Failed message ").append(i + 1).append(": ");
@ -146,7 +165,7 @@ public class MailSendException extends MailException {
super.printStackTrace(ps); super.printStackTrace(ps);
} }
else { else {
ps.println(getClass().getName() + "; nested exception details (" + ps.println(super.toString() + "; message exception details (" +
this.messageExceptions.length + ") are:"); this.messageExceptions.length + ") are:");
for (int i = 0; i < this.messageExceptions.length; i++) { for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i]; Exception subEx = this.messageExceptions[i];
@ -162,7 +181,7 @@ public class MailSendException extends MailException {
super.printStackTrace(pw); super.printStackTrace(pw);
} }
else { else {
pw.println(getClass().getName() + "; nested exception details (" + pw.println(super.toString() + "; message exception details (" +
this.messageExceptions.length + ") are:"); this.messageExceptions.length + ") are:");
for (int i = 0; i < this.messageExceptions.length; i++) { for (int i = 0; i < this.messageExceptions.length; i++) {
Exception subEx = this.messageExceptions[i]; Exception subEx = this.messageExceptions[i];

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,7 +24,6 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import javax.activation.FileTypeMap; import javax.activation.FileTypeMap;
import javax.mail.AuthenticationFailedException; import javax.mail.AuthenticationFailedException;
import javax.mail.MessagingException; import javax.mail.MessagingException;
@ -383,9 +382,24 @@ public class JavaMailSenderImpl implements JavaMailSender {
*/ */
protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException { protected void doSend(MimeMessage[] mimeMessages, Object[] originalMessages) throws MailException {
Map<Object, Exception> failedMessages = new LinkedHashMap<Object, Exception>(); Map<Object, Exception> failedMessages = new LinkedHashMap<Object, Exception>();
Transport transport;
try { try {
Transport transport = getTransport(getSession()); transport = getTransport(getSession());
transport.connect(getHost(), getPort(), getUsername(), getPassword()); transport.connect(getHost(), getPort(), getUsername(), getPassword());
}
catch (AuthenticationFailedException ex) {
throw new MailAuthenticationException(ex);
}
catch (MessagingException ex) {
// Effectively, all messages failed...
for (int i = 0; i < mimeMessages.length; i++) {
Object original = (originalMessages != null ? originalMessages[i] : mimeMessages[i]);
failedMessages.put(original, ex);
}
throw new MailSendException("Mail server connection failed", ex, failedMessages);
}
try { try {
for (int i = 0; i < mimeMessages.length; i++) { for (int i = 0; i < mimeMessages.length; i++) {
MimeMessage mimeMessage = mimeMessages[i]; MimeMessage mimeMessage = mimeMessages[i];
@ -408,15 +422,20 @@ public class JavaMailSenderImpl implements JavaMailSender {
} }
} }
finally { finally {
try {
transport.close(); transport.close();
} }
}
catch (AuthenticationFailedException ex) {
throw new MailAuthenticationException(ex);
}
catch (MessagingException ex) { catch (MessagingException ex) {
throw new MailSendException("Mail server connection failed", ex); if (!failedMessages.isEmpty()) {
throw new MailSendException("Failed to close server connection after message failures", ex,
failedMessages);
} }
else {
throw new MailSendException("Failed to close server connection after message sending", ex);
}
}
}
if (!failedMessages.isEmpty()) { if (!failedMessages.isEmpty()) {
throw new MailSendException(failedMessages); throw new MailSendException(failedMessages);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2006 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,6 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import javax.activation.FileTypeMap; import javax.activation.FileTypeMap;
import javax.mail.Address; import javax.mail.Address;
import javax.mail.Message; import javax.mail.Message;
@ -381,8 +380,29 @@ public class JavaMailSenderTests extends TestCase {
} }
catch (MailSendException ex) { catch (MailSendException ex) {
// expected // expected
ex.printStackTrace();
assertTrue(ex.getFailedMessages() != null); assertTrue(ex.getFailedMessages() != null);
assertTrue(ex.getFailedMessages().isEmpty()); assertEquals(1, ex.getFailedMessages().size());
assertSame(simpleMessage1, ex.getFailedMessages().keySet().iterator().next());
assertSame(ex.getCause(), ex.getFailedMessages().values().iterator().next());
}
}
public void testFailedMailServerClose() throws Exception {
MockJavaMailSender sender = new MockJavaMailSender();
sender.setHost("");
sender.setUsername("username");
sender.setPassword("password");
SimpleMailMessage simpleMessage1 = new SimpleMailMessage();
try {
sender.send(simpleMessage1);
fail("Should have thrown MailSendException");
}
catch (MailSendException ex) {
// expected
ex.printStackTrace();
assertTrue(ex.getFailedMessages() != null);
assertEquals(0, ex.getFailedMessages().size());
} }
} }
@ -515,6 +535,9 @@ public class JavaMailSenderTests extends TestCase {
@Override @Override
public synchronized void close() throws MessagingException { public synchronized void close() throws MessagingException {
if ("".equals(connectedHost)) {
throw new MessagingException("close failure");
}
this.closeCalled = true; this.closeCalled = true;
} }
@ -531,7 +554,7 @@ public class JavaMailSenderTests extends TestCase {
if (message.getSentDate() == null) { if (message.getSentDate() == null) {
throw new MessagingException("No sentDate specified"); throw new MessagingException("No sentDate specified");
} }
if (message.getSubject() != null && message.getSubject().indexOf("custom") != -1) { if (message.getSubject() != null && message.getSubject().contains("custom")) {
assertEquals(new Date(2005, 3, 1), message.getSentDate()); assertEquals(new Date(2005, 3, 1), message.getSentDate());
} }
this.sentMessages.add(message); this.sentMessages.add(message);