1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.transport.mail;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Date;
29 import java.util.Enumeration;
30 import java.util.Iterator;
31 import java.util.List;
32 import javax.activation.DataHandler;
33 import javax.activation.DataSource;
34 import javax.mail.Flags;
35 import javax.mail.Folder;
36 import javax.mail.Header;
37 import javax.mail.Message;
38 import javax.mail.MessagingException;
39 import javax.mail.Session;
40 import javax.mail.Store;
41 import javax.mail.Transport;
42 import javax.mail.URLName;
43 import javax.mail.internet.InternetAddress;
44 import javax.mail.internet.MimeMessage;
45 import javax.mail.search.HeaderTerm;
46 import javax.mail.search.SearchTerm;
47
48 import org.springframework.util.Assert;
49 import org.springframework.ws.WebServiceMessage;
50 import org.springframework.ws.transport.AbstractSenderConnection;
51 import org.springframework.ws.transport.TransportConstants;
52 import org.springframework.ws.transport.WebServiceConnection;
53 import org.springframework.ws.transport.mail.support.MailTransportUtils;
54
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57
58
59
60
61
62
63
64
65
66 public class MailSenderConnection extends AbstractSenderConnection {
67
68 private static final Log logger = LogFactory.getLog(MailSenderConnection.class);
69
70 private final Session session;
71
72 private MimeMessage requestMessage;
73
74 private Message responseMessage;
75
76 private String requestContentType;
77
78 private boolean deleteAfterReceive = false;
79
80 private final URLName storeUri;
81
82 private final URLName transportUri;
83
84 private ByteArrayOutputStream requestBuffer;
85
86 private InternetAddress from;
87
88 private final InternetAddress to;
89
90 private String subject;
91
92 private final long receiveTimeout;
93
94 private Store store;
95
96 private Folder folder;
97
98
99 protected MailSenderConnection(Session session,
100 URLName transportUri,
101 URLName storeUri,
102 InternetAddress to,
103 long receiveTimeout) {
104 Assert.notNull(session, "'session' must not be null");
105 Assert.notNull(transportUri, "'transportUri' must not be null");
106 Assert.notNull(storeUri, "'storeUri' must not be null");
107 Assert.notNull(to, "'to' must not be null");
108 this.session = session;
109 this.transportUri = transportUri;
110 this.storeUri = storeUri;
111 this.to = to;
112 this.receiveTimeout = receiveTimeout;
113 }
114
115
116 public Message getRequestMessage() {
117 return requestMessage;
118 }
119
120
121 public Message getResponseMessage() {
122 return responseMessage;
123 }
124
125
126
127
128
129 void setFrom(InternetAddress from) {
130 this.from = from;
131 }
132
133 void setSubject(String subject) {
134 this.subject = subject;
135 }
136
137
138
139
140 public URI getUri() throws URISyntaxException {
141 return MailTransportUtils.toUri(to, subject);
142 }
143
144
145
146
147 @Override
148 protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
149 try {
150 requestMessage = new MimeMessage(session);
151 requestMessage.setRecipient(Message.RecipientType.TO, to);
152 requestMessage.setSentDate(new Date());
153 if (from != null) {
154 requestMessage.setFrom(from);
155 }
156 if (subject != null) {
157 requestMessage.setSubject(subject);
158 }
159 requestBuffer = new ByteArrayOutputStream();
160 }
161 catch (MessagingException ex) {
162 throw new MailTransportException(ex);
163 }
164 }
165
166 @Override
167 protected void addRequestHeader(String name, String value) throws IOException {
168 try {
169 requestMessage.addHeader(name, value);
170 if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) {
171 requestContentType = value;
172 }
173 }
174 catch (MessagingException ex) {
175 throw new MailTransportException(ex);
176 }
177 }
178
179 @Override
180 protected OutputStream getRequestOutputStream() throws IOException {
181 return requestBuffer;
182 }
183
184 @Override
185 protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
186 Transport transport = null;
187 try {
188 requestMessage.setDataHandler(
189 new DataHandler(new ByteArrayDataSource(requestContentType, requestBuffer.toByteArray())));
190 transport = session.getTransport(transportUri);
191 transport.connect();
192 requestMessage.saveChanges();
193 transport.sendMessage(requestMessage, requestMessage.getAllRecipients());
194 }
195 catch (MessagingException ex) {
196 throw new MailTransportException(ex);
197 }
198 finally {
199 MailTransportUtils.closeService(transport);
200 }
201 }
202
203
204
205
206
207 @Override
208 protected void onReceiveBeforeRead() throws IOException {
209 try {
210 String requestMessageId = requestMessage.getMessageID();
211 Assert.hasLength(requestMessageId, "No Message-ID found on request message [" + requestMessage + "]");
212 try {
213 Thread.sleep(receiveTimeout);
214 }
215 catch (InterruptedException e) {
216
217 Thread.currentThread().interrupt();
218 }
219 openFolder();
220 SearchTerm searchTerm = new HeaderTerm(MailTransportConstants.HEADER_IN_REPLY_TO, requestMessageId);
221 Message[] responses = folder.search(searchTerm);
222 if (responses.length > 0) {
223 if (responses.length > 1) {
224 logger.warn("Received more than one response for request with ID [" + requestMessageId + "]");
225 }
226 responseMessage = responses[0];
227 }
228 if (deleteAfterReceive) {
229 responseMessage.setFlag(Flags.Flag.DELETED, true);
230 }
231 }
232 catch (MessagingException ex) {
233 throw new MailTransportException(ex);
234 }
235 }
236
237 private void openFolder() throws MessagingException {
238 store = session.getStore(storeUri);
239 store.connect();
240 folder = store.getFolder(storeUri);
241 if (folder == null || !folder.exists()) {
242 throw new IllegalStateException("No default folder to receive from");
243 }
244 if (deleteAfterReceive) {
245 folder.open(Folder.READ_WRITE);
246 }
247 else {
248 folder.open(Folder.READ_ONLY);
249 }
250 }
251
252 @Override
253 protected boolean hasResponse() throws IOException {
254 return responseMessage != null;
255 }
256
257 @Override
258 protected Iterator<String> getResponseHeaderNames() throws IOException {
259 try {
260 List<String> headers = new ArrayList<String>();
261 Enumeration<?> enumeration = responseMessage.getAllHeaders();
262 while (enumeration.hasMoreElements()) {
263 Header header = (Header) enumeration.nextElement();
264 headers.add(header.getName());
265 }
266 return headers.iterator();
267 }
268 catch (MessagingException ex) {
269 throw new MailTransportException(ex);
270 }
271 }
272
273 @Override
274 protected Iterator<String> getResponseHeaders(String name) throws IOException {
275 try {
276 String[] headers = responseMessage.getHeader(name);
277 return Arrays.asList(headers).iterator();
278 }
279 catch (MessagingException ex) {
280 throw new MailTransportException(ex);
281
282 }
283 }
284
285 @Override
286 protected InputStream getResponseInputStream() throws IOException {
287 try {
288 return responseMessage.getDataHandler().getInputStream();
289 }
290 catch (MessagingException ex) {
291 throw new MailTransportException(ex);
292 }
293 }
294
295 public boolean hasError() throws IOException {
296 return false;
297 }
298
299 public String getErrorMessage() throws IOException {
300 return null;
301 }
302
303 @Override
304 public void onClose() throws IOException {
305 MailTransportUtils.closeFolder(folder, deleteAfterReceive);
306 MailTransportUtils.closeService(store);
307 }
308
309 private class ByteArrayDataSource implements DataSource {
310
311 private byte[] data;
312
313 private String contentType;
314
315 public ByteArrayDataSource(String contentType, byte[] data) {
316 this.data = data;
317 this.contentType = contentType;
318 }
319
320 public InputStream getInputStream() throws IOException {
321 return new ByteArrayInputStream(data);
322 }
323
324 public OutputStream getOutputStream() throws IOException {
325 throw new UnsupportedOperationException();
326 }
327
328 public String getContentType() {
329 return contentType;
330 }
331
332 public String getName() {
333 return "ByteArrayDataSource";
334 }
335 }
336
337 }