@@ -25,7 +25,6 @@ class ParseFileController {
2525 private final File cachePath ;
2626 private final List <String > currentlyDownloadedFilesNames = new ArrayList <>();
2727
28-
2928 private ParseHttpClient fileClient ;
3029
3130 public ParseFileController (ParseHttpClient restClient , File cachePath ) {
@@ -172,79 +171,80 @@ public Task<File> fetchAsync(
172171 if (cancellationToken != null && cancellationToken .isCancelled ()) {
173172 return Task .cancelled ();
174173 }
175- return Task .call (() -> {
176- final File cacheFile = getCacheFile (state );
174+ return Task .call (
175+ () -> {
176+ final File cacheFile = getCacheFile (state );
177+
178+ synchronized (lock ) {
179+ if (currentlyDownloadedFilesNames .contains (state .name ())) {
180+ while (currentlyDownloadedFilesNames .contains (state .name ())) {
181+ lock .wait ();
182+ }
183+ }
177184
178- synchronized (lock ) {
179- if (currentlyDownloadedFilesNames .contains (state .name ())) {
180- while (currentlyDownloadedFilesNames .contains (state .name ())) {
181- lock .wait ();
185+ if (cacheFile .exists ()) {
186+ return cacheFile ;
187+ } else {
188+ currentlyDownloadedFilesNames .add (state .name ());
189+ }
182190 }
183- }
184-
185- if (cacheFile .exists ()) {
186- return cacheFile ;
187- } else {
188- currentlyDownloadedFilesNames .add (state .name ());
189- }
190- }
191191
192- try {
193- if (cancellationToken != null && cancellationToken .isCancelled ()) {
194- throw new CancellationException ();
195- }
196-
197- // Generate the temp file path for caching ParseFile content based on
198- // ParseFile's url
199- // The reason we do not write to the cacheFile directly is because there
200- // is no way we can
201- // verify if a cacheFile is complete or not. If download is interrupted
202- // in the middle, next
203- // time when we download the ParseFile, since cacheFile has already
204- // existed, we will return
205- // this incomplete cacheFile
206- final File tempFile = getTempFile (state );
207-
208- // network
209- final ParseFileRequest request =
210- new ParseFileRequest (
211- ParseHttpRequest .Method .GET , state .url (), tempFile );
212-
213- // We do not need to delete the temp file since we always try to
214- // overwrite it
215- Task <Void > downloadTask = request . executeAsync (
216- fileClient (),
217- null ,
218- downloadProgressCallback ,
219- cancellationToken
220- );
221- ParseTaskUtils .wait (downloadTask );
222-
223- // If the top-level task was cancelled, don't
224- // actually set the data -- just move on.
225- if (cancellationToken != null && cancellationToken .isCancelled ()) {
226- throw new CancellationException ();
227- }
228- if (downloadTask .isFaulted ()) {
229- ParseFileUtils .deleteQuietly (tempFile );
230- throw new RuntimeException (downloadTask .getError ());
231- }
232-
233- // Since we give the cacheFile pointer to
234- // developers, it is not safe to guarantee
235- // cacheFile always does not exist here, so it is
236- // better to delete it manually,
237- // otherwise moveFile may throw an exception.
238- ParseFileUtils .deleteQuietly (cacheFile );
239- ParseFileUtils .moveFile (tempFile , cacheFile );
240- return cacheFile ;
241- } finally {
242- synchronized (lock ) {
243- currentlyDownloadedFilesNames .remove (state .name ());
244- lock .notifyAll ();
245- }
246- }
247-
248- }, ParseExecutors .io ());
192+ try {
193+ if (cancellationToken != null && cancellationToken .isCancelled ()) {
194+ throw new CancellationException ();
195+ }
196+
197+ // Generate the temp file path for caching ParseFile content based on
198+ // ParseFile's url
199+ // The reason we do not write to the cacheFile directly is because there
200+ // is no way we can
201+ // verify if a cacheFile is complete or not. If download is interrupted
202+ // in the middle, next
203+ // time when we download the ParseFile, since cacheFile has already
204+ // existed, we will return
205+ // this incomplete cacheFile
206+ final File tempFile = getTempFile (state );
207+
208+ // network
209+ final ParseFileRequest request =
210+ new ParseFileRequest (
211+ ParseHttpRequest .Method .GET , state .url (), tempFile );
212+
213+ // We do not need to delete the temp file since we always try to
214+ // overwrite it
215+ Task <Void > downloadTask =
216+ request . executeAsync (
217+ fileClient () ,
218+ null ,
219+ downloadProgressCallback ,
220+ cancellationToken );
221+ ParseTaskUtils .wait (downloadTask );
222+
223+ // If the top-level task was cancelled, don't
224+ // actually set the data -- just move on.
225+ if (cancellationToken != null && cancellationToken .isCancelled ()) {
226+ throw new CancellationException ();
227+ }
228+ if (downloadTask .isFaulted ()) {
229+ ParseFileUtils .deleteQuietly (tempFile );
230+ throw new RuntimeException (downloadTask .getError ());
231+ }
232+
233+ // Since we give the cacheFile pointer to
234+ // developers, it is not safe to guarantee
235+ // cacheFile always does not exist here, so it is
236+ // better to delete it manually,
237+ // otherwise moveFile may throw an exception.
238+ ParseFileUtils .deleteQuietly (cacheFile );
239+ ParseFileUtils .moveFile (tempFile , cacheFile );
240+ return cacheFile ;
241+ } finally {
242+ synchronized (lock ) {
243+ currentlyDownloadedFilesNames .remove (state .name ());
244+ lock .notifyAll ();
245+ }
246+ }
247+ },
248+ ParseExecutors .io ());
249249 }
250250}
0 commit comments