2016-12-21 12 views
2

Я работаю над новым проектом. Я пытаюсь отправить команды на внешний компьютер (Linux) через ethernet с Java. Я использую Jsch для создания соединения с оболочкой. Я устанавливаю ввод и вывод оболочки в System.out и System.in.Как перенаправить System.in в TextField JavaFX?

((ChannelShell)channel).setInputStream(System.in); 
((ChannelShell)channel).setOutputStream(System.out); 

Он работает в консоли! Но мне нужно удалять его из приложения GUI javafx. Я уже решил перенаправление System.out в TextArea:

public void redirectOutputStream() { 
     OutputStream out = new OutputStream() { 

      private final StringBuilder sb = new StringBuilder(); 

      @Override 
      public void write(int b) throws IOException { 
       if (b == '\r') { 
        return; 
       } 

       if (b == '\n') { 
        final String tmp = sb.toString() + "\n"; 
        text.add(tmp); 
        updateText(text); 
        sb.setLength(0); 
       } else { 
        sb.append((char) b); 
       } 
      } 
     }; 

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

Но теперь мне нужно также перенаправить System.in к TextField, так что я могу написать что-то в TextField, нажмите клавишу ввода и отправить его через оболочку к внешний компьютер.

Любая помощь была бы оценена. Благодаря!

EDIT: К сожалению, до сих пор не работает для меня :(... Теперь у меня есть этот кусок кода (я использую JavaFX):

/** Tmp queue for standard input redirecting */ 
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 



@Override 
    public void initialize(URL arg0, ResourceBundle arg1) { 
     redirectOutputStream(); 
     redirectInputStream(); 
} 


/** redirects standard System.out to GUI command_window */ 
public void redirectOutputStream() { 
    OutputStream out = new OutputStream() { 

     private final StringBuilder sb = new StringBuilder(); 

     @Override 
     public void write(int b) throws IOException { 
      if (b == '\r') { 
       return; 
      } 
      if (b == '\n') { 
       final String tmp = sb.toString() + "\n"; 
       text.add(tmp); 
       updateText(text); 
       sb.setLength(0); 
      } else { 
       sb.append((char) b); 
      } 
     } 
    }; 
    System.setOut(new PrintStream(out, true)); 
    System.setErr(new PrintStream(out, true)); 
} 

/** redirects standard System.in to GUI command_line */ 
public void redirectInputStream() { 
    InputStream in = new InputStream() { 

     @Override 
     public int read() throws IOException { 
      try { 
       int c = stdInQueue.take().intValue(); 
       return c; 
      } catch (InterruptedException exc) { 
       Thread.currentThread().interrupt(); 
       return -1; 
      } 
     } 
    }; 
    System.setIn(in); 
} 


@FXML 
    void sendButtonPressed(ActionEvent event) { 
     if (!command_line.getText().isEmpty()) { 
      for (char c : command_line.getText().toCharArray()) { 
       System.out.write(new Integer(c)); //display in ListView (output) 
       stdInQueue.add(new Integer(c)); 
      } 
      System.out.write(new Integer('\n')); //display in ListView (output)  
      stdInQueue.add(new Integer('\n')); 
      command_line.clear(); 
     } 
    } 

Перенаправляющий Системы. out и System.err отлично работает. Он отображается в javafx ListView.

Проблема в том, что при ListView у меня есть «командная строка» javafx TextField, и мне нужно написать некоторую команду ssh в этот TextField и перенаправить его в System.in при нажатии «enter» или нажав «отправить» ".

Причина, по которой мне нужно сделать это, заключается в том, что я использую SSH-связь, которая настроена для System.in и System.out. Он полностью работает в консоли (тестируется), но не в моем графическом приложении.

Спасибо за дальнейшие советы!

+0

Если вы можете создать InputStream, связанный с текстовым полем, попробуйте использовать 'System.setIn (...)'. – Thomas

+0

Извините, я не знаю, как редактировать комментарий ... Я попытался использовать System.setIn (new InputStream()); но мне не удалось преодолеть метод read(). – Zuzana

ответ

0

Вы можете настроить BlockingQueue<Integer> отправлять отдельные символы в, а затем входной поток принимать символы из него:

BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 

System.setIn(new InputStream() { 

    @Override 
    public int read() throws IOException { 
     try { 
      int c = stdInQueue.take().intValue(); 
      return c; 
     } catch (InterruptedException exc) { 
      Thread.currentThread().interrupt(); 
      return -1 ; 
     } 
    } 
}); 

textField.setOnAction(e -> { 
    for (char c : textField.getText().toCharArray()) { 
     stdInQueue.add(new Integer(c)); 
    } 
    stdInQueue.add(new Integer('\n')); 
    textField.clear(); 
}); 

Вот краткий демо: для тестирования я просто настроить фоновый поток, читает из System.in:

import java.io.IOException; 
import java.io.InputStream; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.TextField; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public class StdInFromTextField extends Application { 

    @Override 
    public void start(Stage primaryStage) { 

     TextField textField = new TextField(); 

     BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>(); 

     System.setIn(new InputStream() { 

      @Override 
      public int read() throws IOException { 
       try { 
        int c = stdInQueue.take().intValue(); 
        return c; 
       } catch (InterruptedException exc) { 
        Thread.currentThread().interrupt(); 
        return -1 ; 
       } 
      } 
     }); 

     textField.setOnAction(e -> { 
      for (char c : textField.getText().toCharArray()) { 
       stdInQueue.add(new Integer(c)); 
      } 
      stdInQueue.add(new Integer('\n')); 
      textField.clear(); 
     }); 

     // for testing: 
     Thread readThread = new Thread(() -> { 
      try { 
       int i ; 
       while ((i = System.in.read()) != -1) { 
        System.out.print((char)i); 
       } 
      } catch (IOException exc) { 
       exc.printStackTrace(); 
      } 
     }); 
     readThread.setDaemon(true); 
     readThread.start(); 

     primaryStage.setScene(new Scene(new StackPane(textField), 300, 120)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

Извините, все еще не работает для меня ... Можете ли вы посмотреть на мой код? (см. EDIT) – Zuzana

-1

Хорошо, я рабочий код прямо сейчас. Проблема в том, что я не понял, как перенаправить System.in (возможно, это невозможно сделать). Поэтому мне пришлось перенаправить потоки непосредственно из SSH-коннектора.

Вот как я установил ввод и вывод в JSch потоке:

public class ToradexSSHCommunicator { 

String user; 
String password; 
String ip; 
int port; 

InputStream fromChannel; 
OutputStream toChannel; 

/** logger for error output feed */ 
private static final Logger LOGGER = Logger.getLogger(ToradexSSHCommunicator.class); 

public ToradexSSHCommunicator(String user, String password, String ip, int port) { 
    this.user = user; 
    this.password = password; 
    this.ip = ip; 
    this.port = port; 
} 

public void startup() { 
    Session session = null; 
    ChannelShell channel = null; 
    boolean isConnected = false; 

    JSch jsch = new JSch(); 
    while (!isConnected) { 
     try { 
      session = jsch.getSession(user, ip, port); 

      session.setPassword(password); 
      session.setConfig("StrictHostKeyChecking", "no"); 

      LOGGER.info("Establishing Toradex Connection..."); 
      session.setTimeout(1000); 
      session.connect(); 
      LOGGER.info("Toradex connection established."); 

      LOGGER.info("Creating Toradex channel..."); 
      channel = (ChannelShell) session.openChannel("shell"); 
      LOGGER.info("Toradex channel created."); 

      fromChannel = channel.getInputStream(); 
      toChannel = channel.getOutputStream(); 

      channel.connect(); 
      isConnected = true; 

     } 
     catch (JSchException e) { 
      LOGGER.error("Toradex connection error.....RECONNECTING", e); 
      session.disconnect(); 
     } 
     catch (IOException e) { 
      LOGGER.error("Toradex connection error.....RECONNECTING", e); 
      session.disconnect(); 
     } 
    } 

} 

public InputStream getFromChannel() { 
    return fromChannel; 
} 

public OutputStream getToChannel() { 
    return toChannel; 
    } 
} 

И эта часть GUI, которые используют это потоки:

@FXML 
private ListView<String> command_window_toradex; 
@FXML 
private TextField command_line; 

private ToradexSSHCommunicator comm; 

private BufferedReader br; 
private BufferedWriter bw; 

@FXML 
    void sendButtonPressed(ActionEvent event) { 
     executor.submit(new Task<Void>() { 

      @Override 
      protected Void call() throws Exception { 
       writeCommand(); 
       return null; 
      } 
     }); 
    } 

/** initialize SSH connection to Toradex and redirect input and output streams to GUI */ 
private void initToradex() { 
    comm = new ToradexSSHCommunicator(GuiConstants.TORADEX_USER, GuiConstants.TORADEX_PASSWORD, 
      GuiConstants.TORADEX_IP_ADDRESS, GuiConstants.TORADEX_PORT); 
    comm.startup(); 
    br = new BufferedReader(new InputStreamReader(comm.getFromChannel())); 
    bw = new BufferedWriter(new OutputStreamWriter(comm.getToChannel())); 
} 

private void writeCommand() throws IOException { 
    if (!command_line.getText().isEmpty()) { 
     String command = command_line.getText(); 
     bw.write(command + '\n'); 
     bw.flush(); 
     command_line.clear(); 
    } 
} 

private void readCommand() throws IOException { 
    String commandLine = null; 
    while (true) { 
     commandLine = br.readLine(); 
     textToradex.add(commandLine); 
    } 
} 

Это работает! Однако теперь это весь код, если вам нужна дополнительная помощь, просто спросите.

+0

Прошу прощения ...: -/ – Zuzana

+0

Теперь вот мое решение. – Zuzana