1
1
/*
2
- * Copyright 2002-2018 the original author or authors.
2
+ * Copyright 2002-2019 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
24
24
import java .util .List ;
25
25
import java .util .Map ;
26
26
import java .util .Properties ;
27
+ import java .util .concurrent .locks .Lock ;
28
+ import java .util .concurrent .locks .ReadWriteLock ;
29
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
27
30
28
31
import javax .mail .Authenticator ;
29
32
import javax .mail .FetchProfile ;
@@ -69,7 +72,11 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
69
72
70
73
private final URLName url ;
71
74
72
- private final Object folderMonitor = new Object ();
75
+ private final ReadWriteLock folderLock = new ReentrantReadWriteLock ();
76
+
77
+ private final Lock folderReadLock = this .folderLock .readLock ();
78
+
79
+ private final Lock folderWriteLock = this .folderLock .writeLock ();
73
80
74
81
private String protocol ;
75
82
@@ -134,9 +141,7 @@ public void setProtocol(String protocol) {
134
141
/**
135
142
* Set the {@link Session}. Otherwise, the Session will be created by invocation of
136
143
* {@link Session#getInstance(Properties)} or {@link Session#getInstance(Properties, Authenticator)}.
137
- *
138
144
* @param session The session.
139
- *
140
145
* @see #setJavaMailProperties(Properties)
141
146
* @see #setJavaMailAuthenticator(Authenticator)
142
147
*/
@@ -148,9 +153,7 @@ public void setSession(Session session) {
148
153
/**
149
154
* A new {@link Session} will be created with these properties (and the JavaMailAuthenticator if provided).
150
155
* Use either this method or {@link #setSession}, but not both.
151
- *
152
156
* @param javaMailProperties The javamail properties.
153
- *
154
157
* @see #setJavaMailAuthenticator(Authenticator)
155
158
* @see #setSession(Session)
156
159
*/
@@ -165,9 +168,7 @@ protected Properties getJavaMailProperties() {
165
168
/**
166
169
* Optional, sets the Authenticator to be used to obtain a session. This will not be used if
167
170
* {@link AbstractMailReceiver#setSession} has been used to configure the {@link Session} directly.
168
- *
169
171
* @param javaMailAuthenticator The javamail authenticator.
170
- *
171
172
* @see #setSession(Session)
172
173
*/
173
174
public void setJavaMailAuthenticator (Authenticator javaMailAuthenticator ) {
@@ -176,7 +177,6 @@ public void setJavaMailAuthenticator(Authenticator javaMailAuthenticator) {
176
177
177
178
/**
178
179
* Specify the maximum number of Messages to fetch per call to {@link #receive()}.
179
- *
180
180
* @param maxFetchSize The max fetch size.
181
181
*/
182
182
public void setMaxFetchSize (int maxFetchSize ) {
@@ -185,15 +185,14 @@ public void setMaxFetchSize(int maxFetchSize) {
185
185
186
186
/**
187
187
* Specify whether mail messages should be deleted after retrieval.
188
- *
189
188
* @param shouldDeleteMessages true to delete messages.
190
189
*/
191
190
public void setShouldDeleteMessages (boolean shouldDeleteMessages ) {
192
191
this .shouldDeleteMessages = shouldDeleteMessages ;
193
192
}
193
+
194
194
/**
195
195
* Indicates whether the mail messages should be deleted after being received.
196
- *
197
196
* @return true when messages will be deleted.
198
197
*/
199
198
protected boolean shouldDeleteMessages () {
@@ -243,21 +242,17 @@ public void setEmbeddedPartsAsBytes(boolean embeddedPartsAsBytes) {
243
242
244
243
/**
245
244
* {@link MimeMessage#getContent()} returns just the email body.
246
- *
247
245
* <pre class="code">
248
246
* foo
249
247
* </pre>
250
- *
251
248
* Some subclasses, such as {@code IMAPMessage} return some headers with the body.
252
- *
253
249
* <pre class="code">
254
250
* To: foo@bar
255
251
* From: bar@baz
256
252
* Subject: Test Email
257
253
*
258
254
* foo
259
255
* </pre>
260
- *
261
256
* Starting with version 5.0, messages emitted by mail receivers will render the
262
257
* content in the same way as the {@link MimeMessage} implementation returned by
263
258
* javamail. In versions 2.2 through 4.3, the content was always just the body,
@@ -266,7 +261,6 @@ public void setEmbeddedPartsAsBytes(boolean embeddedPartsAsBytes) {
266
261
* <p>To revert to the previous behavior, set this flag to true. In addition, even
267
262
* if a header mapper is provided, the payload will just be the email body.
268
263
* @param simpleContent true to render simple content.
269
- *
270
264
* @since 5.0
271
265
*/
272
266
public void setSimpleContent (boolean simpleContent ) {
@@ -283,7 +277,6 @@ protected int getFolderOpenMode() {
283
277
284
278
/**
285
279
* Subclasses must implement this method to return new mail messages.
286
- *
287
280
* @return An array of messages.
288
281
* @throws MessagingException Any MessagingException.
289
282
*/
@@ -347,53 +340,67 @@ private Folder obtainFolderInstance() throws MessagingException {
347
340
348
341
@ Override
349
342
public Object [] receive () throws javax .mail .MessagingException {
350
- synchronized (this .folderMonitor ) {
343
+ this .folderReadLock .lock ();
344
+ Folder folder = getFolder ();
345
+ if (folder == null || !folder .isOpen ()) {
346
+ this .folderReadLock .unlock ();
347
+ this .folderWriteLock .lock ();
351
348
try {
352
- this .openFolder ();
353
- if (this .logger .isInfoEnabled ()) {
354
- this .logger .info ("attempting to receive mail from folder [" + getFolder ().getFullName () + "]" );
355
- }
356
- Message [] messages = searchForNewMessages ();
357
- if (this .maxFetchSize > 0 && messages .length > this .maxFetchSize ) {
358
- Message [] reducedMessages = new Message [this .maxFetchSize ];
359
- System .arraycopy (messages , 0 , reducedMessages , 0 , this .maxFetchSize );
360
- messages = reducedMessages ;
361
- }
362
- if (this .logger .isDebugEnabled ()) {
363
- this .logger .debug ("found " + messages .length + " new messages" );
364
- }
365
- if (messages .length > 0 ) {
366
- fetchMessages (messages );
367
- }
368
-
369
- if (this .logger .isDebugEnabled ()) {
370
- this .logger .debug ("Received " + messages .length + " messages" );
371
- }
372
-
373
- MimeMessage [] filteredMessages = filterMessagesThruSelector (messages );
349
+ openFolder ();
350
+ folder = getFolder ();
351
+ this .folderReadLock .lock ();
352
+ }
353
+ finally {
354
+ this .folderWriteLock .unlock ();
355
+ }
356
+ }
357
+ try {
358
+ if (this .logger .isInfoEnabled ()) {
359
+ this .logger .info ("attempting to receive mail from folder [" + folder .getFullName () + "]" );
360
+ }
361
+ Message [] messages = searchForNewMessages ();
362
+ if (this .maxFetchSize > 0 && messages .length > this .maxFetchSize ) {
363
+ Message [] reducedMessages = new Message [this .maxFetchSize ];
364
+ System .arraycopy (messages , 0 , reducedMessages , 0 , this .maxFetchSize );
365
+ messages = reducedMessages ;
366
+ }
367
+ if (this .logger .isDebugEnabled ()) {
368
+ this .logger .debug ("found " + messages .length + " new messages" );
369
+ }
370
+ if (messages .length > 0 ) {
371
+ fetchMessages (messages );
372
+ }
374
373
375
- postProcessFilteredMessages (filteredMessages );
374
+ if (this .logger .isDebugEnabled ()) {
375
+ this .logger .debug ("Received " + messages .length + " messages" );
376
+ }
376
377
377
- if (this .headerMapper != null ) {
378
- org .springframework .messaging .Message <?>[] converted =
379
- new org .springframework .messaging .Message <?>[filteredMessages .length ];
380
- int n = 0 ;
381
- for (MimeMessage message : filteredMessages ) {
382
- Map <String , Object > headers = this .headerMapper .toHeaders (message );
383
- converted [n ++] = getMessageBuilderFactory ().withPayload (extractContent (message , headers ))
384
- .copyHeaders (headers )
385
- .build ();
386
- }
387
- return converted ;
388
- }
389
- else {
390
- return filteredMessages ;
378
+ MimeMessage [] filteredMessages = filterMessagesThruSelector (messages );
379
+
380
+ postProcessFilteredMessages (filteredMessages );
381
+
382
+ if (this .headerMapper != null ) {
383
+ org .springframework .messaging .Message <?>[] converted =
384
+ new org .springframework .messaging .Message <?>[filteredMessages .length ];
385
+ int n = 0 ;
386
+ for (MimeMessage message : filteredMessages ) {
387
+ Map <String , Object > headers = this .headerMapper .toHeaders (message );
388
+ converted [n ++] =
389
+ getMessageBuilderFactory ()
390
+ .withPayload (extractContent (message , headers ))
391
+ .copyHeaders (headers )
392
+ .build ();
391
393
}
394
+ return converted ;
392
395
}
393
- finally {
394
- MailTransportUtils . closeFolder ( this . folder , this . shouldDeleteMessages ) ;
396
+ else {
397
+ return filteredMessages ;
395
398
}
396
399
}
400
+ finally {
401
+ MailTransportUtils .closeFolder (folder , this .shouldDeleteMessages );
402
+ this .folderReadLock .unlock ();
403
+ }
397
404
}
398
405
399
406
private Object extractContent (MimeMessage message , Map <String , Object > headers ) {
@@ -471,17 +478,15 @@ private void setMessageFlags(Message[] filteredMessages) throws MessagingExcepti
471
478
if (flags != null && flags .contains (Flags .Flag .USER )) {
472
479
if (this .logger .isDebugEnabled ()) {
473
480
this .logger .debug ("USER flags are supported by this mail server. Flagging message with '"
474
- + this .userFlag + "' user flag" );
481
+ + this .userFlag + "' user flag" );
475
482
}
476
483
Flags siFlags = new Flags ();
477
484
siFlags .add (this .userFlag );
478
485
message .setFlags (siFlags , true );
479
486
}
480
487
else {
481
- if (this .logger .isDebugEnabled ()) {
482
- this .logger .debug ("USER flags are not supported by this mail server. "
483
- + "Flagging message with system flag" );
484
- }
488
+ this .logger .debug ("USER flags are not supported by this mail server. " +
489
+ "Flagging message with system flag" );
485
490
message .setFlag (Flags .Flag .FLAGGED , true );
486
491
}
487
492
}
@@ -556,12 +561,16 @@ protected void setAdditionalFlags(Message message) throws MessagingException {
556
561
557
562
@ Override
558
563
public void destroy () {
559
- synchronized (this .folderMonitor ) {
564
+ this .folderWriteLock .lock ();
565
+ try {
560
566
MailTransportUtils .closeFolder (this .folder , this .shouldDeleteMessages );
561
567
MailTransportUtils .closeService (this .store );
562
568
this .folder = null ;
563
569
this .store = null ;
564
570
}
571
+ finally {
572
+ this .folderWriteLock .unlock ();
573
+ }
565
574
}
566
575
567
576
@ Override
0 commit comments