You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2012/06/01 16:37:55 UTC

svn commit: r1345205 - in /felix/trunk/webconsole-plugins/gogo: ./ src/main/appended-resources/META-INF/ src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/ src/main/resources/res/ui/

Author: fmeschbe
Date: Fri Jun  1 14:37:54 2012
New Revision: 1345205

URL: http://svn.apache.org/viewvc?rev=1345205&view=rev
Log:
FELIX-3530 Replace JLine with adapted AjaxTerm

Added:
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminal.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminalManager.java
Removed:
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/AggregateCompleter.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/CloseShellException.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/CommandSessionHolder.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/CommandsCompleter.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/NameScoping.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Parser.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/StringsCompleter.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/WebTerminal.java
Modified:
    felix/trunk/webconsole-plugins/gogo/pom.xml
    felix/trunk/webconsole-plugins/gogo/src/main/appended-resources/META-INF/DEPENDENCIES
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Activator.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Console.java
    felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/GogoPlugin.java
    felix/trunk/webconsole-plugins/gogo/src/main/resources/res/ui/gogo.js

Modified: felix/trunk/webconsole-plugins/gogo/pom.xml
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/pom.xml?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/pom.xml (original)
+++ felix/trunk/webconsole-plugins/gogo/pom.xml Fri Jun  1 14:37:54 2012
@@ -78,19 +78,6 @@
 						<Bundle-Activator>
 							org.apache.felix.webconsole.plugins.gogo.impl.Activator
                         </Bundle-Activator>
-                        <Embed-Dependency>
-                            jline;inline=true
-                        </Embed-Dependency>
-                        <Bundle-NativeCode>
-                            META-INF/native/windows32/jansi.dll;osname=Win32;processor=x86,
-                            META-INF/native/windows64/jansi.dll;osname=Win32;processor=x86-64,
-                            <!--
-                            META-INF/native/linux32/libjansi.so;osname=Linux;processor=x86,
-                            META-INF/native/linux64/libjansi.so;osname=Linux;processor=x86-64,
-                            META-INF/native/osx/libjansi.jnilib;osname=MacOSX,
-                            -->
-                            *
-                        </Bundle-NativeCode>
 					</instructions>
 				</configuration>
 			</plugin>
@@ -128,11 +115,5 @@
             <version>2.3</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.sonatype.jline</groupId>
-            <artifactId>jline</artifactId>
-            <version>2.5</version>
-            <scope>provided</scope>
-        </dependency>
  	</dependencies>
 </project>

Modified: felix/trunk/webconsole-plugins/gogo/src/main/appended-resources/META-INF/DEPENDENCIES
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/appended-resources/META-INF/DEPENDENCIES?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/appended-resources/META-INF/DEPENDENCIES (original)
+++ felix/trunk/webconsole-plugins/gogo/src/main/appended-resources/META-INF/DEPENDENCIES Fri Jun  1 14:37:54 2012
@@ -5,10 +5,9 @@ This product includes software developed
 The Apache Software Foundation (http://www.apache.org/).
 Licensed under the Apache License 2.0.
 
-This product includes software from https://github.com/jline/jline2
-Copyright (c) 2002-2006, Marc Prud'hommeaux <mw...@cornell.edu>
-All rights reserved.
-Licensed under the BSD License
+This product includes files derived from Ajaxterm
+http://antony.lesuisse.org/software/ajaxterm/
+Ajaxterm files are released in the Public Domain
 
 This plugin draws from Apache Karaf Console and Web Console bundles.
 Kudos!

Modified: felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Activator.java?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Activator.java (original)
+++ felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Activator.java Fri Jun  1 14:37:54 2012
@@ -18,18 +18,18 @@
  */
 package org.apache.felix.webconsole.plugins.gogo.impl;
 
-import org.fusesource.jansi.AnsiConsole;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
 public class Activator implements BundleActivator {
 
+    private SessionTerminalManager terminalManager;
+
     private GogoPlugin plugin;
 
     public void start(BundleContext context) throws Exception {
-        AnsiConsole.systemInstall();
-
-        this.plugin = new GogoPlugin();
+        this.terminalManager = new SessionTerminalManager(context);
+        this.plugin = new GogoPlugin(this.terminalManager);
         this.plugin.register(context);
     }
 
@@ -38,8 +38,10 @@ public class Activator implements Bundle
             this.plugin.unregister();
             this.plugin = null;
         }
-
-        AnsiConsole.systemUninstall();
+        if (this.terminalManager != null) {
+            this.terminalManager.shutdown();
+            this.terminalManager = null;
+        }
     }
 
 }

