11/*
2- * Copyright 2002-2018 the original author or authors.
2+ * Copyright 2002-2019 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
2424import java .util .List ;
2525import java .util .Map ;
2626import java .util .Properties ;
27+ import java .util .concurrent .locks .Lock ;
28+ import java .util .concurrent .locks .ReadWriteLock ;
29+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
2730
2831import javax .mail .Authenticator ;
2932import javax .mail .FetchProfile ;
@@ -69,7 +72,11 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
6972
7073 private final URLName url ;
7174
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 ();
7380
7481 private String protocol ;
7582
@@ -134,9 +141,7 @@ public void setProtocol(String protocol) {
134141 /**
135142 * Set the {@link Session}. Otherwise, the Session will be created by invocation of
136143 * {@link Session#getInstance(Properties)} or {@link Session#getInstance(Properties, Authenticator)}.
137- *
138144 * @param session The session.
139- *
140145 * @see #setJavaMailProperties(Properties)
141146 * @see #setJavaMailAuthenticator(Authenticator)
142147 */
@@ -148,9 +153,7 @@ public void setSession(Session session) {
148153 /**
149154 * A new {@link Session} will be created with these properties (and the JavaMailAuthenticator if provided).
150155 * Use either this method or {@link #setSession}, but not both.
151- *
152156 * @param javaMailProperties The javamail properties.
153- *
154157 * @see #setJavaMailAuthenticator(Authenticator)
155158 * @see #setSession(Session)
156159 */
@@ -165,9 +168,7 @@ protected Properties getJavaMailProperties() {
165168 /**
166169 * Optional, sets the Authenticator to be used to obtain a session. This will not be used if
167170 * {@link AbstractMailReceiver#setSession} has been used to configure the {@link Session} directly.
168- *
169171 * @param javaMailAuthenticator The javamail authenticator.
170- *
171172 * @see #setSession(Session)
172173 */
173174 public void setJavaMailAuthenticator (Authenticator javaMailAuthenticator ) {
@@ -176,7 +177,6 @@ public void setJavaMailAuthenticator(Authenticator javaMailAuthenticator) {
176177
177178 /**
178179 * Specify the maximum number of Messages to fetch per call to {@link #receive()}.
179- *
180180 * @param maxFetchSize The max fetch size.
181181 */
182182 public void setMaxFetchSize (int maxFetchSize ) {
@@ -185,15 +185,14 @@ public void setMaxFetchSize(int maxFetchSize) {
185185
186186 /**
187187 * Specify whether mail messages should be deleted after retrieval.
188- *
189188 * @param shouldDeleteMessages true to delete messages.
190189 */
191190 public void setShouldDeleteMessages (boolean shouldDeleteMessages ) {
192191 this .shouldDeleteMessages = shouldDeleteMessages ;
193192 }
193+
194194 /**
195195 * Indicates whether the mail messages should be deleted after being received.
196- *
197196 * @return true when messages will be deleted.
198197 */
199198 protected boolean shouldDeleteMessages () {
@@ -243,21 +242,17 @@ public void setEmbeddedPartsAsBytes(boolean embeddedPartsAsBytes) {
243242
244243 /**
245244 * {@link MimeMessage#getContent()} returns just the email body.
246- *
247245 * <pre class="code">
248246 * foo
249247 * </pre>
250- *
251248 * Some subclasses, such as {@code IMAPMessage} return some headers with the body.
252- *
253249 * <pre class="code">
254250 * To: foo@bar
255251 * From: bar@baz
256252 * Subject: Test Email
257253 *
258254 * foo
259255 * </pre>
260- *
261256 * Starting with version 5.0, messages emitted by mail receivers will render the
262257 * content in the same way as the {@link MimeMessage} implementation returned by
263258 * javamail. In versions 2.2 through 4.3, the content was always just the body,
@@ -266,7 +261,6 @@ public void setEmbeddedPartsAsBytes(boolean embeddedPartsAsBytes) {
266261 * <p>To revert to the previous behavior, set this flag to true. In addition, even
267262 * if a header mapper is provided, the payload will just be the email body.
268263 * @param simpleContent true to render simple content.
269- *
270264 * @since 5.0
271265 */
272266 public void setSimpleContent (boolean simpleContent ) {
@@ -283,7 +277,6 @@ protected int getFolderOpenMode() {
283277
284278 /**
285279 * Subclasses must implement this method to return new mail messages.
286- *
287280 * @return An array of messages.
288281 * @throws MessagingException Any MessagingException.
289282 */
@@ -347,53 +340,67 @@ private Folder obtainFolderInstance() throws MessagingException {
347340
348341 @ Override
349342 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 ();
351348 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+ }
374373
375- postProcessFilteredMessages (filteredMessages );
374+ if (this .logger .isDebugEnabled ()) {
375+ this .logger .debug ("Received " + messages .length + " messages" );
376+ }
376377
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 ();
391393 }
394+ return converted ;
392395 }
393- finally {
394- MailTransportUtils . closeFolder ( this . folder , this . shouldDeleteMessages ) ;
396+ else {
397+ return filteredMessages ;
395398 }
396399 }
400+ finally {
401+ MailTransportUtils .closeFolder (folder , this .shouldDeleteMessages );
402+ this .folderReadLock .unlock ();
403+ }
397404 }
398405
399406 private Object extractContent (MimeMessage message , Map <String , Object > headers ) {
@@ -471,17 +478,15 @@ private void setMessageFlags(Message[] filteredMessages) throws MessagingExcepti
471478 if (flags != null && flags .contains (Flags .Flag .USER )) {
472479 if (this .logger .isDebugEnabled ()) {
473480 this .logger .debug ("USER flags are supported by this mail server. Flagging message with '"
474- + this .userFlag + "' user flag" );
481+ + this .userFlag + "' user flag" );
475482 }
476483 Flags siFlags = new Flags ();
477484 siFlags .add (this .userFlag );
478485 message .setFlags (siFlags , true );
479486 }
480487 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" );
485490 message .setFlag (Flags .Flag .FLAGGED , true );
486491 }
487492 }
@@ -556,12 +561,16 @@ protected void setAdditionalFlags(Message message) throws MessagingException {
556561
557562 @ Override
558563 public void destroy () {
559- synchronized (this .folderMonitor ) {
564+ this .folderWriteLock .lock ();
565+ try {
560566 MailTransportUtils .closeFolder (this .folder , this .shouldDeleteMessages );
561567 MailTransportUtils .closeService (this .store );
562568 this .folder = null ;
563569 this .store = null ;
564570 }
571+ finally {
572+ this .folderWriteLock .unlock ();
573+ }
565574 }
566575
567576 @ Override
0 commit comments