Search code examples
javabeanshell

Can I write to the Beanshell console from Java?


I'm using Beanshell as an embedded debugging tool in my app. 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).

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.

But I'd like to write code in Java that I can call from Beanshell, which will output to the Beanshell console - ie. 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.

Is this possible?


edit: To further clarify, I'm setting up a Beanshell server as follows:

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)


Solution

  • 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

    print(clients.debugCientList());
    

    will give you an output on your telnet

    or if you need it more logger like, you need to interact with the Interpreter object directly

    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. 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)

    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); }
        }
    }