Search code examples
javajava-threads

Java: Start sub process with own terminal


I have two controllers and one program that starts them both. One is an emulator that produces data, the other analyzes the data. The two controllers depend on each other and communicate using RMI. Therefore, I start the emulator in another thread and the analyzer in my main thread. That works perfectly fine.

Now the problem is, that they both produce quite a lot of output on the console and I really would like them to print to two different terminals. Is there a way to do that?

I tried to start the emulator as a sub process within a new command line (platform independence would be the next step)

String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
            + separator + "bin" + separator + "java";
ProcessBuilder processBuilder = 
            new ProcessBuilder(
            "\"" + path + "\"", 
            "-cp", 
            classpath,
            TheEumlator.class.getName());

String command = StringUtils.join(processBuilder.command(), " ");

Process p = Runtime.getRuntime().exec(String.format("cmd /c start cmd.exe /K %s", command));

However, the classpath is way too long and the output of cmd.exe is The command line is too long.

Do you have any idea how to produce another thread or process with its own output terminal? I'd be happy for any suggestion.

Cheers

UPDATE

I combined the answer of OlaviMustanoja with this solution http://unserializableone.blogspot.co.uk/2009/01/redirecting-systemout-and-systemerr-to.html

It now uses standard System.out, System.err and stack trace. Also, it scrolls.

public class ConsoleWindow implements Runnable {

    private String title;
    private JFrame frame;
    private JTextArea outputArea;
    private JScrollPane scrollPane;

    public ConsoleWindow(String title, boolean redirectStreams) {
        this.title = title;
        this.outputArea = new JTextArea(30, 80);
        this.outputArea.setEditable(false);

        if (redirectStreams)
            redirectSystemStreams();
    }

    public ConsoleWindow(String title) {
        this(title, false);
    }

    @Override
    public void run() {
        frame = new JFrame(this.title);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        scrollPane = new JScrollPane(outputArea);
        JPanel outputPanel = new JPanel(new FlowLayout());
        outputPanel.add(scrollPane);

        frame.add(outputPanel);
        frame.pack();
        frame.setVisible(true);
    }

    private void updateTextArea(final String text) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                outputArea.append(text);
            }
        });
    }

    private void redirectSystemStreams() {
        OutputStream out = new OutputStream() {
            @Override
            public void write(int b) throws IOException {
                updateTextArea(String.valueOf((char) b));
            }

            @Override
            public void write(byte[] b, int off, int len) throws IOException {
                updateTextArea(new String(b, off, len));
            }

            @Override
            public void write(byte[] b) throws IOException {
                write(b, 0, b.length);
            }
        };

        System.setOut(new PrintStream(out, true));
        System.setErr(new PrintStream(out, true));
    }

    public void println(String msg) {
        updateTextArea(msg + "\n");
    }

    public void println(Throwable t) {
        println(t.toString());
    }

    public void print(String msg) {
        updateTextArea(msg);
    }

    public void printStackTrace(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        t.printStackTrace(pw);
        this.println(sw.toString());
    }
}

Solution

  • Is it necessary to output the messages to these consoles? If not, you could simply implement a class (say, OutputWindow) that takes messages in some way and shows them in the window.

    To better illustrate the point I made in my comment, consider the following implementation of OutputWindow:

    class OutputWindow implements Runnable {
    
        private String title;
        private JFrame frame;
        private JTextArea outputArea;
    
        public OutputWindow(String title) {
            this.title = title;
            this.outputArea = new JTextArea(15, 50);
            this.outputArea.setEditable(false);
        }
    
        @Override
        public void run() {
            frame = new JFrame(this.title);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            JPanel outputPanel = new JPanel(new FlowLayout());
            outputPanel.add(outputArea);
    
            frame.add(outputPanel);
            frame.pack();
            frame.setVisible(true);
        }
    
        public void println(String msg) {
            outputArea.append(msg + "\n");
        }
    
        public void println(Throwable t) {
            this.println(t.toString());
        }
    
        public void print(String msg) {
            outputArea.append(msg);
        }
    
        public void printStackTrace(Throwable t) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            t.printStackTrace(pw);
            this.println(sw.toString());
        }
    
    }
    

    A simple, rather quickly tested piece of code. One would open a new "console" like this:

    OutputWindow console = new OutputWindow("Console");
    SwingUtilities.invokeLater(console);
    

    You can try it out:

    OutputWindow console = new OutputWindow("Console");
    SwingUtilities.invokeLater(console);
    
    try {
        System.out.println(2 / 0);     // just to throw an exception
    } catch (ArithmeticException ex) {
        console.printStackTrace(ex);
    }
    

    The advantage in doing this is the extent to which you can customize it! Endless possibilities. Create your own state of the art console with super awesome colors and any kind of functionality you want.