You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by rw...@apache.org on 2018/06/04 15:41:02 UTC

svn commit: r1832859 - in /pivot/trunk: core/src/org/apache/pivot/util/Console.java tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java tests/src/org/apache/pivot/tests/console_test.bxml wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java

Author: rwhitcomb
Date: Mon Jun  4 15:41:02 2018
New Revision: 1832859

URL: http://svn.apache.org/viewvc?rev=1832859&view=rev
Log:
Improvements to "Console" debugging package:
* Allow override of output streams (defaults to System.out and .err).
* Make Console into a non-static class, but with a default that always
  logs to the system console.
* Make a TextAreaOutputStream that can make itself into a PrintStream
  for use with Console.
* Make a test program (TextAreaConsoleTest) that uses a small text area
  to demonstrate logging using the Console class inside a window.

Added:
    pivot/trunk/tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java
    pivot/trunk/tests/src/org/apache/pivot/tests/console_test.bxml
    pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java
Modified:
    pivot/trunk/core/src/org/apache/pivot/util/Console.java

Modified: pivot/trunk/core/src/org/apache/pivot/util/Console.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/util/Console.java?rev=1832859&r1=1832858&r2=1832859&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/util/Console.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/util/Console.java Mon Jun  4 15:41:02 2018
@@ -16,34 +16,123 @@
  */
 package org.apache.pivot.util;
 
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.net.UnknownHostException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.file.NoSuchFileException;
+
 /**
  * Utility class for a simple log to the console, for example from scripts.
  */
 public final class Console {
 
-    private Console() {
+    /** Used to output a null message value, so user knows a null "something" was logged. */
+    private static final String NULL = "<null>";
+
+    /** For static logging, the singleton instance pointing to the system console to use. */
+    private static final Console CONSOLE = new Console();
+
+    /** The print stream to use for "output" logging.  Defaults to {@link System#out}. */
+    private PrintStream out = System.out;
+    /** The print stream to use for "error" logging.  Defaults to {@link System#err}. */
+    private PrintStream err = System.err;
+
+
+    public Console() {
+    }
+
+    public Console(final PrintStream stream) {
+        setStreams(stream);
+    }
+
+    public Console(final PrintStream output, final PrintStream error) {
+        setOutputStream(output);
+        setErrorStream(error);
+    }
+
+    public static Console getDefault() {
+        return CONSOLE;
+    }
+
+    private void checkNotDefault() {
+        if (this == CONSOLE) {
+            throw new IllegalStateException("Cannot modify default Console object.");
+        }
+    }
+
+    public void setStreams(final PrintStream stream) {
+        checkNotDefault();
+        out = err = stream;
+    }
+
+    public void setOutputStream(final PrintStream output) {
+        checkNotDefault();
+        out = output;
+    }
+
+    public void setErrorStream(final PrintStream error) {
+        checkNotDefault();
+        err = error;
     }
 
-    public static final void log(String message) {
+    /**
+     * Log the given message to the "output" stream.
+     *
+     * @param message The message to log.
+     * @see #logOutput
+     */
+    public void log(final String message) {
         logOutput(message);
     }
 
-    public static final void log(Throwable t) {
+    /**
+     * Log the given exception (basically print the stack trace) to the "error" stream.
+     *
+     * @param t The exception to log.
+     */
+    public void log(final Throwable t) {
         if (t != null) {
-            t.printStackTrace();
+            t.printStackTrace(err);
         }
     }
 
-    public static final void logExceptionMessage(Throwable t) {
-        logOutput(t.getMessage());
+    /**
+     * Get a user-friendly message from the given exception.
+     *
+     * @param t The throwable (exception) in question.
+     * @return Start with the localized exception message, but use the
+     * simple name of the exception if there is no message, or if the
+     * exception is one of a short list of "funny" exceptions where the
+     * message by itself is ambiguous, prepend the simple name of the
+     * exception to the message.
+     */
+    public static String getExceptionMessage(final Throwable t) {
+        String msg = t.getLocalizedMessage();
+        if (msg == null || msg.isEmpty()) {
+            msg = t.getClass().getSimpleName();
+        } else if ((t instanceof UnknownHostException)
+                || (t instanceof NoClassDefFoundError)
+                || (t instanceof ClassNotFoundException)
+                || (t instanceof NullPointerException)
+                || (t instanceof CharacterCodingException)
+                || (t instanceof FileNotFoundException)
+                || (t instanceof NoSuchFileException)) {
+            msg = String.format("%1$s: %2$s", t.getClass().getSimpleName(), msg);
+        }
+        return msg;
     }
 
-    public static final void logOutput(String message) {
-        System.out.println(message != null ? message : "");
+    public void logExceptionMessage(final Throwable t) {
+        logOutput(getExceptionMessage(t));
     }
 
-    public static final void logError(String message) {
-        System.err.println(message != null ? message : "");
+    public void logOutput(final String message) {
+        out.println(message == null ? NULL : message);
+    }
+
+    public void logError(final String message) {
+        err.println(message == null ? NULL : message);
     }
 
     /**
@@ -53,9 +142,12 @@ public final class Console {
      * or a format string using the remaining args (can be {@code null}).
      * @param args The optional arguments used to format the final message.
      */
-    public static final void logMethod(String message, Object... args) {
-        logOutput(ClassUtils.getCallingMethod(1) + ": " +
-            (message == null ? "" : String.format(message, args)));
+    public void logMethod(final String message, final Object... args) {
+        logOutput(
+              ClassUtils.getCallingMethod(1)
+            + ": "
+            + (message == null ? NULL : String.format(message, args))
+        );
     }
 
     /**
@@ -67,12 +159,12 @@ public final class Console {
      * or a format string using the remaining args (can be {@code null}).
      * @param args The optional arguments used to format the final message.
      */
-    public static final void logMethod(String prefix, String message, Object... args) {
+    public void logMethod(final String prefix, final String message, final Object... args) {
         logOutput(
-            (prefix == null ? "" : prefix + " ") +
-            ClassUtils.getCallingMethod(1) +
-            ": " +
-            (message == null ? "" : String.format(message, args))
+              (prefix == null ? "" : prefix + " ")
+            + ClassUtils.getCallingMethod(1)
+            + ": "
+            + (message == null ? NULL : String.format(message, args))
         );
     }
 

Added: pivot/trunk/tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java?rev=1832859&view=auto
==============================================================================
--- pivot/trunk/tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java (added)
+++ pivot/trunk/tests/src/org/apache/pivot/tests/TextAreaConsoleTest.java Mon Jun  4 15:41:02 2018
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.tests;
+
+import java.io.IOException;
+import org.apache.pivot.beans.BXML;
+import org.apache.pivot.beans.BXMLSerializer;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.util.Console;
+import org.apache.pivot.serialization.SerializationException;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.PushButton;
+import org.apache.pivot.wtk.TextArea;
+import org.apache.pivot.wtk.Window;
+import org.apache.pivot.wtk.util.TextAreaOutputStream;
+
+
+public class TextAreaConsoleTest implements Application {
+    @BXML private Window window;
+    @BXML private PushButton logMessageButton;
+    @BXML private TextArea consoleArea;
+    private Console console;
+    private int line = 1;
+
+    @Override
+    public void startup(Display display, Map<String, String> properties) {
+        BXMLSerializer serializer = new BXMLSerializer();
+        try {
+            serializer.readObject(TextAreaConsoleTest.class, "console_test.bxml");
+            serializer.bind(this);
+        } catch (IOException | SerializationException ex) {
+            throw new RuntimeException(ex);
+        }
+        console = new Console(new TextAreaOutputStream(consoleArea).toPrintStream());
+        logMessageButton.getButtonPressListeners().add((button) -> console.log(String.format("%1$d. Hello, World!", line++)));
+        window.open(display);
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (window != null) {
+            window.close();
+        }
+        return false;
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(TextAreaConsoleTest.class, args);
+    }
+}

Added: pivot/trunk/tests/src/org/apache/pivot/tests/console_test.bxml
URL: http://svn.apache.org/viewvc/pivot/trunk/tests/src/org/apache/pivot/tests/console_test.bxml?rev=1832859&view=auto
==============================================================================
--- pivot/trunk/tests/src/org/apache/pivot/tests/console_test.bxml (added)
+++ pivot/trunk/tests/src/org/apache/pivot/tests/console_test.bxml Mon Jun  4 15:41:02 2018
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License,
+Version 2.0 (the "License"); you may not use this file except in
+compliance with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<Window bxml:id="window" title="Console Text Area Test" maximized="true"
+    xmlns:bxml="http://pivot.apache.org/bxml"
+    xmlns:collections="org.apache.pivot.collections"
+    xmlns:content="org.apache.pivot.wtk.content"
+    xmlns="org.apache.pivot.wtk">
+  <TablePane>
+    <columns>
+      <TablePane.Column width="1*"/>
+    </columns>
+    <rows>
+      <TablePane.Row height="3*">
+        <FlowPane>
+          <PushButton bxml:id="logMessageButton" buttonData="Log Message"/>
+        </FlowPane>
+      </TablePane.Row>
+      <TablePane.Row height="1*">
+        <Border title="Console">
+          <ScrollPane>
+            <TextArea bxml:id="consoleArea" editable="false"/>
+          </ScrollPane>
+        </Border>
+      </TablePane.Row>
+    </rows>
+  </TablePane>
+</Window>

Added: pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java
URL: http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java?rev=1832859&view=auto
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java (added)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/util/TextAreaOutputStream.java Mon Jun  4 15:41:02 2018
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.wtk.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import org.apache.pivot.wtk.ApplicationContext;
+import org.apache.pivot.wtk.Bounds;
+import org.apache.pivot.wtk.TextArea;
+
+/**
+ * Creates an {@link OutputStream} that outputs to a {@link TextArea}
+ * (in the EDT thread, using callbacks) for display.
+ * <p> Can be used with the {@link org.apache.pivot.util.Console} class for output (using the
+ * {@link #toPrintStream} method).
+ */
+public final class TextAreaOutputStream extends OutputStream {
+    /** The TextArea we are going to stream to. */
+    private TextArea textArea;
+
+    /** The buffered line for this stream. */
+    private ByteArrayOutputStream lineBuffer = new ByteArrayOutputStream(256);
+
+    /**
+     * Only constructor given the {@link TextArea} to stream to.
+     *
+     * @param textAreaToUse The TextArea to use for output.
+     */
+    public TextAreaOutputStream(final TextArea textAreaToUse) {
+        this.textArea = textAreaToUse;
+    }
+
+    /**
+     * @throws IOException if this stream is already closed.
+     */
+    private void checkIfOpen() throws IOException {
+        if (textArea == null || lineBuffer == null) {
+            throw new IOException("TextAreaOutputStream is closed.");
+        }
+    }
+
+    /**
+     * Flush the (byte) line buffer if there is anything cached.
+     * @param addNewLine If there is anything to flush, also add a newline
+     * ('\n') character at the end.
+     */
+    private void flushLineBuffer(final boolean addNewLine) {
+        if (lineBuffer.size() > 0) {
+            byte[] bytes = lineBuffer.toByteArray();
+            // TODO: should we have a charset to use here??
+            String text = new String(bytes);
+            int length = textArea.getCharacterCount();
+            textArea.insertText(text, length);
+            if (addNewLine) {
+                int newLength = length + text.length();
+                textArea.insertText("\n", newLength);
+            }
+            lineBuffer.reset();
+            Bounds beginningOfLineBounds = textArea.getCharacterBounds(length);
+            ApplicationContext.queueCallback(() -> textArea.scrollAreaToVisible(beginningOfLineBounds));
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        flush();
+        this.textArea = null;
+        this.lineBuffer = null;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        checkIfOpen();
+        flushLineBuffer(false);
+    }
+
+    @Override
+    public void write(final int b) throws IOException {
+        if (b == '\n') {
+            flushLineBuffer(true);
+        } else if (b != '\r') {
+            lineBuffer.write(b);
+        }
+    }
+
+    /**
+     * @return A new {@link PrintStream} using this object as the basis.
+     */
+    public PrintStream toPrintStream() {
+        return new PrintStream(this);
+    }
+
+}