Modified: felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Console.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Console.java?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Console.java (original)
+++ felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/Console.java Fri Jun  1 14:37:54 2012
@@ -18,52 +18,24 @@
  */
 package org.apache.felix.webconsole.plugins.gogo.impl;
 
-import java.io.CharArrayWriter;
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.InterruptedIOException;
 import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.Reader;
 import java.util.Map;
-import java.util.Properties;
+import java.util.Map.Entry;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import jline.Terminal;
-import jline.UnsupportedTerminal;
-import jline.console.ConsoleReader;
-import jline.console.completer.Completer;
-import jline.console.history.PersistentHistory;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Converter;
-import org.fusesource.jansi.Ansi;
 
 public class Console implements Runnable {
 
-    public static final String SHELL_INIT_SCRIPT = "karaf.shell.init.script";
-
-    public static final String PROMPT = "PROMPT";
-
-    public static final String DEFAULT_PROMPT = "\u001B[1m${USER}\u001B[0m@${APPLICATION}> ";
-
-    public static final String PRINT_STACK_TRACES = "karaf.printStackTraces";
-
-    public static final String LAST_EXCEPTION = "karaf.lastException";
-
     public static final String IGNORE_INTERRUPTS = "karaf.ignoreInterrupts";
 
     protected CommandSession session;
 
-    private ConsoleReader reader;
-
     private BlockingQueue<Integer> queue;
 
     private boolean interrupt;
@@ -76,8 +48,6 @@ public class Console implements Runnable
 
     private Runnable closeCallback;
 
-    private Terminal terminal;
-
     private InputStream consoleInput;
 
     private InputStream in;
@@ -88,28 +58,20 @@ public class Console implements Runnable
 
     private Thread thread;
 
-    public Console(CommandProcessor processor, InputStream in, PrintStream out, PrintStream err, Terminal term,
-            Runnable closeCallback) throws Exception {
+    public Console(CommandProcessor processor, InputStream in, PrintStream out, PrintStream err,
+            Runnable closeCallback, Map<String, String> sessionProps) throws Exception {
         this.in = in;
         this.out = out;
         this.err = err;
         this.queue = new ArrayBlockingQueue<Integer>(1024);
-        this.terminal = term == null ? new UnsupportedTerminal() : term;
         this.consoleInput = new ConsoleInputStream();
         this.session = processor.createSession(this.consoleInput, this.out, this.err);
-        this.session.put("SCOPE", "shell:osgi:*");
         this.closeCallback = closeCallback;
 
-        reader = new ConsoleReader(this.consoleInput, new PrintWriter(this.out), getClass().getResourceAsStream(
-            "keybinding.properties"), this.terminal);
-
-        session.put(".jline.history", reader.getHistory());
-        Completer completer = createCompleter();
-        if (completer != null) {
-            reader.addCompleter(completer);
-        }
-        if (Boolean.getBoolean("jline.nobell")) {
-            reader.setBellEnabled(false);
+        if (sessionProps != null) {
+            for (Entry<String, String> entry: sessionProps.entrySet()) {
+                this.session.put(entry.getKey(), entry.getValue());
+            }
         }
         pipe = new Thread(new Pipe());
         pipe.setName("gogo shell pipe thread");
@@ -121,109 +83,30 @@ public class Console implements Runnable
     }
 
     public void close() {
-        // System.err.println("Closing");
-        if (reader.getHistory() instanceof PersistentHistory) {
-            try {
-                ((PersistentHistory) reader.getHistory()).flush();
-            } catch (IOException e) {
-                // ignore
-            }
-        }
         running = false;
-        CommandSessionHolder.unset();
         pipe.interrupt();
     }
 
     public void run() {
-        ThreadLocal<CommandSessionHolder> consoleState = new ThreadLocal<CommandSessionHolder>();
         thread = Thread.currentThread();
-        CommandSessionHolder.setSession(session);
         running = true;
         pipe.start();
-        welcome();
-        setSessionProperties();
-        String scriptFileName = System.getProperty(SHELL_INIT_SCRIPT);
-        if (scriptFileName != null) {
-            Reader r = null;
-            try {
-                File scriptFile = new File(scriptFileName);
-                r = new InputStreamReader(new FileInputStream(scriptFile));
-                CharArrayWriter w = new CharArrayWriter();
-                int n;
-                char[] buf = new char[8192];
-                while ((n = r.read(buf)) > 0) {
-                    w.write(buf, 0, n);
-                }
-                session.execute(new String(w.toCharArray()));
-            } catch (Exception e) {
-                System.err.println("Error in initialization script: " + e.getMessage());
-            } finally {
-                if (r != null) {
-                    try {
-                        r.close();
-                    } catch (IOException e) {
-                        // Ignore
-                    }
-                }
-            }
-        }
-        while (running) {
-            try {
-                String command = null;
-                boolean loop = true;
-                boolean first = true;
-                while (loop) {
-                    checkInterrupt();
-                    String line = reader.readLine(first ? getPrompt() : "> ");
-                    if (line == null) {
-                        break;
-                    }
-                    if (command == null) {
-                        command = line;
-                    } else {
-                        command += " " + line;
-                    }
-                    if (reader.getHistory().size() == 0) {
-                        reader.getHistory().add(command);
-                    } else {
-                        reader.getHistory().replace(command);
-                    }
-                    try {
-                        new Parser(command, 0).program();
-                        loop = false;
-                    } catch (Exception e) {
-                        loop = true;
-                        first = false;
-                    }
-                }
-                if (command == null) {
-                    break;
-                }
-                // session.getConsole().println("Executing: " + line);
-                Object result = session.execute(command);
-                if (result != null) {
-                    session.getConsole().println(session.format(result, Converter.INSPECT));
-                }
-            } catch (InterruptedIOException e) {
-                // System.err.println("^C");
-                // TODO: interrupt current thread
-            } catch (CloseShellException e) {
-                break;
-            } catch (Exception t) {
-                try {
-                    session.put(LAST_EXCEPTION, t);
-                    session.getConsole().print(Ansi.ansi().fg(Ansi.Color.RED).toString());
-                    session.getConsole().println(
-                        "Error executing command: "
-                            + (t.getMessage() != null ? t.getMessage() : t.getClass().getName()));
-                    session.getConsole().print(Ansi.ansi().fg(Ansi.Color.DEFAULT).toString());
-                } catch (Exception ignore) {
-                    // ignore
-                }
-            }
+        try
+        {
+            session.execute("gosh --login --noshutdown");
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace(this.err);
+        }
+        finally
+        {
+            session.close();
+
+            this.out.println("Good Bye!");
         }
         close();
-        // System.err.println("Exiting console...");
+
         if (closeCallback != null) {
             closeCallback.run();
         }
@@ -243,90 +126,6 @@ public class Console implements Runnable
         return Boolean.parseBoolean(s.toString());
     }
 
-    protected void welcome() {
-        Properties props = loadBrandingProperties();
-        String welcome = props.getProperty("welcome");
-        if (welcome != null && welcome.length() > 0) {
-            session.getConsole().println(welcome);
-        }
-    }
-
-    protected void setSessionProperties() {
-        Properties props = loadBrandingProperties();
-        for (Map.Entry<Object, Object> entry : props.entrySet()) {
-            String key = (String) entry.getKey();
-            if (key.startsWith("session.")) {
-                session.put(key.substring("session.".length()), entry.getValue());
-            }
-        }
-    }
-
-    protected Completer createCompleter() {
-        return new CommandsCompleter(session);
-    }
-
-    protected Properties loadBrandingProperties() {
-        Properties props = new Properties();
-        loadProps(props, "org/apache/karaf/shell/console/branding.properties");
-        loadProps(props, "org/apache/karaf/branding/branding.properties");
-        return props;
-    }
-
-    protected void loadProps(Properties props, String resource) {
-        InputStream is = null;
-        try {
-            is = getClass().getClassLoader().getResourceAsStream(resource);
-            if (is != null) {
-                props.load(is);
-            }
-        } catch (IOException e) {
-            // ignore
-        } finally {
-            if (is != null) {
-                try {
-                    is.close();
-                } catch (IOException e) {
-                    // Ignore
-                }
-            }
-        }
-    }
-
-    protected String getPrompt() {
-        try {
-            String prompt;
-            try {
-                Object p = session.get(PROMPT);
-                if (p != null) {
-                    prompt = p.toString();
-                } else {
-                    Properties properties = loadBrandingProperties();
-                    if (properties.getProperty("prompt") != null) {
-                        prompt = properties.getProperty("prompt");
-                        // we put the PROMPT in ConsoleSession to avoid to read
-                        // the properties file each time.
-                        session.put(PROMPT, prompt);
-                    } else {
-                        prompt = DEFAULT_PROMPT;
-                    }
-                }
-            } catch (Throwable t) {
-                prompt = DEFAULT_PROMPT;
-            }
-            Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(prompt);
-            while (matcher.find()) {
-                Object rep = session.get(matcher.group(1));
-                if (rep != null) {
-                    prompt = prompt.replace(matcher.group(0), rep.toString());
-                    matcher.reset(prompt);
-                }
-            }
-            return prompt;
-        } catch (Throwable t) {
-            return "$ ";
-        }
-    }
-
     private void checkInterrupt() throws IOException {
         if (Thread.interrupted() || interrupt) {
             interrupt = false;
@@ -408,14 +207,13 @@ public class Console implements Runnable
             try {
                 while (running) {
                     try {
-                        int c = terminal.readCharacter(in);
+                        int c = in.read();
                         if (c == -1) {
                             return;
                         } else if (c == 4 && !getBoolean(IGNORE_INTERRUPTS)) {
                             err.println("^D");
                         } else if (c == 3 && !getBoolean(IGNORE_INTERRUPTS)) {
                             err.println("^C");
-                            reader.getCursorBuffer().clear();
                             interrupt();
                         }
                         queue.put(c);

Modified: felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/GogoPlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/GogoPlugin.java?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/GogoPlugin.java (original)
+++ felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/GogoPlugin.java Fri Jun  1 14:37:54 2012
@@ -22,22 +22,12 @@
 
 package org.apache.felix.webconsole.plugins.gogo.impl;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.InterruptedIOException;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.util.zip.GZIPOutputStream;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
 import org.apache.felix.webconsole.SimpleWebConsolePlugin;
 import org.osgi.framework.BundleContext;
 
@@ -54,175 +44,71 @@ public class GogoPlugin extends SimpleWe
     public static final String TITLE = "Gogo";
 
     public static final int TERM_WIDTH = 120;
+
     public static final int TERM_HEIGHT = 39;
 
-    private CommandProcessor commandProcessor;
+    private final SessionTerminalManager terminalManager;
 
-    public GogoPlugin() {
+    public GogoPlugin(final SessionTerminalManager terminalManager) {
         super(LABEL, TITLE, null);
+        this.terminalManager = terminalManager;
     }
 
     @Override
     public void activate(BundleContext bundleContext) {
         super.activate(bundleContext);
-        this.commandProcessor = new CommandProcessor() {
-            public CommandSession createSession(InputStream in, PrintStream out, PrintStream err) {
-                return ((CommandProcessor) getService(CommandProcessor.class.getName())).createSession(in, out, err);
-            }
-        };
     }
 
     @Override
     public void deactivate() {
-        this.commandProcessor = null;
         super.deactivate();
     }
 
-    protected void renderContent( HttpServletRequest request, HttpServletResponse response ) throws IOException
-    {
+    protected void renderContent(HttpServletRequest request, HttpServletResponse response) throws IOException {
         PrintWriter pw = response.getWriter();
 
         String appRoot = request.getContextPath() + request.getServletPath();
-        pw.println( "<link href=\"" + appRoot + "/gogo/res/ui/gogo.css\" rel=\"stylesheet\" type=\"text/css\" />" );
-        pw.println( "<script src=\"" + appRoot + "/gogo/res/ui/gogo.js\" type=\"text/javascript\"></script>" );
-        pw.println( "<div id='console'><div id='term'></div></div>" );
-        pw.println( "<script type=\"text/javascript\"><!--" );
-        pw.println( "window.onload = function() { gogo.Terminal(document.getElementById(\"term\"), " + TERM_WIDTH + ", " + TERM_HEIGHT + "); }" );
-        pw.println( "--></script>" );
+        pw.println("<link href=\"" + appRoot + "/gogo/res/ui/gogo.css\" rel=\"stylesheet\" type=\"text/css\" />");
+        pw.println("<script src=\"" + appRoot + "/gogo/res/ui/gogo.js\" type=\"text/javascript\"></script>");
+        pw.println("<p id=\"statline\" class=\"statline\">&nbsp;</p>");
+        pw.println("<div id='console'><div id='term'></div></div>");
+        pw.println("<script type=\"text/javascript\"><!--");
+        pw.println("window.onload = function() { gogo.Terminal(document.getElementById(\"term\"), " + TERM_WIDTH + ", "
+            + TERM_HEIGHT + "); }");
+        pw.println("--></script>");
     }
 
     @Override
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
         String encoding = request.getHeader("Accept-Encoding");
         boolean supportsGzip = (encoding != null && encoding.toLowerCase().indexOf("gzip") > -1);
-        SessionTerminal st = getSessionTerminal(request);
-        String str = request.getParameter("k");
-        String f = request.getParameter("f");
-        String dump = st.handle(str, f != null && f.length() > 0);
-        if (dump != null) {
-            if (supportsGzip) {
-                response.setHeader("Content-Encoding", "gzip");
-                response.setHeader("Content-Type", "text/html");
-                try {
-                    GZIPOutputStream gzos =  new GZIPOutputStream(response.getOutputStream());
-                    gzos.write(dump.getBytes());
-                    gzos.close();
-                } catch (IOException ie) {
-                    // handle the error here
-                    ie.printStackTrace();
-                }
-            } else {
-                response.getOutputStream().write(dump.getBytes());
-            }
-        }
-    }
-
-    private SessionTerminal getSessionTerminal(final HttpServletRequest request) throws IOException{
-        final Object terminal = request.getSession(true).getAttribute("terminal");
-        if (terminal instanceof SessionTerminal) {
-            final SessionTerminal st = (SessionTerminal) terminal;
-            if (!st.isClosed()) {
-                return st;
-            }
-        }
-
-        final SessionTerminal st = new SessionTerminal(request.getRemoteUser());
-        request.getSession().setAttribute("terminal", st);
-        return st;
-    }
-
-    public class SessionTerminal implements Runnable {
-
-        private Terminal terminal;
-        private Console console;
-        private PipedOutputStream in;
-        private PipedInputStream out;
-        private boolean closed;
-
-        public SessionTerminal(final String user) throws IOException {
-            try {
-                this.terminal = new Terminal(TERM_WIDTH, TERM_HEIGHT);
-                terminal.write("\u001b\u005B20\u0068"); // set newline mode on
-
-                in = new PipedOutputStream();
-                out = new PipedInputStream();
-                PrintStream pipedOut = new PrintStream(new PipedOutputStream(out), true);
-
-                console = new Console(commandProcessor,
-                                      new PipedInputStream(in),
-                                      pipedOut,
-                                      pipedOut,
-                                      new WebTerminal(TERM_WIDTH, TERM_HEIGHT),
-                                      null);
-                CommandSession session = console.getSession();
-                session.put("APPLICATION", System.getProperty("karaf.name", "root"));
-                session.put("USER", user);
-                session.put("COLUMNS", Integer.toString(TERM_WIDTH));
-                session.put("LINES", Integer.toString(TERM_HEIGHT));
-            } catch (IOException e) {
-                e.printStackTrace();
-                throw e;
-            } catch (Exception e) {
-                e.printStackTrace();
-                throw (IOException) new IOException().initCause(e);
-            }
-            new Thread(console).start();
-            new Thread(this).start();
-        }
-
-        public boolean isClosed() {
-            return closed;
-        }
-
-        public String handle(String str, boolean forceDump) throws IOException {
-            try {
-                if (str != null && str.length() > 0) {
-                    String d = terminal.pipe(str);
-                    for (byte b : d.getBytes()) {
-                        in.write(b);
-                    }
-                    in.flush();
-                }
-            } catch (IOException e) {
-                closed = true;
-                throw e;
-            }
-            try {
-                return terminal.dump(10, forceDump);
-            } catch (InterruptedException e) {
-                throw new InterruptedIOException(e.toString());
-            }
-        }
-
-        public void run() {
-            try {
-                for (;;) {
-                    byte[] buf = new byte[8192];
-                    int l = out.read(buf);
-                    InputStreamReader r = new InputStreamReader(new ByteArrayInputStream(buf, 0, l));
-                    StringBuilder sb = new StringBuilder();
-                    for (;;) {
-                        int c = r.read();
-                        if (c == -1) {
-                            break;
-                        }
-                        sb.append((char) c);
-                    }
-                    if (sb.length() > 0) {
-                        terminal.write(sb.toString());
-                    }
-                    String s = terminal.read();
-                    if (s != null && s.length() > 0) {
-                        for (byte b : s.getBytes()) {
-                            in.write(b);
-                        }
+        SessionTerminal st = terminalManager.getSessionTerminal(request);
+        if (st != null) {
+            String str = request.getParameter("k");
+            String f = request.getParameter("f");
+            String dump = st.handle(str, f != null && f.length() > 0);
+            if (dump != null) {
+                if (supportsGzip) {
+                    response.setHeader("Content-Encoding", "gzip");
+                    response.setHeader("Content-Type", "text/html; charset=UTF-8");
+                    try {
+                        GZIPOutputStream gzos = new GZIPOutputStream(response.getOutputStream());
+                        gzos.write(dump.getBytes("UTF-8"));
+                        gzos.close();
+                    } catch (IOException ie) {
+                        // handle the error here
+                        ie.printStackTrace();
                     }
+                } else {
+                    response.setContentType("text/html; charset=UTF-8");
+                    response.getOutputStream().write(dump.getBytes("UTF-8"));
                 }
-            } catch (IOException e) {
-                closed = true;
-                e.printStackTrace();
             }
+        } else {
+            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
         }
 
+        response.flushBuffer();
     }
+
 }

Added: felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminal.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminal.java?rev=1345205&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminal.java (added)
+++ felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminal.java Fri Jun  1 14:37:54 2012
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.webconsole.plugins.gogo.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.io.PrintStream;
+import java.util.HashMap;
+
+import org.apache.felix.service.command.CommandProcessor;
+
+public class SessionTerminal implements Runnable {
+
+    private Terminal terminal;
+    private Console console;
+    private PipedOutputStream in;
+    private PipedInputStream out;
+    private boolean closed;
+
+    @SuppressWarnings("serial")
+    public SessionTerminal(final CommandProcessor commandProcessor, final String user) throws IOException {
+        try {
+            this.terminal = new Terminal(GogoPlugin.TERM_WIDTH, GogoPlugin.TERM_HEIGHT);
+            terminal.write("\u001b\u005B20\u0068"); // set newline mode on
+
+            in = new PipedOutputStream();
+            out = new PipedInputStream();
+            PrintStream pipedOut = new PrintStream(new PipedOutputStream(out), true);
+
+            console = new Console(commandProcessor, new PipedInputStream(in), pipedOut, pipedOut, new Runnable() {
+                public void run() {
+                    SessionTerminal.this.terminal.write("done...");
+                    close();
+                }
+            }, new HashMap<String, String>() {
+                {
+                    put("USER", user);
+                    put("COLUMNS", Integer.toString(GogoPlugin.TERM_WIDTH));
+                    put("LINES", Integer.toString(GogoPlugin.TERM_HEIGHT));
+                }
+            });
+        } catch (IOException e) {
+            throw e;
+        } catch (Exception e) {
+            throw (IOException) new IOException().initCause(e);
+        }
+        new Thread(console).start();
+        new Thread(this).start();
+    }
+
+    public boolean isClosed() {
+        return closed;
+    }
+
+    public void close() {
+        if (!closed) {
+            this.closed = true;
+
+            this.console.close();
+
+            try {
+                this.in.close();
+            } catch (IOException e) {
+            }
+            try {
+                this.out.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
+    public String handle(String str, boolean forceDump) throws IOException {
+        try {
+            if (str != null && str.length() > 0) {
+                String d = terminal.pipe(str);
+                // echo unless backspace
+                if (d.charAt(0) != '\b') {
+                    terminal.write(d);
+                }
+                in.write(d.getBytes());
+                in.flush();
+            }
+        } catch (IOException e) {
+            // ignore
+        }
+        try {
+            return terminal.dump(10, forceDump);
+        } catch (InterruptedException e) {
+            throw new InterruptedIOException(e.toString());
+        }
+    }
+
+    public void run() {
+        try {
+            for (;;) {
+                byte[] buf = new byte[8192];
+                int l = out.read(buf);
+                InputStreamReader r = new InputStreamReader(new ByteArrayInputStream(buf, 0, l));
+                StringBuilder sb = new StringBuilder();
+                for (;;) {
+                    int c = r.read();
+                    if (c == -1) {
+                        break;
+                    }
+                    sb.append((char) c);
+                }
+                if (sb.length() > 0) {
+                    terminal.write(sb.toString());
+                }
+                String s = terminal.read();
+                if (s != null && s.length() > 0) {
+                    for (byte b : s.getBytes()) {
+                        in.write(b);
+                    }
+                }
+            }
+        } catch (IOException e) {
+            closed = true;
+            e.printStackTrace();
+        }
+    }
+
+}
\ No newline at end of file

Added: felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminalManager.java
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminalManager.java?rev=1345205&view=auto
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminalManager.java (added)
+++ felix/trunk/webconsole-plugins/gogo/src/main/java/org/apache/felix/webconsole/plugins/gogo/impl/SessionTerminalManager.java Fri Jun  1 14:37:54 2012
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.webconsole.plugins.gogo.impl;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * The <code>SessionTerminalManager</code> manages {@link SessionTerminal}
+ * instances on behalf of the {@link GogoPlugin}. The instances are stored in
+ * HttpSessions and cleared when (a) the owning session is destroyed and (b)
+ * when this manager is {@link #shutdown() shut down}.
+ */
+public class SessionTerminalManager implements HttpSessionListener {
+
+    private final ServiceRegistration service;
+
+    private final ServiceTracker commandProcessor;
+
+    private final Set<SessionTerminal> sessions = new HashSet<SessionTerminal>();
+
+    @SuppressWarnings("serial")
+    public SessionTerminalManager(final BundleContext context) {
+        this.commandProcessor = new ServiceTracker(context, CommandProcessor.class.getName(), null) {
+            @Override
+            public void removedService(ServiceReference reference, Object service) {
+                cleanupSessions();
+                super.removedService(reference, service);
+            }
+        };
+        this.commandProcessor.open();
+
+        Hashtable<String, Object> props = new Hashtable<String, Object>();
+        props.put(Constants.SERVICE_DESCRIPTION, "Gogo Shell Terminal Session Reaper");
+        service = context.registerService(HttpSessionListener.class.getName(), this, props);
+    }
+
+    void shutdown() {
+        this.service.unregister();
+        this.commandProcessor.close();
+        this.cleanupSessions();
+    }
+
+    SessionTerminal getSessionTerminal(final HttpServletRequest request) throws IOException {
+        final HttpSession session = request.getSession(true);
+        final Object terminal = session.getAttribute("terminal");
+        if (terminal instanceof SessionTerminal) {
+            final SessionTerminal st = (SessionTerminal) terminal;
+            if (!st.isClosed()) {
+                return st;
+            }
+        }
+
+        final CommandProcessor cp = (CommandProcessor) this.commandProcessor.getService();
+        if (cp != null) {
+            final SessionTerminal st = new SessionTerminal(cp, request.getRemoteUser());
+            this.sessions.add(st);
+            session.setAttribute("terminal", st);
+            return st;
+        }
+
+        // no session because there is no command processor !
+        return null;
+    }
+
+    public void sessionCreated(HttpSessionEvent event) {
+        // don't care
+    }
+
+    public void sessionDestroyed(HttpSessionEvent event) {
+        final Object terminal = event.getSession().getAttribute("terminal");
+        if (terminal instanceof SessionTerminal) {
+            sessions.remove(terminal);
+            ((SessionTerminal) terminal).close();
+        }
+    }
+
+    void cleanupSessions() {
+        for (SessionTerminal session : sessions) {
+            session.close();
+        }
+        this.sessions.clear();
+    }
+}

Modified: felix/trunk/webconsole-plugins/gogo/src/main/resources/res/ui/gogo.js
URL: http://svn.apache.org/viewvc/felix/trunk/webconsole-plugins/gogo/src/main/resources/res/ui/gogo.js?rev=1345205&r1=1345204&r2=1345205&view=diff
==============================================================================
--- felix/trunk/webconsole-plugins/gogo/src/main/resources/res/ui/gogo.js (original)
+++ felix/trunk/webconsole-plugins/gogo/src/main/resources/res/ui/gogo.js Fri Jun  1 14:37:54 2012
@@ -36,7 +36,7 @@ gogo.Terminal_ctor = function(div, width
 
    var dstat = document.createElement('pre');
    var sled = document.createElement('span');
-   var sdebug = document.createElement('span');
+   var sdebug = document.getElementById('statline');
    var dterm = document.createElement('div');
 
    function debug(s) {
@@ -45,11 +45,11 @@ gogo.Terminal_ctor = function(div, width
 
    function error() {
        sled.className = 'off';
-       debug("Connection lost timeout ts:" + ((new Date).getTime()));
+       debug("Gogo Shell Processor not available");
    }
 
    function update() {
-       if (sending == 0) {
+       if (sending == 0 /* && keybuf.length > 0 */ ) {
            sending = 1;
            sled.className = 'on';
            var r = new XMLHttpRequest();
@@ -79,8 +79,10 @@ gogo.Terminal_ctor = function(div, width
                        sending=0;
                        sled.className = 'off';
                        timeout = window.setTimeout(update, rmax);
+                   } else if (r.status == 500) {
+                       debug("Gogo Shell Processor not available")
                    } else {
-                       debug("Connection error status:" + r.status);
+                       debug("General failure with Gogo Shell: " + r.status);
                    }
                }
            }
@@ -183,11 +185,13 @@ gogo.Terminal_ctor = function(div, width
             default:    k = String.fromCharCode(kc); break;
         }
 
+        var s = encodeURIComponent(k);
+        
 //        debug("fromkeydown=" + fromkeydown + ", ev.keyCode=" + ev.keyCode + ", " +
 //              "ev.which=" + ev.which + ", ev.ctrlKey=" + ev.ctrlKey + ", " +
-//              "kc=" + kc + ", k=" + k);
+//              "kc=" + kc + ", k=" + k + ", s=" + s);
 
-        queue(encodeURIComponent(k));
+        queue(s);
 
         ev.cancelBubble = true;
         if (ev.stopPropagation) ev.stopPropagation();
@@ -203,8 +207,22 @@ gogo.Terminal_ctor = function(div, width
                  113:1, 114:1, 115:1, 116:1, 117:1, 118:1, 119:1, 120:1, 121:1, 122:1, 123:1 };
            if (o[ev.keyCode] || ev.ctrlKey || ev.altKey) {
                keypress(ev, true);
+           } else {
+               ev.cancelBubble = true;
+               if (ev.stopPropagation) ev.stopPropagation();
+               if (ev.preventDefault) ev.preventDefault();
            }
    }
+   
+   function ignoreKey(ev) {
+       if (!ev) {
+           ev = window.event;
+       }
+       
+       ev.cancelBubble = true;
+       if (ev.stopPropagation) ev.stopPropagation();
+       if (ev.preventDefault) ev.preventDefault();
+   }
 
    function init() {
        if (typeof(XMLHttpRequest) == "undefined") {
@@ -220,18 +238,22 @@ gogo.Terminal_ctor = function(div, width
            throw new Error("This browser does not support XMLHttpRequest.");
          };
        }
+       
        sled.appendChild(document.createTextNode('\xb7'));
        sled.className = 'off';
        dstat.appendChild(sled);
        dstat.appendChild(document.createTextNode(' '));
-       dstat.appendChild(sdebug);
+//       dstat.appendChild(sdebug);
        dstat.className = 'stat';
+       
        div.appendChild(dstat);
        var d = document.createElement('div');
        d.appendChild(dterm);
        div.appendChild(d);
+       
        document.onkeypress = keypress;
-       document.onkeydown = keydown;
+       document.onkeydown = ignoreKey;
+       document.onkeyup = ignoreKey;
        timeout = window.setTimeout(update, 100);
    }