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..721f6a686fd 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().isActive())) { + this.getMainFrame().getDialogService() + .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.")); + } } 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..23dafbb137e 100644 --- a/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java +++ b/src/main/java/org/jabref/gui/util/DefaultFileUpdateMonitor.java @@ -7,10 +7,12 @@ 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.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; @@ -29,11 +31,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 +64,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 isActive() { + 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 (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); + 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..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; /** @@ -9,7 +8,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 +16,9 @@ public void addListenerForFile(Path file, FileUpdateListener listener) throws IO public void removeListener(Path path, FileUpdateListener listener) { } + + @Override + 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 f6e2a53a9e1..a34754508bf 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 isActive(); } 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); + } +} 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