|
1 | 1 | package org.jabref.gui.fieldeditors;
|
2 | 2 |
|
3 | 3 | import java.io.IOException;
|
4 |
| -import java.net.MalformedURLException; |
5 | 4 | import java.nio.file.Files;
|
6 | 5 | import java.nio.file.Path;
|
7 | 6 | import java.util.ArrayList;
|
|
11 | 10 | import java.util.function.BiPredicate;
|
12 | 11 | import java.util.function.Supplier;
|
13 | 12 |
|
14 |
| -import javax.net.ssl.HostnameVerifier; |
15 |
| -import javax.net.ssl.HttpsURLConnection; |
16 |
| -import javax.net.ssl.SSLHandshakeException; |
17 |
| -import javax.net.ssl.SSLSocketFactory; |
18 |
| - |
19 | 13 | import javafx.beans.Observable;
|
20 | 14 | import javafx.beans.binding.Bindings;
|
21 | 15 | import javafx.beans.binding.ObjectBinding;
|
|
32 | 26 | import org.jabref.gui.AbstractViewModel;
|
33 | 27 | import org.jabref.gui.DialogService;
|
34 | 28 | import org.jabref.gui.desktop.JabRefDesktop;
|
35 |
| -import org.jabref.gui.externalfiles.FileDownloadTask; |
36 | 29 | import org.jabref.gui.externalfiletype.ExternalFileType;
|
37 | 30 | import org.jabref.gui.externalfiletype.ExternalFileTypes;
|
38 |
| -import org.jabref.gui.externalfiletype.StandardExternalFileType; |
39 | 31 | import org.jabref.gui.icon.IconTheme;
|
40 | 32 | import org.jabref.gui.icon.JabRefIcon;
|
| 33 | +import org.jabref.gui.linkedfile.DownloadLinkedFileAction; |
41 | 34 | import org.jabref.gui.linkedfile.LinkedFileEditDialogView;
|
42 | 35 | import org.jabref.gui.mergeentries.MultiMergeEntriesView;
|
43 |
| -import org.jabref.gui.util.BackgroundTask; |
44 | 36 | import org.jabref.gui.util.ControlHelper;
|
45 | 37 | import org.jabref.gui.util.TaskExecutor;
|
46 | 38 | import org.jabref.logic.externalfiles.LinkedFileHandler;
|
47 |
| -import org.jabref.logic.importer.FetcherClientException; |
48 |
| -import org.jabref.logic.importer.FetcherServerException; |
49 | 39 | import org.jabref.logic.importer.Importer;
|
50 | 40 | import org.jabref.logic.importer.ParserResult;
|
51 | 41 | import org.jabref.logic.importer.fileformat.PdfContentImporter;
|
|
54 | 44 | import org.jabref.logic.importer.fileformat.PdfVerbatimBibTextImporter;
|
55 | 45 | import org.jabref.logic.importer.fileformat.PdfXmpImporter;
|
56 | 46 | import org.jabref.logic.l10n.Localization;
|
57 |
| -import org.jabref.logic.net.URLDownload; |
58 |
| -import org.jabref.logic.util.io.FileNameUniqueness; |
59 | 47 | import org.jabref.logic.util.io.FileUtil;
|
60 | 48 | import org.jabref.model.database.BibDatabaseContext;
|
61 | 49 | import org.jabref.model.entry.BibEntry;
|
@@ -421,146 +409,47 @@ public void edit() {
|
421 | 409 | this.linkedFile.setLink(file.getLink());
|
422 | 410 | this.linkedFile.setDescription(file.getDescription());
|
423 | 411 | this.linkedFile.setFileType(file.getFileType());
|
| 412 | + this.linkedFile.setSourceURL(file.getSourceUrl()); |
424 | 413 | });
|
425 | 414 | }
|
426 | 415 |
|
427 |
| - public void download() { |
428 |
| - if (!linkedFile.isOnlineLink()) { |
429 |
| - throw new UnsupportedOperationException("In order to download the file it has to be an online link"); |
430 |
| - } |
431 |
| - try { |
432 |
| - Optional<Path> targetDirectory = databaseContext.getFirstExistingFileDir(preferencesService.getFilePreferences()); |
433 |
| - if (targetDirectory.isEmpty()) { |
434 |
| - dialogService.showErrorDialogAndWait(Localization.lang("Download file"), Localization.lang("File directory is not set or does not exist!")); |
435 |
| - return; |
436 |
| - } |
437 |
| - |
438 |
| - URLDownload urlDownload = new URLDownload(linkedFile.getLink()); |
439 |
| - if (!checkSSLHandshake(urlDownload)) { |
440 |
| - return; |
441 |
| - } |
442 |
| - |
443 |
| - BackgroundTask<Path> downloadTask = prepareDownloadTask(targetDirectory.get(), urlDownload); |
444 |
| - downloadTask.onSuccess(destination -> { |
445 |
| - boolean isDuplicate; |
446 |
| - try { |
447 |
| - isDuplicate = FileNameUniqueness.isDuplicatedFile(targetDirectory.get(), destination.getFileName(), dialogService); |
448 |
| - } catch (IOException e) { |
449 |
| - LOGGER.error("FileNameUniqueness.isDuplicatedFile failed", e); |
450 |
| - return; |
451 |
| - } |
452 |
| - |
453 |
| - if (!isDuplicate) { |
454 |
| - // we need to call LinkedFileViewModel#fromFile, because we need to make the path relative to the configured directories |
455 |
| - LinkedFile newLinkedFile = LinkedFilesEditorViewModel.fromFile( |
456 |
| - destination, |
457 |
| - databaseContext.getFileDirectories(preferencesService.getFilePreferences()), |
458 |
| - preferencesService.getFilePreferences()); |
459 |
| - entry.replaceDownloadedFile(linkedFile.getLink(), newLinkedFile); |
460 |
| - |
461 |
| - // Notify in bar when the file type is HTML. |
462 |
| - if (newLinkedFile.getFileType().equals(StandardExternalFileType.URL.getName())) { |
463 |
| - dialogService.notify(Localization.lang("Downloaded website as an HTML file.")); |
464 |
| - LOGGER.debug("Downloaded website {} as an HTML file at {}", linkedFile.getLink(), destination); |
465 |
| - } |
466 |
| - } |
467 |
| - }); |
468 |
| - downloadProgress.bind(downloadTask.workDonePercentageProperty()); |
469 |
| - downloadTask.titleProperty().set(Localization.lang("Downloading")); |
470 |
| - downloadTask.messageProperty().set( |
471 |
| - Localization.lang("Fulltext for") + ": " + entry.getCitationKey().orElse(Localization.lang("New entry"))); |
472 |
| - downloadTask.showToUser(true); |
473 |
| - downloadTask.onFailure(ex -> { |
474 |
| - LOGGER.error("Error downloading from URL: " + urlDownload, ex); |
475 |
| - String fetcherExceptionMessage = ex.getMessage(); |
476 |
| - int statusCode; |
477 |
| - if (ex instanceof FetcherClientException clientException) { |
478 |
| - statusCode = clientException.getStatusCode(); |
479 |
| - if (statusCode == 401) { |
480 |
| - dialogService.showInformationDialogAndWait(Localization.lang("Failed to download from URL"), Localization.lang("401 Unauthorized: Access Denied. You are not authorized to access this resource. Please check your credentials and try again. If you believe you should have access, please contact the administrator for assistance.\nURL: %0 \n %1", urlDownload.getSource(), fetcherExceptionMessage)); |
481 |
| - } else if (statusCode == 403) { |
482 |
| - dialogService.showInformationDialogAndWait(Localization.lang("Failed to download from URL"), Localization.lang("403 Forbidden: Access Denied. You do not have permission to access this resource. Please contact the administrator for assistance or try a different action.\nURL: %0 \n %1", urlDownload.getSource(), fetcherExceptionMessage)); |
483 |
| - } else if (statusCode == 404) { |
484 |
| - dialogService.showInformationDialogAndWait(Localization.lang("Failed to download from URL"), Localization.lang("404 Not Found Error: The requested resource could not be found. It seems that the file you are trying to download is not available or has been moved. Please verify the URL and try again. If you believe this is an error, please contact the administrator for further assistance.\nURL: %0 \n %1", urlDownload.getSource(), fetcherExceptionMessage)); |
485 |
| - } |
486 |
| - } else if (ex instanceof FetcherServerException serverException) { |
487 |
| - statusCode = serverException.getStatusCode(); |
488 |
| - dialogService.showInformationDialogAndWait(Localization.lang("Failed to download from URL"), |
489 |
| - Localization.lang("Error downloading from URL. Cause is likely the server side. HTTP Error %0 \n %1 \nURL: %2 \nPlease try again later or contact the server administrator.", statusCode, fetcherExceptionMessage, urlDownload.getSource())); |
490 |
| - } else { |
491 |
| - dialogService.showErrorDialogAndWait(Localization.lang("Failed to download from URL"), Localization.lang("Error message: %0 \nURL: %1 \nPlease check the URL and try again.", fetcherExceptionMessage, urlDownload.getSource())); |
492 |
| - } |
493 |
| - }); |
494 |
| - taskExecutor.execute(downloadTask); |
495 |
| - } catch (MalformedURLException exception) { |
496 |
| - dialogService.showErrorDialogAndWait(Localization.lang("Invalid URL"), exception); |
497 |
| - } |
| 416 | + public void redownload() { |
| 417 | + LOGGER.info("Redownloading file from " + linkedFile.getSourceUrl()); |
| 418 | + if (linkedFile.getSourceUrl().isEmpty() || !LinkedFile.isOnlineLink(linkedFile.getSourceUrl())) { |
| 419 | + throw new UnsupportedOperationException("In order to download the file, the source url has to be an online link"); |
498 | 420 | }
|
499 | 421 |
|
500 |
| - public boolean checkSSLHandshake(URLDownload urlDownload) { |
501 |
| - try { |
502 |
| - urlDownload.canBeReached(); |
503 |
| - } catch (kong.unirest.UnirestException ex) { |
504 |
| - if (ex.getCause() instanceof SSLHandshakeException) { |
505 |
| - if (dialogService.showConfirmationDialogAndWait(Localization.lang("Download file"), |
506 |
| - Localization.lang("Unable to find valid certification path to requested target(%0), download anyway?", |
507 |
| - urlDownload.getSource().toString()))) { |
508 |
| - return true; |
509 |
| - } else { |
510 |
| - dialogService.notify(Localization.lang("Download operation canceled.")); |
511 |
| - return false; |
512 |
| - } |
513 |
| - } else { |
514 |
| - LOGGER.error("Error while checking if the file can be downloaded", ex); |
515 |
| - dialogService.notify(Localization.lang("Error downloading")); |
516 |
| - return false; |
517 |
| - } |
518 |
| - } |
519 |
| - return true; |
520 |
| - } |
| 422 | + String fileName = Path.of(linkedFile.getLink()).getFileName().toString(); |
521 | 423 |
|
522 |
| - public BackgroundTask<Path> prepareDownloadTask(Path targetDirectory, URLDownload urlDownload) { |
523 |
| - SSLSocketFactory defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); |
524 |
| - HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); |
525 |
| - return BackgroundTask |
526 |
| - .wrap(() -> { |
527 |
| - Optional<ExternalFileType> suggestedType = inferFileType(urlDownload); |
528 |
| - ExternalFileType externalFileType = suggestedType.orElse(StandardExternalFileType.PDF); |
529 |
| - |
530 |
| - String suggestedName = linkedFileHandler.getSuggestedFileName(externalFileType.getExtension()); |
531 |
| - String fulltextDir = FileUtil.createDirNameFromPattern(databaseContext.getDatabase(), entry, preferencesService.getFilePreferences().getFileDirectoryPattern()); |
532 |
| - suggestedName = FileNameUniqueness.getNonOverWritingFileName(targetDirectory.resolve(fulltextDir), suggestedName); |
533 |
| - return targetDirectory.resolve(fulltextDir).resolve(suggestedName); |
534 |
| - }) |
535 |
| - .then(destination -> new FileDownloadTask(urlDownload.getSource(), destination)) |
536 |
| - .onFailure(ex -> LOGGER.error("Error in download", ex)) |
537 |
| - .onFinished(() -> URLDownload.setSSLVerification(defaultSSLSocketFactory, defaultHostnameVerifier)); |
538 |
| - } |
539 |
| - |
540 |
| - private Optional<ExternalFileType> inferFileType(URLDownload urlDownload) { |
541 |
| - Optional<ExternalFileType> suggestedType = inferFileTypeFromMimeType(urlDownload); |
542 |
| - |
543 |
| - // If we did not find a file type from the MIME type, try based on extension: |
544 |
| - if (suggestedType.isEmpty()) { |
545 |
| - suggestedType = inferFileTypeFromURL(urlDownload.getSource().toExternalForm()); |
546 |
| - } |
547 |
| - return suggestedType; |
| 424 | + DownloadLinkedFileAction downloadLinkedFileAction = new DownloadLinkedFileAction( |
| 425 | + databaseContext, |
| 426 | + entry, |
| 427 | + linkedFile, |
| 428 | + linkedFile.getSourceUrl(), |
| 429 | + dialogService, |
| 430 | + preferencesService.getFilePreferences(), |
| 431 | + taskExecutor, |
| 432 | + fileName); |
| 433 | + downloadProgress.bind(downloadLinkedFileAction.downloadProgress()); |
| 434 | + downloadLinkedFileAction.execute(); |
548 | 435 | }
|
549 | 436 |
|
550 |
| - private Optional<ExternalFileType> inferFileTypeFromMimeType(URLDownload urlDownload) { |
551 |
| - String mimeType = urlDownload.getMimeType(); |
552 |
| - |
553 |
| - if (mimeType != null) { |
554 |
| - LOGGER.debug("MIME Type suggested: " + mimeType); |
555 |
| - return ExternalFileTypes.getExternalFileTypeByMimeType(mimeType, preferencesService.getFilePreferences()); |
556 |
| - } else { |
557 |
| - return Optional.empty(); |
| 437 | + public void download() { |
| 438 | + LOGGER.info("Downloading file from " + linkedFile.getSourceUrl()); |
| 439 | + if (!linkedFile.isOnlineLink()) { |
| 440 | + throw new UnsupportedOperationException("In order to download the file it has to be an online link"); |
558 | 441 | }
|
559 |
| - } |
560 | 442 |
|
561 |
| - private Optional<ExternalFileType> inferFileTypeFromURL(String url) { |
562 |
| - return URLUtil.getSuffix(url, preferencesService.getFilePreferences()) |
563 |
| - .flatMap(extension -> ExternalFileTypes.getExternalFileTypeByExt(extension, preferencesService.getFilePreferences())); |
| 443 | + DownloadLinkedFileAction downloadLinkedFileAction = new DownloadLinkedFileAction( |
| 444 | + databaseContext, |
| 445 | + entry, |
| 446 | + linkedFile, |
| 447 | + linkedFile.getLink(), |
| 448 | + dialogService, |
| 449 | + preferencesService.getFilePreferences(), |
| 450 | + taskExecutor); |
| 451 | + downloadProgress.bind(downloadLinkedFileAction.downloadProgress()); |
| 452 | + downloadLinkedFileAction.execute(); |
564 | 453 | }
|
565 | 454 |
|
566 | 455 | public LinkedFile getFile() {
|
|
0 commit comments