Custom telnet Groovy shells – version with shared context

A follow-up to the previous postcustom Telnet shared Groovy shells. This time having shared context for all shells, i.e. shared variables!

The trick was to get Binding object from current Groovy shell Interpreter and pass it in constructor to Groovy shells that we instantiate programmatically on socket connections. Not sure if it’s thread safe BTW (this isn’t production ready (-: ).

The code is based on Groovy Shell internals a bit, so should probably be run only from Groovy shell. (And just in case – I’m using version 1.8.4 of Groovy).

In any case, here’s again some demo video:

UPD: Also there’s the thread-safe version.
In it each shell will have it’s own Binding object, i.e. separate variables context.
But on creating shell we’ll inject two variables into that context:
sharedConcurrentMap – an instance of ConcurrentHashMap which will serve as thread-safe shared context for all shells, and is pre-populated with “server” and “sockets” (the latter are also made thread-safe);
thisShellSocket – a socket that is used for this child shell.

See source code at the end of the post.

As usual, a little demo video:

The source code
1. The non-thread-safe version

server = new ServerSocket(54321);
sockets = [];

serverThread = new Thread() {
    private ServerSocket server;
    private Collection sockets;
    private Binding binding;
    
    public void run() {
      
        while(!server.isClosed()) {
            server.accept {
                socket ->
                println "Socket connection established"
                sockets.add(socket)
                socket.withStreams {
                    input, output ->
                        println "Instantiating shell\n"
                        org.codehaus.groovy.tools.shell.Groovysh shell = new org.codehaus.groovy.tools.shell.Groovysh(binding, new org.codehaus.groovy.tools.shell.IO(input,output,output));
                        shell.run("");
                        println "Shell exit\n"
                }
                sockets.remove(socket)
            }
        }
    }

    public Thread init(ServerSocket server, Collection sockets, Binding binding) {
        this.server = server;
        this.sockets = sockets;
        this.binding = binding;
        return this;
    }
}.init(server, sockets, this.binding);

serverThread.start();

2. The thread-safe version

sharedConcurrentMap = new java.util.concurrent.ConcurrentHashMap();
server = new ServerSocket(54321);
sockets = new java.util.concurrent.ConcurrentLinkedQueue();

sharedConcurrentMap.put("server", server);
sharedConcurrentMap.put("sockets", sockets);

serverThread = new Thread() {
    private ServerSocket server;
    private Collection sockets;
    private java.util.concurrent.ConcurrentHashMap sharedConcurrentMap;
    
    public void run() {
      
        while(!server.isClosed()) {
            server.accept {
                socket ->
                println "Socket connection established"
                sockets.add(socket)
                socket.withStreams {
                    input, output ->
                        println "Instantiating shell\n"
                        org.codehaus.groovy.tools.shell.Groovysh shell = new org.codehaus.groovy.tools.shell.Groovysh(new org.codehaus.groovy.tools.shell.IO(input,output,output));
                        shell.interp.context.setVariable("sharedConcurrentMap", sharedConcurrentMap);
                        shell.interp.context.setVariable("thisShellSocket", socket);
                        shell.run("");
                        println "Shell exit\n"
                }
                sockets.remove(socket)
            }
        }
    }

    public Thread init(ServerSocket server, Collection sockets, java.util.concurrent.ConcurrentHashMap sharedConcurrentMap) {
        this.server = server;
        this.sockets = sockets;
        this.sharedConcurrentMap = sharedConcurrentMap;
        return this;
    }
}.init(server, sockets, this.sharedConcurrentMap);

serverThread.start();
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s