From 151da625e24289df1f7e73bd9724ed12841197fb Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Tue, 23 Jun 2020 18:05:04 -0500 Subject: [PATCH 1/7] Workaround for Issue 6073 Previously, the program was crashing for Unix users when inotify had reached its max file limit. Since the only way to fix this seems to be to close applications or to edit privileged system files, the proposed solution is to notify the user of the issue and give them the option of continuing usage of the application. fixes #6073 --- CHANGELOG.md | 1 + src/main/java/org/jabref/JabRefGUI.java | 7 +++++ .../gui/util/DefaultFileUpdateMonitor.java | 29 ++++++++++++++----- .../model/util/DummyFileUpdateMonitor.java | 7 ++++- .../jabref/model/util/FileUpdateMonitor.java | 6 ++++ .../WatchServiceUnavailableException.java | 9 ++++++ 6 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/jabref/model/util/WatchServiceUnavailableException.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 47a94281554..2524552b8d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where downloaded files would be moved to a directory named after the citationkey when no file directory pattern is specified [#6589](https://github.com/JabRef/jabref/issues/6589) - We fixed an issue with the creation of a group of cited entries which incorrectly showed the message that the library had been modified externally whenever saving the library. [#6420](https://github.com/JabRef/jabref/issues/6420) - We fixed an issue with the creation of a group of cited entries. Now the file path to an aux file gets validated. [#6585](https://github.com/JabRef/jabref/issues/6585) +- We fixed an issue on Linux systems where the application would crash upon inotify failure. Now, the user is prompted with a warning, and given the choice to continue the session. [#6073](https://github.com/JabRef/jabref/issues/6073) ### Removed diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index cef5e7d6656..45c8ca644c1 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -104,6 +104,13 @@ private void openWindow(Stage mainStage) { } }); Platform.runLater(this::openDatabases); + + if(!(Globals.getFileUpdateMonitor().active())) { + this.getMainFrame().getDialogService() + .showErrorDialogAndWait("Unable to monitor file changes. Please close files " + + "and processes and restart. You may encounter errors if you continue " + + "with this session."); + } } private void openDatabases() { diff --git a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java index f5600df45c5..bb938e0e01b 100644 --- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java +++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java @@ -8,12 +8,16 @@ import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.Objects; +import java.util.Optional; +import org.jabref.JabRefException; +import org.jabref.logic.layout.format.Default; import org.jabref.model.util.FileUpdateListener; import org.jabref.model.util.FileUpdateMonitor; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import org.jabref.model.util.WatchServiceUnavailableException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,11 +33,14 @@ public class DefaultFileUpdateMonitor implements Runnable, FileUpdateMonitor { private final Multimap listeners = ArrayListMultimap.create(20, 4); private WatchService watcher; + private Optional filesystemMonitorFailure; @Override public void run() { try (WatchService watcher = FileSystems.getDefault().newWatchService()) { this.watcher = watcher; + filesystemMonitorFailure = Optional.empty(); + while (true) { WatchKey key; try { @@ -59,23 +66,29 @@ public void run() { } Thread.yield(); } - } catch (Throwable e) { - LOGGER.error("FileUpdateMonitor has been interrupted.", e); + } catch (IOException e) { + filesystemMonitorFailure = Optional.of(new WatchServiceUnavailableException(e.getMessage(), + e.getLocalizedMessage(), e.getCause())); + LOGGER.warn(filesystemMonitorFailure.get().getLocalizedMessage(), e); } } + public boolean active() { + return filesystemMonitorFailure.isEmpty(); + } + private void notifyAboutChange(Path path) { listeners.get(path).forEach(FileUpdateListener::fileUpdated); } @Override public void addListenerForFile(Path file, FileUpdateListener listener) throws IOException { - Objects.requireNonNull(watcher, "You need to start the file monitor before watching files"); - - // We can't watch files directly, so monitor their parent directory for updates - Path directory = file.toAbsolutePath().getParent(); - directory.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); - listeners.put(file, listener); + if (active()) { + // We can't watch files directly, so monitor their parent directory for updates + Path directory = file.toAbsolutePath().getParent(); + directory.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); + listeners.put(file, listener); + } } @Override diff --git a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java index d531bb4561e..cde10f0fe74 100644 --- a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java @@ -9,7 +9,7 @@ */ public class DummyFileUpdateMonitor implements FileUpdateMonitor { @Override - public void addListenerForFile(Path file, FileUpdateListener listener) throws IOException { + public void addListenerForFile(Path file, FileUpdateListener listener) { } @@ -17,4 +17,9 @@ public void addListenerForFile(Path file, FileUpdateListener listener) throws IO public void removeListener(Path path, FileUpdateListener listener) { } + + @Override + public boolean active() { + return false; + } } diff --git a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java index f6e2a53a9e1..b35af542dbf 100644 --- a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java @@ -18,4 +18,10 @@ public interface FileUpdateMonitor { * @param path The path to remove. */ void removeListener(Path path, FileUpdateListener listener); + + /** + * Indicates whether or not the native system's file monitor has successfully started. + * @return True is process is running; false otherwise. + */ + boolean active(); } diff --git a/src/main/java/org/jabref/model/util/WatchServiceUnavailableException.java b/src/main/java/org/jabref/model/util/WatchServiceUnavailableException.java new file mode 100644 index 00000000000..0b87c080939 --- /dev/null +++ b/src/main/java/org/jabref/model/util/WatchServiceUnavailableException.java @@ -0,0 +1,9 @@ +package org.jabref.model.util; + +import org.jabref.JabRefException; + +public class WatchServiceUnavailableException extends JabRefException { + public WatchServiceUnavailableException(final String message, final String localizedMessage, final Throwable cause) { + super(message, localizedMessage, cause); + } +} From 63dabffe4ef99a715c60429e2c676c780f406042 Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Tue, 23 Jun 2020 18:10:27 -0500 Subject: [PATCH 2/7] Workaround for Issue 6073 Previously, the program was crashing for Unix users when inotify had reached its max file limit. Since the only way to fix this seems to be to close applications or to edit privileged system files, the proposed solution is to notify the user of the issue and give them the option of continuing usage of the application. fixes #6073 --- src/main/java/org/jabref/JabRefGUI.java | 2 +- .../java/org/jabref/gui/util/DefaultFileUpdateMonitor.java | 6 ++---- .../java/org/jabref/model/util/DummyFileUpdateMonitor.java | 2 +- src/main/java/org/jabref/model/util/FileUpdateMonitor.java | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 45c8ca644c1..53094899b4f 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -105,7 +105,7 @@ private void openWindow(Stage mainStage) { }); Platform.runLater(this::openDatabases); - if(!(Globals.getFileUpdateMonitor().active())) { + if(!(Globals.getFileUpdateMonitor().isActive())) { this.getMainFrame().getDialogService() .showErrorDialogAndWait("Unable to monitor file changes. Please close files " + "and processes and restart. You may encounter errors if you continue " + diff --git a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java index bb938e0e01b..90610067e84 100644 --- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java +++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java @@ -7,11 +7,9 @@ import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; -import java.util.Objects; import java.util.Optional; import org.jabref.JabRefException; -import org.jabref.logic.layout.format.Default; import org.jabref.model.util.FileUpdateListener; import org.jabref.model.util.FileUpdateMonitor; @@ -73,7 +71,7 @@ public void run() { } } - public boolean active() { + public boolean isActive() { return filesystemMonitorFailure.isEmpty(); } @@ -83,7 +81,7 @@ private void notifyAboutChange(Path path) { @Override public void addListenerForFile(Path file, FileUpdateListener listener) throws IOException { - if (active()) { + if (isActive()) { // We can't watch files directly, so monitor their parent directory for updates Path directory = file.toAbsolutePath().getParent(); directory.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); diff --git a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java index cde10f0fe74..0f9dc25d300 100644 --- a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java @@ -19,7 +19,7 @@ public void removeListener(Path path, FileUpdateListener listener) { } @Override - public boolean active() { + public boolean isActive() { return false; } } diff --git a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java index b35af542dbf..533fe11fd50 100644 --- a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java @@ -23,5 +23,5 @@ public interface FileUpdateMonitor { * Indicates whether or not the native system's file monitor has successfully started. * @return True is process is running; false otherwise. */ - boolean active(); + boolean isActive(); } From 6a2baf4538d5f7e5bc7a34b156d13470a8cd9f87 Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Thu, 25 Jun 2020 13:43:22 -0500 Subject: [PATCH 3/7] Style fix. Style edits according to JabRef preferences. --- src/main/java/org/jabref/JabRefGUI.java | 2 +- src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 53094899b4f..6fc914c6c7f 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -105,7 +105,7 @@ private void openWindow(Stage mainStage) { }); Platform.runLater(this::openDatabases); - if(!(Globals.getFileUpdateMonitor().isActive())) { + if (!(Globals.getFileUpdateMonitor().isActive())) { this.getMainFrame().getDialogService() .showErrorDialogAndWait("Unable to monitor file changes. Please close files " + "and processes and restart. You may encounter errors if you continue " + diff --git a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java index 90610067e84..23dafbb137e 100644 --- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java +++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java @@ -12,10 +12,10 @@ import org.jabref.JabRefException; import org.jabref.model.util.FileUpdateListener; import org.jabref.model.util.FileUpdateMonitor; +import org.jabref.model.util.WatchServiceUnavailableException; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import org.jabref.model.util.WatchServiceUnavailableException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From a548eb9e2f65449a13843b224bf18d28a35d5593 Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Thu, 25 Jun 2020 13:49:39 -0500 Subject: [PATCH 4/7] Localization instead of raw string. --- src/main/java/org/jabref/JabRefGUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/JabRefGUI.java b/src/main/java/org/jabref/JabRefGUI.java index 6fc914c6c7f..721f6a686fd 100644 --- a/src/main/java/org/jabref/JabRefGUI.java +++ b/src/main/java/org/jabref/JabRefGUI.java @@ -107,9 +107,9 @@ private void openWindow(Stage mainStage) { if (!(Globals.getFileUpdateMonitor().isActive())) { this.getMainFrame().getDialogService() - .showErrorDialogAndWait("Unable to monitor file changes. Please close files " + + .showErrorDialogAndWait(Localization.lang("Unable to monitor file changes. Please close files " + "and processes and restart. You may encounter errors if you continue " + - "with this session."); + "with this session.")); } } From 53ae78f88aae49c2112dcc16f70207e78ca55585 Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Thu, 25 Jun 2020 16:06:00 -0500 Subject: [PATCH 5/7] Style fix #2. --- src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java index 0f9dc25d300..85ef84508d3 100644 --- a/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/DummyFileUpdateMonitor.java @@ -1,6 +1,5 @@ package org.jabref.model.util; -import java.io.IOException; import java.nio.file.Path; /** From ec1b2bb72ac9c6fae1e7d7d6b583b794d18b00e4 Mon Sep 17 00:00:00 2001 From: Caleb Tillman Date: Wed, 1 Jul 2020 09:42:57 -0500 Subject: [PATCH 6/7] Localization addition. Added #6073 error message to localizaiton file. --- src/main/resources/l10n/JabRef_en.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 3bb17ba3aaf..a6915545929 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1,3 +1,4 @@ +Unable\ to\ monitor\ file\ changes.\ Please\ close\ files\ and\ processes\ and\ restart.\ You\ may\ encounter\ errors\ if\ you\ continue\ with\ this\ session.=Unable to monitor file changes. Please close files and processes and restart. You may encounter errors if you continue with this session. %0\ contains\ the\ regular\ expression\ %1=%0 contains the regular expression %1 %0\ contains\ the\ term\ %1=%0 contains the term %1 From 2b14b4d8865cf370aaa66e7a636148f25dc2663a Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 1 Jul 2020 20:51:06 +0200 Subject: [PATCH 7/7] Minor stylistic update --- src/main/java/org/jabref/model/util/FileUpdateMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java index 533fe11fd50..a34754508bf 100644 --- a/src/main/java/org/jabref/model/util/FileUpdateMonitor.java +++ b/src/main/java/org/jabref/model/util/FileUpdateMonitor.java @@ -21,7 +21,7 @@ public interface FileUpdateMonitor { /** * Indicates whether or not the native system's file monitor has successfully started. - * @return True is process is running; false otherwise. + * @return true is process is running; false otherwise. */ boolean isActive(); }