View Javadoc
1   /*
2    * Copyright 2002-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.mail;
18  
19  import java.io.PrintStream;
20  import java.io.PrintWriter;
21  import java.util.LinkedHashMap;
22  import java.util.Map;
23  
24  import org.springframework.util.ObjectUtils;
25  
26  /**
27   * Exception thrown when a mail sending error is encountered.
28   * Can register failed messages with their exceptions.
29   *
30   * @author Dmitriy Kopylenko
31   * @author Juergen Hoeller
32   */
33  @SuppressWarnings("serial")
34  public class MailSendException extends MailException {
35  
36  	private transient final Map<Object, Exception> failedMessages;
37  
38  	private Exception[] messageExceptions;
39  
40  
41  	/**
42  	 * Constructor for MailSendException.
43  	 * @param msg the detail message
44  	 */
45  	public MailSendException(String msg) {
46  		this(msg, null);
47  	}
48  
49  	/**
50  	 * Constructor for MailSendException.
51  	 * @param msg the detail message
52  	 * @param cause the root cause from the mail API in use
53  	 */
54  	public MailSendException(String msg, Throwable cause) {
55  		super(msg, cause);
56  		this.failedMessages = new LinkedHashMap<Object, Exception>();
57  	}
58  
59  	/**
60  	 * Constructor for registration of failed messages, with the
61  	 * messages that failed as keys, and the thrown exceptions as values.
62  	 * <p>The messages should be the same that were originally passed
63  	 * to the invoked send method.
64  	 * @param msg the detail message
65  	 * @param cause the root cause from the mail API in use
66  	 * @param failedMessages Map of failed messages as keys and thrown
67  	 * exceptions as values
68  	 */
69  	public MailSendException(String msg, Throwable cause, Map<Object, Exception> failedMessages) {
70  		super(msg, cause);
71  		this.failedMessages = new LinkedHashMap<Object, Exception>(failedMessages);
72  		this.messageExceptions = failedMessages.values().toArray(new Exception[failedMessages.size()]);
73  	}
74  
75  	/**
76  	 * Constructor for registration of failed messages, with the
77  	 * messages that failed as keys, and the thrown exceptions as values.
78  	 * <p>The messages should be the same that were originally passed
79  	 * to the invoked send method.
80  	 * @param failedMessages Map of failed messages as keys and thrown
81  	 * exceptions as values
82  	 */
83  	public MailSendException(Map<Object, Exception> failedMessages) {
84  		this(null, null, failedMessages);
85  	}
86  
87  
88  	/**
89  	 * Return a Map with the failed messages as keys, and the thrown exceptions
90  	 * as values.
91  	 * <p>Note that a general mail server connection failure will not result
92  	 * in failed messages being returned here: A message will only be
93  	 * contained here if actually sending it was attempted but failed.
94  	 * <p>The messages will be the same that were originally passed to the
95  	 * invoked send method, that is, SimpleMailMessages in case of using
96  	 * the generic MailSender interface.
97  	 * <p>In case of sending MimeMessage instances via JavaMailSender,
98  	 * the messages will be of type MimeMessage.
99  	 * <p><b>NOTE:</b> This Map will not be available after serialization.
100 	 * Use {@link #getMessageExceptions()} in such a scenario, which will
101 	 * be available after serialization as well.
102 	 * @return the Map of failed messages as keys and thrown exceptions as values
103 	 * @see SimpleMailMessage
104 	 * @see javax.mail.internet.MimeMessage
105 	 */
106 	public final Map<Object, Exception> getFailedMessages() {
107 		return this.failedMessages;
108 	}
109 
110 	/**
111 	 * Return an array with thrown message exceptions.
112 	 * <p>Note that a general mail server connection failure will not result
113 	 * in failed messages being returned here: A message will only be
114 	 * contained here if actually sending it was attempted but failed.
115 	 * @return the array of thrown message exceptions,
116 	 * or an empty array if no failed messages
117 	 */
118 	public final Exception[] getMessageExceptions() {
119 		return (this.messageExceptions != null ? this.messageExceptions : new Exception[0]);
120 	}
121 
122 
123 	@Override
124 	public String getMessage() {
125 		if (ObjectUtils.isEmpty(this.messageExceptions)) {
126 			return super.getMessage();
127 		}
128 		else {
129 			StringBuilder sb = new StringBuilder();
130 			String baseMessage = super.getMessage();
131 			if (baseMessage != null) {
132 				sb.append(baseMessage).append(". ");
133 			}
134 			sb.append("Failed messages: ");
135 			for (int i = 0; i < this.messageExceptions.length; i++) {
136 				Exception subEx = this.messageExceptions[i];
137 				sb.append(subEx.toString());
138 				if (i < this.messageExceptions.length - 1) {
139 					sb.append("; ");
140 				}
141 			}
142 			return sb.toString();
143 		}
144 	}
145 
146 	@Override
147 	public String toString() {
148 		if (ObjectUtils.isEmpty(this.messageExceptions)) {
149 			return super.toString();
150 		}
151 		else {
152 			StringBuilder sb = new StringBuilder(super.toString());
153 			sb.append("; message exceptions (").append(this.messageExceptions.length).append(") are:");
154 			for (int i = 0; i < this.messageExceptions.length; i++) {
155 				Exception subEx = this.messageExceptions[i];
156 				sb.append('\n').append("Failed message ").append(i + 1).append(": ");
157 				sb.append(subEx);
158 			}
159 			return sb.toString();
160 		}
161 	}
162 
163 	@Override
164 	public void printStackTrace(PrintStream ps) {
165 		if (ObjectUtils.isEmpty(this.messageExceptions)) {
166 			super.printStackTrace(ps);
167 		}
168 		else {
169 			ps.println(super.toString() + "; message exception details (" +
170 					this.messageExceptions.length + ") are:");
171 			for (int i = 0; i < this.messageExceptions.length; i++) {
172 				Exception subEx = this.messageExceptions[i];
173 				ps.println("Failed message " + (i + 1) + ":");
174 				subEx.printStackTrace(ps);
175 			}
176 		}
177 	}
178 
179 	@Override
180 	public void printStackTrace(PrintWriter pw) {
181 		if (ObjectUtils.isEmpty(this.messageExceptions)) {
182 			super.printStackTrace(pw);
183 		}
184 		else {
185 			pw.println(super.toString() + "; message exception details (" +
186 					this.messageExceptions.length + ") are:");
187 			for (int i = 0; i < this.messageExceptions.length; i++) {
188 				Exception subEx = this.messageExceptions[i];
189 				pw.println("Failed message " + (i + 1) + ":");
190 				subEx.printStackTrace(pw);
191 			}
192 		}
193 	}
194 
195 }