Th3Br1x
Th3Br1x

Reputation: 1

Transfer the System.out to another class and read from it

i am working on a selfmade console (API, with GUI) and wanted to transfer the output from a program A, using my console, to my console class B, then read a string from it (the output from program A).

All answers i found were about creating a new PrintStream around a ByteArrayOutputStream etc.

The reason why i want to do this, is because i want to keep the code as easy as possible for others (best solution: one method to call in the program,).

It would be great if something like this would be possible for the programmer using my API:

ConsoleAPI c = new ConsoleAPI();
c.setOutput(System.out);
System.out.println("Hello World!");

I don't think, this is possible, but maybe it is. :)

Thanks in advance!

Upvotes: 0

Views: 294

Answers (2)

Axel
Axel

Reputation: 14159

Here is some code I once wrote to redirect System streams. Basically, calling ConsoleHandler.redirectSystemStreams() will give you an instance of ConsoleHandler that you can add listeners to. The listeners will be called when new output is available.

Hope that helps to get you started.

ConsoleHandler

package com.dua3.util.io;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;

public class ConsoleHandler implements Closeable {

  public static final int SYSTEM_OUT = 1;
  public static final int SYSTEM_ERR = 2;
  public static final int COPY_TO_SYSTEM_OUT = 8;
  protected final ByteArrayOutputStream outBytes;
  protected final PrintStream out;
  protected final List<ConsoleListener> consoleListeners;

  public synchronized static ConsoleHandler redirectSystemStreams(int what) {
    final PrintStream oldSystemOut = System.out;
    final PrintStream oldSystemErr = System.err;

    final boolean copyToSystemOut = (what & COPY_TO_SYSTEM_OUT) != 0;
    final boolean redirectSystemOut = (what & SYSTEM_OUT) != 0;
    final boolean redirectSystemErr = (what & SYSTEM_ERR) != 0;

    ConsoleHandler consoleHandler = new ConsoleHandler() {

      @Override
      public void close() throws IOException {
        // check state
        if (redirectSystemOut && System.out != this.out) {
          throw new IOException("System.out was redirected and can not be restored!");
        }

        if (redirectSystemErr && System.err != this.out) {
          throw new IOException("System.err was redirected and can not be restored!");
        }

        // restore System Streams
        if (redirectSystemOut) {
          System.setOut(oldSystemOut);
        }
        if (System.err == this.out) {
          System.setErr(oldSystemErr);
        }

        // call super implementation
        super.close();
      }

      @Override
      protected void contentChanged(String data) {
        super.contentChanged(data);
        if (copyToSystemOut) {
          oldSystemOut.append(data);
        }
      }
    };

    // redirect streams to console handler
    if (redirectSystemOut) {
      System.setOut(consoleHandler.getOut());
    }

    if (redirectSystemErr) {
      System.setErr(consoleHandler.getOut());
    }

    return consoleHandler;
  }

  public ConsoleHandler() {
    this.consoleListeners = new LinkedList<ConsoleListener>();
    this.outBytes = createByteStream();
    this.out = createOutputStream();
  }

  private ByteArrayOutputStream createByteStream() {
    return new ByteArrayOutputStream(256) {

      @Override
      public void flush() throws IOException {
        super.flush();
        flushBuffer();
      }
    };
  }

  private PrintStream createOutputStream() {
    return new PrintStream(outBytes, true);
  }

  void flushBuffer() {
    // append current content
    final String data = outBytes.toString();

    // debugging shows that system streams are flushed rather often even
    // when no new input was received, so suppress meaningless contentChanged
    // events
    if (!data.isEmpty()) {
      // reset the byte array
      outBytes.reset();

      // inform listeners
      contentChanged(data);
    }
  }

  protected void contentChanged(String data) {
    ConsoleEvent ce = new ConsoleEvent(data);
    for (ConsoleListener listener : consoleListeners) {
      listener.contentChanged(ce);
    }
  }

  public void addConsoleListener(ConsoleListener listener) {
    consoleListeners.add(listener);
  }

  public void removeConsoleListener(ConsoleListener listener) {
    consoleListeners.remove(listener);
  }

  public PrintStream getOut() {
    return out;
  }

  @Override
  public void close() throws IOException {
  }
}

ConsoleListener

package com.dua3.util.io;

import com.dua3.util.io.ConsoleEvent;

public interface ConsoleListener {

  void contentChanged(ConsoleEvent ce);

}

ConsoleEvent

package com.dua3.util.io;

public class ConsoleEvent {

  private final String data;

  public ConsoleEvent(String data) {
    this.data = data;
  }

  public String getData() {
    return data;
  }

}

Upvotes: 0

peter.petrov
peter.petrov

Reputation: 39447

System.out is an object of type PrintStream.
You can pass it around between classes like any other PrintStream object.

So your ConsoleAPI.setOutput method needs to take a PrintStream as parameter.
Then you'll be able to do what you want.

http://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html

Upvotes: 1

Related Questions