2

I am learning JavaFX and experimenting with it. I tried to build a Console/Command Prompt . But i don't know how to redirect Input/Output/Error From ProcessBuilder to TextArea.

Code:

  public class JavaFXConsole extends Application {

 ProcessBuilder pb;
Process process;
TextArea ta;
String input = "";
int counter = 0;
//static BufferedReader stdInput, stdError;

//static Thread outputThread;
@Override
public void start(Stage primaryStage) {
    ta = new TextArea("$");
    ta.setOnKeyTyped(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent event) {
            {
                input = input.concat(event.getCharacter());
                System.out.println(input);
            }

        }
    });

    final KeyCombination keyComb1 = new KeyCodeCombination(KeyCode.C,
            KeyCombination.CONTROL_DOWN);
    ta.setOnKeyPressed(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent event) {
            if (event.getCode() == KeyCode.ENTER) {
                getOutPut(input);
                input = "";
                System.out.println("Command Sent");
            } else if (keyComb1.match(event)) {
                System.out.println("Control+C pressed");
            }
        }
    });

    HBox root = new HBox();
    root.getChildren().add(ta);

    pb = new ProcessBuilder("bash");
    try {
        process = pb.start();

    } catch (IOException ex) {
        Logger.getLogger(JavaFXConsole.class.getName()).log(Level.SEVERE, null, ex);
    }
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

public void getOutPut(String command) {

    Thread outputThread = new Thread(new Runnable() {

        @Override
        public void run() {

            try {
                BufferedReader stdInput, stdError;
                stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));

                stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

                OutputStream out;
                out = process.getOutputStream();
                out.write(command.getBytes());
                //out.flush();
                out.close();
                // read the output from the command
                System.out.println("Here is the standard output of the command:\n");
                String s = null;
                String output = "";
                int ocounter = 0;
                while ((s = stdInput.readLine()) != null) {
                    ocounter++;
                    System.out.println(s);
                    String str = s;
                    Platform.runLater(new Runnable() {

                        @Override
                        public void run() {
                            ta.appendText(">"+str + "\n");
                        }
                    });

                }

                output = "";

                ocounter = 0;
                // read any errors from the attempted command
                System.out.println("Here is the standard error of the command (if any):\n");
                while ((s = stdError.readLine()) != null) {
                    ocounter++;
                    System.out.println(s);
                    String str = s;
                    Platform.runLater(new Runnable() {

                        @Override
                        public void run() {
                            ta.appendText("*"+str + "\n");
                        }
                    });

                }
                Platform.runLater(new Runnable() {

                    @Override
                    public void run() {
                        ta.appendText("$");
                    }
                });

                // stdError.close();
                // stdInput.close();
            } catch (IOException ex) {
                Logger.getLogger(JavaFXConsole.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
    });

    outputThread.start();

}


/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

Any suggestion will be helpful. :)

Edit : 1

Did Improved a little , But Now getting exception, Can execute only One Command

If i don't close the stream in out.close();. Command will not execute.

   Jan 22, 2015 10:54:57 PM javafxconsole.JavaFXConsole$2 handle
   SEVERE: null
java.io.IOException: Stream closed
at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:433)
at java.io.OutputStream.write(OutputStream.java:116)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
at javafxconsole.JavaFXConsole$2.handle(JavaFXConsole.java:69)
at javafxconsole.JavaFXConsole$2.handle(JavaFXConsole.java:58)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)

