You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2015/01/28 14:08:09 UTC

[1/2] karaf git commit: [KARAF-3455] Support for custom command parsers

Repository: karaf
Updated Branches:
  refs/heads/master cb7518351 -> cbbed8ac4


http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
index 16e73ca..f0652f8 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
@@ -32,6 +32,7 @@ import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
 import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
 import org.apache.karaf.shell.support.ShellUtil;
 
 public class HeadlessSessionImpl implements Session {
@@ -68,7 +69,8 @@ public class HeadlessSessionImpl implements Session {
 
     @Override
     public Object execute(CharSequence commandline) throws Exception {
-        return session.execute(commandline);
+        String command = CommandLineParser.parse(this, commandline.toString());
+        return session.execute(command);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
index ad2c729..1f52fbe 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.support.CommandException;
 
@@ -45,6 +46,11 @@ public abstract class TopLevelCommand implements Command {
     }
 
     @Override
+    public Parser getParser() {
+        return null;
+    }
+
+    @Override
     public Object execute(Session session, List<Object> arguments) throws Exception {
         if (arguments.contains("--help")) {
             printHelp(System.out);

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
index 3b9ae33..945a429 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
@@ -29,6 +29,7 @@ import org.apache.felix.utils.properties.InterpolationHelper;
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.CommandLine;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
@@ -129,6 +130,11 @@ public class HelpCommand implements Command {
         };
     }
 
+    @Override
+    public Parser getParser() {
+        return null;
+    }
+
     protected void printHelp(PrintStream out) {
         out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
         out.print("        ");

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
index 0fc6cde..822c712 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
@@ -25,6 +25,7 @@ import org.apache.felix.service.command.CommandSession;
 import org.apache.felix.service.command.Function;
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Session;
 
 public class SecuredCommand implements Command, Function {
@@ -56,6 +57,11 @@ public class SecuredCommand implements Command, Function {
     }
 
     @Override
+    public Parser getParser() {
+        return null;
+    }
+
+    @Override
     public Object execute(Session session, List<Object> arguments) throws Exception {
         factory.checkSecurity(this, session, arguments);
         return command.execute(session, arguments);

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
deleted file mode 100644
index 9124795..0000000
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.karaf.shell.impl.console.parsing;
-
-import java.util.List;
-
-import org.apache.karaf.shell.api.console.CommandLine;
-
-/**
- *  The result of a delimited buffer.
- */
-public class CommandLineImpl implements CommandLine {
-
-    private final String[] arguments;
-    private final int cursorArgumentIndex;
-    private final int argumentPosition;
-    private final int bufferPosition;
-    private final String buffer;
-
-    public static CommandLine build(String buffer, int cursor) {
-        return build(buffer, cursor, true);
-    }
-    
-	public static CommandLine build(String buffer, int cursor, boolean expansionEnabled) { //CQL-Handling
-		Parser parser = new Parser(buffer, cursor, expansionEnabled);
-        try {
-            List<List<List<String>>> program = parser.program();
-            List<String> pipe = program.get(parser.c0).get(parser.c1);
-            return new CommandLineImpl(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor, buffer);
-        } catch (Throwable t) {
-            return new CommandLineImpl(new String[] { buffer }, 0, cursor, cursor, buffer);
-        }
-	}
-
-    /**
-     *  @param  arguments           the array of tokens
-     *  @param  cursorArgumentIndex the token index of the cursor
-     *  @param  argumentPosition    the position of the cursor in the
-     *                              current token
-     *  @param  bufferPosition      the position of the cursor in the whole buffer
-     *  @param buffer               the whole buffer
-     */
-    public CommandLineImpl(String[] arguments, int cursorArgumentIndex, int argumentPosition, int bufferPosition, String buffer) {
-        this.arguments = arguments;
-        this.cursorArgumentIndex = cursorArgumentIndex;
-        this.argumentPosition = argumentPosition;
-        this.bufferPosition = bufferPosition;
-        this.buffer = buffer;
-    }
-
-    public int getCursorArgumentIndex() {
-        return this.cursorArgumentIndex;
-    }
-
-    public String getCursorArgument() {
-        if ((cursorArgumentIndex < 0)
-            || (cursorArgumentIndex >= arguments.length)) {
-            return null;
-        }
-
-        return arguments[cursorArgumentIndex];
-    }
-
-    public int getArgumentPosition() {
-        return this.argumentPosition;
-    }
-
-    public String[] getArguments() {
-        return this.arguments;
-    }
-
-    public int getBufferPosition() {
-        return this.bufferPosition;
-    }
-
-    public String getBuffer() {
-        return this.buffer;
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
new file mode 100644
index 0000000..b5f28fb
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineParser.java
@@ -0,0 +1,113 @@
+/*
+ * 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.karaf.shell.impl.console.parsing;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
+import org.apache.karaf.shell.support.parsing.GogoParser;
+
+public class CommandLineParser {
+
+    public static CommandLine buildCommandLine(Session session, String command, int cursor) {
+        int pos = 0;
+        while (true) {
+            String rem = command.substring(pos);
+            GogoParser cmdNameParser = new GogoParser(rem, rem.length());
+            String name = cmdNameParser.value();
+            name = session.resolveCommand(name);
+
+            Parser cmdParser = null;
+            for (Command cmd : session.getRegistry().getCommands()) {
+                if (name.equals(cmd.getScope() + ":" + cmd.getName())) {
+                    cmdParser = cmd.getParser();
+                    break;
+                }
+            }
+            if (cmdParser == null) {
+                cmdParser = new DefaultParser();
+            }
+
+            CommandLine cmdLine = cmdParser.parse(session, rem, cursor - pos);
+            int length = cmdLine.getBuffer().length();
+            if (length < rem.length()) {
+                char ch = rem.charAt(length);
+                if (ch == ';' || ch == '|') {
+                    length++;
+                } else {
+                    throw new IllegalArgumentException("Unrecognized character: '" + ch + "'");
+                }
+            }
+            pos += length;
+            if (cursor <= pos) {
+                return cmdLine;
+            }
+        }
+    }
+
+    public static String parse(Session session, String command) {
+        StringBuilder parsed = new StringBuilder();
+        int pos = 0;
+        while (pos < command.length()) {
+            String rem = command.substring(pos);
+            GogoParser cmdNameParser = new GogoParser(rem, rem.length());
+            String name = cmdNameParser.value();
+            name = session.resolveCommand(name);
+
+            Parser cmdParser = null;
+            for (Command cmd : session.getRegistry().getCommands()) {
+                if (name.equals(cmd.getScope() + ":" + cmd.getName())) {
+                    cmdParser = cmd.getParser();
+                    break;
+                }
+            }
+            if (cmdParser == null) {
+                cmdParser = new DefaultParser();
+            }
+
+            CommandLine cmdLine = cmdParser.parse(session, rem, rem.length());
+            for (int i = 0 ; i < cmdLine.getArguments().length; i++) {
+                String arg = cmdLine.getArguments()[i];
+                if (i > 0) {
+                    parsed.append(" ");
+                }
+                parsed.append(arg);
+            }
+
+            int length = cmdLine.getBuffer().length();
+            if (length < rem.length()) {
+                char ch = rem.charAt(length);
+                if (ch == ';' || ch == '|') {
+                    parsed.append(" ");
+                    parsed.append(ch);
+                    parsed.append(" ");
+                    length++;
+                } else {
+                    throw new IllegalArgumentException("Unrecognized character: '" + ch + "'");
+                }
+            }
+            pos += length;
+        }
+
+        return parsed.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
deleted file mode 100644
index 73f4b98..0000000
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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.
- */
-// DWB14: parser loops if // comment at start of program
-// DWB15: allow program to have trailing ';'
-package org.apache.karaf.shell.impl.console.parsing;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class Parser {
-
-    int current = 0;
-    String text;
-    boolean escaped;
-    static final String SPECIAL = "<;|{[\"'$`(=";
-
-    List<List<List<String>>> program;
-    List<List<String>> statements;
-    List<String> statement;
-    int cursor;
-    int start = -1;
-    int c0;
-    int c1;
-    int c2;
-    int c3;
-    
-    private boolean isExpansionEnabled; //CQL-Handling
-
-    public Parser(String text, int cursor) {
-        this(text, cursor, true);
-    }
-
-    //CQL-Handling
-    public Parser(String text, int cursor, boolean expansionEnabled) {
-    	this.text = text;
-        this.cursor = cursor;
-        this.isExpansionEnabled = expansionEnabled; //CQL-Handling
-	}
-
-	void ws() {
-        // derek: BUGFIX: loop if comment  at beginning of input
-        //while (!eof() && Character.isWhitespace(peek())) {
-        while (!eof() && (!escaped && Character.isWhitespace(peek()) || current == 0)) {
-            if (current != 0 || !escaped && Character.isWhitespace(peek())) {
-                current++;
-            }
-            if (peek() == '/' && current < text.length() - 2
-                && text.charAt(current + 1) == '/') {
-                comment();
-            }
-            if (current == 0) {
-                break;
-            }
-        }
-    }
-
-    private void comment() {
-        while (!eof() && peek() != '\n' && peek() != '\r') {
-            next();
-        }
-    }
-
-    boolean eof() {
-        return current >= text.length();
-    }
-
-    char peek() {
-        return peek(false);
-    }
-
-    char peek(boolean increment) {
-        escaped = false;
-        if (eof()) {
-            return 0;
-        }
-
-        int last = current;
-        char c = text.charAt(current++);
-
-        if (c == '\\') {
-            escaped = true;
-            if (eof()) {
-                throw new RuntimeException("Eof found after \\");
-            }
-
-            c = text.charAt(current++);
-
-            switch (c) {
-                case 't':
-                    c = '\t';
-                    break;
-                case '\r':
-                case '\n':
-                    c = ' ';
-                    break;
-                case 'b':
-                    c = '\b';
-                    break;
-                case 'f':
-                    c = '\f';
-                    break;
-                case 'n':
-                    c = '\n';
-                    break;
-                case 'r':
-                    c = '\r';
-                    break;
-                case 'u':
-                    c = unicode();
-                    current += 4;
-                    break;
-                default:
-                    // We just take the next character literally
-                    // but have the escaped flag set, important for {},[] etc
-            }
-        }
-        if (cursor > last && cursor <= current) {
-            c0 = program != null ? program.size() : 0;
-            c1 = statements != null ? statements.size() : 0;
-            c2 = statement != null ? statement.size() : 0;
-            c3 = (start >= 0) ? current - start : 0;
-        }
-        if (!increment) {
-            current = last;
-        }
-        return c;
-    }
-
-    public List<List<List<String>>> program() {
-        program = new ArrayList<List<List<String>>>();
-        ws();
-        if (!eof()) {
-            program.add(pipeline());
-            while (peek() == ';') {
-                current++;
-                List<List<String>> pipeline = pipeline();
-                program.add(pipeline);
-            }
-        }
-        if (!eof()) {
-            throw new RuntimeException("Program has trailing text: " + context(current));
-        }
-
-        List<List<List<String>>> p = program;
-        program = null;
-        return p;
-    }
-
-    CharSequence context(int around) {
-        return text.subSequence(Math.max(0, current - 20), Math.min(text.length(),
-            current + 4));
-    }
-
-    public List<List<String>> pipeline() {
-        statements = new ArrayList<List<String>>();
-        statements.add(statement());
-        while (peek() == '|') {
-            current++;
-            ws();
-            if (!eof()) {
-                statements.add(statement());
-            }
-            else {
-                statements.add(new ArrayList<String>());
-                break;
-            }
-        }
-        List<List<String>> s = statements;
-        statements = null;
-        return s;
-    }
-
-    public List<String> statement() {
-        statement = new ArrayList<String>();
-        statement.add(value());
-        while (!eof()) {
-            ws();
-            if (peek() == '|' || peek() == ';') {
-                break;
-            }
-
-            if (!eof()) {
-                statement.add(messy());
-            }
-        }
-        List<String> s = statement;
-        statement = null;
-        return s;
-    }
-
-    public String messy()
-    {
-        start = current;
-        char c = peek();
-        if (c > 0 && SPECIAL.indexOf(c) < 0) {
-            current++;
-            try {
-                while (!eof()) {
-                    c = peek();
-                    if (!escaped && (c == ';' || c == '|' || Character.isWhitespace(c))) {
-                        break;
-                    }
-                    next();
-                }
-                return text.substring(start, current);
-            } finally {
-                start = -1;
-            }
-        }
-        else {
-            return value();
-        }
-    }
-
-    String value() {
-        ws();
-
-        start = current;
-        try {
-            char c = next();
-            if (!escaped && isExpansionEnabled) { //CQL-Handling
-                switch (c) {
-                    case '{':
-                        return text.substring(start, find('}', '{'));
-                    case '(':
-                        return text.substring(start, find(')', '('));
-                    case '[':
-                        return text.substring(start, find(']', '['));
-                    case '<':
-                        return text.substring(start, find('>', '<'));
-                    case '=':
-                        return text.substring(start, current);
-                    case '"':
-                    case '\'':
-                        quote(c);
-                        break;
-                }
-            }
-
-            // Some identifier or number
-            while (!eof()) {
-                c = peek();
-                if (!escaped) {
-                    if (Character.isWhitespace(c) || c == ';' || c == '|' || c == '=') {
-                        break;
-                    }
-                    else if (c == '{' && isExpansionEnabled) { //CQL-Handling
-                        next();
-                        find('}', '{');
-                    }
-                    else if (c == '(' && isExpansionEnabled) { //CQL-Handling
-                        next();
-                        find(')', '(');
-                    }
-                    else if (c == '<') {
-                        next();
-                        find('>', '<');
-                    }
-                    else if (c == '[') {
-                        next();
-                        find(']', '[');
-                    }
-                    else if (c == '\'' || c == '"') {
-                        next();
-                        quote(c);
-                        next();
-                    }
-                    else {
-                        next();
-                    }
-                }
-                else {
-                    next();
-                }
-            }
-            return text.substring(start, current);
-        } finally {
-            start = -1;
-        }
-    }
-
-    boolean escaped() {
-        return escaped;
-    }
-
-    char next() {
-        return peek(true);
-    }
-
-    char unicode() {
-        if (current + 4 > text.length()) {
-            throw new IllegalArgumentException("Unicode \\u escape at eof at pos ..."
-                + context(current) + "...");
-        }
-
-        String s = text.subSequence(current, current + 4).toString();
-        int n = Integer.parseInt(s, 16);
-        return (char) n;
-    }
-
-    int find(char target, char deeper) {
-        int start = current;
-        int level = 1;
-
-        while (level != 0) {
-            if (eof()) {
-                throw new RuntimeException("Eof found in the middle of a compound for '"
-                    + target + deeper + "', begins at " + context(start));
-            }
-
-            char c = next();
-            if (!escaped) {
-                if (c == target) {
-                    level--;
-                } else {
-                    if (c == deeper) {
-                        level++;
-                    } else {
-                        if (c == '"') {
-                            quote('"');
-                        } else {
-                            if (c == '\'') {
-                                quote('\'');
-                            }
-                            else {
-                                if (c == '`') {
-                                    quote('`');
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return current;
-    }
-
-    int quote(char which) {
-        while (!eof() && (peek() != which || escaped)) {
-            next();
-        }
-
-        return current++;
-    }
-
-    CharSequence findVar() {
-        int start = current;
-        char c = peek();
-
-        if (c == '{') {
-            next();
-            int end = find('}', '{');
-            return text.subSequence(start, end);
-        }
-        if (c == '(') {
-            next();
-            int end = find(')', '(');
-            return text.subSequence(start, end);
-        }
-
-        if (Character.isJavaIdentifierPart(c)) {
-            while (c == '$') {
-                c = next();
-            }
-            while (!eof() && (Character.isJavaIdentifierPart(c) || c == '.') && c != '$') {
-                next();
-                c = peek();
-            }
-            return text.subSequence(start, current);
-        }
-        throw new IllegalArgumentException(
-            "Reference to variable does not match syntax of a variable: "
-                + context(start));
-    }
-
-    public String toString() {
-        return "..." + context(current) + "...";
-    }
-
-    public String unescape() {
-        StringBuilder sb = new StringBuilder();
-        while (!eof()) {
-            sb.append(next());
-        }
-        return sb.toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
new file mode 100644
index 0000000..0589a29
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/CommandLineImpl.java
@@ -0,0 +1,80 @@
+/*
+ * 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.karaf.shell.support.parsing;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+
+/**
+ *  The result of a delimited buffer.
+ */
+public class CommandLineImpl implements CommandLine {
+
+    private final String[] arguments;
+    private final int cursorArgumentIndex;
+    private final int argumentPosition;
+    private final int bufferPosition;
+    private final String buffer;
+
+    /**
+     *  @param  arguments           the array of tokens
+     *  @param  cursorArgumentIndex the token index of the cursor
+     *  @param  argumentPosition    the position of the cursor in the
+     *                              current token
+     *  @param  bufferPosition      the position of the cursor in the whole buffer
+     *  @param buffer               the whole buffer
+     */
+    public CommandLineImpl(String[] arguments, int cursorArgumentIndex, int argumentPosition, int bufferPosition, String buffer) {
+        this.arguments = arguments;
+        this.cursorArgumentIndex = cursorArgumentIndex;
+        this.argumentPosition = argumentPosition;
+        this.bufferPosition = bufferPosition;
+        this.buffer = buffer;
+    }
+
+    public int getCursorArgumentIndex() {
+        return this.cursorArgumentIndex;
+    }
+
+    public String getCursorArgument() {
+        if ((cursorArgumentIndex < 0)
+            || (cursorArgumentIndex >= arguments.length)) {
+            return null;
+        }
+
+        return arguments[cursorArgumentIndex];
+    }
+
+    public int getArgumentPosition() {
+        return this.argumentPosition;
+    }
+
+    public String[] getArguments() {
+        return this.arguments;
+    }
+
+    public int getBufferPosition() {
+        return this.bufferPosition;
+    }
+
+    public String getBuffer() {
+        return this.buffer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
new file mode 100644
index 0000000..7b01042
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/DefaultParser.java
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+// DWB14: parser loops if // comment at start of program
+// DWB15: allow program to have trailing ';'
+package org.apache.karaf.shell.support.parsing;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+
+public class DefaultParser implements Parser {
+
+    @Override
+    public CommandLine parse(Session session, String command, int cursor) {
+        GogoParser parser = new GogoParser(command, cursor);
+        List<String> args = parser.statement();
+        return new CommandLineImpl(
+                        args.toArray(new String[args.size()]),
+                        parser.cursorArgumentIndex(),
+                        parser.argumentPosition(),
+                        cursor,
+                        command.substring(0, parser.position()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
new file mode 100644
index 0000000..73a1584
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/parsing/GogoParser.java
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ */
+// DWB14: parser loops if // comment at start of program
+// DWB15: allow program to have trailing ';'
+package org.apache.karaf.shell.support.parsing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GogoParser {
+
+    int current = 0;
+    String text;
+    boolean escaped;
+    static final String SPECIAL = "<;|{[\"'$`(=";
+
+    List<List<List<String>>> program;
+    List<List<String>> statements;
+    List<String> statement;
+    int cursor;
+    int start = -1;
+    int c0;
+    int c1;
+    int c2;
+    int c3;
+    
+    public GogoParser(String text, int cursor) {
+    	this.text = text;
+        this.cursor = cursor;
+	}
+
+	public void ws() {
+        // derek: BUGFIX: loop if comment  at beginning of input
+        //while (!eof() && Character.isWhitespace(peek())) {
+        while (!eof() && (!escaped && Character.isWhitespace(peek()) || current == 0)) {
+            if (current != 0 || !escaped && Character.isWhitespace(peek())) {
+                current++;
+            }
+            if (peek() == '/' && current < text.length() - 2
+                && text.charAt(current + 1) == '/') {
+                comment();
+            }
+            if (current == 0) {
+                break;
+            }
+        }
+    }
+
+    private void comment() {
+        while (!eof() && peek() != '\n' && peek() != '\r') {
+            next();
+        }
+    }
+
+    public boolean eof() {
+        return current >= text.length();
+    }
+
+    public char peek() {
+        return peek(false);
+    }
+
+    char peek(boolean increment) {
+        escaped = false;
+        if (eof()) {
+            return 0;
+        }
+
+        int last = current;
+        char c = text.charAt(current++);
+
+        if (c == '\\') {
+            escaped = true;
+            if (eof()) {
+                throw new RuntimeException("Eof found after \\");
+            }
+
+            c = text.charAt(current++);
+
+            switch (c) {
+                case 't':
+                    c = '\t';
+                    break;
+                case '\r':
+                case '\n':
+                    c = ' ';
+                    break;
+                case 'b':
+                    c = '\b';
+                    break;
+                case 'f':
+                    c = '\f';
+                    break;
+                case 'n':
+                    c = '\n';
+                    break;
+                case 'r':
+                    c = '\r';
+                    break;
+                case 'u':
+                    c = unicode();
+                    current += 4;
+                    break;
+                default:
+                    // We just take the next character literally
+                    // but have the escaped flag set, important for {},[] etc
+            }
+        }
+        if (cursor > last && cursor <= current) {
+            c0 = program != null ? program.size() : 0;
+            c1 = statements != null ? statements.size() : 0;
+            c2 = statement != null ? statement.size() : 0;
+            c3 = (start >= 0) ? current - start : 0;
+        }
+        if (!increment) {
+            current = last;
+        }
+        return c;
+    }
+
+    public List<List<List<String>>> program() {
+        program = new ArrayList<List<List<String>>>();
+        ws();
+        if (!eof()) {
+            program.add(pipeline());
+            while (peek() == ';') {
+                current++;
+                List<List<String>> pipeline = pipeline();
+                program.add(pipeline);
+            }
+        }
+        if (!eof()) {
+            throw new RuntimeException("Program has trailing text: " + context(current));
+        }
+
+        List<List<List<String>>> p = program;
+        program = null;
+        return p;
+    }
+
+    CharSequence context(int around) {
+        return text.subSequence(Math.max(0, current - 20), Math.min(text.length(),
+            current + 4));
+    }
+
+    public List<List<String>> pipeline() {
+        statements = new ArrayList<List<String>>();
+        statements.add(statement());
+        while (peek() == '|') {
+            current++;
+            ws();
+            if (!eof()) {
+                statements.add(statement());
+            }
+            else {
+                statements.add(new ArrayList<String>());
+                break;
+            }
+        }
+        List<List<String>> s = statements;
+        statements = null;
+        return s;
+    }
+
+    public List<String> statement() {
+        statement = new ArrayList<String>();
+        statement.add(value());
+        while (!eof()) {
+            ws();
+            if (peek() == '|' || peek() == ';') {
+                break;
+            }
+
+            if (!eof()) {
+                statement.add(messy());
+            }
+        }
+        List<String> s = statement;
+        statement = null;
+        return s;
+    }
+
+    public String messy()
+    {
+        start = current;
+        char c = peek();
+        if (c > 0 && SPECIAL.indexOf(c) < 0) {
+            current++;
+            try {
+                while (!eof()) {
+                    c = peek();
+                    if (!escaped && (c == ';' || c == '|' || Character.isWhitespace(c))) {
+                        break;
+                    }
+                    next();
+                }
+                return text.substring(start, current);
+            } finally {
+                start = -1;
+            }
+        }
+        else {
+            return value();
+        }
+    }
+
+    public int position() {
+        return current;
+    }
+
+    public int cursorArgumentIndex() {
+        return c2;
+    }
+
+    public int argumentPosition() {
+        return c3;
+    }
+
+    public String value() {
+        ws();
+
+        start = current;
+        try {
+            char c = next();
+            if (!escaped) {
+                switch (c) {
+                    case '{':
+                        return text.substring(start, find('}', '{'));
+                    case '(':
+                        return text.substring(start, find(')', '('));
+                    case '[':
+                        return text.substring(start, find(']', '['));
+                    case '<':
+                        return text.substring(start, find('>', '<'));
+                    case '=':
+                        return text.substring(start, current);
+                    case '"':
+                    case '\'':
+                        quote(c);
+                        break;
+                }
+            }
+
+            // Some identifier or number
+            while (!eof()) {
+                c = peek();
+                if (!escaped) {
+                    if (Character.isWhitespace(c) || c == ';' || c == '|' || c == '=') {
+                        break;
+                    }
+                    else if (c == '{') {
+                        next();
+                        find('}', '{');
+                    }
+                    else if (c == '(') {
+                        next();
+                        find(')', '(');
+                    }
+                    else if (c == '<') {
+                        next();
+                        find('>', '<');
+                    }
+                    else if (c == '[') {
+                        next();
+                        find(']', '[');
+                    }
+                    else if (c == '\'' || c == '"') {
+                        next();
+                        quote(c);
+                        next();
+                    }
+                    else {
+                        next();
+                    }
+                }
+                else {
+                    next();
+                }
+            }
+            return text.substring(start, current);
+        } finally {
+            start = -1;
+        }
+    }
+
+    public boolean escaped() {
+        return escaped;
+    }
+
+    public char next() {
+        return peek(true);
+    }
+
+    char unicode() {
+        if (current + 4 > text.length()) {
+            throw new IllegalArgumentException("Unicode \\u escape at eof at pos ..."
+                + context(current) + "...");
+        }
+
+        String s = text.subSequence(current, current + 4).toString();
+        int n = Integer.parseInt(s, 16);
+        return (char) n;
+    }
+
+    int find(char target, char deeper) {
+        int start = current;
+        int level = 1;
+
+        while (level != 0) {
+            if (eof()) {
+                throw new RuntimeException("Eof found in the middle of a compound for '"
+                    + target + deeper + "', begins at " + context(start));
+            }
+
+            char c = next();
+            if (!escaped) {
+                if (c == target) {
+                    level--;
+                } else {
+                    if (c == deeper) {
+                        level++;
+                    } else {
+                        if (c == '"') {
+                            quote('"');
+                        } else {
+                            if (c == '\'') {
+                                quote('\'');
+                            }
+                            else {
+                                if (c == '`') {
+                                    quote('`');
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return current;
+    }
+
+    int quote(char which) {
+        while (!eof() && (peek() != which || escaped)) {
+            next();
+        }
+
+        return current++;
+    }
+
+    CharSequence findVar() {
+        int start = current;
+        char c = peek();
+
+        if (c == '{') {
+            next();
+            int end = find('}', '{');
+            return text.subSequence(start, end);
+        }
+        if (c == '(') {
+            next();
+            int end = find(')', '(');
+            return text.subSequence(start, end);
+        }
+
+        if (Character.isJavaIdentifierPart(c)) {
+            while (c == '$') {
+                c = next();
+            }
+            while (!eof() && (Character.isJavaIdentifierPart(c) || c == '.') && c != '$') {
+                next();
+                c = peek();
+            }
+            return text.subSequence(start, current);
+        }
+        throw new IllegalArgumentException(
+            "Reference to variable does not match syntax of a variable: "
+                + context(start));
+    }
+
+    public String toString() {
+        return "..." + context(current) + "...";
+    }
+
+    public String unescape() {
+        StringBuilder sb = new StringBuilder();
+        while (!eof()) {
+            sb.append(next());
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
----------------------------------------------------------------------
diff --git a/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java b/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
new file mode 100644
index 0000000..7e8a727
--- /dev/null
+++ b/shell/core/src/test/java/org/apache/karaf/shell/impl/console/parsing/ParsingTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.karaf.shell.impl.console.parsing;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Parsing;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.impl.action.command.ActionCommand;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.apache.karaf.shell.impl.console.HeadlessSessionImpl;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.support.parsing.CommandLineImpl;
+import org.apache.karaf.shell.support.parsing.DefaultParser;
+import org.apache.karaf.shell.support.parsing.GogoParser;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class ParsingTest {
+
+    @Test
+    public void testDefaultParser() {
+        String command = " foo  bar (a +  b) ; another command ";
+        String subCmd = " foo  bar (a +  b) ";
+        DefaultParser parser = new DefaultParser();
+        CommandLine line = parser.parse(null, command, command.length());
+        assertEquals(3, line.getArguments().length);
+        assertEquals("foo", line.getArguments()[0]);
+        assertEquals("bar", line.getArguments()[1]);
+        assertEquals("(a +  b)", line.getArguments()[2]);
+        assertEquals(subCmd, line.getBuffer());
+
+    }
+
+    @Test
+    public void testCommandLineParser() {
+
+        SessionFactoryImpl sessionFactory = new SessionFactoryImpl(new ThreadIOImpl());
+        ManagerImpl manager = new ManagerImpl(sessionFactory, sessionFactory);
+        sessionFactory.getRegistry().register(new ActionCommand(manager, FooCommand.class));
+        sessionFactory.getRegistry().register(new ActionCommand(manager, AnotherCommand.class));
+        sessionFactory.getRegistry().register(new CustomParser());
+        Session session = new HeadlessSessionImpl(sessionFactory, sessionFactory.getCommandProcessor(),
+                new ByteArrayInputStream(new byte[0]), new PrintStream(new ByteArrayOutputStream()), new PrintStream(new ByteArrayOutputStream())
+        );
+
+        String parsed = CommandLineParser.parse(session, " foo bar (a + b); another   command with spaces ");
+        assertEquals("foo bar (a + b) ; another \"command with spaces\"", parsed);
+
+    }
+
+    @Command(scope = "scope", name = "foo")
+    static class FooCommand implements Action {
+        @Override
+        public Object execute() throws Exception {
+            return null;
+        }
+    }
+
+    @Command(scope = "scope", name = "another")
+    @Parsing(CustomParser.class)
+    static class AnotherCommand implements Action {
+        @Override
+        public Object execute() throws Exception {
+            return null;
+        }
+    }
+
+    static class CustomParser implements Parser {
+
+        @Override
+        public CommandLine parse(Session session, String command, int cursor) {
+            GogoParser parser = new GogoParser(command, cursor);
+            List<String> args = new ArrayList<>();
+            args.add(parser.value());
+            parser.ws();
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                char ch = parser.next();
+                if (ch == 0 || ch == ';' || ch == '|') {
+                    break;
+                } else {
+                    sb.append(ch);
+                }
+            }
+            String arg = sb.toString().trim();
+            if (!arg.isEmpty()) {
+                args.add("\"" + arg + "\"");
+            }
+            return new CommandLineImpl(args.toArray(new String[args.size()]), args.size() - 1, sb.length(),
+                            parser.position(),
+                            command.substring(0, parser.position()));
+        }
+    }
+
+}


[2/2] karaf git commit: [KARAF-3455] Support for custom command parsers

Posted by gn...@apache.org.
[KARAF-3455] Support for custom command parsers


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/cbbed8ac
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/cbbed8ac
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/cbbed8ac

Branch: refs/heads/master
Commit: cbbed8ac4d992756d1da1f6aff2de60943032169
Parents: cb75183
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Wed Jan 28 12:06:34 2015 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Wed Jan 28 12:08:25 2015 +0100

----------------------------------------------------------------------
 jdbc/pom.xml                                    |   1 +
 .../karaf/jdbc/command/ExecuteCommand.java      |   5 +
 .../apache/karaf/jdbc/command/QueryCommand.java |   5 +
 .../jdbc/command/completers/SqlCompleter.java   |  52 ++
 .../karaf/jdbc/command/parsing/JdbcParser.java  |  75 ++
 .../karaf/shell/compat/CommandTracker.java      |  11 +
 .../org/apache/felix/gogo/runtime/Closure.java  | 686 ----------------
 .../felix/gogo/runtime/CommandSessionImpl.java  | 404 ---------
 .../org/apache/felix/gogo/runtime/Parser.java   | 181 -----
 .../apache/felix/gogo/runtime/Tokenizer.java    | 813 -------------------
 .../apache/karaf/shell/api/action/Parsing.java  |  39 +
 .../apache/karaf/shell/api/console/Command.java |   7 +
 .../apache/karaf/shell/api/console/Parser.java  |  28 +
 .../impl/action/command/ActionCommand.java      |  28 +
 .../shell/impl/action/command/ManagerImpl.java  |   5 +-
 .../impl/console/CompleterAsCompletor.java      |  14 +-
 .../shell/impl/console/ConsoleSessionImpl.java  |  17 +-
 .../shell/impl/console/HeadlessSessionImpl.java |   4 +-
 .../impl/console/commands/TopLevelCommand.java  |   6 +
 .../impl/console/commands/help/HelpCommand.java |   6 +
 .../console/osgi/secured/SecuredCommand.java    |   6 +
 .../impl/console/parsing/CommandLineImpl.java   |  95 ---
 .../impl/console/parsing/CommandLineParser.java | 113 +++
 .../shell/impl/console/parsing/Parser.java      | 404 ---------
 .../shell/support/parsing/CommandLineImpl.java  |  80 ++
 .../shell/support/parsing/DefaultParser.java    |  43 +
 .../karaf/shell/support/parsing/GogoParser.java | 408 ++++++++++
 .../shell/impl/console/parsing/ParsingTest.java | 122 +++
 28 files changed, 1050 insertions(+), 2608 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/jdbc/pom.xml
----------------------------------------------------------------------
diff --git a/jdbc/pom.xml b/jdbc/pom.xml
index 41bc234..d98ef28 100644
--- a/jdbc/pom.xml
+++ b/jdbc/pom.xml
@@ -87,6 +87,7 @@
                         <Private-Package>
                             org.apache.karaf.jdbc.command,
                             org.apache.karaf.jdbc.command.completers,
+                            org.apache.karaf.jdbc.command.parsing,
                             org.apache.karaf.jdbc.internal,
                             org.apache.karaf.jdbc.internal.osgi,
                             org.apache.karaf.util,

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
index 480ab51..137f085 100644
--- a/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/ExecuteCommand.java
@@ -17,12 +17,16 @@
 package org.apache.karaf.jdbc.command;
 
 import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.jdbc.command.completers.SqlCompleter;
+import org.apache.karaf.jdbc.command.parsing.JdbcParser;
 import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Parsing;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 
 @Command(scope = "jdbc", name = "execute", description = "Execute a SQL command on a given JDBC datasource")
+@Parsing(JdbcParser.class)
 @Service
 public class ExecuteCommand extends JdbcCommandSupport {
 
@@ -31,6 +35,7 @@ public class ExecuteCommand extends JdbcCommandSupport {
     String datasource;
 
     @Argument(index = 1, name = "command", description = "The SQL command to execute", required = true, multiValued = false)
+    @Completion(SqlCompleter.class)
     String command;
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
index 297288b..34089b3 100644
--- a/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/QueryCommand.java
@@ -20,14 +20,18 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.karaf.jdbc.command.completers.DataSourcesNameCompleter;
+import org.apache.karaf.jdbc.command.completers.SqlCompleter;
+import org.apache.karaf.jdbc.command.parsing.JdbcParser;
 import org.apache.karaf.shell.api.action.Argument;
 import org.apache.karaf.shell.api.action.Command;
 import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Parsing;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.apache.karaf.shell.support.table.Row;
 import org.apache.karaf.shell.support.table.ShellTable;
 
 @Command(scope = "jdbc", name = "query", description = "Execute a SQL query on a JDBC datasource")
+@Parsing(JdbcParser.class)
 @Service
 public class QueryCommand extends JdbcCommandSupport {
 
@@ -36,6 +40,7 @@ public class QueryCommand extends JdbcCommandSupport {
     String datasource;
 
     @Argument(index = 1, name = "query", description = "The SQL query to execute", required = true, multiValued = false)
+    @Completion(SqlCompleter.class)
     String query;
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/SqlCompleter.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/SqlCompleter.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/SqlCompleter.java
new file mode 100644
index 0000000..eb3015d
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/completers/SqlCompleter.java
@@ -0,0 +1,52 @@
+/*
+ * 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.karaf.jdbc.command.completers;
+
+import java.util.List;
+
+import org.apache.karaf.jdbc.JdbcService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Completer SQL
+ */
+@Service
+public class SqlCompleter implements Completer {
+
+    @Reference
+    private JdbcService jdbcService;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+        // TODO: implement SQL completion
+        return -1;
+    }
+
+    public JdbcService getJdbcService() {
+        return jdbcService;
+    }
+
+    public void setJdbcService(JdbcService jdbcService) {
+        this.jdbcService = jdbcService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/jdbc/src/main/java/org/apache/karaf/jdbc/command/parsing/JdbcParser.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/karaf/jdbc/command/parsing/JdbcParser.java b/jdbc/src/main/java/org/apache/karaf/jdbc/command/parsing/JdbcParser.java
new file mode 100644
index 0000000..90238c3
--- /dev/null
+++ b/jdbc/src/main/java/org/apache/karaf/jdbc/command/parsing/JdbcParser.java
@@ -0,0 +1,75 @@
+package org.apache.karaf.jdbc.command.parsing;
+
+/*
+ * 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.
+ */
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Parser;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.parsing.CommandLineImpl;
+import org.apache.karaf.shell.support.parsing.GogoParser;
+
+/**
+ * A parser for JDBC commands using SQL.
+ */
+@Service
+public class JdbcParser implements Parser {
+
+    @Override
+    public CommandLine parse(Session session, String command, int cursor) {
+        GogoParser parser = new GogoParser(command, cursor);
+        List<String> args = parser.statement();
+        List<String> nargs = new ArrayList<>();
+        int state = 0;
+        for (String arg : args) {
+            switch (state) {
+            // command
+            case 0:
+                nargs.add(arg);
+                state = 1;
+                break;
+            // option or target
+            case 1:
+                nargs.add(arg);
+                if (!arg.startsWith("-")) {
+                    state = 2;
+                }
+                break;
+            // first sql fragment
+            case 2:
+                nargs.add(arg);
+                state = 3;
+                break;
+            // addtional sql
+            case 3:
+                nargs.set(nargs.size() - 1, nargs.get(nargs.size() - 1) + " " + arg);
+                break;
+            }
+        }
+        nargs.set(nargs.size() - 1, "\"" + nargs.get(nargs.size() - 1) + "\"");
+        return new CommandLineImpl(
+                nargs.toArray(new String[nargs.size()]),
+                parser.cursorArgumentIndex(),
+                Math.max(parser.argumentPosition(), nargs.size()),
+                cursor,
+                command.substring(0, parser.position()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java b/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
index 191735c..a923cb7 100644
--- a/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
+++ b/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.commands.Command;
 import org.apache.karaf.shell.commands.CommandWithAction;
 import org.apache.karaf.shell.api.console.CommandLine;
@@ -97,6 +98,11 @@ public class CommandTracker implements ServiceTrackerCustomizer<Object, Object>
                 }
 
                 @Override
+                public Parser getParser() {
+                    return null;
+                }
+
+                @Override
                 public Object execute(Session session, List<Object> arguments) throws Exception {
                     // TODO: remove not really nice cast
                     CommandSession commandSession = (CommandSession) session.get(".commandSession");
@@ -140,6 +146,11 @@ public class CommandTracker implements ServiceTrackerCustomizer<Object, Object>
                 }
 
                 @Override
+                public Parser getParser() {
+                    return null;
+                }
+
+                @Override
                 public Object execute(Session session, List<Object> arguments) throws Exception {
                     // TODO: remove not really nice cast
                     CommandSession commandSession = (CommandSession) session.get(".commandSession");

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/felix/gogo/runtime/Closure.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Closure.java b/shell/core/src/main/java/org/apache/felix/gogo/runtime/Closure.java
deleted file mode 100644
index 4994ec3..0000000
--- a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Closure.java
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * 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.gogo.runtime;
-
-import java.io.EOFException;
-import java.util.*;
-import java.util.Map.Entry;
-
-import org.apache.felix.gogo.runtime.Tokenizer.Type;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Function;
-
-public class Closure implements Function, Evaluate
-{
-    public static final String LOCATION = ".location";
-    private static final String DEFAULT_LOCK = ".defaultLock";
-
-    private static final long serialVersionUID = 1L;
-    private static final ThreadLocal<String> location = new ThreadLocal<String>();
-
-    private final CommandSessionImpl session;
-    private final Closure parent;
-    private final CharSequence source;
-    private final List<List<List<Token>>> program;
-    private final Object script;
-
-    private Token errTok;
-    private Token errTok2;
-    private List<Object> parms = null;
-    private List<Object> parmv = null;
-
-    public Closure(CommandSessionImpl session, Closure parent, CharSequence source) throws Exception
-    {
-        this.session = session;
-        this.parent = parent;
-        this.source = source;
-        script = session.get("0"); // by convention, $0 is script name
-
-        try
-        {
-            program = new Parser(source, isExpansionEnabled()).program(); //CQL-Handling
-        }
-        catch (Exception e)
-        {
-            throw setLocation(e);
-        }
-    }
-
-    public CommandSessionImpl session()
-    {
-        return session;
-    }
-
-    private Exception setLocation(Exception e)
-    {
-        if (session.get(DEFAULT_LOCK) == null)
-        {
-            String loc = location.get();
-            if (null == loc)
-            {
-                loc = (null == script ? "" : script + ":");
-
-                if (e instanceof SyntaxError)
-                {
-                    SyntaxError se = (SyntaxError) e;
-                    loc += se.line() + "." + se.column();
-                }
-                else if (null != errTok)
-                {
-                    loc += errTok.line + "." + errTok.column;
-                }
-
-                location.set(loc);
-            }
-            else if (null != script && !loc.contains(":"))
-            {
-                location.set(script + ":" + loc);
-            }
-
-            session.put(LOCATION, location.get());
-        }
-
-        if (e instanceof EOFError)
-        { // map to public exception, so interactive clients can provide more input
-            EOFException eofe = new EOFException(e.getMessage());
-            eofe.initCause(e);
-            return eofe;
-        }
-
-        return e;
-    }
-
-    // implements Function interface
-    public Object execute(CommandSession x, List<Object> values) throws Exception
-    {
-        try
-        {
-            location.remove();
-            session.variables.remove(LOCATION);
-            return execute(values);
-        }
-        catch (Exception e)
-        {
-            throw setLocation(e);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private Object execute(List<Object> values) throws Exception
-    {
-        if (null != values)
-        {
-            parmv = values;
-            parms = new ArgList(parmv);
-        }
-        else if (null != parent)
-        {
-            // inherit parent closure parameters
-            parms = parent.parms;
-            parmv = parent.parmv;
-        }
-        else
-        {
-            // inherit session parameters
-            Object args = session.get("args");
-            if (null != args && args instanceof List<?>)
-            {
-                parmv = (List<Object>) args;
-                parms = new ArgList(parmv);
-            }
-        }
-
-        Pipe last = null;
-        Object[] mark = Pipe.mark();
-
-        for (List<List<Token>> pipeline : program)
-        {
-            ArrayList<Pipe> pipes = new ArrayList<Pipe>();
-
-            for (List<Token> statement : pipeline)
-            {
-                Pipe current = new Pipe(this, statement);
-
-                if (pipes.isEmpty())
-                {
-                    if (current.out == null)
-                    {
-                        current.setIn(session.in);
-                        current.setOut(session.out);
-                        current.setErr(session.err);
-                    }
-                }
-                else
-                {
-                    Pipe previous = pipes.get(pipes.size() - 1);
-                    previous.connect(current);
-                }
-                pipes.add(current);
-            }
-
-            if (pipes.size() == 1)
-            {
-                pipes.get(0).run();
-            }
-            else if (pipes.size() > 1)
-            {
-                for (Pipe pipe : pipes)
-                {
-                    pipe.start();
-                }
-                try
-                {
-                    for (Pipe pipe : pipes)
-                    {
-                        pipe.join();
-                    }
-                }
-                catch (InterruptedException e)
-                {
-                    for (Pipe pipe : pipes)
-                    {
-                        pipe.interrupt();
-                    }
-                    throw e;
-                }
-            }
-
-            last = pipes.remove(pipes.size() - 1);
-
-            for (Pipe pipe : pipes)
-            {
-                if (pipe.exception != null)
-                {
-                    // can't throw exception, as result is defined by last pipe
-                    Object oloc = session.get(LOCATION);
-                    String loc = (String.valueOf(oloc).contains(":") ? oloc + ": "
-                        : "pipe: ");
-                    session.err.println(loc + pipe.exception);
-                    session.put("pipe-exception", pipe.exception);
-                }
-            }
-
-            if (last.exception != null)
-            {
-                Pipe.reset(mark);
-                throw last.exception;
-            }
-        }
-
-        Pipe.reset(mark); // reset IO in case same thread used for new client
-
-        return last == null ? null : last.result;
-    }
-
-    private Object eval(Object v)
-    {
-        String s = v.toString();
-        if ("null".equals(s))
-        {
-            v = null;
-        }
-        else if ("false".equals(s))
-        {
-            v = false;
-        }
-        else if ("true".equals(s))
-        {
-            v = true;
-        }
-        else
-        {
-            try
-            {
-                v = s;
-                v = Double.parseDouble(s);    // if it parses as double
-                v = Long.parseLong(s);        // see whether it is integral
-            }
-            catch (NumberFormatException e)
-            {
-            }
-        }
-        return v;
-    }
-
-    public Object eval(final Token t) throws Exception
-    {
-        Object v = null;
-
-        switch (t.type)
-        {
-            case WORD:
-                v = Tokenizer.expand(t, this);
-
-                if (t == v)
-                {
-                    v = eval(v);
-                }
-                break;
-
-            case CLOSURE:
-                v = new Closure(session, this, t);
-                break;
-
-            case EXECUTION:
-                v = new Closure(session, this, t).execute(session, parms);
-                break;
-
-            case ARRAY:
-                v = array(t);
-                break;
-
-            case ASSIGN:
-                v = t.type;
-                break;
-
-            case EXPR:
-                v = expr(t.value);
-                break;
-
-            default:
-                throw new SyntaxError(t.line, t.column, "unexpected token: " + t.type);
-        }
-
-        return v;
-    }
-
-    //extra handling for CQL-Shell
-    private boolean isExpansionEnabled() {
-        Object v = session.get("org.apache.felix.gogo.expansion");
-        if (v != null) {
-            return Boolean.parseBoolean(v.toString());
-        }
-        return true;
-    }
-
-    /*
-     * executeStatement handles the following cases:
-     *    <string> '=' word // simple assignment
-     *    <string> '=' word word.. // complex assignment
-     *    <bareword> word.. // command invocation
-     *    <object> // value of <object>
-     *    <object> word.. // method call
-     */
-    public Object executeStatement(List<Token> statement) throws Exception
-    {
-        Object echo = session.get("echo");
-        String xtrace = null;
-
-        if (echo != null && !"false".equals(echo.toString()))
-        {
-            // set -x execution trace
-            StringBuilder buf = new StringBuilder("+");
-            for (Token token : statement)
-            {
-                buf.append(' ');
-                buf.append(token.source());
-            }
-            xtrace = buf.toString();
-            session.err.println(xtrace);
-        }
-
-        List<Object> values = new ArrayList<Object>();
-        errTok = statement.get(0);
-
-        if ((statement.size() > 3) && Type.ASSIGN.equals(statement.get(1).type))
-        {
-            errTok2 = statement.get(2);
-        }
-
-        for (Token t : statement)
-        {
-            Object v = isExpansionEnabled() ? eval(t) : t.toString();
-
-            if ((Type.EXECUTION == t.type) && (statement.size() == 1))
-            {
-                return v;
-            }
-
-            if (parms == v && parms != null)
-            {
-                values.addAll(parms); // explode $args array
-            }
-            else
-            {
-                values.add(v);
-            }
-        }
-
-        Object cmd = values.remove(0);
-        if (cmd == null)
-        {
-            if (values.isEmpty())
-            {
-                return null;
-            }
-
-            throw new RuntimeException("Command name evaluates to null: " + errTok);
-        }
-
-        if (cmd instanceof CharSequence && values.size() > 0
-            && Type.ASSIGN.equals(values.get(0)))
-        {
-            values.remove(0);
-            String scmd = cmd.toString();
-            Object value;
-
-            if (values.size() == 0)
-            {
-                return session.variables.remove(scmd);
-            }
-
-            if (values.size() == 1)
-            {
-                value = values.get(0);
-            }
-            else
-            {
-                cmd = values.remove(0);
-                if (null == cmd)
-                {
-                    throw new RuntimeException("Command name evaluates to null: "
-                        + errTok2);
-                }
-
-                trace2(xtrace, cmd, values);
-
-                value = bareword(statement.get(2)) ? executeCmd(cmd.toString(), values)
-                    : executeMethod(cmd, values);
-            }
-
-            return assignment(scmd, value);
-        }
-
-        trace2(xtrace, cmd, values);
-
-        return bareword(statement.get(0)) ? executeCmd(cmd.toString(), values)
-            : executeMethod(cmd, values);
-    }
-
-    // second level expanded execution trace
-    private void trace2(String trace1, Object cmd, List<Object> values)
-    {
-        if ("verbose".equals(session.get("echo")))
-        {
-            StringBuilder buf = new StringBuilder("+ " + cmd);
-
-            for (Object value : values)
-            {
-                buf.append(' ');
-                buf.append(value);
-            }
-
-            String trace2 = buf.toString();
-
-            if (!trace2.equals(trace1))
-            {
-                session.err.println("+" + trace2);
-            }
-        }
-    }
-
-    private boolean bareword(Token t) throws Exception
-    {
-        return ((t.type == Type.WORD) && (t == Tokenizer.expand(t, this)) && (eval((Object) t) instanceof String));
-    }
-
-    private Object executeCmd(String scmd, List<Object> values) throws Exception
-    {
-        String scopedFunction = scmd;
-        Object x = get(scmd);
-
-        if (!(x instanceof Function))
-        {
-            if (scmd.indexOf(':') < 0)
-            {
-                scopedFunction = "*:" + scmd;
-            }
-
-            x = get(scopedFunction);
-
-            if (x == null || !(x instanceof Function))
-            {
-                // try default command handler
-                if (session.get(DEFAULT_LOCK) == null)
-                {
-                    x = get("default");
-                    if (x == null)
-                    {
-                        x = get("*:default");
-                    }
-
-                    if (x instanceof Function)
-                    {
-                        try
-                        {
-                            session.put(DEFAULT_LOCK, true);
-                            values.add(0, scmd);
-                            return ((Function) x).execute(session, values);
-                        }
-                        finally
-                        {
-                            session.variables.remove(DEFAULT_LOCK);
-                        }
-                    }
-                }
-
-                throw new CommandNotFoundException(scmd);
-            }
-        }
-        return ((Function) x).execute(session, values);
-    }
-
-    private Object executeMethod(Object cmd, List<Object> values) throws Exception
-    {
-        if (values.isEmpty())
-        {
-            return cmd;
-        }
-
-        boolean dot = values.size() > 1 && ".".equals(String.valueOf(values.get(0)));
-
-        // FELIX-1473 - allow method chaining using dot pseudo-operator, e.g.
-        //  (bundle 0) . loadClass java.net.InetAddress . localhost . hostname
-        //  (((bundle 0) loadClass java.net.InetAddress ) localhost ) hostname
-        if (dot)
-        {
-            Object target = cmd;
-            ArrayList<Object> args = new ArrayList<Object>();
-            values.remove(0);
-
-            for (Object arg : values)
-            {
-                if (".".equals(arg))
-                {
-                    target = Reflective.invoke(session, target,
-                        args.remove(0).toString(), args);
-                    args.clear();
-                }
-                else
-                {
-                    args.add(arg);
-                }
-            }
-
-            if (args.size() == 0)
-            {
-                return target;
-            }
-
-            return Reflective.invoke(session, target, args.remove(0).toString(), args);
-        }
-        else if (cmd.getClass().isArray() && values.size() == 1)
-        {
-            Object[] cmdv = (Object[]) cmd;
-            String index = values.get(0).toString();
-            return "length".equals(index) ? cmdv.length : cmdv[Integer.parseInt(index)];
-        }
-        else
-        {
-            return Reflective.invoke(session, cmd, values.remove(0).toString(), values);
-        }
-    }
-
-    private Object assignment(String name, Object value)
-    {
-        session.variables.put(name, value);
-        return value;
-    }
-
-    private Object expr(CharSequence expr) throws Exception
-    {
-        return session.expr(expr);
-    }
-
-    private Object array(Token array) throws Exception
-    {
-        List<Token> list = new ArrayList<Token>();
-        Map<Token, Token> map = new LinkedHashMap<Token, Token>();
-        (new Parser(array, isExpansionEnabled())).array(list, map); //CQL-Handling
-
-        if (map.isEmpty())
-        {
-            List<Object> olist = new ArrayList<Object>();
-            for (Token t : list)
-            {
-                Object oval = eval(t);
-                if (oval.getClass().isArray())
-                {
-                    for (Object o : (Object[]) oval)
-                    {
-                        olist.add(o);
-                    }
-                }
-                else
-                {
-                    olist.add(oval);
-                }
-            }
-            return olist;
-        }
-        else
-        {
-            Map<Object, Object> omap = new LinkedHashMap<Object, Object>();
-            for (Entry<Token, Token> e : map.entrySet())
-            {
-                Token key = e.getKey();
-                Object k = eval(key);
-                if (!(k instanceof String))
-                {
-                    throw new SyntaxError(key.line, key.column,
-                        "map key null or not String: " + key);
-                }
-                omap.put(k, eval(e.getValue()));
-            }
-            return omap;
-        }
-    }
-
-    public Object get(String name)
-    {
-        if (parms != null)
-        {
-            if ("args".equals(name))
-            {
-                return parms;
-            }
-
-            if ("argv".equals(name))
-            {
-                return parmv;
-            }
-
-            if ("it".equals(name))
-            {
-                return parms.get(0);
-            }
-
-            if (name.length() == 1 && Character.isDigit(name.charAt(0)))
-            {
-                int i = name.charAt(0) - '0';
-                if (i > 0)
-                {
-                    return parms.get(i - 1);
-                }
-            }
-        }
-
-        return session.get(name);
-    }
-
-    public Object put(String key, Object value)
-    {
-        return session.variables.put(key, value);
-    }
-
-    @Override
-    public String toString()
-    {
-        return source.toString().trim().replaceAll("\n+", "\n").replaceAll(
-            "([^\\\\{(\\[])\n", "\\1;").replaceAll("[ \\\\\t\n]+", " ");
-    }
-
-    /**
-     * List that overrides toString() for implicit $args expansion.
-     * Also checks for index out of bounds, so that $1 evaluates to null
-     * rather than throwing IndexOutOfBoundsException.
-     * e.g. x = { a$args }; x 1 2 => a1 2 and not a[1, 2]
-     */
-    class ArgList extends AbstractList<Object>
-    {
-        private List<Object> list;
-
-        public ArgList(List<Object> args)
-        {
-            this.list = args;
-        }
-
-        @Override
-        public String toString()
-        {
-            StringBuilder buf = new StringBuilder();
-            for (Object o : list)
-            {
-                if (buf.length() > 0)
-                    buf.append(' ');
-                buf.append(o);
-            }
-            return buf.toString();
-        }
-
-        @Override
-        public Object get(int index)
-        {
-            return index < list.size() ? list.get(index) : null;
-        }
-
-        @Override
-        public Object remove(int index)
-        {
-            return list.remove(index);
-        }
-
-        @Override
-        public int size()
-        {
-            return list.size();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java b/shell/core/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
deleted file mode 100644
index ee3c09b..0000000
--- a/shell/core/src/main/java/org/apache/felix/gogo/runtime/CommandSessionImpl.java
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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.
- */
-// DWB8: throw IllegatlStateException if session used after closed (as per rfc132)
-// DWB9: there is no API to list all variables: https://www.osgi.org/bugzilla/show_bug.cgi?id=49
-// DWB10: add SCOPE support: https://www.osgi.org/bugzilla/show_bug.cgi?id=51
-package org.apache.felix.gogo.runtime;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Converter;
-import org.apache.felix.service.command.Function;
-import org.apache.felix.service.threadio.ThreadIO;
-
-public class CommandSessionImpl implements CommandSession, Converter
-{
-    public static final String SESSION_CLOSED = "session is closed";
-    public static final String VARIABLES = ".variables";
-    public static final String COMMANDS = ".commands";
-    private static final String COLUMN = "%-20s %s\n";
-    
-    protected InputStream in;
-    protected PrintStream out;
-    PrintStream err;
-    
-    private final CommandProcessorImpl processor;
-    protected final Map<String, Object> variables = new HashMap<String, Object>();
-    private boolean closed;
-
-    protected CommandSessionImpl(CommandProcessorImpl shell, InputStream in, PrintStream out, PrintStream err)
-    {
-        this.processor = shell;
-        this.in = in;
-        this.out = out;
-        this.err = err;
-    }
-    
-    ThreadIO threadIO()
-    {
-        return processor.threadIO;
-    }
-
-    public void close()
-    {
-        this.closed = true;
-    }
-
-    public Object execute(CharSequence commandline) throws Exception
-    {
-        assert processor != null;
-        assert processor.threadIO != null;
-
-        if (closed)
-        {
-            throw new IllegalStateException(SESSION_CLOSED);
-        }
-
-        processor.beforeExecute(this, commandline);
-
-        try
-        {
-            Closure impl = new Closure(this, null, commandline);
-            Object result = impl.execute(this, null);
-            processor.afterExecute(this, commandline, result);
-            return result;
-        }
-        catch (Exception e)
-        {
-            processor.afterExecute(this, commandline, e);
-            throw e;
-        }
-    }
-
-    public InputStream getKeyboard()
-    {
-        return in;
-    }
-
-    public Object get(String name)
-    {
-        // there is no API to list all variables, so overload name == null
-        if (name == null || VARIABLES.equals(name))
-        {
-            return Collections.unmodifiableSet(variables.keySet());
-        }
-
-        if (COMMANDS.equals(name))
-        {
-            return processor.getCommands();
-        }
-
-        Object val = processor.constants.get(name);
-        if( val != null )
-        {
-            return val;
-        }
-
-        val = variables.get("#" + name);
-        if (val instanceof Function)
-        {
-            try
-            {
-                val = ((Function) val).execute(this, null);
-            }
-            catch (Exception e)
-            {
-                // Ignore
-            }
-            return val;
-        }
-        else if( val != null )
-        {
-            return val;
-        }
-
-        val = variables.get(name);
-        if( val != null )
-        {
-            return val;
-        }
-
-        return processor.getCommand(name, variables.get("SCOPE"));
-    }
-
-    public void put(String name, Object value)
-    {
-        synchronized (variables)
-        {
-            variables.put(name, value);
-        }
-    }
-
-    public PrintStream getConsole()
-    {
-        return out;
-    }
-
-    @SuppressWarnings("unchecked")
-    public CharSequence format(Object target, int level, Converter escape)
-        throws Exception
-    {
-        if (target == null)
-        {
-            return "null";
-        }
-
-        if (target instanceof CharSequence)
-        {
-            return (CharSequence) target;
-        }
-
-        for (Converter c : processor.converters)
-        {
-            CharSequence s = c.format(target, level, this);
-            if (s != null)
-            {
-                return s;
-            }
-        }
-
-        if (target.getClass().isArray())
-        {
-            if (target.getClass().getComponentType().isPrimitive())
-            {
-                if (target.getClass().getComponentType() == boolean.class)
-                {
-                    return Arrays.toString((boolean[]) target);
-                }
-                else
-                {
-                    if (target.getClass().getComponentType() == byte.class)
-                    {
-                        return Arrays.toString((byte[]) target);
-                    }
-                    else
-                    {
-                        if (target.getClass().getComponentType() == short.class)
-                        {
-                            return Arrays.toString((short[]) target);
-                        }
-                        else
-                        {
-                            if (target.getClass().getComponentType() == int.class)
-                            {
-                                return Arrays.toString((int[]) target);
-                            }
-                            else
-                            {
-                                if (target.getClass().getComponentType() == long.class)
-                                {
-                                    return Arrays.toString((long[]) target);
-                                }
-                                else
-                                {
-                                    if (target.getClass().getComponentType() == float.class)
-                                    {
-                                        return Arrays.toString((float[]) target);
-                                    }
-                                    else
-                                    {
-                                        if (target.getClass().getComponentType() == double.class)
-                                        {
-                                            return Arrays.toString((double[]) target);
-                                        }
-                                        else
-                                        {
-                                            if (target.getClass().getComponentType() == char.class)
-                                            {
-                                                return Arrays.toString((char[]) target);
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            target = Arrays.asList((Object[]) target);
-        }
-        if (target instanceof Collection)
-        {
-            if (level == Converter.INSPECT)
-            {
-                StringBuilder sb = new StringBuilder();
-                Collection<?> c = (Collection<?>) target;
-                for (Object o : c)
-                {
-                    sb.append(format(o, level + 1, this));
-                    sb.append("\n");
-                }
-                return sb;
-            }
-            else
-            {
-                if (level == Converter.LINE)
-                {
-                    StringBuilder sb = new StringBuilder();
-                    Collection<?> c = (Collection<?>) target;
-                    sb.append("[");
-                    for (Object o : c)
-                    {
-                        if (sb.length() > 1)
-                        {
-                            sb.append(", ");
-                        }
-                        sb.append(format(o, level + 1, this));
-                    }
-                    sb.append("]");
-                    return sb;
-                }
-            }
-        }
-        if (target instanceof Dictionary)
-        {
-            Map<Object, Object> result = new HashMap<Object, Object>();
-            for (Enumeration e = ((Dictionary) target).keys(); e.hasMoreElements();)
-            {
-                Object key = e.nextElement();
-                result.put(key, ((Dictionary) target).get(key));
-            }
-            target = result;
-        }
-        if (target instanceof Map)
-        {
-            if (level == Converter.INSPECT)
-            {
-                StringBuilder sb = new StringBuilder();
-                Map<?, ?> c = (Map<?, ?>) target;
-                for (Map.Entry<?, ?> entry : c.entrySet())
-                {
-                    CharSequence key = format(entry.getKey(), level + 1, this);
-                    sb.append(key);
-                    for (int i = key.length(); i < 20; i++)
-                    {
-                        sb.append(' ');
-                    }
-                    sb.append(format(entry.getValue(), level + 1, this));
-                    sb.append("\n");
-                }
-                return sb;
-            }
-            else
-            {
-                if (level == Converter.LINE)
-                {
-                    StringBuilder sb = new StringBuilder();
-                    Map<?, ?> c = (Map<?, ?>) target;
-                    sb.append("[");
-                    for (Map.Entry<?, ?> entry : c.entrySet())
-                    {
-                        if (sb.length() > 1)
-                        {
-                            sb.append(", ");
-                        }
-                        sb.append(format(entry, level + 1, this));
-                    }
-                    sb.append("]");
-                    return sb;
-                }
-            }
-        }
-        if (level == Converter.INSPECT)
-        {
-            return inspect(target);
-        }
-        else
-        {
-            return target.toString();
-        }
-    }
-
-    CharSequence inspect(Object b)
-    {
-        boolean found = false;
-        Formatter f = new Formatter();
-        Method methods[] = b.getClass().getMethods();
-        for (Method m : methods)
-        {
-            try
-            {
-                String name = m.getName();
-                if (m.getName().startsWith("get") && !m.getName().equals("getClass")
-                    && m.getParameterTypes().length == 0
-                    && Modifier.isPublic(m.getModifiers()))
-                {
-                    found = true;
-                    name = name.substring(3);
-                    m.setAccessible(true);
-                    Object value = m.invoke(b, (Object[]) null);
-                    f.format(COLUMN, name, format(value, Converter.LINE, this));
-                }
-            }
-            catch (IllegalAccessException e)
-            {
-                // Ignore
-            }
-            catch (Exception e)
-            {
-                e.printStackTrace();
-            }
-        }
-        if (found)
-        {
-            return (StringBuilder) f.out();
-        }
-        else
-        {
-            return b.toString();
-        }
-    }
-
-    public Object convert(Class<?> desiredType, Object in)
-    {
-        return processor.convert(desiredType, in);
-    }
-
-    public CharSequence format(Object result, int inspect)
-    {
-        try
-        {
-            return format(result, inspect, this);
-        }
-        catch (Exception e)
-        {
-            return "<can not format " + result + ":" + e;
-        }
-    }
-
-    public Object expr(CharSequence expr)
-    {
-        return processor.expr(this, expr);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/felix/gogo/runtime/Parser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Parser.java b/shell/core/src/main/java/org/apache/felix/gogo/runtime/Parser.java
deleted file mode 100644
index b036830..0000000
--- a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Parser.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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.
- */
-// DWB14: parser loops if // comment at start of program
-// DWB15: allow program to have trailing ';'
-package org.apache.felix.gogo.runtime;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.gogo.runtime.Tokenizer.Type;
-
-public class Parser
-{
-    private final Tokenizer tz;
-
-    public Parser(CharSequence program) {
-    	tz = new Tokenizer(program, null, false, true);
-    }
-    
-    public Parser(CharSequence program, boolean isExpansionEnabled)
-    {
-        tz = new Tokenizer(program, null, false, isExpansionEnabled);
-    }
-
-    public List<List<List<Token>>> program()
-    {
-        List<List<List<Token>>> program = new ArrayList<List<List<Token>>>();
-        
-        while (tz.next() != Type.EOT)
-        {
-            program.add(pipeline());
-            
-            switch (tz.type())
-            {
-                case SEMICOLON:
-                case NEWLINE:
-                    continue;
-            }
-            
-            break;
-        }
-
-        if (tz.next() != Type.EOT)
-            throw new RuntimeException("Program has trailing text: " + tz.value());
-
-        return program;
-    }
-
-    private List<List<Token>> pipeline()
-    {
-        List<List<Token>> pipeline = new ArrayList<List<Token>>();
-        
-        while (true)
-        {
-            pipeline.add(command());
-            switch (tz.type())
-            {
-                case PIPE:
-                    if (tz.next() == Type.EOT)
-                    {
-                        Token t = tz.token();
-                        throw new EOFError(t.line, t.column, "unexpected EOT after pipe '|'");
-                    }
-                    break;
-
-                default:
-                    return pipeline;
-            }
-        }
-    }
-
-    private List<Token> command()
-    {
-        List<Token> command = new ArrayList<Token>();
-
-        while (true)
-        {
-            Token t = tz.token();
-            
-            switch (t.type)
-            {
-                case WORD:
-                case CLOSURE:
-                case EXECUTION:
-                case ARRAY:
-                case ASSIGN:
-                case EXPR:
-                    break;
-                    
-                default:
-                    throw new SyntaxError(t.line, t.column, "unexpected token: " + t.type);
-            }
-            
-            command.add(t);
-            
-            switch (tz.next())
-            {
-                case PIPE:
-                case SEMICOLON:
-                case NEWLINE:
-                case EOT:
-                    return command;
-            }
-        }
-    }
-    
-    public void array(List<Token> list, Map<Token, Token> map) throws Exception
-    {
-        Token lt = null;
-        boolean isMap = false;
-
-        while (tz.next() != Type.EOT)
-        {
-            if (isMap)
-            {
-                Token key = lt;
-                lt = null;
-                if (null == key)
-                {
-                    key = tz.token();
-
-                    if (tz.next() != Type.ASSIGN)
-                    {
-                        Token t = tz.token();
-                        throw new SyntaxError(t.line, t.column,
-                            "map expected '=', found: " + t);
-                    }
-
-                    tz.next();
-                }
-
-                Token k = (list.isEmpty() ? key : list.remove(0));
-                Token v = tz.token();
-                map.put(k, v);
-            }
-            else
-            {
-                switch (tz.type())
-                {
-                    case WORD:
-                    case CLOSURE:
-                    case EXECUTION:
-                    case ARRAY:
-                        lt = tz.token();
-                        list.add(lt);
-                        break;
-
-                    case ASSIGN:
-                        if (list.size() == 1)
-                        {
-                            isMap = true;
-                            break;
-                        }
-                        // fall through
-                    default:
-                        lt = tz.token();
-                        throw new SyntaxError(lt.line, lt.column,
-                            "unexpected token in list: " + lt);
-                }
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/felix/gogo/runtime/Tokenizer.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Tokenizer.java b/shell/core/src/main/java/org/apache/felix/gogo/runtime/Tokenizer.java
deleted file mode 100644
index 866db9e..0000000
--- a/shell/core/src/main/java/org/apache/felix/gogo/runtime/Tokenizer.java
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * 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.gogo.runtime;
-
-/**
- * Bash-like tokenizer.
- * 
- * Single and double quotes are just like Bash - single quotes escape everything
- * (including backslashes), newlines are allowed in quotes.
- * backslash-newline indicates a line continuation and is removed.
- * 
- * Variable expansion is just like Bash: $NAME or ${NAME[[:][-+=?WORD]},
- * except it can yield any Object. Variables expanded within double-quotes,
- * or adjacent to a String are converted to String.
- * 
- * Unlike bash, indirect variable expansion is supported using ${$NAME}.
- * 
- * Only a single variable assignment is recognized, with '=' being the second token.
- * (Bash allows name1=value1 name2=value2 ... command args)
- * 
- * Comments can only start where white space is allowed:
- * # or // starts a line comment, /* starts a block comment.
- * The following common uses do NOT start comments:
- *    ls http://example.com#anchor
- *    ls $dir/*.java
- * 
- * @see http://wiki.bash-hackers.org/syntax/basicgrammar
- */
-public class Tokenizer
-{
-    public enum Type
-    {
-        ASSIGN('='), PIPE('|'), SEMICOLON(';'), NEWLINE, ARRAY, CLOSURE, EXPR, EXECUTION, WORD, EOT;
-
-        private char c;
-
-        Type()
-        {
-        }
-
-        Type(char c)
-        {
-            this.c = c;
-        }
-
-        @Override
-        public String toString()
-        {
-            return (c == 0 ? super.toString() : "'" + c + "'");
-        }
-    }
-
-    private static final boolean DEBUG = false;
-    private static final char EOT = (char) -1;
-
-    private final CharSequence text;
-    private final Evaluate evaluate;
-    private final boolean inArray;
-    private final boolean inQuote;
-    //extra to disable some special handling of brackets etc. needed for CQL-Completion
-    private final boolean isExpansionEnabled;
-
-    private Type type = Type.NEWLINE;
-    private CharSequence value;
-    private Token token;
-
-    private short line;
-    private short column;
-    private char ch;
-    private int index;
-    private boolean firstWord;
-
-    public Tokenizer(CharSequence text)
-    {
-        this(text, null, false, true);
-    }
-    
-    public Tokenizer(CharSequence text, Evaluate evaluate, boolean inQuote)
-    {
-    	this(text, evaluate, inQuote, true);
-    }
-
-    //This constructor gets the isExpansionEnabled flag for extra handling of a CQL-Like shell
-    public Tokenizer(CharSequence text, Evaluate evaluate, boolean inQuote, boolean isExpansionEnabled)
-    {
-        this.text = text;
-        this.evaluate = evaluate;
-        this.inQuote = inQuote;
-        this.isExpansionEnabled  = isExpansionEnabled;
-        index = 0;
-        line = column = 1;
-
-        boolean array = false;
-
-        if (text instanceof Token)
-        {
-            Token t = (Token) text;
-            line = t.line;
-            column = t.column;
-            array = (Type.ARRAY == t.type);
-        }
-
-        inArray = array;
-        getch();
-
-        if (DEBUG)
-        {
-            if (inArray)
-                System.err.println("Tokenizer[" + text + "]");
-            else
-                System.err.println("Tokenizer<" + text + ">");
-        }
-    }
-
-    public Type type()
-    {
-        return type;
-    }
-
-    public CharSequence value()
-    {
-        return value;
-    }
-
-    public Token token()
-    {
-        return token;
-    }
-
-    public Type next()
-    {
-        final Type prevType = type;
-        token = null;
-        value = null;
-
-        short tLine;
-        short tColumn;
-
-        while (true)
-        {
-            skipSpace();
-            tLine = line;
-            tColumn = column;
-
-            switch (ch)
-            {
-                case EOT:
-                    type = Type.EOT;
-                    break;
-
-                case '\n':
-                    getch();
-                    if (inArray)
-                        continue;
-                    // only return NEWLINE once and not if not preceded by ; or |
-                    switch (prevType)
-                    {
-                        case PIPE:
-                        case SEMICOLON:
-                        case NEWLINE:
-                            continue;
-
-                        default:
-                            type = Type.NEWLINE;
-                            break;
-                    }
-                    break;
-
-                case '{':
-                case '(':
-                case '[':
-                	if (isExpansionEnabled) { //Disabled for CQL
-	                    value = group();
-	                    getch();
-                	} else {
-                		//treat it as normal word
-                		value = word();
-                        type = Type.WORD;
-                	}
-                    break;
-
-                case ';':
-                    getch();
-                    type = Type.SEMICOLON;
-                    break;
-
-                case '|':
-                    getch();
-                    type = Type.PIPE;
-                    break;
-
-                case '=':
-                    if (firstWord || inArray)
-                    {
-                        getch();
-                        type = Type.ASSIGN;
-                        break;
-                    }
-                    // fall through
-                default:
-                    value = word();
-                    type = Type.WORD;
-            }
-
-            firstWord = (Type.WORD == type && (Type.WORD != prevType && Type.ASSIGN != prevType));
-            token = new Token(type, value, tLine, tColumn);
-
-            if (DEBUG)
-            {
-                System.err.print("<" + type + ">");
-                if (Type.EOT == type)
-                {
-                    System.err.println();
-                }
-            }
-
-            return type;
-        }
-    }
-
-    private CharSequence word()
-    {
-        int start = index - 1;
-        int skipCR = 0;
-
-        do
-        {
-            switch (ch)
-            {
-                case '\n':
-                    if (index >= 2 && text.charAt(index - 2) == '\r')
-                        skipCR = 1;
-                    // fall through
-                case '=':
-                    if ((Type.WORD == type || Type.ASSIGN == type) && '=' == ch
-                        && !inArray)
-                        continue;
-                    // fall through
-                case ' ':
-                case '\t':
-                case '|':
-                case ';':
-                    return text.subSequence(start, index - 1 - skipCR);
-
-                case '{':
-                    group();
-                    break;
-
-                case '\\':
-                    escape();
-                    break;
-
-                case '\'':
-                case '"':
-                    skipQuote();
-                    break;
-            }
-        }
-        while (getch() != EOT);
-
-        return text.subSequence(start, index - 1);
-    }
-
-    private CharSequence group()
-    {
-        final char push = ch;
-        final char push2;
-        final char pop;
-        final char pop2;
-
-        switch (ch)
-        {
-            case '{':
-                type = Type.CLOSURE;
-                push2 = 0;
-                pop = '}';
-                pop2 = 0;
-                break;
-            case '(':
-                if (peek() == '(') {
-                    getch();
-                    push2 = '(';
-                    type = Type.EXPR;
-                    pop = ')';
-                    pop2 = ')';
-                } else {
-                    type = Type.EXECUTION;
-                    push2 = 0;
-                    pop = ')';
-                    pop2 = 0;
-                }
-                break;
-            case '[':
-                type = Type.ARRAY;
-                push2 = 0;
-                pop = ']';
-                pop2 = 0;
-                break;
-            default:
-                assert false;
-                push2 = 0;
-                pop = 0;
-                pop2 = 0;
-        }
-
-        short sLine = line;
-        short sCol = column;
-        int start = index;
-        int depth = 1;
-
-        while (true)
-        {
-            boolean comment = false;
-
-            switch (ch)
-            {
-                case '{':
-                case '(':
-                case '[':
-                case '\n':
-                    comment = true;
-                    break;
-            }
-
-            if (getch() == EOT)
-            {
-                throw new EOFError(sLine, sCol, "unexpected EOT looking for matching '"
-                    + pop + "'");
-            }
-
-            // don't recognize comments that start within a word
-            if (comment || isBlank(ch))
-                skipSpace();
-
-            switch (ch)
-            {
-                case '"':
-                case '\'':
-                    skipQuote();
-                    break;
-
-                case '\\':
-                    ch = escape();
-                    break;
-
-                default:
-                    if (push == ch) {
-                        depth++;
-                    }
-                    else if (pop == ch && --depth == 0) {
-                        if (pop2 == 0)
-                            return text.subSequence(start, index - 1);
-                        else if (pop2 == peek()) {
-                            getch();
-                            return text.subSequence(start, index - 2);
-                        }
-                    }
-            }
-        }
-
-    }
-
-    private char escape()
-    {
-        assert '\\' == ch;
-
-        switch (getch())
-        {
-            case 'u':
-                getch();
-                getch();
-                getch();
-                getch();
-
-                if (EOT == ch)
-                {
-                    throw new EOFError(line, column, "unexpected EOT in \\u escape");
-                }
-
-                String u = text.subSequence(index - 4, index).toString();
-
-                try
-                {
-                    return (char) Integer.parseInt(u, 16);
-                }
-                catch (NumberFormatException e)
-                {
-                    throw new SyntaxError(line, column, "bad unicode escape: \\u" + u);
-                }
-
-            case EOT:
-                throw new EOFError(line, column, "unexpected EOT in \\ escape");
-
-            case '\n':
-                return '\0'; // line continuation
-
-            case '\\':
-            case '\'':
-            case '"':
-            case '$':
-                return ch;
-
-            default:
-                return ch;
-        }
-    }
-
-    private void skipQuote()
-    {
-        assert '\'' == ch || '"' == ch;
-        final char quote = ch;
-        final short sLine = line;
-        final short sCol = column;
-
-        while (getch() != EOT)
-        {
-            if (quote == ch)
-                return;
-
-            if ((quote == '"') && ('\\' == ch))
-                escape();
-        }
-
-        throw new EOFError(sLine, sCol, "unexpected EOT looking for matching quote: "
-            + quote);
-    }
-
-    private void skipSpace()
-    {
-        while (true)
-        {
-            while (isBlank(ch))
-            {
-                getch();
-            }
-
-            // skip continuation lines, but not other escapes
-            if (('\\' == ch) && (peek() == '\n'))
-            {
-                getch();
-                getch();
-                continue;
-            }
-
-            // skip comments
-            if (('/' == ch) || ('#' == ch))
-            {
-                if (('#' == ch) || (peek() == '/'))
-                {
-                    while ((getch() != EOT) && ('\n' != ch))
-                    {
-                    }
-                    continue;
-                }
-                else if ('*' == peek())
-                {
-                    short sLine = line;
-                    short sCol = column;
-                    getch();
-
-                    while ((getch() != EOT) && !(('*' == ch) && (peek() == '/')))
-                    {
-                    }
-
-                    if (EOT == ch)
-                    {
-                        throw new EOFError(sLine, sCol,
-                            "unexpected EOT looking for closing comment: */");
-                    }
-
-                    getch();
-                    getch();
-                    continue;
-                }
-            }
-
-            break;
-        }
-    }
-
-    private boolean isBlank(char ch)
-    {
-        return ' ' == ch || '\t' == ch;
-    }
-
-    private boolean isName(char ch)
-    {
-        return Character.isJavaIdentifierPart(ch) && (ch != '$') || ('.' == ch);
-    }
-
-    /**
-     * expand variables, quotes and escapes in word.
-     * @param vars
-     * @return
-     * @throws Exception 
-     */
-    public static Object expand(CharSequence word, Evaluate eval) throws Exception
-    {
-        return expand(word, eval, false);
-    }
-
-    private static Object expand(CharSequence word, Evaluate eval, boolean inQuote) throws Exception
-    {
-        final String special = "$\\\"'";
-        int i = word.length();
-
-        while ((--i >= 0) && (special.indexOf(word.charAt(i)) == -1))
-        {
-        }
-
-        // shortcut if word doesn't contain any special characters
-        if (i < 0)
-            return word;
-
-        return new Tokenizer(word, eval, inQuote).expand();
-    }
-
-    public Object expand(CharSequence word, short line, short column) throws Exception
-    {
-        return expand(new Token(Type.WORD, word, line, column), evaluate, inQuote);
-    }
-
-    private Token word(CharSequence value)
-    {
-        return new Token(Type.WORD, value, line, column);
-    }
-
-    private Object expand() throws Exception
-    {
-        StringBuilder buf = new StringBuilder();
-
-        while (ch != EOT)
-        {
-            int start = index;
-
-            switch (ch)
-            {
-                case '$':
-                    Object val = expandVar();
-
-                    if (EOT == ch && buf.length() == 0)
-                    {
-                        return val;
-                    }
-
-                    if (null != val)
-                    {
-                        buf.append(val);
-                    }
-
-                    continue; // expandVar() has already read next char
-
-                case '\\':
-                    ch = (inQuote && ("u$\\\n\"".indexOf(peek()) == -1)) ? '\\'
-                        : escape();
-
-                    if (ch != '\0') // ignore line continuation
-                    {
-                        buf.append(ch);
-                    }
-
-                    break;
-
-                case '"':
-                    Token ww = word(null);
-                    skipQuote();
-                    ww.value = text.subSequence(start, index - 1);
-                    value = ww;
-                    Object expand = expand(value, evaluate, true);
-
-                    if (eot() && buf.length() == 0 && value == expand)
-                    {
-                        // FELIX-2468 avoid returning CharSequence implementation
-                        return ww.value.toString();
-                    }
-
-                    if (null != expand)
-                    {
-                        buf.append(expand.toString());
-                    }
-                    break;
-
-                case '\'':
-                    if (!inQuote)
-                    {
-                        skipQuote();
-                        value = text.subSequence(start, index - 1);
-
-                        if (eot() && buf.length() == 0)
-                        {
-                            return value;
-                        }
-
-                        buf.append(value);
-                        break;
-                    }
-                    // else fall through
-                default:
-                    buf.append(ch);
-            }
-
-            getch();
-        }
-
-        return buf.toString();
-    }
-
-    private Object expandVar() throws Exception
-    {
-        assert '$' == ch;
-        Object val;
-
-        if (getch() != '{')
-        {
-            if ('(' == ch)
-            {
-                short sLine = line;
-                short sCol = column;
-                if ('(' == peek())
-                {
-                    val = evaluate.eval(new Token(Type.EXPR, group(), sLine, sCol));
-                    getch();
-                }
-                else
-                {
-                    // support $(...) FELIX-2433
-                    val = evaluate.eval(new Token(Type.EXECUTION, group(), sLine, sCol));
-                    getch();
-                }
-            }
-            else
-            {
-                int start = index - 1;
-                while (isName(ch))
-                {
-                    getch();
-                }
-
-                if (index - 1 == start)
-                {
-                    val = "$";
-                }
-                else
-                {
-                    String name = text.subSequence(start, index - 1).toString();
-                    val = evaluate.get(name);
-                }
-            }
-        }
-        else
-        {
-            // ${NAME[[:]-+=?]WORD}
-            short sLine = line;
-            short sCol = column;
-            CharSequence group = group();
-            char c;
-            int i = 0;
-
-            while (i < group.length())
-            {
-                switch (group.charAt(i))
-                {
-                    case ':':
-                    case '-':
-                    case '+':
-                    case '=':
-                    case '?':
-                        break;
-
-                    default:
-                        ++i;
-                        continue;
-                }
-                break;
-            }
-
-            sCol += i;
-
-            String name = String.valueOf(expand(group.subSequence(0, i), sLine, sCol));
-
-            for (int j = 0; j < name.length(); ++j)
-            {
-                if (!isName(name.charAt(j)))
-                {
-                    throw new SyntaxError(sLine, sCol, "bad name: ${" + group + "}");
-                }
-            }
-
-            val = evaluate.get(name);
-
-            if (i < group.length())
-            {
-                c = group.charAt(i++);
-                if (':' == c)
-                {
-                    c = (i < group.length() ? group.charAt(i++) : EOT);
-                }
-
-                CharSequence word = group.subSequence(i, group.length());
-
-                switch (c)
-                {
-                    case '-':
-                    case '=':
-                        if (null == val)
-                        {
-                            val = expand(word, evaluate, false);
-                            if ('=' == c)
-                            {
-                                evaluate.put(name, val);
-                            }
-                        }
-                        break;
-
-                    case '+':
-                        if (null != val)
-                        {
-                            val = expand(word, evaluate, false);
-                        }
-                        break;
-
-                    case '?':
-                        if (null == val)
-                        {
-                            val = expand(word, evaluate, false);
-                            if (null == val || val.toString().length() == 0)
-                            {
-                                val = "parameter not set";
-                            }
-                            throw new IllegalArgumentException(name + ": " + val);
-                        }
-                        break;
-
-                    default:
-                        throw new SyntaxError(sLine, sCol, "bad substitution: ${" + group
-                            + "}");
-                }
-            }
-            getch();
-        }
-
-        return val;
-    }
-
-    /**
-     * returns true if getch() will return EOT
-     * @return
-     */
-    private boolean eot()
-    {
-        return index >= text.length();
-    }
-
-    private char getch()
-    {
-        return ch = getch(false);
-    }
-
-    private char peek()
-    {
-        return getch(true);
-    }
-
-    private char getch(boolean peek)
-    {
-        if (eot())
-        {
-            if (!peek)
-            {
-                ++index;
-                ch = EOT;
-            }
-            return EOT;
-        }
-
-        int current = index;
-        char c = text.charAt(index++);
-
-        if (('\r' == c) && !eot() && (text.charAt(index) == '\n'))
-            c = text.charAt(index++);
-
-        if (peek)
-        {
-            index = current;
-        }
-        else if ('\n' == c)
-        {
-            ++line;
-            column = 0;
-        }
-        else
-            ++column;
-
-        return c;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/api/action/Parsing.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Parsing.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Parsing.java
new file mode 100644
index 0000000..d9808c5
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Parsing.java
@@ -0,0 +1,39 @@
+/*
+ * 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.karaf.shell.api.action;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The @Parsing annotation can be used on a {@link org.apache.karaf.shell.api.action.Command}
+ * to specify a custom {@link org.apache.karaf.shell.api.console.Parser} to use for the command.
+ *
+ * @see org.apache.karaf.shell.api.console.Parser
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Parsing {
+
+    /**
+     * The parser class to use for this command.
+     */
+    Class<?> value();
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
index 4bb1db0..8ac47fc 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
@@ -48,4 +48,11 @@ public interface Command extends Function {
      */
     Completer getCompleter(boolean scoped);
 
+    /**
+     * Retrieve the parser associated with this command or null for the default one.
+     *
+     * @return
+     */
+    Parser getParser();
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/api/console/Parser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Parser.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Parser.java
new file mode 100644
index 0000000..c653c27
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Parser.java
@@ -0,0 +1,28 @@
+/*
+ * 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.karaf.shell.api.console;
+
+/**
+ * A <code>Parser</code> is used by the console to parse a command line.
+ */
+public interface Parser {
+
+    CommandLine parse(Session session, String command, int cursor);
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
index 4cd58ca..9c33d34 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
@@ -22,8 +22,10 @@ import java.util.List;
 
 import org.apache.karaf.shell.api.action.Action;
 import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Parsing;
 import org.apache.karaf.shell.api.console.CommandLine;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Session;
 
 public class ActionCommand implements org.apache.karaf.shell.api.console.Command {
@@ -60,6 +62,15 @@ public class ActionCommand implements org.apache.karaf.shell.api.console.Command
         return new ArgumentCompleter(this, scoped);
     }
 
+    @Override
+    public Parser getParser() {
+        Parsing parsing = actionClass.getAnnotation(Parsing.class);
+        if (parsing != null) {
+            return new DelayedParser(parsing.value());
+        }
+        return null;
+    }
+
     protected Completer getCompleter(Class<?> clazz) {
         return new DelayedCompleter(clazz);
     }
@@ -106,4 +117,21 @@ public class ActionCommand implements org.apache.karaf.shell.api.console.Command
         }
     }
 
+    public static class DelayedParser implements Parser {
+        private final Class<?> clazz;
+
+        public DelayedParser(Class<?> clazz) {
+            this.clazz = clazz;
+        }
+
+        @Override
+        public CommandLine parse(Session session, String command, int cursor) {
+            Object service = session.getRegistry().getService(clazz);
+            if (service instanceof Parser) {
+                return ((Parser) service).parse(session, command, cursor);
+            }
+            throw new IllegalStateException("Could not find specified parser");
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
index 470b4f5..79ee43c 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
@@ -35,6 +35,7 @@ import org.apache.karaf.shell.api.action.lifecycle.Manager;
 import org.apache.karaf.shell.api.action.lifecycle.Reference;
 import org.apache.karaf.shell.api.action.lifecycle.Service;
 import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Parser;
 import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.support.converter.GenericType;
 
@@ -140,7 +141,9 @@ public class ManagerImpl implements Manager {
             }
             registrations.register(command);
         }
-        if (allowCustomServices || Completer.class.isAssignableFrom(clazz)) {
+        if (allowCustomServices
+                || Completer.class.isAssignableFrom(clazz)
+                || Parser.class.isAssignableFrom(clazz)) {
             try {
                 // Create completer
                 Object completer = instantiate(clazz);

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
index e732dfa..49a4420 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
@@ -20,9 +20,10 @@ package org.apache.karaf.shell.impl.console;
 
 import java.util.List;
 
+import org.apache.karaf.shell.api.console.CommandLine;
 import org.apache.karaf.shell.api.console.Completer;
 import org.apache.karaf.shell.api.console.Session;
-import org.apache.karaf.shell.impl.console.parsing.CommandLineImpl;
+import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
 
 public class CompleterAsCompletor implements jline.console.completer.Completer {
 
@@ -36,15 +37,8 @@ public class CompleterAsCompletor implements jline.console.completer.Completer {
 
     @SuppressWarnings("unchecked")
 	public int complete(String buffer, int cursor, @SuppressWarnings("rawtypes") List candidates) {
-        return completer.complete(session, CommandLineImpl.build(buffer, cursor, isExpansionEnabled()), candidates); //CQL-Handling
+        CommandLine cmdLine = CommandLineParser.buildCommandLine(session, buffer, cursor);
+        return completer.complete(session, cmdLine, candidates);
     }
 
-    //special handling for CQL-Shell, disables the brackets from completion
-    private boolean isExpansionEnabled() {
-        Object v = session.get("org.apache.felix.gogo.expansion");
-        if (v != null) {
-            return Boolean.parseBoolean(v.toString());
-        }
-        return true;
-    }
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/cbbed8ac/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
index 3d63123..4ff0c96 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
@@ -53,6 +53,7 @@ import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
 import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
 import org.apache.karaf.shell.support.ShellUtil;
 import org.apache.karaf.shell.support.completers.FileCompleter;
 import org.apache.karaf.shell.support.completers.FileOrUriCompleter;
@@ -358,13 +359,12 @@ public class ConsoleSessionImpl implements Session {
 
     private String readAndParseCommand() throws IOException {
         String command = null;
-        boolean loop = true;
         boolean first = true;
-        while (loop) {
+        while (true) {
             checkInterrupt();
             String line = reader.readLine(first ? getPrompt() : "> ");
             if (line == null) {
-                break;
+                return null;
             }
             if (command == null) {
                 command = line;
@@ -386,24 +386,15 @@ public class ConsoleSessionImpl implements Session {
                 }
             }
             if (command.length() > 0 && command.charAt(command.length() - 1) == '\\') {
-                loop = true;
                 first = false;
             } else {
                 try {
-                    Class<?> cl = CommandSession.class.getClassLoader().loadClass("org.apache.felix.gogo.runtime.Parser");
-                    Object parser = cl.getConstructor(CharSequence.class).newInstance(command);
-                    cl.getMethod("program").invoke(parser);
-                    loop = false;
+                    return CommandLineParser.parse(this, command);
                 } catch (Exception e) {
-                    loop = true;
                     first = false;
-                } catch (Throwable t) {
-                    // Reflection problem ? just quit
-                    loop = false;
                 }
             }
         }
-        return command;
     }
 
     private void executeScript(String scriptFileName) {