3

アプリに埋め込まれたデバッグ ツールとして Beanshell を使用しています。これは、自分のアプリに telnet で接続し、実行中にその内部をいじることができることを意味します (私は通常、telnet セッションを rlwrap でラップします)。

問題は、アプリケーション自体の stdout ではなく、Beanshell コンソールに出力する唯一の方法が、Beanshell 内の print() メソッドであることです。

しかし、Beanshell コンソールに出力する Beanshell から呼び出すことができるコードを Java で書きたいと思います。System.out または System.err を使用しようとした場合に発生するように、アプリケーションの stdout には送信されず、telnet セッションに表示されます。

これは可能ですか?


編集:さらに明確にするために、次のように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);
    }
}

(アプリケーションの System.out ではなく) telnet セッションに出力する Java 関数を記述できるように、これをどのように変更すればよいでしょうか?

4

3 に答える 3

2

最近コメント無視されてるみたいなのでコピペしておきます。

デバッグ情報を標準出力に出力するメソッドを使用する代わりに、そのデバッグ情報を返します。

class ClientList {
 Integer clients = 0;
 public String debugClientList() {
   return clients.toString();
 }

そしてそれをbeanshellから呼び出します

print(clients.debugCientList());

telnetで出力が得られます

または、ロガーのようにもっと必要な場合は、 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);
 }

さらにコーディングが必要になるため、コメントに返信しています。telnet の実装では、接続ごとに異なるインタープリターが使用されるため、telnet クライアントに出力するために、そのインタープリターをオブジェクトに公開する必要があります。最も簡単な方法は、server() スクリプト コマンドを使用する代わりに、デフォルトの telnet サーバーの一部を変更し、変更したものを使用してサーバーを起動することです (これは lgpl または Sun のライセンス条項に基づいています)。

この方法では、接続ごとにインタープリターが開始されることに注意してください。簡単で迅速な修正は、実行中のすべてのインタープリターのリストを維持し、それぞれにデバッグ情報を出力することです。

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); }
    }
}
于 2009-11-26T15:55:53.940 に答える
0

ハックなしでは不可能だと思います...申し訳ありませんが、BSHのtelnetサーバー実装を適応させています。

私たちが見ているクラスは ですbsh.util.Sessiond。開始すると、telnet サーバーを開いて維持します。コマンドを受け取るたびに、新しいワーカー スレッドを作成します。これにより、(ソケットから派生した) 正しい入力ストリームと出力ストリームを使用して新しい bsh.Interpreter が作成され、インタープリターが実行されます。

System.outしたがって、解釈されたコマンドの出力のみが telnet クライアントに送信されるのは理にかなっていますSystem.err

しかし、それはまさにあなたの場合に行わなければならないことです:インタープリターがコマンドを実行する前にソケット出力ストリームにリダイレクトSystem.outし、完了後にストリームをリセットします。System.err

bsh.util.Sessiondクラスを のようなものにコピーしmybsh.util.DebuggerSessiond、リダイレクション コードを内部クラス SessiondConnection の run メソッドに適用し、bsh/commands/server.bshこの「新しい」telnet サーバーを追加で (または元のサーバーの代わりに) 起動するように変更することをお勧めします。(おそらく、このスクリプトはサーバーを起動します...)

ソースコードはここにあります: beanshell リポジトリ

于 2009-12-01T13:48:48.673 に答える
-1

いずれにせよ、すべてのアプリケーションの出力が何らかのロギング フレームワークを使用して書き込まれている場合、ロギングに加えてファイルが beanshell コンソールに書き込むと言うカスタム アペンダー/ハンドラーを作成できますか? ビーンシェル コマンドを実行した後、コンソール ロギングを有効または無効にする可能性があります。

(以前は beanshell を知らなかったのですが、便利そうです!)

于 2009-11-25T23:10:06.900 に答える