[英]Can I write to the Beanshell console from Java?
I'm using Beanshell as an embedded debugging tool in my app. 我在我的应用程序中使用Beanshell作为嵌入式调试工具。 It means I can telnet to my app and poke around with its internals while it is running (I typically wrap the telnet session with rlwrap).
这意味着我可以远程登录到我的应用程序并在其运行时使用其内部功能(我通常用rlwrap包装telnet会话)。
The problem is that the only way I've found to print to the Beanshell console, rather than stdout of the application itself, is the print() method within Beanshell. 问题是,我发现打印到Beanshell控制台的唯一方法是Beanshell中的print()方法,而不是应用程序本身的stdout。
But I'd like to write code in Java that I can call from Beanshell, which will output to the Beanshell console - ie. 但我想用Java编写代码,我可以从Beanshell调用它,它将输出到Beanshell控制台 - 即。 it will be shown in my telnet session, not sent to stdout of the application, as happens if you try to use System.out or System.err.
它将显示在我的telnet会话中,而不是发送到应用程序的stdout,如果您尝试使用System.out或System.err。
Is this possible? 这可能吗?
edit: To further clarify, I'm setting up a Beanshell server as follows: 编辑:为了进一步说明,我正在设置一个Beanshell服务器,如下所示:
public static void setUpBeanshell() {
try {
i.setShowResults(true);
i.eval(new InputStreamReader(Bsh.class.getResourceAsStream("init.bsh")));
i.eval("server(" + Main.globalConfig.beanShellPort + ");");
} catch (final EvalError e) {
Main.log.error("Error generated while starting BeanShell server", e);
}
}
How would I modify this such that I can write a Java function that outputs to the telnet session (rather than to System.out of my application) 我如何修改它,以便我可以编写一个输出到telnet会话的Java函数(而不是我的应用程序的System.out)
I'll copy it there as it seems that comments are disregarded this days. 我会把它复制到那里,因为这些日子里的评论似乎被忽视了。
you can: instead of having a method which print debug information to the standard output returns that debug information: 你可以:而不是有一个方法将调试信息打印到标准输出返回调试信息:
class ClientList {
Integer clients = 0;
public String debugClientList() {
return clients.toString();
}
and then calling it from beanshell 然后从beanshell调用它
print(clients.debugCientList());
will give you an output on your telnet 会在你的telnet上给你一个输出
or if you need it more logger like, you need to interact with the Interpreter object directly 或者如果你需要更多的记录器,你需要直接与Interpreter对象进行交互
InterpreterSingleton {
public static final void Console console = new Interpreter();
}
....
class ClientList {
Integer clients = 0;
public void addClient(Client c) {
....
InterpreterSingleton.console.print("Client added, clients now are " + clients);
}
I'm replying there to the comment as it will need some more coding; 我在那里回复评论,因为它需要更多的编码; the telnet implementation uses a different interpreter for each connection, so you have to expose that interpreter to the objects for printing to the telnet client.
telnet实现为每个连接使用不同的解释器,因此您必须将该解释器公开给对象以便打印到telnet客户端。 The quickest way is to change some bit in the default telnet server and use the modified one to start your server, instead of using the server() scripted command (it's under lgpl or sun license terms)
最快的方法是在默认的telnet服务器中更改一些位并使用修改后的服务器启动服务器,而不是使用server()脚本命令(它在lgpl或sun许可条款下)
note that this way have an interpreter started for each connection; 请注意,这种方式为每个连接启动了一个解释器; the easy and quick fix is to maintain a list of all the running interpreters and print to each one the debugging information, so:
简单快速的解决方法是维护所有正在运行的解释器的列表,并向每个解释器打印调试信息,因此:
class InterpreterSingletonList {
public static final void Set<Interpreter> is = new HashSet();
void printToAll(String s) {
for (Interpreter i: is) {
i.print(s);
}
}
}
package bsh.util;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
import bsh.*;
/**
BeanShell remote session server.
Starts instances of bsh for client connections.
Note: the sessiond effectively maps all connections to the same interpreter
(shared namespace).
*/
public class Sessiond extends Thread
{
private ServerSocket ss;
NameSpace globalNameSpace;
public Sessiond(NameSpace globalNameSpace, int port) throws IOException
{
ss = new ServerSocket(port);
this.globalNameSpace = globalNameSpace;
}
public void run()
{
try
{
while(true)
new SessiondConnection(globalNameSpace, ss.accept()).start();
}
catch(IOException e) { System.out.println(e); }
}
}
class SessiondConnection extends Thread
{
NameSpace globalNameSpace;
Socket client;
SessiondConnection(NameSpace globalNameSpace, Socket client)
{
this.client = client;
this.globalNameSpace = globalNameSpace;
}
public void run()
{
try
{
InputStream in = client.getInputStream();
PrintStream out = new PrintStream(client.getOutputStream());
/* this is the one you're looking for */
Interpreter i = new Interpreter(
new InputStreamReader(in), out, out, true, globalNameSpace);
i.setExitOnEOF( false ); // don't exit interp
/*store the interpreter on the list*/
InterpreterSingletonList.is.add(i);
i.run();
/*remove it (i.run() blocks)*/
InterpreterSingletonList.is.remove(i);
}
catch(IOException e) { System.out.println(e); }
}
}
I think it's not possible with out hack..., sorry, adapting the telnet server implementation of BSH. 我认为这是不可能的黑客...,抱歉,适应BSH的telnet服务器实现。
The class we're looking at is bsh.util.Sessiond
. 我们
bsh.util.Sessiond
的类是bsh.util.Sessiond
。 Once started, it opens and maintains a telnet server. 一旦启动,它将打开并维护一个telnet服务器。 When ever it receives a command, it creates a new worker thread, this on creates a new bsh.Interpreter with the correct input and output streams (derived from the socket) and runs the interpreter.
当它收到命令时,它会创建一个新的工作线程,这将创建一个新的bsh.Interpreter,其中包含正确的输入和输出流(从套接字派生)并运行解释器。
So it makes sense, that only output of interpreted commands is send to the telnet client, because System.out
and System.err
are not redirected. 所以有意义的是,只有解释命令的输出才会发送到telnet客户端,因为
System.out
和System.err
不会被重定向。
But that exactly is what has to be done in your case: redirect System.out
and System.err
to the sockets output stream before the interpreter runs the command and reset the streams after completion. 但这正是您需要做的事情:在解释器运行命令之前将
System.out
和System.err
重定向到套接字输出流,并在完成后重置流。
I'd suggest, you copy the bsh.util.Sessiond
class to something like mybsh.util.DebuggerSessiond
, apply the redirection code to the run method of the inner class SessiondConnection and modify bsh/commands/server.bsh
to start this 'new' telnet server in addition (or instead of the original one). 我建议你将
bsh.util.Sessiond
类复制到类似mybsh.util.DebuggerSessiond
东西,将重定向代码应用到内部类SessiondConnection的run方法,并修改bsh/commands/server.bsh
以启动这个'new 'telnet服务器另外(或代替原来的)。 (I guess, this script starts the servers...) (我想,这个脚本启动了服务器...)
Source code can be found here: beanshell repository 源代码可以在这里找到: beanshell存储库
If all your application's output is written using some logging framework anyways, you could write a custom appender/handler which besides logging to say a file would write to the beanshell console in addition? 如果所有应用程序的输出都是使用某些日志记录框架编写的,那么您可以编写一个自定义appender / handler,除了日志记录之外还要写一个文件会写入beanshell控制台吗? Possibly enabling and disabling the console-logging after executing some beanshell command.
执行某些beanshell命令后,可能启用和禁用控制台日志记录。
(I wasn't aware of beanshell before, but it seems useful!) (我以前不知道豆壳,但它看起来很有用!)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.