diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindow.java b/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindow.java deleted file mode 100644 index e1c99d343179384ddb8863c7cbe6e82a8d325c54..0000000000000000000000000000000000000000 --- a/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindow.java +++ /dev/null @@ -1,69 +0,0 @@ -package cz.fidentis.analyst.core; - -import cz.fidentis.analyst.Logger; -import java.awt.BorderLayout; -import java.util.List; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; -import javax.swing.SwingWorker; -import org.openide.windows.TopComponent; -import org.openide.windows.WindowManager; - -/** - * Wrapper of the default Java Netbeans Platform output window. - * This wrapper runs in the worker thread, reads messages logged through - * the {@link cz.fidentis.analyst.Logger} and displays them in the output window. - * - * The {@code OutputWindow} is currently executed from - * the {@link cz.fidentis.analyst.core.ProjectTopComp}, which is always presented. - * - * @author Radek Oslejsek - */ -public class OutputWindow extends SwingWorker<String, String> { - - private static JTextArea textArea; - - /** - * Constructor. - */ - public OutputWindow() { - TopComponent outputWin = WindowManager.getDefault().findTopComponent("output"); - textArea = new JTextArea(); - JScrollPane sp = new JScrollPane(textArea); - outputWin.add(sp, BorderLayout.CENTER); - } - - /** - * Reads messages of the {@code Logger} in the background and re-sends them - * the {@link #process(java.util.List)} method. - * - * @return Complete text displayed in the output window. - * @throws Exception - */ - @Override - protected String doInBackground() throws Exception { - String line = Logger.reader().readLine(); - while (line != null) { - publish(line); - line = Logger.reader().readLine(); - } - return textArea.getText(); - } - - /** - * Takes text lines process by the {@link #doInBackground()} method and - * adds them to the output window. - * - * @param chunks process lines - */ - @Override - protected void process(List<String> chunks) { - StringBuilder sb = new StringBuilder(); - sb.append(textArea.getText()); - chunks.forEach(str -> { - sb.append(str + System.lineSeparator()); - }); - textArea.setText(sb.toString()); - } - -} diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindowThread.java b/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindowThread.java new file mode 100644 index 0000000000000000000000000000000000000000..eed010d254a336665068dd03be5664c673c6fc0e --- /dev/null +++ b/GUI/src/main/java/cz/fidentis/analyst/core/OutputWindowThread.java @@ -0,0 +1,122 @@ +package cz.fidentis.analyst.core; + +import cz.fidentis.analyst.Logger; +import java.awt.BorderLayout; +import java.io.IOException; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import org.openide.util.Exceptions; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; + +/** + * Wrapper of the default Java Netbeans Platform output window. + * This singleton runs in the background, reads messages logged through + * the {@link cz.fidentis.analyst.Logger} and displays them in the output window. + * + * This singleton is currently executed from + * the {@link cz.fidentis.analyst.core.ProjectTopComp}, which is always presented + * in the FIDENTIS application. + * + * @author Radek Oslejsek + */ +public class OutputWindowThread extends Thread { + + private JTextArea textArea; + + private static OutputWindowThread instance; + + protected OutputWindowThread() { + TopComponent outputWin = WindowManager.getDefault().findTopComponent("output"); + textArea = new JTextArea(); + JScrollPane sp = new JScrollPane(textArea); + outputWin.add(sp, BorderLayout.CENTER); + } + + /** + * Starts the redirection of messages logged via the {@link cz.fidentis.analyst.Logger} + * into the output window. + * + * @return {@code false} if the singleton/thread is already executed, + * {@code true} otherwise. + */ + public static boolean execute() { + if (instance != null) { + return false; + } + instance = new OutputWindowThread(); + instance.start(); // executes the run() method + Logger.redirectToPipe(); + return true; + } + + /** + * Stops the redirection of messages logged via the {@link cz.fidentis.analyst.Logger} + * into the output window. + * + * @param err If {@code true} then the logged messages are redirected to the system error output. + * Otherwise, the system standard output is used. + * @return {@code false} if the singleton/thread is already stopped, + * {@code true} otherwise. + */ + public static boolean stopExecution(boolean err) { + if (instance == null) { + return false; + } + if (err) { + Logger.redirectToStdErr(); + } else { + Logger.redirectToStdOut(); + } + instance = null; + return true; + } + + /** + * Stops the redirection of messages logged via the {@link cz.fidentis.analyst.Logger} + * into the output window. The messages are redirected into the system standard output. + * + * @return {@code false} if the singleton/thread is already stopped, + * {@code true} otherwise. + */ + public static boolean stopExecution() { + return stopExecution(false); + } + + @Override + public void run() { + int errorCounter = 0; + + while (true) { + try { + String line = Logger.read(); + if (line != null) { + StringBuilder sb = new StringBuilder(); + sb.append(textArea.getText()) + .append(line) + .append(System.lineSeparator()); + textArea.setText(sb.toString()); + textArea.setCaretPosition(textArea.getDocument().getLength()); + errorCounter = 0; + } else { + //System.out.println("No datain the message pipe"); + fallAsleep(2000); + } + } catch (IOException ex) { + if (errorCounter < 8) { + errorCounter++; + } + System.out.println("IOException: " + ex); + fallAsleep(errorCounter * 1000); + } + } + } + + protected void fallAsleep(int mil) { + try { + sleep(mil); + } catch (InterruptedException ex) { + Exceptions.printStackTrace(ex); + } + } +} diff --git a/GUI/src/main/java/cz/fidentis/analyst/core/ProjectTopComp.java b/GUI/src/main/java/cz/fidentis/analyst/core/ProjectTopComp.java index 0c74a3e5b0fbb7f8e1ad8055e5ad448ac4d9c9b8..a5850328d862d6644115f06c9833b44af20f57c1 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/core/ProjectTopComp.java +++ b/GUI/src/main/java/cz/fidentis/analyst/core/ProjectTopComp.java @@ -81,9 +81,9 @@ public final class ProjectTopComp extends TopComponent { putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE); putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE); - // Execute OutputWindow in the worker thread so that messages - // logged via Logger are displayed in the output window - (new OutputWindow()).execute(); + // Execute infinite OutputWindowThread that redirects messages logged + // via Logger into the standard output window + OutputWindowThread.execute(); } /** diff --git a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java index b39d4a10e3850e7ee8f1deea4468bc989015f65e..ce879fb9f36d5a21491b8856024ff93d73d620bd 100644 --- a/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java +++ b/GUI/src/main/java/cz/fidentis/analyst/registration/RegistrationAction.java @@ -306,8 +306,6 @@ public class RegistrationAction extends ControlPanelAction { * otherwise set color to default */ private void calculateFeaturePoints() { - Logger.print("Calculation of feature points"); - if (getPrimaryDrawableFace() == null) { // scene not yet initiated return; } diff --git a/MeshModel/src/main/java/cz/fidentis/analyst/Logger.java b/MeshModel/src/main/java/cz/fidentis/analyst/Logger.java index a4220075a64f248ed587e61e75134ae6e520db04..df629174b7161e8e55cf82dc2621b5528d485331 100644 --- a/MeshModel/src/main/java/cz/fidentis/analyst/Logger.java +++ b/MeshModel/src/main/java/cz/fidentis/analyst/Logger.java @@ -14,16 +14,17 @@ import java.util.logging.Level; * A logging class that can be used from anywhere to display debugging or other * messages. * <p> - * Messages are printed into the standard output unless the {@link #reader()} - * method is called. Then the messages are redirected to the returned {@code BufferedReader}. + * Messages are printed into the system standard output by default. But can be also + * redirected to system error output or into the pipe. * </p> * <p> - * The implementation supposes that the caller of the {@link #reader()} method - * (or other object} will read the messages from the {@code BufferedReader} forever. - * Otherwise, the program can freeze due to the full buffer. + * If the messages are redirected into pipe, then <b>a consumer has to be running + * concurrently</b> and reading the data through the {@link #read()} method. + * <b>Otherwise, the program can freeze due to the full buffer!</b> * </p> * <p> - * FIDENTIS application automatically redirects logged messages to the output window. + * FIDENTIS application automatically redirects logged messages to the output window + * via the {@code OutputWindowThread}. * </p> * <p> * <b>Usage:</b> @@ -39,6 +40,8 @@ import java.util.logging.Level; */ public final class Logger { + private static final int PIPE_SIZE = 10240; // default is 1024 + private static PrintStream out = System.out; private static BufferedReader in; @@ -48,21 +51,53 @@ public final class Logger { } /** - * Redirects logs from standard output to the {@code BufferedReader}. + * Redirects messages into a pipe. + * <b>A consumer has to be running concurrently</b> and reading the messages + * through the {@link #read()} method. + * Otherwise, the program can freeze due to the full buffer! + */ + public static synchronized void redirectToPipe() { + if (in != null) { + return; + } + + PipedOutputStream pOut = new PipedOutputStream(); + out = new PrintStream(pOut); + try { + in = new BufferedReader(new InputStreamReader(new PipedInputStream(pOut, PIPE_SIZE))); + } catch (IOException ex) { + java.util.logging.Logger.getLogger(Logger.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Redirects messages into the system standard output. + */ + public static synchronized void redirectToStdOut() { + out = System.out; + in = null; + } + + /** + * Redirects messages into the system error output. + */ + public static synchronized void redirectToStdErr() { + out = System.err; + in = null; + } + + /** + * Returns an event message. If the logger is redirected to standard or error output, + * then {@code null} is returned. Also, if the is no message, {@code null} is returned. * - * @return {@code BufferedReader} to which the logs are redirected. + * @return Event message or {@code null} + * @throws IOException on error in reading the message buffer. */ - public static BufferedReader reader() { - if (in == null) { - PipedOutputStream pOut = new PipedOutputStream(); - out = new PrintStream(pOut); - try { - in = new BufferedReader(new InputStreamReader(new PipedInputStream(pOut))); - } catch (IOException ex) { - java.util.logging.Logger.getLogger(Logger.class.getName()).log(Level.SEVERE, null, ex); - } + public static String read() throws IOException { + if (in == null/* || !in.ready()*/) { + return null; } - return in; + return in.readLine(); } /** @@ -76,6 +111,7 @@ public final class Logger { + " [duration unknown]: " + msg.trim(); out.println(outMsg); + out.flush(); } /** @@ -112,8 +148,9 @@ public final class Logger { duration.toMillisPart()) + "]: " + msg.trim(); - + out.println(outMsg); + out.flush(); } }