diff --git a/src/main/java/org/jabref/gui/desktop/os/Linux.java b/src/main/java/org/jabref/gui/desktop/os/Linux.java index a39c6e335d2..579b4986774 100644 --- a/src/main/java/org/jabref/gui/desktop/os/Linux.java +++ b/src/main/java/org/jabref/gui/desktop/os/Linux.java @@ -11,8 +11,10 @@ import java.util.Optional; import java.util.StringJoiner; +import org.jabref.JabRefExecutorService; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; +import org.jabref.gui.util.StreamGobbler; import org.jabref.preferences.JabRefPreferences; import org.slf4j.Logger; @@ -22,6 +24,7 @@ import static org.jabref.preferences.JabRefPreferences.USE_PDF_READER; public class Linux implements NativeDesktop { + private static final Logger LOGGER = LoggerFactory.getLogger(Linux.class); @Override @@ -34,14 +37,13 @@ public void openFile(String filePath, String fileType) throws IOException { } else { viewer = "xdg-open"; } - String[] cmdArray = { viewer, filePath }; - Process p = Runtime.getRuntime().exec(cmdArray); - // When the stream is full at some point, then blocks the execution of the program - // See https://stackoverflow.com/questions/10981969/why-is-going-through-geterrorstream-necessary-to-run-a-process. - BufferedReader in = new BufferedReader(new InputStreamReader(p.getErrorStream())); - String line; - line = in.readLine(); - LOGGER.debug("Received output: " + line); + ProcessBuilder processBuilder = new ProcessBuilder(viewer, filePath); + Process process = processBuilder.start(); + StreamGobbler streamGobblerInput = new StreamGobbler(process.getInputStream(), LOGGER::debug); + StreamGobbler streamGobblerError = new StreamGobbler(process.getErrorStream(), LOGGER::debug); + + JabRefExecutorService.INSTANCE.execute(streamGobblerInput); + JabRefExecutorService.INSTANCE.execute(streamGobblerError); } @Override @@ -53,17 +55,18 @@ public void openFileWithApplication(String filePath, String application) throws } else { openWith = new String[] {"xdg-open"}; } - String[] cmdArray = new String[openWith.length + 1]; System.arraycopy(openWith, 0, cmdArray, 0, openWith.length); cmdArray[cmdArray.length - 1] = filePath; - Process p = Runtime.getRuntime().exec(cmdArray); - // When the stream is full at some point, then blocks the execution of the program - // See https://stackoverflow.com/questions/10981969/why-is-going-through-geterrorstream-necessary-to-run-a-process. - BufferedReader in = new BufferedReader(new InputStreamReader(p.getErrorStream())); - String line; - line = in.readLine(); - LOGGER.debug("Received output: " + line); + + ProcessBuilder processBuilder = new ProcessBuilder(cmdArray); + Process process = processBuilder.start(); + + StreamGobbler streamGobblerInput = new StreamGobbler(process.getInputStream(), LOGGER::debug); + StreamGobbler streamGobblerError = new StreamGobbler(process.getErrorStream(), LOGGER::debug); + + JabRefExecutorService.INSTANCE.execute(streamGobblerInput); + JabRefExecutorService.INSTANCE.execute(streamGobblerError); } @Override @@ -118,7 +121,7 @@ public void openPdfWithParameters(String filePath, List parameters) thro openFileWithApplication(filePath, sj.toString()); } else { - openFile( filePath, "PDF"); + openFile(filePath, "PDF"); } } diff --git a/src/main/java/org/jabref/gui/util/StreamGobbler.java b/src/main/java/org/jabref/gui/util/StreamGobbler.java new file mode 100644 index 00000000000..b2131968f87 --- /dev/null +++ b/src/main/java/org/jabref/gui/util/StreamGobbler.java @@ -0,0 +1,32 @@ +package org.jabref.gui.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StreamGobbler implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(StreamGobbler.class); + + private InputStream inputStream; + private Consumer consumer; + + public StreamGobbler(InputStream inputStream, Consumer consumer) { + this.inputStream = inputStream; + this.consumer = consumer; + } + + @Override + public void run() { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + reader.lines().forEach(consumer); + } catch (IOException e) { + LOGGER.error("Error when reading process stream from external application", e); + } + } +}