2012-09-03 17 views
1

我正在使用Primefaces的终端组件和JSch ssh到远程桌面。由于执行通道的执行需要很多时间,因为会话和通道都在每个命令处关闭,我没有设法解决这个问题。所以我将频道改为shell,现在我试图“重定向”标准输入/输出队列。这里是我的代码的样子:将JSch的标准iostream重定向到primefaces终端

import org.apache.commons.io.IOUtils; 
import org.apache.commons.lang3.StringUtils; 

@ManagedBean 
@SessionScoped 
public class TerminalController implements Serializable{ 

    public TerminalController(){ 
    jsch=new JSch(); 
    InputStream in=null; 
    PrintStream out=System.out; 
try{ 
         session=jsch.getSession(user, ip, port); 
         session.setConfig("StrictHostKeyChecking", "no"); 
         session.setPassword(passwd); 
         session.connect(); 
         channel=session.openChannel("shell");  
         channel.setInputStream(in); 
         channel.setOutputStream(out); 
         channel.connect(); 
}catch(Exception ee){ 
         System.out.println(ee); 
} } 
    public String handleCommand(String command, String[] params) { 
    command=command+StringUtils.join(params," "); 

        in=IOUtils.toInputStream(command); 
        String result=out.toString(); 
        out.flush(); 
        return result;} 

我知道这是一团糟,我仍然是java的初学者。 我想到的另一个问题是,在从iostream到字符串的转换中,我可能会失去输入按钮功能!我在等你的建议,解决方案和建议。

回答

0

设置in变量对通道没有影响,并且调用out.toString()不会得到任何结果。

您需要将写入命令(带其参数)到通道,然后从那里读取输出。另外,请不要使用setInputStreamsetOutputStream方法(如果您有现成的数据流要读取或要写入哪些数据流,那么这些方法很好)。

public class TerminalController implements Serializable{ 

    BufferedReader fromChannel; 
    PrintWriter toChannel; 
    Channel channel; 
    Session session; 

    public TerminalController(){ 
     jsch=new JSch(); 
     try { 
      session=jsch.getSession(user, ip, port); 
      session.setConfig("StrictHostKeyChecking", "no"); 
      session.setPassword(passwd); 
      session.connect(); 
      channel = session.openChannel("shell");  
      InputStream inStream = channel.getInputStream(); 
      fromChannel = new BufferedReader(new InputStreamReader(inStream, "UTF-8")); 
      OutputStream outStream = channel.getOutputStream(); 
      toChannel = new PrintWriter(new OutputStreamWriter(outStream, "UTF-8")); 
      channel.connect(); 
     } catch(Exception ee) { 
      ee.printStackTrace(); 
     } 
    } 

    public String handleCommand(String command, String[] params) { 
     command = command + StringUtils.join(params," "); 
     toChannel.println(command); 
     StringBuilder result = new StringBuilder(); 
     while(true) { 
      String line = fromChannel.readLine(); 
      result.append(line); 
      if(looksLikePrompt(line)) 
       return result.toString(); 
      result.append("\n"); 
     } 
    } 
} 

难的部分,当从远程命令的输出完成实际上是知道的,你需要返回(这是在looksLikePrompt方法,我不知道怎么写)。

我不确定Primeface的终端组件的CommandHandler原理是否是创建交互式终端的正确设计,终端不需要知道命令何时完成。当命令需要更多输入时会发生什么?

+1

非常感谢您的回答。那么Primefaces的终端组件不是终端仿真的明智选择,这一事实我觉得太晚了。说实话,我喜欢它的两件事是:个性化提示(带有xhtml属性)和命令历史记录(最多100个或更多)。 looksLikePrompt方法我可以解决,但我遇到了更大的问题。起初,我开始使用Exec频道,但我不能重复使用相同的频道,甚至不止一次尝试条件结构,它不工作。我不完全了解JSch。 – JohnTube

+0

每个可执行通道只能使用一次(对于一个命令),但您应该可以使用同一会话。不要在各个命令之间使用session.disconnect()(之后,您需要一个新的会话)。 –

+0

我没有使用session.disconnect()!我认为我的代码缺少的是Thread.sleep(n);或者,在每个命令之后,bean作用域的选择会自动结束会话。 – JohnTube

1
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 

import javax.faces.bean.ManagedBean; 
import javax.faces.bean.SessionScoped; 

import org.apache.commons.lang.StringUtils; 
import org.fusesource.jansi.AnsiConsole; 
import org.fusesource.jansi.AnsiString; 

import com.jcraft.jsch.Channel; 
import com.jcraft.jsch.JSch; 
import com.jcraft.jsch.Session; 

@ManagedBean 
@SessionScoped 
public class TerminalController { 
    BufferedReader fromChannel; 
    PrintWriter toChannel; 
    Channel channel; 
    Session session; 
    JSch jsch; 

    public TerminalController() { 
     jsch = new JSch(); 
     try { 
      session = jsch.getSession("leoks", "localhost", 22); 
      session.setConfig("StrictHostKeyChecking", "no"); 
      session.setPassword("xxx"); 
      session.connect(Integer.MAX_VALUE); // 3 secs timeout 
      channel = session.openChannel("shell"); 
      InputStream inStream = channel.getInputStream(); 
      fromChannel = new BufferedReader(new InputStreamReader(inStream, 
        "UTF-8")); 
      OutputStream outStream = channel.getOutputStream(); 
      toChannel = new PrintWriter(new OutputStreamWriter(outStream, 
        "UTF-8")); 
      channel.connect(); 

      StringBuilder result = new StringBuilder(); 
      boolean stop = false; 
      while (!stop) { 
       // prompt does not end with newline... 
       char c = (char) fromChannel.read(); 
       result.append(c); 
       System.out.print(c); 
       if (result.toString().endsWith("$")) { 
        System.out.print("<<<"); 
        stop = true; 
       } 
      } 

     } catch (Exception ee) { 
      ee.printStackTrace(); 
     } 
    } 

    public String handleCommand(String command, String[] params) 
      throws IOException { 
     command = command + " " + StringUtils.join(params, " "); 
     toChannel.println(command); 
     toChannel.flush(); 
     StringBuilder result = new StringBuilder(); 
     AnsiConsole.systemInstall(); 
     while (true) { 
      char c = (char) fromChannel.read(); 
      result.append(c); 
      if (c == '$') { 
       AnsiString as = new AnsiString(result.toString()); 
       String s = as.getPlain().toString(); 
       s = s.replaceAll("\n", "<br>"); 
       AnsiConsole.systemUninstall(); 
       return s; 
      } 
     } 
    } 
} 

Jansi也有需要一些工作正常替换\ n,其中BR因为终端组件呈现HTML和静默忽略任何畸形字符串完全控制代码的HTML渲染类。你也可以用固定宽度字体更换终端CSS定义,例如,使用CSS如

.ui-widget 
{ 
    font-family: "Courier New", Courier, monospace; 
    font-size: 0.8em; 
} 

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:p="http://primefaces.org/ui"> 
<h:head> 
    <title>Terminal POC</title> 
</h:head> 
<h:body> 
    <h:outputStylesheet library="css" name="styles.css" /> 
    <h:form> 
     <p:terminal 
      commandHandler="#{terminalController.handleCommand}" 
      height="300px" 
      welcomeMessage="Welcome..." 
      prompt="&gt;" /> 
    </h:form> 
</h:body> 
</html>