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:10 UTC
[2/2] karaf git commit: [KARAF-3455] Support for custom command
parsers
[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) {