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.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50
51 import org.springframework.util.Assert;
52 import org.springframework.ws.WebServiceMessage;
53 import org.springframework.ws.transport.AbstractSenderConnection;
54 import org.springframework.ws.transport.TransportConstants;
55 import org.springframework.ws.transport.WebServiceConnection;
56 import org.springframework.ws.transport.mail.support.MailTransportUtils;
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 protected void onSendBeforeWrite(WebServiceMessage message) throws IOException {
148 try {
149 requestMessage = new MimeMessage(session);
150 requestMessage.setRecipient(Message.RecipientType.TO, to);
151 requestMessage.setSentDate(new Date());
152 if (from != null) {
153 requestMessage.setFrom(from);
154 }
155 if (subject != null) {
156 requestMessage.setSubject(subject);
157 }
158 requestBuffer = new ByteArrayOutputStream();
159 }
160 catch (MessagingException ex) {
161 throw new MailTransportException(ex);
162 }
163 }
164
165 protected void addRequestHeader(String name, String value) throws IOException {
166 try {
167 requestMessage.addHeader(name, value);
168 if (TransportConstants.HEADER_CONTENT_TYPE.equals(name)) {
169 requestContentType = value;
170 }
171 }
172 catch (MessagingException ex) {
173 throw new MailTransportException(ex);
174 }
175 }
176
177 protected OutputStream getRequestOutputStream() throws IOException {
178 return requestBuffer;
179 }
180
181 protected void onSendAfterWrite(WebServiceMessage message) throws IOException {
182 Transport transport = null;
183 try {
184 requestMessage.setDataHandler(
185 new DataHandler(new ByteArrayDataSource(requestContentType, requestBuffer.toByteArray())));
186 transport = session.getTransport(transportUri);
187 transport.connect();
188 requestMessage.saveChanges();
189 transport.sendMessage(requestMessage, requestMessage.getAllRecipients());
190 }
191 catch (MessagingException ex) {
192 throw new MailTransportException(ex);
193 }
194 finally {
195 MailTransportUtils.closeService(transport);
196 }
197 }
198
199
200
201
202
203 protected void onReceiveBeforeRead() throws IOException {
204 try {
205 String requestMessageId = requestMessage.getMessageID();
206 Assert.hasLength(requestMessageId, "No Message-ID found on request message [" + requestMessage + "]");
207 try {
208 Thread.sleep(receiveTimeout);
209 }
210 catch (InterruptedException e) {
211
212 Thread.currentThread().interrupt();
213 }
214 openFolder();
215 SearchTerm searchTerm = new HeaderTerm(MailTransportConstants.HEADER_IN_REPLY_TO, requestMessageId);
216 Message[] responses = folder.search(searchTerm);
217 if (responses.length > 0) {
218 if (responses.length > 1) {
219 logger.warn("Received more than one response for request with ID [" + requestMessageId + "]");
220 }
221 responseMessage = responses[0];
222 }
223 if (deleteAfterReceive) {
224 responseMessage.setFlag(Flags.Flag.DELETED, true);
225 }
226 }
227 catch (MessagingException ex) {
228 throw new MailTransportException(ex);
229 }
230 }
231
232 private void openFolder() throws MessagingException {
233 store = session.getStore(storeUri);
234 store.connect();
235 folder = store.getFolder(storeUri);
236 if (folder == null || !folder.exists()) {
237 throw new IllegalStateException("No default folder to receive from");
238 }
239 if (deleteAfterReceive) {
240 folder.open(Folder.READ_WRITE);
241 }
242 else {
243 folder.open(Folder.READ_ONLY);
244 }
245 }
246
247 protected boolean hasResponse() throws IOException {
248 return responseMessage != null;
249 }
250
251 protected Iterator getResponseHeaderNames() throws IOException {
252 try {
253 List headers = new ArrayList();
254 Enumeration enumeration = responseMessage.getAllHeaders();
255 while (enumeration.hasMoreElements()) {
256 Header header = (Header) enumeration.nextElement();
257 headers.add(header.getName());
258 }
259 return headers.iterator();
260 }
261 catch (MessagingException ex) {
262 throw new MailTransportException(ex);
263 }
264 }
265
266 protected Iterator getResponseHeaders(String name) throws IOException {
267 try {
268 String[] headers = responseMessage.getHeader(name);
269 return Arrays.asList(headers).iterator();
270 }
271 catch (MessagingException ex) {
272 throw new MailTransportException(ex);
273
274 }
275 }
276
277 protected InputStream getResponseInputStream() throws IOException {
278 try {
279 return responseMessage.getDataHandler().getInputStream();
280 }
281 catch (MessagingException ex) {
282 throw new MailTransportException(ex);
283 }
284 }
285
286 public boolean hasError() throws IOException {
287 return false;
288 }
289
290 public String getErrorMessage() throws IOException {
291 return null;
292 }
293
294 public void onClose() throws IOException {
295 MailTransportUtils.closeFolder(folder, deleteAfterReceive);
296 MailTransportUtils.closeService(store);
297 }
298
299 private class ByteArrayDataSource implements DataSource {
300
301 private byte[] data;
302
303 private String contentType;
304
305 public ByteArrayDataSource(String contentType, byte[] data) {
306 this.data = data;
307 this.contentType = contentType;
308 }
309
310 public InputStream getInputStream() throws IOException {
311 return new ByteArrayInputStream(data);
312 }
313
314 public OutputStream getOutputStream() throws IOException {
315 throw new UnsupportedOperationException();
316 }
317
318 public String getContentType() {
319 return contentType;
320 }
321
322 public String getName() {
323 return "ByteArrayDataSource";
324 }
325 }
326
327 }