at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$KeyHandler.process(Scene.java:3931)
at javafx.scene.Scene$KeyHandler.access$1800(Scene.java:3877)
at javafx.scene.Scene.impl_processKeyEvent(Scene.java:2006)
at javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2468)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:197)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:147)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:227)
at com.sun.glass.ui.View.handleKeyEvent(View.java:544)
at com.sun.glass.ui.View.notifyKey(View.java:954)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$45(GtkApplication.java:126)
at com.sun.glass.ui.gtk.GtkApplication$$Lambda$42/379110473.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
DeepSidhu1313
  • 805
  • 15
  • 31
  • 1
    See the answer here: http://stackoverflow.com/questions/12361600/javafx-fxml-communication-between-application-and-controller-classes (specifically, the Controller class) – colti Jan 21 '15 at 16:01
  • @colti But how can i send input from TextArea to ProcessBuilder? Getting output is the easy part. But maintaining both at same time , i don't know how can we achieve that? – DeepSidhu1313 Jan 22 '15 at 09:09
  • Read the answer found at that link. A thread is created to continuously read from the ProcessBuilder, and send whatever is read to the JavaFX thread to update the TextArea. – colti Jan 22 '15 at 14:42
  • @colti yes that's what i said getting output is easy part. But how to send keystrokes(input) from text area to ProcessBuilder. – DeepSidhu1313 Jan 22 '15 at 14:57
  • 1
    Your post states the opposite: "From ProcessBuilder to TextArea". Anyways, do the same thing - create a thread that listens for keystrokes on the TextArea (i.e. keypressed event) and sends it to the ProcessBuilder. – colti Jan 22 '15 at 15:39
  • @colti I updated the code, but now given exception occurs. If i don't close the stream command will not execute. Is there any way to solve this problem. – DeepSidhu1313 Jan 22 '15 at 17:38
  • Don't call `out.close();` on every key press. This causes the underlying input stream to be closed. Only call it *once* when you no longer need it. `out.flush()` should work instead. Why did you comment it out? – colti Jan 22 '15 at 18:32
  • @colti bcz it was not working, Commands were not getting executed. – DeepSidhu1313 Jan 22 '15 at 19:02

1 Answers1

3

I solved the problem, there was no need to close the streams. Only append \n at the end of each command and flush the stream. Speacial thanks to Julio Gessar my friend which provided me solution after giving a single look to code. Here is the code. I hope this code can be used to create custom terminals or terminal emulators using Java and JavaFX. Thanks to @colti for responding to my question.

Here is the code :

   /**
    *
    * @author nika
    */
    public class JavaFXConsole extends Application {

ProcessBuilder pb;
Process process;
TextArea ta;
String input = "";
int counter = 0;
BufferedReader stdInput, stdError;
OutputStream out;

//static BufferedReader stdInput, stdError;
//static Thread outputThread;
@Override
public void start(Stage primaryStage) throws InterruptedException {
    ta = new TextArea("/bin/bash\n");
    ta.setOnKeyTyped(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent event) {
            {

                input = input.concat(event.getCharacter());
                System.out.println(input);
            }

        }
    });

    final KeyCombination keyComb1 = new KeyCodeCombination(KeyCode.C,
            KeyCombination.CONTROL_DOWN);
    ta.setOnKeyPressed(new EventHandler<KeyEvent>() {

        @Override
        public void handle(KeyEvent event) {
            if (event.getCode() == KeyCode.ENTER) {
                try {
                    //getOutPut(input+"\n");
                    String command = input.replaceAll("\r", "") + "\n";
                    command = input.replaceAll("\b", "");
                    out.write(command.getBytes());
                    out.flush();
                    //getOutPut(command);
                    input = "";
                    System.out.println("Command Sent");
                } catch (IOException ex) {
                    Logger.getLogger(JavaFXConsole.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else if (keyComb1.match(event)) {

                System.out.println("Control+C pressed");
            }else if (event.getCode()== KeyCode.BACK_SPACE){
             //    input=input.substring(0, input.length()-1);
              //  System.out.println(input);
            }

        }
    });

    HBox root = new HBox();
    root.getChildren().add(ta);

    pb = new ProcessBuilder("/bin/bash");
    new Thread(new Runnable() {

        @Override
        public void run() {
            try {
                process = pb.start();
                stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));

                stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));

                //OutputStream out;
                out = process.getOutputStream();

                StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream(), "ERROR");

    // any output?
                StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), "OUTPUT");

    // start gobblers
                outputGobbler.start();
                errorGobbler.start();

                process.waitFor();

            } catch (IOException ex) {
                Logger.getLogger(JavaFXConsole.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException ex) {
                Logger.getLogger(JavaFXConsole.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }).start();

    Scene scene = new Scene(root, 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();

}


private class StreamGobbler extends Thread {

    InputStream is;
    String type;

    private StreamGobbler(InputStream is, String type) {
        this.is = is;
        this.type = type;
    }

    @Override
    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(type + "> " + line);
                String str =line;
                 Platform.runLater(new Runnable() {

                        @Override
                        public void run() {
                            ta.appendText(">" + str + "\n");

                        }
                    });
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}
DeepSidhu1313
  • 805
  • 15
  • 31