JavaFX webview: How to forward System.out and System.err to the Firebug Lite console?

228 views Asked by At

I've found several examples on how to pipe and redirect messages from System.out and System.err. Having decided to develop an application using the JavaFX Webview and Dukescript, I've found useful having one place where to display all messages, i.e. the Firebug Lite console.

See below.

PS This is the exact opposite as this

1

There are 1 answers

0
ZiglioUK On

First define an abstract class

public abstract class FirebugConsole extends OutputStream {

  abstract void log( String msg );

  StringBuilder sb = new StringBuilder();

  @Override
  public void write(int i) {
    sb.append((char)i);
  }

  @Override
  public void flush() {
    if( sb.length() >0 && !sb.toString().equals("\r\n"))
      log(sb.toString());
    sb = new StringBuilder();
  }  
}

Then extend it with methods that implement native calls into JavaScript. Here's for example how to write log messages

public class FirebugConsoleInfo extends FirebugConsole{
  @net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
      + "Firebug.Console.log(msg);")
  public native void log( String msg );
}

Finally, pipe System.out and System.err to those objects

  public static void onPageLoad() throws Exception {
  ...
      System.setOut(new PrintStream(new FirebugConsoleInfo(), true));
      System.setErr(new PrintStream(new FirebugConsoleError(), true));
  ...
  }

Note: for some reasons the usual console.log() doesn't work for me, I know Firebug doesn't bind a console if a console object is already present, so I suspect the WebFX webview must itself pipe console.log messages to System.out in the first place.

Update

The solution above doesn't work when the messages are generated by a thread other than the browser's. Here's an updated solution based on BrwsrCtx.execute()

  public abstract static class FirebugConsole extends OutputStream {
    protected final BrwsrCtx ctx;

    public FirebugConsole( BrwsrCtx ctx ){
      this.ctx = ctx;
    }
    abstract void logNative( String msg );

    void log(String msg) {
      ctx.execute(new Runnable(){
        @Override
        public void run() {
          logNative(msg);
        }
      });
    }

    StringBuilder sb = new StringBuilder();

    @Override
    public void write(int i) {
      sb.append((char)i);
    }

    @Override
    public void flush() {
      if( sb.length() >0 && !sb.toString().equals("\r\n"))
        log(sb.toString());
      sb = new StringBuilder();
    }  
  }

  public static class FirebugConsoleInfo extends FirebugConsole{
    public FirebugConsoleInfo(BrwsrCtx ctx) {
      super(ctx);
    }

    @net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
        + "Firebug.Console.log(msg);")
    public native void logNative( String msg );

  }

  public static class FirebugConsoleError extends FirebugConsole{
    public FirebugConsoleError(BrwsrCtx ctx) {
      super(ctx);
    }

    @net.java.html.js.JavaScriptBody(args = { "msg" }, body = ""
        + "Firebug.Console.error(msg);")
    public native void logNative( String msg );
    }
 }

and

  public static void onPageLoad() throws Exception {
      BrwsrCtx ctx = BrwsrCtx.findDefault(GoGPS_Fx.class);
      System.setOut(new PrintStream(new FirebugConsoleInfo(ctx), true));
      System.setErr(new PrintStream(new FirebugConsoleError(ctx), true));
  }

Note: it's quite slow for large logs, there might be faster alternatives (StringWriter is one). But I suspect the bottleneck is the passing of messages back and forth from Java to JavaScript.