You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by cs...@apache.org on 2014/02/24 11:27:59 UTC
[01/11] KARAF-2772 Extracting command-api
Repository: karaf
Updated Branches:
refs/heads/command-api [created] 1ee78df92
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
deleted file mode 100644
index 7cbf05c..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
+++ /dev/null
@@ -1,62 +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.console.completer;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.Completer;
-import org.junit.Test;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-
-public class BooleanCompleterTest extends CompleterTestSupport {
-
- @Test
- public void testCompleteArgumnets() throws Exception {
- CommandSession session = new DummyCommandSession();
- Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
-
- // arg 0
- assertEquals(Arrays.asList("true "), complete(comp, "action t"));
- assertEquals(Arrays.asList("false "), complete(comp, "action f"));
-
- // arg 1
- assertEquals(Arrays.asList("true "), complete(comp, "action false t"));
- assertEquals(Arrays.asList("false "), complete(comp, "action true f"));
-
- // unknown args
- assertEquals(Arrays.asList(), complete(comp, "action c"));
- assertEquals(Arrays.asList(), complete(comp, "action true true a"));
- }
-
- public static class MyAction implements Action {
- @Argument(index = 0)
- Boolean foo;
- @Argument(index = 1)
- boolean bar;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
deleted file mode 100644
index e5341a5..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
+++ /dev/null
@@ -1,34 +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.console.completer;
-
-import org.apache.karaf.shell.console.Completer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Useful base class for completion related test cases
- */
-public abstract class CompleterTestSupport {
- protected List<String> complete(Completer completer, String buf) {
- List<String> candidates = new ArrayList<String>();
- completer.complete(buf, buf.length(), candidates);
- return candidates;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
deleted file mode 100644
index 2ec4a81..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
+++ /dev/null
@@ -1,74 +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.console.completer;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.CompleterValues;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.Completer;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-public class CompleterValuesTest extends CompleterTestSupport {
-
- @Test
- public void testCompleteArgumnets() throws Exception {
- CommandSession session = new DummyCommandSession();
- Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
-
- // arg 0
- assertEquals(Arrays.asList("a1", "a2", "a3"), complete(comp, "action a"));
- assertEquals(Arrays.asList("b4", "b5"), complete(comp, "action b"));
-
- // arg 1
- assertEquals(Arrays.asList("c2", "c3"), complete(comp, "action a1 c"));
- assertEquals(Arrays.asList("d5", "d6", "d7"), complete(comp, "action b4 d"));
-
- // unknown args
- assertEquals(Arrays.asList(), complete(comp, "action c"));
- assertEquals(Arrays.asList(), complete(comp, "action a1 d5 a"));
- }
-
- public static class MyAction implements Action {
- @Argument(index = 0)
- String foo;
- @Argument(index = 1)
- String bar;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
-
- @CompleterValues(index = 0)
- public String[] getFooValues() {
- return new String[]{"a1", "a2", "a3", "b4", "b5"};
- }
-
- @CompleterValues(index = 1)
- public List<String> getBarValues() {
- return Arrays.asList("c2", "c3", "d5", "d6", "d7");
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
deleted file mode 100644
index 25d0485..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
+++ /dev/null
@@ -1,172 +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.console.completer;
-
-import java.util.Arrays;
-
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.basic.Context;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.karaf.shell.commands.basic.SimpleSubShell;
-import org.apache.karaf.shell.console.CommandSessionHolder;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.ExitAction;
-import org.apache.karaf.shell.console.SessionProperties;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class CompletionTest extends CompleterTestSupport {
-
- @Test
- public void testSubShellCompletion() throws Exception {
- Context context = new Context();
- context.set("SCOPE", "*");
- context.set(SessionProperties.COMPLETION_MODE, "subshell");
- CommandSessionHolder.setSession(context.getSession());
-
- context.addCommand("*", new SimpleSubShell("foo"), "foo");
- context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
- context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
- context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
-
- Completer comp = new CommandsCompleter(context.getSession());
-
- context.execute("foo");
- assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
- assertEquals(Arrays.asList("exit ", "my-action ", "one-action "), complete(comp, ""));
- assertEquals(Arrays.asList(), complete(comp, "an"));
- assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
- complete(comp, "my-action --"));
- assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
-
- context.execute("exit");
- assertEquals(Arrays.asList(), complete(comp, "my"));
- assertEquals(Arrays.asList("exit ", "foo "), complete(comp, ""));
- assertEquals(Arrays.asList(), complete(comp, "an"));
- }
-
- @Test
- public void testFirstCompletion() throws Exception {
- Context context = new Context();
- context.set("SCOPE", "*");
- context.set(SessionProperties.COMPLETION_MODE, "first");
- CommandSessionHolder.setSession(context.getSession());
-
- context.addCommand("*", new SimpleSubShell("foo"), "foo");
- context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
- context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
- context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
-
- Completer comp = new CommandsCompleter(context.getSession());
-
- context.execute("foo");
- assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
- assertEquals(Arrays.asList("my-action ", "one-action "), complete(comp, ""));
- assertEquals(Arrays.asList("another "), complete(comp, "an"));
- assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
- complete(comp, "my-action --"));
- assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
-
- context.execute("exit");
- assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
- assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
- "bar:one-action", "exit", "foo",
- "foo:my-action", "foo:one-action", "my-action",
- "one-action", "one-action"), complete(comp, ""));
- assertEquals(Arrays.asList("another "), complete(comp, "an"));
- }
-
- @Test
- public void testGlobalCompletion() throws Exception {
- Context context = new Context();
- context.set("SCOPE", "*");
- context.set(SessionProperties.COMPLETION_MODE, "global");
- CommandSessionHolder.setSession(context.getSession());
-
- context.addCommand("*", new SimpleSubShell("foo"), "foo");
- context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
- context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
- context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
- context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
-
- Completer comp = new CommandsCompleter(context.getSession());
-
- context.execute("foo");
- assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
- assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
- "bar:one-action", "exit", "foo",
- "foo:my-action", "foo:one-action", "my-action",
- "one-action", "one-action"), complete(comp, ""));
- assertEquals(Arrays.asList("another "), complete(comp, "an"));
- assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
- complete(comp, "my-action --"));
- assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
-
- context.execute("exit");
- assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
- assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
- "bar:one-action", "exit", "foo",
- "foo:my-action", "foo:one-action", "my-action",
- "one-action", "one-action"), complete(comp, ""));
- assertEquals(Arrays.asList("another "), complete(comp, "an"));
- }
-
- public static class MyAction implements Action {
- @Option(name = "-f", aliases = { "--foo" })
- int f;
-
- @Option(name = "-c", aliases = "--check")
- boolean check;
-
- @Option(name = "-s", aliases = "--string")
- String string;
-
- @Option(name = "-i", aliases = "--integer")
- String integer;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
- }
-
- public static class MyActionTwoArguments implements Action {
-
- @Option(name = "--dummy")
- boolean dummy;
-
- @Argument(index = 0, name = "one", description = "one description", required = true, multiValued = false)
- private String one;
-
- @Argument(index = 1, name = "two", description = "two description", required = true, multiValued = false)
- private String two;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
-
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
deleted file mode 100644
index ac1a894..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
+++ /dev/null
@@ -1,48 +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.console.completer;
-
-import java.io.InputStream;
-import java.io.PrintStream;
-
-import org.apache.felix.service.command.CommandSession;
-
-public class DummyCommandSession implements CommandSession {
- public Object convert(Class<?> type, Object instance) {
- return null;
- }
- public CharSequence format(Object target, int level) {
- return null;
- }
- public void put(String name, Object value) {
- }
- public Object get(String name) {
- return null;
- }
- public PrintStream getConsole() {
- return null;
- }
- public InputStream getKeyboard() {
- return null;
- }
- public void close() {
- }
- public Object execute(CharSequence commandline) throws Exception {
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
deleted file mode 100644
index 0405371..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
+++ /dev/null
@@ -1,56 +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.console.completer;
-
-import java.io.File;
-import java.util.Arrays;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.Completer;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class FileCompleterTest extends CompleterTestSupport {
-
- @Test
- public void testCompleteArgumnets() throws Exception {
- CommandSession session = new DummyCommandSession();
- Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
-
- // arg 0
- assertEquals(Arrays.asList("src"+File.separator), complete(comp, "action s"));
- assertEquals(Arrays.asList("main"+File.separator), complete(comp, "action src/m"));
- assertEquals(Arrays.asList("java"+File.separator), complete(comp, "action src/main/j"));
- }
-
- public static class MyAction implements Action {
- @Argument(index = 0)
- File foo;
- @Argument(index = 1)
- File bar;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/help/pom.xml
----------------------------------------------------------------------
diff --git a/shell/help/pom.xml b/shell/help/pom.xml
index 2bb514e..3870f36 100644
--- a/shell/help/pom.xml
+++ b/shell/help/pom.xml
@@ -39,17 +39,12 @@
<dependencies>
<dependency>
- <groupId>org.fusesource.jansi</groupId>
- <artifactId>jansi</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.table</artifactId>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.command.api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/help/src/main/java/org/apache/karaf/shell/help/impl/CommandListHelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/help/src/main/java/org/apache/karaf/shell/help/impl/CommandListHelpProvider.java b/shell/help/src/main/java/org/apache/karaf/shell/help/impl/CommandListHelpProvider.java
index 98102c4..6df6c9f 100644
--- a/shell/help/src/main/java/org/apache/karaf/shell/help/impl/CommandListHelpProvider.java
+++ b/shell/help/src/main/java/org/apache/karaf/shell/help/impl/CommandListHelpProvider.java
@@ -25,21 +25,17 @@ import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
-import jline.Terminal;
-
import org.apache.felix.gogo.commands.Action;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.command.Function;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.CommandWithAction;
-import org.apache.karaf.shell.commands.basic.AbstractCommand;
import org.apache.karaf.shell.commands.meta.ActionMetaDataFactory;
import org.apache.karaf.shell.console.HelpProvider;
import org.apache.karaf.shell.console.NameScoping;
import org.apache.karaf.shell.console.SessionProperties;
import org.apache.karaf.shell.table.Col;
import org.apache.karaf.shell.table.ShellTable;
-import org.fusesource.jansi.Ansi;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
@@ -113,10 +109,8 @@ public class CommandListHelpProvider implements HelpProvider {
}
protected void printMethodList(CommandSession session, PrintStream out, SortedMap<String, String> commands) {
- Terminal term = (Terminal) session.get(".jline.terminal");
- int termWidth = term != null ? term.getWidth() : 80;
- out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("COMMANDS").a(Ansi.Attribute.RESET));
- ShellTable table = new ShellTable().noHeaders().separator(" ").size(termWidth);
+ out.println("COMMANDS");
+ ShellTable table = new ShellTable().noHeaders().separator(" ").size(getWidth(session));
table.column(new Col("Command").maxSize(35));
table.column(new Col("Description"));
for (Map.Entry<String,String> entry : commands.entrySet()) {
@@ -126,6 +120,11 @@ public class CommandListHelpProvider implements HelpProvider {
table.print(out, true);
}
+ private int getWidth(CommandSession session) {
+ Object cols = session.get("COLUMNS");
+ return (cols != null && cols instanceof Integer) ? (Integer)cols : 80;
+ }
+
protected Function unProxy(Function function) {
try {
if (function.getClass().getName().contains("CommandProxy")) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/pom.xml
----------------------------------------------------------------------
diff --git a/shell/pom.xml b/shell/pom.xml
index d8dc873..68dd0e8 100644
--- a/shell/pom.xml
+++ b/shell/pom.xml
@@ -34,6 +34,7 @@
<name>Apache Karaf :: Shell</name>
<modules>
+ <module>command-api</module>
<module>commands</module>
<module>console</module>
<module>ssh</module>
[06/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.2.0.xsd
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.2.0.xsd b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.2.0.xsd
new file mode 100644
index 0000000..afc00f4
--- /dev/null
+++ b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.2.0.xsd
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<!-- $Rev: 699828 $ $Date: 2008-09-28 16:35:27 +0200 (Sun, 28 Sep 2008) $ -->
+
+<xsd:schema xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ targetNamespace="http://karaf.apache.org/xmlns/shell/v1.2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
+
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the configuration elements for Apache Karaf commands support.
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="command-bundle">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command bundle.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element ref="command" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="scan" type="Tscan"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:simpleType name="Tscan">
+ <xsd:restriction>
+ <xsd:simpleType>
+ <xsd:list itemType="Tpackage" />
+ </xsd:simpleType>
+ <xsd:minLength value="1" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="Tpackage">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="\*|[a-z]+(\.[a-z]+)+(\.\*)?" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:element name="command">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <!--
+ NOTE: Not using an xsd:choice here, as I can't seem to figure out how to get it to properly
+ validate the min/max of the containted elements. W/o the xsd:choice the validation
+ works, though have to define elements in order :-(
+ -->
+ <xsd:element ref="action" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="documenter" minOccurs="0" maxOccurs="1"/>
+ <xsd:choice minOccurs="0" maxOccurs="1">
+ <xsd:element ref="completer"/>
+ <xsd:element ref="completers"/>
+ </xsd:choice>
+ <xsd:element ref="optional-completers" minOccurs="0" maxOccurs="1"/>
+ <xsd:element ref="message-source" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:group name="commandComponentElements">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid elements for command components. This is based on beans:beanElements,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="argument" type="bp:Targument"/>
+ <xsd:element name="property" type="bp:Tproperty"/>
+ <!--
+ NOTE: This seems to cause schema validation problems... not really sure why
+ <xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
+ -->
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:attributeGroup name="commandComponentAttributes">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid attributes for command components. This is based on beans:beanAttributes,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="class" type="xsd:string"/>
+ <xsd:attribute name="depends-on" type="xsd:string"/>
+ <xsd:attribute name="init-method" type="xsd:string"/>
+ <xsd:attribute name="factory-method" type="xsd:string"/>
+ <xsd:attribute name="factory-bean" type="xsd:string"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:attributeGroup>
+
+ <xsd:complexType name="commandComponent" abstract="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Support for command component elements, which are all basically just beans.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:group ref="commandComponentElements"/>
+ <xsd:attributeGroup ref="commandComponentAttributes"/>
+ </xsd:complexType>
+
+ <xsd:element name="action">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command action.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="documenter">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command documenter.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completer">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command completer.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completers">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable command completer with a set of completers.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element name="bean" type="bp:Tbean"/>
+ <xsd:element name="ref" type="bp:Tref"/>
+ <xsd:element name="null" type="bp:Tnull"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="optional-completers">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable command completer with a set of completers.
+ These completers are used for option value completion.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="bp:TtypedCollection">
+ <xsd:sequence>
+ <xsd:element name="entry" type="bp:TmapEntry" minOccurs="0"
+ maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="key-type" type="bp:Ttype" />
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="message-source">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command message source.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+</xsd:schema>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/Context.java b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
new file mode 100644
index 0000000..e378789
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
@@ -0,0 +1,67 @@
+/*
+ * 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.commands.basic;
+
+import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.gogo.runtime.CommandSessionImpl;
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.felix.service.command.CommandSession;
+
+public class Context extends CommandProcessorImpl
+{
+ public static final String EMPTY = "";
+ CommandSessionImpl session;
+ static ThreadIOImpl threadio;
+
+ static
+ {
+ threadio = new ThreadIOImpl();
+ threadio.start();
+ }
+
+ public Context()
+ {
+ super(threadio);
+ addCommand("shell", this, "addCommand");
+ addCommand("shell", this, "removeCommand");
+ addCommand("shell", this, "eval");
+ session = (CommandSessionImpl) createSession(System.in, System.out, System.err);
+ }
+
+
+ public Object execute(CharSequence source) throws Exception
+ {
+ return session.execute(source);
+ }
+
+ public void set(String name, Object value)
+ {
+ session.put(name, value);
+ }
+
+ public Object get(String name)
+ {
+ return session.get(name);
+ }
+
+ public CommandSession getSession() {
+ return session;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java
new file mode 100644
index 0000000..77e9b57
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.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.commands.basic;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.karaf.shell.console.SubShellAction;
+
+public class SimpleSubShell extends SimpleCommand {
+
+ private final String subshell;
+
+ public SimpleSubShell(String subshell) {
+ super(SubShellAction.class);
+ this.subshell = subshell;
+ }
+
+ @Override
+ public Action createNewAction() {
+ SubShellAction action = (SubShellAction) super.createNewAction();
+ action.setSubShell(subshell);
+ return action;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
new file mode 100644
index 0000000..ce55446
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
@@ -0,0 +1,184 @@
+/*
+ * 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.commands.basic;
+
+import java.util.List;
+import java.util.Arrays;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import junit.framework.TestCase;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.CommandException;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.ExitAction;
+
+public class TestCommands extends TestCase {
+
+ public void testSubShellScope() throws Exception {
+ Context c = new Context();
+ c.set("SCOPE", "*");
+ c.addCommand("*", new SimpleSubShell("foo"), "foo");
+ c.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
+
+ String scope = (String) c.get("SCOPE");
+ c.execute("foo");
+ assertEquals("foo:" + scope, c.get("SCOPE"));
+ c.execute("exit");
+ assertEquals(scope, c.get("SCOPE"));
+ }
+
+ public void testPrompt() throws Exception {
+ Context c = new Context();
+ c.addCommand("echo", this);
+ c.set("USER", "test");
+ c.set("APPLICATION", "karaf");
+ //c.set("SCOPE", "");
+ Object p = c.execute("echo \"@|bold ${USER}|@${APPLICATION}:@|bold ${SCOPE}|> \"");
+ System.out.println("Prompt: " + p);
+ }
+
+ public void testCommand() throws Exception {
+ Context c = new Context();
+ c.addCommand("*", this, "capture");
+ c.addCommand("*", new SimpleCommand(MyAction.class), "my-action");
+
+ // Test help
+ Object help = c.execute("my-action --help | capture");
+ assertTrue(help instanceof String);
+ assertTrue(((String) help).indexOf("My Action") >= 0);
+ assertTrue(((String) help).indexOf("First option") >= 0);
+ assertTrue(((String) help).indexOf("Bundle ids") >= 0);
+
+ // Test required argument
+ try {
+ c.execute("my-action");
+ fail("Action should have thrown an exception because of a missing argument");
+ } catch (CommandException e) {
+ // ignore
+ }
+
+ // Test required argument
+ assertEquals(Arrays.asList(3), c.execute("my-action 3"));
+
+ // Test required argument
+ assertEquals(Arrays.asList(3), c.execute("my-action 3"));
+
+ // Test required argument
+ assertEquals(Arrays.asList(3, 5), c.execute("my-action 3 5"));
+
+ // Test option
+ assertEquals(Arrays.asList(4), c.execute("my-action -i 3"));
+
+ // Test option alias
+ assertEquals(Arrays.asList(4), c.execute("my-action --increment 3"));
+ }
+
+ public void testCommandTwoArguments() throws Exception {
+ Context c = new Context();
+ c.addCommand("*", new SimpleCommand(MyActionTwoArguments.class), "my-action-two-arguments");
+
+ // test required arguments
+ try {
+ c.execute("my-action-two-arguments");
+ fail("Action should have thrown an exception because of a missing argument");
+ } catch (CommandException e) {
+ assertEquals("Argument one is required", e.getMessage());
+ }
+
+ try {
+ c.execute("my-action-two-arguments 1");
+ fail("Action should have thrown an exception because of a missing argument");
+ } catch (CommandException e) {
+ assertEquals("Argument two is required", e.getMessage());
+ }
+
+ c.execute("my-action-two-arguments 1 2");
+ }
+
+ public String capture() throws IOException {
+ StringWriter sw = new StringWriter();
+ BufferedReader rdr = new BufferedReader(new InputStreamReader(System.in));
+ String s = rdr.readLine();
+ while (s != null) {
+ sw.write(s);
+ s = rdr.readLine();
+ }
+ return sw.toString();
+ }
+
+ public CharSequence echo(Object args[]) {
+ if (args == null) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ String del = "";
+ for (Object arg : args) {
+ sb.append(del);
+ if (arg != null) {
+ sb.append(arg);
+ del = " ";
+ }
+ }
+ return sb;
+ }
+
+ @Command(scope = "test", name = "my-action", description = "My Action")
+ public static class MyAction implements Action {
+
+ @Option(name = "-i", aliases = {"--increment"}, description = "First option")
+ private boolean increment;
+
+ @Argument(name = "ids", description = "Bundle ids", required = true, multiValued = true)
+ private List<Integer> ids;
+
+ public Object execute(CommandSession session) throws Exception {
+ if (increment) {
+ for (int i = 0; i < ids.size(); i++) {
+ ids.set(i, ids.get(i) + 1);
+ }
+ }
+ return ids;
+ }
+ }
+
+ @Command(scope = "test", name = "my-action-two-arguments", description = "My Action with two arguments")
+ public static class MyActionTwoArguments implements Action {
+
+ @Argument(index = 0, name = "one", description = "one description", required = true, multiValued = false)
+ private String one;
+
+ @Argument(index = 1, name = "two", description = "two description", required = true, multiValued = false)
+ private String two;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
new file mode 100644
index 0000000..24762f5
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
@@ -0,0 +1,35 @@
+/*
+ * 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.commands.meta;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import junit.framework.TestCase;
+
+import org.apache.karaf.shell.commands.meta.ActionMetaData;
+
+public class TestFormatting extends TestCase {
+
+ public void testFormat() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ActionMetaData.printFormatted(" ", " This is a test with a long paragraph\n\n with an indented paragraph\nAnd another one\n", 20, new PrintStream(baos, true), true);
+ System.err.println(baos.toString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
new file mode 100644
index 0000000..e140ab3
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
@@ -0,0 +1,145 @@
+/**
+ * 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.console.completer;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ArgumentCompleterTest extends CompleterTestSupport {
+
+ @Test
+ public void testParser1() throws Exception {
+ Parser parser = new Parser("echo foo | cat bar ; ta", 23);
+ List<List<List<String>>> p = parser.program();
+ assertEquals(1, parser.c0);
+ assertEquals(0, parser.c1);
+ assertEquals(0, parser.c2);
+ assertEquals(2, parser.c3);
+ }
+
+ @Test
+ public void testParser2() throws Exception {
+ Parser parser = new Parser("echo foo ; cat bar | ta", 23);
+ List<List<List<String>>> p = parser.program();
+ assertEquals(1, parser.c0);
+ assertEquals(1, parser.c1);
+ assertEquals(0, parser.c2);
+ assertEquals(2, parser.c3);
+ }
+
+ @Test
+ public void testParser3() throws Exception {
+ Parser parser = new Parser("echo foo ; cat bar | ta", 22);
+ List<List<List<String>>> p = parser.program();
+ assertEquals(1, parser.c0);
+ assertEquals(1, parser.c1);
+ assertEquals(0, parser.c2);
+ assertEquals(1, parser.c3);
+ }
+
+ @Test
+ public void testParser4() throws Exception {
+ Parser parser = new Parser("echo foo ; cat bar | ta reta", 27);
+ List<List<List<String>>> p = parser.program();
+ assertEquals(1, parser.c0);
+ assertEquals(1, parser.c1);
+ assertEquals(1, parser.c2);
+ assertEquals(3, parser.c3);
+ }
+
+ @Test
+ public void testParser5() throws Exception {
+ Parser parser = new Parser("echo foo ; cat bar | ta reta", 24);
+ List<List<List<String>>> p = parser.program();
+ assertEquals(1, parser.c0);
+ assertEquals(1, parser.c1);
+ assertEquals(1, parser.c2);
+ assertEquals(0, parser.c3);
+ }
+
+ @Test
+ public void testCompleteOptions() throws Exception {
+ CommandSession session = new DummyCommandSession();
+ Completer comp = new ArgumentCompleter(session, new MyFunction(), "my:action");
+ assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string", "-c", "-f","-i","-s"), complete(comp, "action -"));
+ assertEquals(Arrays.asList(), complete(comp, "action --foo "));
+ assertEquals(Arrays.asList("action "), complete(comp, "acti"));
+ assertEquals(Arrays.asList("my:action "), complete(comp, "my:ac"));
+ assertEquals(Arrays.asList("--foo "), complete(comp, "action --f"));
+ assertEquals(Arrays.asList("--help "), complete(comp, "action --h"));
+ assertEquals(Arrays.asList("-c "), complete(comp, "action -c"));
+ assertEquals(Arrays.asList("--check "), complete(comp, "action -f 2 --c"));
+ assertEquals(Arrays.asList("foo1 "), complete(comp, "action -f 2 --check foo1"));
+ assertEquals(Arrays.asList("bar1", "bar2"), complete(comp, "action -f 2 --check foo1 "));
+ assertEquals(Arrays.asList("one", "two"), complete(comp, "action -s "));
+ assertEquals(Arrays.asList("one", "two"), complete(comp, "action --string "));
+ assertEquals(Arrays.asList("two "), complete(comp, "action -s t"));
+ assertEquals(Arrays.asList("1", "2"), complete(comp, "action -i "));
+ assertEquals(Arrays.asList("1", "2"), complete(comp, "action --integer "));
+ assertEquals(Arrays.asList("2 "), complete(comp, "action -i 2"));
+ }
+
+ public static class MyFunction extends SimpleCommand implements CompletableFunction {
+ public MyFunction() {
+ super(MyAction.class);
+ }
+ public List<Completer> getCompleters() {
+ return Arrays.<Completer>asList(
+ new StringsCompleter(Arrays.asList("foo1", "foo2")),
+ new StringsCompleter(Arrays.asList("bar1", "bar2"))
+ );
+ }
+
+ public Map<String,Completer> getOptionalCompleters() {
+ Map<String,Completer> completers = new HashMap<String,Completer>();
+ completers.put("-s",new StringsCompleter(Arrays.asList("one","two")));
+ completers.put("--integer",new StringsCompleter(Arrays.asList("1","2")));
+ return completers;
+ }
+ }
+
+ public static class MyAction implements Action {
+ @Option(name = "-f", aliases = { "--foo" })
+ int f;
+
+ @Option(name = "-c", aliases = "--check")
+ boolean check;
+
+ @Option(name = "-s", aliases = "--string")
+ String string;
+
+ @Option(name = "-i", aliases = "--integer")
+ String integer;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
new file mode 100644
index 0000000..7cbf05c
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/BooleanCompleterTest.java
@@ -0,0 +1,62 @@
+/**
+ *
+ * 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.console.completer;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.Completer;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+
+public class BooleanCompleterTest extends CompleterTestSupport {
+
+ @Test
+ public void testCompleteArgumnets() throws Exception {
+ CommandSession session = new DummyCommandSession();
+ Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
+
+ // arg 0
+ assertEquals(Arrays.asList("true "), complete(comp, "action t"));
+ assertEquals(Arrays.asList("false "), complete(comp, "action f"));
+
+ // arg 1
+ assertEquals(Arrays.asList("true "), complete(comp, "action false t"));
+ assertEquals(Arrays.asList("false "), complete(comp, "action true f"));
+
+ // unknown args
+ assertEquals(Arrays.asList(), complete(comp, "action c"));
+ assertEquals(Arrays.asList(), complete(comp, "action true true a"));
+ }
+
+ public static class MyAction implements Action {
+ @Argument(index = 0)
+ Boolean foo;
+ @Argument(index = 1)
+ boolean bar;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
new file mode 100644
index 0000000..e5341a5
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterTestSupport.java
@@ -0,0 +1,34 @@
+/**
+ *
+ * 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.console.completer;
+
+import org.apache.karaf.shell.console.Completer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Useful base class for completion related test cases
+ */
+public abstract class CompleterTestSupport {
+ protected List<String> complete(Completer completer, String buf) {
+ List<String> candidates = new ArrayList<String>();
+ completer.complete(buf, buf.length(), candidates);
+ return candidates;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
new file mode 100644
index 0000000..2ec4a81
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompleterValuesTest.java
@@ -0,0 +1,74 @@
+/**
+ *
+ * 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.console.completer;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.CompleterValues;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.Completer;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class CompleterValuesTest extends CompleterTestSupport {
+
+ @Test
+ public void testCompleteArgumnets() throws Exception {
+ CommandSession session = new DummyCommandSession();
+ Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
+
+ // arg 0
+ assertEquals(Arrays.asList("a1", "a2", "a3"), complete(comp, "action a"));
+ assertEquals(Arrays.asList("b4", "b5"), complete(comp, "action b"));
+
+ // arg 1
+ assertEquals(Arrays.asList("c2", "c3"), complete(comp, "action a1 c"));
+ assertEquals(Arrays.asList("d5", "d6", "d7"), complete(comp, "action b4 d"));
+
+ // unknown args
+ assertEquals(Arrays.asList(), complete(comp, "action c"));
+ assertEquals(Arrays.asList(), complete(comp, "action a1 d5 a"));
+ }
+
+ public static class MyAction implements Action {
+ @Argument(index = 0)
+ String foo;
+ @Argument(index = 1)
+ String bar;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+
+ @CompleterValues(index = 0)
+ public String[] getFooValues() {
+ return new String[]{"a1", "a2", "a3", "b4", "b5"};
+ }
+
+ @CompleterValues(index = 1)
+ public List<String> getBarValues() {
+ return Arrays.asList("c2", "c3", "d5", "d6", "d7");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
new file mode 100644
index 0000000..25d0485
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/CompletionTest.java
@@ -0,0 +1,172 @@
+/**
+ *
+ * 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.console.completer;
+
+import java.util.Arrays;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.commands.basic.Context;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.karaf.shell.commands.basic.SimpleSubShell;
+import org.apache.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.ExitAction;
+import org.apache.karaf.shell.console.SessionProperties;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class CompletionTest extends CompleterTestSupport {
+
+ @Test
+ public void testSubShellCompletion() throws Exception {
+ Context context = new Context();
+ context.set("SCOPE", "*");
+ context.set(SessionProperties.COMPLETION_MODE, "subshell");
+ CommandSessionHolder.setSession(context.getSession());
+
+ context.addCommand("*", new SimpleSubShell("foo"), "foo");
+ context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
+ context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
+ context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
+
+ Completer comp = new CommandsCompleter(context.getSession());
+
+ context.execute("foo");
+ assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
+ assertEquals(Arrays.asList("exit ", "my-action ", "one-action "), complete(comp, ""));
+ assertEquals(Arrays.asList(), complete(comp, "an"));
+ assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
+ complete(comp, "my-action --"));
+ assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
+
+ context.execute("exit");
+ assertEquals(Arrays.asList(), complete(comp, "my"));
+ assertEquals(Arrays.asList("exit ", "foo "), complete(comp, ""));
+ assertEquals(Arrays.asList(), complete(comp, "an"));
+ }
+
+ @Test
+ public void testFirstCompletion() throws Exception {
+ Context context = new Context();
+ context.set("SCOPE", "*");
+ context.set(SessionProperties.COMPLETION_MODE, "first");
+ CommandSessionHolder.setSession(context.getSession());
+
+ context.addCommand("*", new SimpleSubShell("foo"), "foo");
+ context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
+ context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
+ context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
+
+ Completer comp = new CommandsCompleter(context.getSession());
+
+ context.execute("foo");
+ assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
+ assertEquals(Arrays.asList("my-action ", "one-action "), complete(comp, ""));
+ assertEquals(Arrays.asList("another "), complete(comp, "an"));
+ assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
+ complete(comp, "my-action --"));
+ assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
+
+ context.execute("exit");
+ assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
+ assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
+ "bar:one-action", "exit", "foo",
+ "foo:my-action", "foo:one-action", "my-action",
+ "one-action", "one-action"), complete(comp, ""));
+ assertEquals(Arrays.asList("another "), complete(comp, "an"));
+ }
+
+ @Test
+ public void testGlobalCompletion() throws Exception {
+ Context context = new Context();
+ context.set("SCOPE", "*");
+ context.set(SessionProperties.COMPLETION_MODE, "global");
+ CommandSessionHolder.setSession(context.getSession());
+
+ context.addCommand("*", new SimpleSubShell("foo"), "foo");
+ context.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
+ context.addCommand("foo", new SimpleCommand(MyAction.class), "my-action");
+ context.addCommand("foo", new SimpleCommand(MyActionTwoArguments.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyAction.class), "one-action");
+ context.addCommand("bar", new SimpleCommand(MyActionTwoArguments.class), "another");
+
+ Completer comp = new CommandsCompleter(context.getSession());
+
+ context.execute("foo");
+ assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
+ assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
+ "bar:one-action", "exit", "foo",
+ "foo:my-action", "foo:one-action", "my-action",
+ "one-action", "one-action"), complete(comp, ""));
+ assertEquals(Arrays.asList("another "), complete(comp, "an"));
+ assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string"),
+ complete(comp, "my-action --"));
+ assertEquals(Arrays.asList("--dummy", "--help"), complete(comp, "one-action --"));
+
+ context.execute("exit");
+ assertEquals(Arrays.asList("my-action "), complete(comp, "my"));
+ assertEquals(Arrays.asList("*:exit", "*:foo", "another", "bar:another",
+ "bar:one-action", "exit", "foo",
+ "foo:my-action", "foo:one-action", "my-action",
+ "one-action", "one-action"), complete(comp, ""));
+ assertEquals(Arrays.asList("another "), complete(comp, "an"));
+ }
+
+ public static class MyAction implements Action {
+ @Option(name = "-f", aliases = { "--foo" })
+ int f;
+
+ @Option(name = "-c", aliases = "--check")
+ boolean check;
+
+ @Option(name = "-s", aliases = "--string")
+ String string;
+
+ @Option(name = "-i", aliases = "--integer")
+ String integer;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+ }
+
+ public static class MyActionTwoArguments implements Action {
+
+ @Option(name = "--dummy")
+ boolean dummy;
+
+ @Argument(index = 0, name = "one", description = "one description", required = true, multiValued = false)
+ private String one;
+
+ @Argument(index = 1, name = "two", description = "two description", required = true, multiValued = false)
+ private String two;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
new file mode 100644
index 0000000..ac1a894
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/DummyCommandSession.java
@@ -0,0 +1,48 @@
+/**
+ *
+ * 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.console.completer;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import org.apache.felix.service.command.CommandSession;
+
+public class DummyCommandSession implements CommandSession {
+ public Object convert(Class<?> type, Object instance) {
+ return null;
+ }
+ public CharSequence format(Object target, int level) {
+ return null;
+ }
+ public void put(String name, Object value) {
+ }
+ public Object get(String name) {
+ return null;
+ }
+ public PrintStream getConsole() {
+ return null;
+ }
+ public InputStream getKeyboard() {
+ return null;
+ }
+ public void close() {
+ }
+ public Object execute(CharSequence commandline) throws Exception {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
new file mode 100644
index 0000000..0405371
--- /dev/null
+++ b/shell/command-api/src/test/java/org/apache/karaf/shell/console/completer/FileCompleterTest.java
@@ -0,0 +1,56 @@
+/**
+ *
+ * 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.console.completer;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.basic.SimpleCommand;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.Completer;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class FileCompleterTest extends CompleterTestSupport {
+
+ @Test
+ public void testCompleteArgumnets() throws Exception {
+ CommandSession session = new DummyCommandSession();
+ Completer comp = new ArgumentCompleter(session, new SimpleCommand(MyAction.class), "my:action");
+
+ // arg 0
+ assertEquals(Arrays.asList("src"+File.separator), complete(comp, "action s"));
+ assertEquals(Arrays.asList("main"+File.separator), complete(comp, "action src/m"));
+ assertEquals(Arrays.asList("java"+File.separator), complete(comp, "action src/main/j"));
+ }
+
+ public static class MyAction implements Action {
+ @Argument(index = 0)
+ File foo;
+ @Argument(index = 1)
+ File bar;
+
+ public Object execute(CommandSession session) throws Exception {
+ return null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/commands/pom.xml
----------------------------------------------------------------------
diff --git a/shell/commands/pom.xml b/shell/commands/pom.xml
index 15fb8c7..1e857ca 100644
--- a/shell/commands/pom.xml
+++ b/shell/commands/pom.xml
@@ -40,7 +40,7 @@
<dependencies>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.command.api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/pom.xml
----------------------------------------------------------------------
diff --git a/shell/console/pom.xml b/shell/console/pom.xml
index 6fe1ac0..56f7beb 100644
--- a/shell/console/pom.xml
+++ b/shell/console/pom.xml
@@ -38,6 +38,11 @@
</properties>
<dependencies>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.command.api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
@@ -67,16 +72,6 @@
</dependency>
<dependency>
- <groupId>org.apache.aries.blueprint</groupId>
- <artifactId>org.apache.aries.blueprint.api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.aries.blueprint</groupId>
- <artifactId>org.apache.aries.blueprint.core</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.gogo.runtime</artifactId>
<scope>provided</scope>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/Action.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/Action.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/Action.java
deleted file mode 100644
index 0727f24..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/Action.java
+++ /dev/null
@@ -1,29 +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.commands;
-
-import org.apache.felix.service.command.CommandSession;
-
-@Deprecated
-public interface Action {
-
- Object execute(CommandSession session) throws Exception;
-
-}
-
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/Argument.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/Argument.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/Argument.java
deleted file mode 100644
index 33c15bf..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/Argument.java
+++ /dev/null
@@ -1,49 +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.commands;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-/**
- * Represents a positional argument on a command line (as opposed to an optional named {@link Option}
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-@Deprecated
-public @interface Argument {
-
- public static final String DEFAULT_STRING = "DEFAULT";
-
- String DEFAULT = "##default";
-
- String name() default DEFAULT;
-
- String description() default "";
-
- boolean required() default false;
-
- int index() default 0;
-
- boolean multiValued() default false;
-
- String valueToShowInHelp() default DEFAULT_STRING;
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/Command.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/Command.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/Command.java
deleted file mode 100644
index 10c494a..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/Command.java
+++ /dev/null
@@ -1,53 +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.commands;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-/**
- * Used to denote a class represents a command which is executable within a shell/scope or as a
- * command line process.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-@Deprecated
-public @interface Command {
- /**
- * Returns the scope or sub shell of the command
- */
- String scope();
-
- /**
- * REturns the name of the command if used inside a shell
- */
- String name();
-
- /**
- * Returns the description of the command which is used to generate command line help
- */
- String description() default "";
-
- /**
- * Returns a detailed description of the command
- */
- String detailedDescription() default "";
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandException.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandException.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandException.java
deleted file mode 100644
index 3c02d63..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandException.java
+++ /dev/null
@@ -1,63 +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.commands;
-
-import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
-
-/**
- * Base class for exceptions thrown when executing commands.
- */
-@Deprecated
-public class CommandException extends Exception {
-
- private String help;
-
- public CommandException() {
- }
-
- public CommandException(String message) {
- super(message);
- }
-
- public CommandException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public CommandException(Throwable cause) {
- super(cause);
- }
-
- public CommandException(String help, String message) {
- super(message);
- this.help = help;
- }
-
- public CommandException(String help, String message, Throwable cause) {
- super(message, cause);
- this.help = help;
- }
-
- public String getNiceHelp() {
- return help != null ? help
- : SimpleAnsi.COLOR_RED + "Error executing command: "
- + getMessage() != null ? getMessage() : getClass().getName()
- + SimpleAnsi.COLOR_DEFAULT;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
deleted file mode 100644
index e09cf64..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
+++ /dev/null
@@ -1,32 +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.commands;
-
-import org.apache.felix.service.command.Function;
-
-@Deprecated
-public interface CommandWithAction extends Function {
-
- Class<? extends Action> getActionClass();
-
- Action createNewAction();
-
- void releaseAction(Action action) throws Exception;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
deleted file mode 100644
index 99129e5..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
+++ /dev/null
@@ -1,37 +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.commands;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Represents a method which can return a List or Array of values used for a
- * {@link org.apache.karaf.shell.console.Completer}
- * which is associated with the index of an
- * {@link org.apache.karaf.shell.commands.Argument}
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD, ElementType.FIELD})
-@Deprecated
-public @interface CompleterValues {
- int index() default 0;
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/Option.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/Option.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/Option.java
deleted file mode 100644
index 1ce6f75..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/Option.java
+++ /dev/null
@@ -1,48 +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.commands;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-/**
- * Used to mark an optional named command line option who's name typically starts with "--"
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-@Deprecated
-public @interface Option {
-
- public static final String DEFAULT_STRING = "DEFAULT";
-
- String name();
-
- String[] aliases() default {};
-
- String description() default "";
-
- boolean required() default false;
-
- boolean multiValued() default false;
-
- String valueToShowInHelp() default DEFAULT_STRING;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/SubShell.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/SubShell.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/SubShell.java
deleted file mode 100644
index 0206964..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/SubShell.java
+++ /dev/null
@@ -1,46 +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.commands;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-@Deprecated
-public @interface SubShell {
-
- /**
- * Returns the name of the command if used inside a shell
- */
- String name();
-
- /**
- * Returns the description of the command which is used to generate command line help
- */
- String description() default "";
-
- /**
- * Returns a detailed description of the command
- */
- String detailedDescription() default "";
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
deleted file mode 100644
index 809ed67..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
+++ /dev/null
@@ -1,64 +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.commands.basic;
-
-import java.util.List;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.gogo.commands.CommandWithAction;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Function;
-
-@Deprecated
-public abstract class AbstractCommand implements Function, CommandWithAction {
-
- public Object execute(CommandSession session, List<Object> arguments) throws Exception {
- Action action = createNewAction();
- try {
- if (getPreparator().prepare(action, session, arguments)) {
- return action.execute(session);
- } else {
- return null;
- }
- } finally {
- releaseAction(action);
- }
- }
-
- public Class<? extends Action> getActionClass() {
- return createNewAction().getClass();
- }
-
- public abstract Action createNewAction();
-
- /**
- * Release the used Action.
- * This method has to be overridden for pool based Actions.
- * @param action Action that was executed
- * @throws Exception if something went wrong during the Action release
- */
- public void releaseAction(Action action) throws Exception {
- // Do nothing by default (stateful)
- }
-
- protected ActionPreparator getPreparator() throws Exception {
- return new DefaultActionPreparator();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
deleted file mode 100644
index 65fe24e..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
+++ /dev/null
@@ -1,31 +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.commands.basic;
-
-import java.util.List;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-
-@Deprecated
-public interface ActionPreparator {
-
- boolean prepare(Action action, CommandSession session, List<Object> arguments) throws Exception;
-
-}
[11/11] git commit: KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
KARAF-2772 Extracting command-api
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/1ee78df9
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/1ee78df9
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/1ee78df9
Branch: refs/heads/command-api
Commit: 1ee78df92a1345d2236c0000d22962d69324b787
Parents: 6fdb03b
Author: Christian Schneider <ch...@die-schneider.net>
Authored: Mon Feb 24 11:27:32 2014 +0100
Committer: Christian Schneider <ch...@die-schneider.net>
Committed: Mon Feb 24 11:27:32 2014 +0100
----------------------------------------------------------------------
jaas/modules/pom.xml | 1 +
pom.xml | 5 +
shell/command-api/NOTICE | 71 +++
shell/command-api/pom.xml | 131 +++++
.../karaf/shell/console/branding-ssh.properties | 34 ++
.../karaf/shell/console/branding.properties | 33 ++
.../org/apache/felix/gogo/commands/Action.java | 29 +
.../apache/felix/gogo/commands/Argument.java | 49 ++
.../org/apache/felix/gogo/commands/Command.java | 53 ++
.../felix/gogo/commands/CommandException.java | 63 +++
.../felix/gogo/commands/CommandWithAction.java | 32 ++
.../felix/gogo/commands/CompleterValues.java | 37 ++
.../org/apache/felix/gogo/commands/Option.java | 48 ++
.../apache/felix/gogo/commands/SubShell.java | 46 ++
.../gogo/commands/basic/AbstractCommand.java | 64 +++
.../gogo/commands/basic/ActionPreparator.java | 31 +
.../commands/basic/DefaultActionPreparator.java | 566 ++++++++++++++++++
.../commands/converter/DefaultConverter.java | 402 +++++++++++++
.../gogo/commands/converter/GenericType.java | 196 +++++++
.../gogo/commands/converter/ReifiedType.java | 118 ++++
.../org/apache/karaf/shell/commands/Action.java | 40 ++
.../apache/karaf/shell/commands/Argument.java | 48 ++
.../apache/karaf/shell/commands/Command.java | 53 ++
.../karaf/shell/commands/CommandException.java | 64 +++
.../karaf/shell/commands/CommandWithAction.java | 31 +
.../apache/karaf/shell/commands/Completer.java | 34 ++
.../karaf/shell/commands/CompleterValues.java | 37 ++
.../apache/karaf/shell/commands/HelpOption.java | 54 ++
.../karaf/shell/commands/InfoProvider.java | 30 +
.../org/apache/karaf/shell/commands/Option.java | 46 ++
.../karaf/shell/commands/ansi/SimpleAnsi.java | 28 +
.../shell/commands/basic/AbstractCommand.java | 62 ++
.../shell/commands/basic/ActionPreparator.java | 42 ++
.../commands/basic/DefaultActionPreparator.java | 223 ++++++++
.../shell/commands/basic/SimpleCommand.java | 82 +++
.../commands/converter/DefaultConverter.java | 401 +++++++++++++
.../shell/commands/converter/GenericType.java | 195 +++++++
.../shell/commands/converter/ReifiedType.java | 116 ++++
.../shell/commands/meta/ActionMetaData.java | 296 ++++++++++
.../commands/meta/ActionMetaDataFactory.java | 251 ++++++++
.../karaf/shell/console/AbstractAction.java | 50 ++
.../shell/console/BlueprintContainerAware.java | 27 +
.../karaf/shell/console/BundleContextAware.java | 27 +
.../shell/console/CloseShellException.java | 27 +
.../shell/console/CommandSessionHolder.java | 38 ++
.../shell/console/CompletableFunction.java | 31 +
.../apache/karaf/shell/console/Completer.java | 27 +
.../org/apache/karaf/shell/console/Console.java | 29 +
.../apache/karaf/shell/console/ExitAction.java | 46 ++
.../karaf/shell/console/HelpProvider.java | 26 +
.../karaf/shell/console/MultiException.java | 95 ++++
.../apache/karaf/shell/console/NameScoping.java | 79 +++
.../karaf/shell/console/OsgiCommandSupport.java | 103 ++++
.../karaf/shell/console/SessionProperties.java | 28 +
.../apache/karaf/shell/console/SubShell.java | 38 ++
.../karaf/shell/console/SubShellAction.java | 39 ++
.../console/commands/AnnotatedSubShell.java | 43 ++
.../shell/console/commands/BasicSubShell.java | 51 ++
.../console/commands/BlueprintCommand.java | 110 ++++
.../shell/console/commands/GenericType.java | 195 +++++++
.../console/commands/NamespaceHandler.java | 523 +++++++++++++++++
.../commands/NumberToStringConverter.java | 36 ++
.../console/completer/AggregateCompleter.java | 91 +++
.../console/completer/ArgumentCompleter.java | 567 +++++++++++++++++++
.../completer/CommandNamesCompleter.java | 103 ++++
.../console/completer/CommandsCompleter.java | 321 +++++++++++
.../shell/console/completer/FileCompleter.java | 147 +++++
.../shell/console/completer/NullCompleter.java | 32 ++
.../console/completer/OldArgumentCompleter.java | 448 +++++++++++++++
.../karaf/shell/console/completer/Parser.java | 396 +++++++++++++
.../console/completer/StringsCompleter.java | 103 ++++
.../org/apache/karaf/shell/inject/Destroy.java | 29 +
.../org/apache/karaf/shell/inject/Init.java | 29 +
.../apache/karaf/shell/inject/Reference.java | 29 +
.../org/apache/karaf/shell/inject/Service.java | 29 +
.../blueprint/shell-namespacehandler.xml | 42 ++
.../src/main/resources/OSGI-INF/bundle.info | 14 +
.../console/commands/karaf-shell-1.0.0.xsd | 217 +++++++
.../console/commands/karaf-shell-1.1.0.xsd | 209 +++++++
.../console/commands/karaf-shell-1.2.0.xsd | 225 ++++++++
.../karaf/shell/commands/basic/Context.java | 67 +++
.../shell/commands/basic/SimpleSubShell.java | 39 ++
.../shell/commands/basic/TestCommands.java | 184 ++++++
.../shell/commands/meta/TestFormatting.java | 35 ++
.../completer/ArgumentCompleterTest.java | 145 +++++
.../console/completer/BooleanCompleterTest.java | 62 ++
.../console/completer/CompleterTestSupport.java | 34 ++
.../console/completer/CompleterValuesTest.java | 74 +++
.../shell/console/completer/CompletionTest.java | 172 ++++++
.../console/completer/DummyCommandSession.java | 48 ++
.../console/completer/FileCompleterTest.java | 56 ++
shell/commands/pom.xml | 2 +-
shell/console/pom.xml | 15 +-
.../org/apache/felix/gogo/commands/Action.java | 29 -
.../apache/felix/gogo/commands/Argument.java | 49 --
.../org/apache/felix/gogo/commands/Command.java | 53 --
.../felix/gogo/commands/CommandException.java | 63 ---
.../felix/gogo/commands/CommandWithAction.java | 32 --
.../felix/gogo/commands/CompleterValues.java | 37 --
.../org/apache/felix/gogo/commands/Option.java | 48 --
.../apache/felix/gogo/commands/SubShell.java | 46 --
.../gogo/commands/basic/AbstractCommand.java | 64 ---
.../gogo/commands/basic/ActionPreparator.java | 31 -
.../commands/basic/DefaultActionPreparator.java | 566 ------------------
.../commands/converter/DefaultConverter.java | 402 -------------
.../gogo/commands/converter/GenericType.java | 196 -------
.../gogo/commands/converter/ReifiedType.java | 118 ----
.../org/apache/karaf/shell/commands/Action.java | 40 --
.../apache/karaf/shell/commands/Argument.java | 48 --
.../apache/karaf/shell/commands/Command.java | 53 --
.../karaf/shell/commands/CommandException.java | 64 ---
.../karaf/shell/commands/CommandWithAction.java | 31 -
.../apache/karaf/shell/commands/Completer.java | 34 --
.../karaf/shell/commands/CompleterValues.java | 37 --
.../apache/karaf/shell/commands/HelpOption.java | 54 --
.../karaf/shell/commands/InfoProvider.java | 30 -
.../org/apache/karaf/shell/commands/Option.java | 46 --
.../karaf/shell/commands/ansi/SimpleAnsi.java | 30 -
.../shell/commands/basic/AbstractCommand.java | 62 --
.../shell/commands/basic/ActionPreparator.java | 42 --
.../commands/basic/DefaultActionPreparator.java | 223 --------
.../shell/commands/basic/SimpleCommand.java | 82 ---
.../commands/converter/DefaultConverter.java | 401 -------------
.../shell/commands/converter/GenericType.java | 195 -------
.../shell/commands/converter/ReifiedType.java | 116 ----
.../shell/commands/meta/ActionMetaData.java | 296 ----------
.../commands/meta/ActionMetaDataFactory.java | 251 --------
.../karaf/shell/console/AbstractAction.java | 50 --
.../shell/console/BlueprintContainerAware.java | 27 -
.../karaf/shell/console/BundleContextAware.java | 27 -
.../shell/console/CloseShellException.java | 27 -
.../shell/console/CommandSessionHolder.java | 38 --
.../shell/console/CompletableFunction.java | 31 -
.../apache/karaf/shell/console/Completer.java | 27 -
.../org/apache/karaf/shell/console/Console.java | 29 -
.../apache/karaf/shell/console/ExitAction.java | 46 --
.../karaf/shell/console/HelpProvider.java | 26 -
.../karaf/shell/console/MultiException.java | 95 ----
.../apache/karaf/shell/console/NameScoping.java | 79 ---
.../karaf/shell/console/OsgiCommandSupport.java | 103 ----
.../karaf/shell/console/SessionProperties.java | 28 -
.../apache/karaf/shell/console/SubShell.java | 38 --
.../karaf/shell/console/SubShellAction.java | 39 --
.../console/commands/AnnotatedSubShell.java | 43 --
.../shell/console/commands/BasicSubShell.java | 51 --
.../console/commands/BlueprintCommand.java | 110 ----
.../shell/console/commands/GenericType.java | 195 -------
.../console/commands/NamespaceHandler.java | 523 -----------------
.../commands/NumberToStringConverter.java | 36 --
.../console/completer/AggregateCompleter.java | 91 ---
.../console/completer/ArgumentCompleter.java | 567 -------------------
.../completer/CommandNamesCompleter.java | 103 ----
.../console/completer/CommandsCompleter.java | 321 -----------
.../shell/console/completer/FileCompleter.java | 147 -----
.../shell/console/completer/NullCompleter.java | 32 --
.../console/completer/OldArgumentCompleter.java | 448 ---------------
.../karaf/shell/console/completer/Parser.java | 396 -------------
.../console/completer/StringsCompleter.java | 103 ----
.../org/apache/karaf/shell/inject/Destroy.java | 29 -
.../org/apache/karaf/shell/inject/Init.java | 29 -
.../apache/karaf/shell/inject/Reference.java | 29 -
.../org/apache/karaf/shell/inject/Service.java | 29 -
.../karaf/shell/commands/basic/Context.java | 67 ---
.../shell/commands/basic/SimpleSubShell.java | 39 --
.../shell/commands/basic/TestCommands.java | 184 ------
.../shell/commands/meta/TestFormatting.java | 35 --
.../completer/ArgumentCompleterTest.java | 145 -----
.../console/completer/BooleanCompleterTest.java | 62 --
.../console/completer/CompleterTestSupport.java | 34 --
.../console/completer/CompleterValuesTest.java | 74 ---
.../shell/console/completer/CompletionTest.java | 172 ------
.../console/completer/DummyCommandSession.java | 48 --
.../console/completer/FileCompleterTest.java | 56 --
shell/help/pom.xml | 7 +-
.../help/impl/CommandListHelpProvider.java | 15 +-
shell/pom.xml | 1 +
176 files changed, 9772 insertions(+), 8802 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/jaas/modules/pom.xml
----------------------------------------------------------------------
diff --git a/jaas/modules/pom.xml b/jaas/modules/pom.xml
index a74adc2..908674e 100644
--- a/jaas/modules/pom.xml
+++ b/jaas/modules/pom.xml
@@ -57,6 +57,7 @@
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.fileinstall</artifactId>
+ <scope>provided</scope>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 1b5d4e9..d80d27c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -636,6 +636,11 @@
<dependency>
<groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.command.api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/NOTICE
----------------------------------------------------------------------
diff --git a/shell/command-api/NOTICE b/shell/command-api/NOTICE
new file mode 100644
index 0000000..de8d101
--- /dev/null
+++ b/shell/command-api/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2013 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+OW2 (http://www.ow2.org/).
+Licensed under the BSD License.
+
+This product includes software developed at
+OPS4J (http://www.ops4j.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+Eclipse Foundation (http://www.eclipse.org/).
+Licensed under the EPL.
+
+This product includes software written by
+Antony Lesuisse.
+Licensed under Public Domain.
+
+
+II. Used Software
+
+This product uses software developed at
+FUSE Source (http://www.fusesource.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+AOP Alliance (http://aopalliance.sourceforge.net/).
+Licensed under the Public Domain.
+
+This product uses software developed at
+Tanuki Software (http://www.tanukisoftware.com/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+Jasypt (http://jasypt.sourceforge.net/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+JLine (http://jline.sourceforge.net).
+Licensed under the BSD License.
+
+This product uses software developed at
+SLF4J (http://www.slf4j.org/).
+Licensed under the MIT License.
+
+This product uses software developed at
+SpringSource (http://www.springsource.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software from http://www.json.org.
+Copyright (c) 2002 JSON.org
+
+
+III. License Summary
+- Apache License 2.0
+- BSD License
+- EPL License
+- MIT License
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/pom.xml
----------------------------------------------------------------------
diff --git a/shell/command-api/pom.xml b/shell/command-api/pom.xml
new file mode 100644
index 0000000..7e453f8
--- /dev/null
+++ b/shell/command-api/pom.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <!--
+
+ 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.
+ -->
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>shell</artifactId>
+ <version>3.1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.karaf.shell.command.api</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Karaf :: Shell :: Command :: API</name>
+ <description>Action and Command API, support classes for implementing commands</description>
+
+ <properties>
+ <appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.aries.blueprint</groupId>
+ <artifactId>org.apache.aries.blueprint.api</artifactId>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.aries.blueprint</groupId>
+ <artifactId>org.apache.aries.blueprint.core</artifactId>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.gogo.runtime</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${project.basedir}/src/main/resources</directory>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*.info</include>
+ </includes>
+ </resource>
+ <resource>
+ <directory>${project.basedir}/src/main/filtered-resources</directory>
+ <filtering>true</filtering>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ *
+ </Import-Package>
+ <Export-Package>
+ org.apache.karaf.shell.commands;version=${project.version},
+ org.apache.karaf.shell.commands;version=2.3.0,
+ org.apache.karaf.shell.commands.basic;version=${project.version},
+ org.apache.karaf.shell.commands.basic;version=2.3.0,
+ org.apache.karaf.shell.commands.converter;version=${project.version},
+ org.apache.karaf.shell.commands.converter;version=2.3.0,
+ org.apache.karaf.shell.commands.meta;version=${project.version},
+ org.apache.karaf.shell.commands.meta;version=2.3.0,
+ org.apache.karaf.shell.console;version=${project.version},
+ org.apache.karaf.shell.console;version=2.3.0,
+ org.apache.karaf.shell.console.commands;version=${project.version},
+ org.apache.karaf.shell.console.commands;version=2.3.0,
+ org.apache.karaf.shell.console.completer;version=${project.version},
+ org.apache.karaf.shell.console.completer;version=2.3.0,
+ org.apache.karaf.shell.inject;version=${project.version},
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties b/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties
new file mode 100644
index 0000000..978484b
--- /dev/null
+++ b/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties
@@ -0,0 +1,34 @@
+##
+## 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.
+##
+
+welcome = \
+\u001B[36m __ __ ____ \u001B[0m\r\n\
+\u001B[36m / //_/____ __________ _/ __/ \u001B[0m\r\n\
+\u001B[36m / ,< / __ `/ ___/ __ `/ /_ \u001B[0m\r\n\
+\u001B[36m / /| |/ /_/ / / / /_/ / __/ \u001B[0m\r\n\
+\u001B[36m /_/ |_|\\__,_/_/ \\__,_/_/ \u001B[0m\r\n\
+\r\n\
+\u001B[1m Apache Karaf\u001B[0m (${project.version})\r\n\
+\r\n\
+Hit '\u001B[1m<tab>\u001B[0m' for a list of available commands\r\n\
+ and '\u001B[1m[cmd] --help\u001B[0m' for help on a specific command.\r\n\
+Hit '\u001B[1msystem:shutdown\u001B[0m' to shutdown Karaf.\r\n\
+Hit '\u001B[1m<ctrl-d>\u001B[0m' or type '\u001B[1mlogout\u001B[0m' to disconnect shell from current session.\r\n
+
+
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties b/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties
new file mode 100644
index 0000000..3fbcb0a
--- /dev/null
+++ b/shell/command-api/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties
@@ -0,0 +1,33 @@
+##
+## 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.
+##
+
+welcome = \
+\u001B[36m __ __ ____ \u001B[0m\r\n\
+\u001B[36m / //_/____ __________ _/ __/ \u001B[0m\r\n\
+\u001B[36m / ,< / __ `/ ___/ __ `/ /_ \u001B[0m\r\n\
+\u001B[36m / /| |/ /_/ / / / /_/ / __/ \u001B[0m\r\n\
+\u001B[36m /_/ |_|\\__,_/_/ \\__,_/_/ \u001B[0m\r\n\
+\r\n\
+\u001B[1m Apache Karaf\u001B[0m (${project.version})\r\n\
+\r\n\
+Hit '\u001B[1m<tab>\u001B[0m' for a list of available commands\r\n\
+ and '\u001B[1m[cmd] --help\u001B[0m' for help on a specific command.\r\n\
+Hit '\u001B[1m<ctrl-d>\u001B[0m' or type '\u001B[1msystem:shutdown\u001B[0m' or '\u001B[1mlogout\u001B[0m' to shutdown Karaf.\r\n
+
+
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Action.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Action.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Action.java
new file mode 100644
index 0000000..0727f24
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Action.java
@@ -0,0 +1,29 @@
+/*
+ * 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.commands;
+
+import org.apache.felix.service.command.CommandSession;
+
+@Deprecated
+public interface Action {
+
+ Object execute(CommandSession session) throws Exception;
+
+}
+
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Argument.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Argument.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Argument.java
new file mode 100644
index 0000000..33c15bf
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Argument.java
@@ -0,0 +1,49 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Represents a positional argument on a command line (as opposed to an optional named {@link Option}
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+@Deprecated
+public @interface Argument {
+
+ public static final String DEFAULT_STRING = "DEFAULT";
+
+ String DEFAULT = "##default";
+
+ String name() default DEFAULT;
+
+ String description() default "";
+
+ boolean required() default false;
+
+ int index() default 0;
+
+ boolean multiValued() default false;
+
+ String valueToShowInHelp() default DEFAULT_STRING;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Command.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Command.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Command.java
new file mode 100644
index 0000000..10c494a
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Command.java
@@ -0,0 +1,53 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Used to denote a class represents a command which is executable within a shell/scope or as a
+ * command line process.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Deprecated
+public @interface Command {
+ /**
+ * Returns the scope or sub shell of the command
+ */
+ String scope();
+
+ /**
+ * REturns the name of the command if used inside a shell
+ */
+ String name();
+
+ /**
+ * Returns the description of the command which is used to generate command line help
+ */
+ String description() default "";
+
+ /**
+ * Returns a detailed description of the command
+ */
+ String detailedDescription() default "";
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandException.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandException.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandException.java
new file mode 100644
index 0000000..3c02d63
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandException.java
@@ -0,0 +1,63 @@
+/*
+ * 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.commands;
+
+import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
+
+/**
+ * Base class for exceptions thrown when executing commands.
+ */
+@Deprecated
+public class CommandException extends Exception {
+
+ private String help;
+
+ public CommandException() {
+ }
+
+ public CommandException(String message) {
+ super(message);
+ }
+
+ public CommandException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public CommandException(Throwable cause) {
+ super(cause);
+ }
+
+ public CommandException(String help, String message) {
+ super(message);
+ this.help = help;
+ }
+
+ public CommandException(String help, String message, Throwable cause) {
+ super(message, cause);
+ this.help = help;
+ }
+
+ public String getNiceHelp() {
+ return help != null ? help
+ : SimpleAnsi.COLOR_RED + "Error executing command: "
+ + getMessage() != null ? getMessage() : getClass().getName()
+ + SimpleAnsi.COLOR_DEFAULT;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
new file mode 100644
index 0000000..e09cf64
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CommandWithAction.java
@@ -0,0 +1,32 @@
+/*
+ * 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.commands;
+
+import org.apache.felix.service.command.Function;
+
+@Deprecated
+public interface CommandWithAction extends Function {
+
+ Class<? extends Action> getActionClass();
+
+ Action createNewAction();
+
+ void releaseAction(Action action) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
new file mode 100644
index 0000000..99129e5
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/CompleterValues.java
@@ -0,0 +1,37 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Represents a method which can return a List or Array of values used for a
+ * {@link org.apache.karaf.shell.console.Completer}
+ * which is associated with the index of an
+ * {@link org.apache.karaf.shell.commands.Argument}
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Deprecated
+public @interface CompleterValues {
+ int index() default 0;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Option.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Option.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Option.java
new file mode 100644
index 0000000..1ce6f75
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/Option.java
@@ -0,0 +1,48 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Used to mark an optional named command line option who's name typically starts with "--"
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+@Deprecated
+public @interface Option {
+
+ public static final String DEFAULT_STRING = "DEFAULT";
+
+ String name();
+
+ String[] aliases() default {};
+
+ String description() default "";
+
+ boolean required() default false;
+
+ boolean multiValued() default false;
+
+ String valueToShowInHelp() default DEFAULT_STRING;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/SubShell.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/SubShell.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/SubShell.java
new file mode 100644
index 0000000..0206964
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/SubShell.java
@@ -0,0 +1,46 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+@Deprecated
+public @interface SubShell {
+
+ /**
+ * Returns the name of the command if used inside a shell
+ */
+ String name();
+
+ /**
+ * Returns the description of the command which is used to generate command line help
+ */
+ String description() default "";
+
+ /**
+ * Returns a detailed description of the command
+ */
+ String detailedDescription() default "";
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
new file mode 100644
index 0000000..809ed67
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/AbstractCommand.java
@@ -0,0 +1,64 @@
+/*
+ * 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.commands.basic;
+
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.gogo.commands.CommandWithAction;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+
+@Deprecated
+public abstract class AbstractCommand implements Function, CommandWithAction {
+
+ public Object execute(CommandSession session, List<Object> arguments) throws Exception {
+ Action action = createNewAction();
+ try {
+ if (getPreparator().prepare(action, session, arguments)) {
+ return action.execute(session);
+ } else {
+ return null;
+ }
+ } finally {
+ releaseAction(action);
+ }
+ }
+
+ public Class<? extends Action> getActionClass() {
+ return createNewAction().getClass();
+ }
+
+ public abstract Action createNewAction();
+
+ /**
+ * Release the used Action.
+ * This method has to be overridden for pool based Actions.
+ * @param action Action that was executed
+ * @throws Exception if something went wrong during the Action release
+ */
+ public void releaseAction(Action action) throws Exception {
+ // Do nothing by default (stateful)
+ }
+
+ protected ActionPreparator getPreparator() throws Exception {
+ return new DefaultActionPreparator();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
new file mode 100644
index 0000000..65fe24e
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/ActionPreparator.java
@@ -0,0 +1,31 @@
+/*
+ * 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.commands.basic;
+
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+
+@Deprecated
+public interface ActionPreparator {
+
+ boolean prepare(Action action, CommandSession session, List<Object> arguments) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
new file mode 100644
index 0000000..6b7865e
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
@@ -0,0 +1,566 @@
+/*
+ * 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.commands.basic;
+
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.*;
+import java.io.PrintStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.gogo.commands.CommandException;
+import org.apache.felix.gogo.commands.Option;
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.gogo.commands.converter.DefaultConverter;
+import org.apache.felix.gogo.commands.converter.GenericType;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.NameScoping;
+
+@Deprecated
+public class DefaultActionPreparator implements ActionPreparator {
+
+ public static final Option HELP = new Option() {
+ public String name() {
+ return "--help";
+ }
+
+ public String[] aliases() {
+ return new String[]{};
+ }
+
+ public String description() {
+ return "Display this help message";
+ }
+
+ public boolean required() {
+ return false;
+ }
+
+ public boolean multiValued() {
+ return false;
+ }
+
+ public String valueToShowInHelp() {
+ return Option.DEFAULT_STRING;
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return Option.class;
+ }
+ };
+
+ public boolean prepare(Action action, CommandSession session, List<Object> params) throws Exception {
+ Map<Option, Field> options = new HashMap<Option, Field>();
+ Map<Argument, Field> arguments = new HashMap<Argument, Field>();
+ List<Argument> orderedArguments = new ArrayList<Argument>();
+ // Introspect
+ for (Class type = action.getClass(); type != null; type = type.getSuperclass()) {
+ for (Field field : type.getDeclaredFields()) {
+ Option option = field.getAnnotation(Option.class);
+ if (option != null) {
+ options.put(option, field);
+ }
+ Argument argument = field.getAnnotation(Argument.class);
+ if (argument != null) {
+ if (Argument.DEFAULT.equals(argument.name())) {
+ final Argument delegate = argument;
+ final String name = field.getName();
+ argument = new Argument() {
+ public String name() {
+ return name;
+ }
+
+ public String description() {
+ return delegate.description();
+ }
+
+ public boolean required() {
+ return delegate.required();
+ }
+
+ public int index() {
+ return delegate.index();
+ }
+
+ public boolean multiValued() {
+ return delegate.multiValued();
+ }
+
+ public String valueToShowInHelp() {
+ return delegate.valueToShowInHelp();
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return delegate.annotationType();
+ }
+ };
+ }
+ arguments.put(argument, field);
+ int index = argument.index();
+ while (orderedArguments.size() <= index) {
+ orderedArguments.add(null);
+ }
+ if (orderedArguments.get(index) != null) {
+ throw new IllegalArgumentException("Duplicate argument index: " + index);
+ }
+ orderedArguments.set(index, argument);
+ }
+ }
+ }
+ // Check indexes are correct
+ for (int i = 0; i < orderedArguments.size(); i++) {
+ if (orderedArguments.get(i) == null) {
+ throw new IllegalArgumentException("Missing argument for index: " + i);
+ }
+ }
+ // Populate
+ Map<Option, Object> optionValues = new HashMap<Option, Object>();
+ Map<Argument, Object> argumentValues = new HashMap<Argument, Object>();
+ boolean processOptions = true;
+ int argIndex = 0;
+ for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
+ Object param = it.next();
+ // Check for help
+ if (HELP.name().equals(param) || Arrays.asList(HELP.aliases()).contains(param)) {
+ printUsage(session, action, options, arguments, System.out);
+ return false;
+ }
+ if (processOptions && param instanceof String && ((String) param).startsWith("-")) {
+ boolean isKeyValuePair = ((String) param).indexOf('=') != -1;
+ String name;
+ Object value = null;
+ if (isKeyValuePair) {
+ name = ((String) param).substring(0, ((String) param).indexOf('='));
+ value = ((String) param).substring(((String) param).indexOf('=') + 1);
+ } else {
+ name = (String) param;
+ }
+ Option option = null;
+ for (Option opt : options.keySet()) {
+ if (name.equals(opt.name()) || Arrays.asList(opt.aliases()).contains(name)) {
+ option = opt;
+ break;
+ }
+ }
+ if (option == null) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + " undefined option "
+ + INTENSITY_BOLD + param + INTENSITY_NORMAL
+ + COLOR_DEFAULT,
+ "Undefined option: " + param
+ );
+ } else {
+ throw new CommandException("Undefined option: " + param);
+ }
+ }
+ Field field = options.get(option);
+ if (value == null && (field.getType() == boolean.class || field.getType() == Boolean.class)) {
+ value = Boolean.TRUE;
+ }
+ if (value == null && it.hasNext()) {
+ value = it.next();
+ }
+ if (value == null) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + " missing value for option "
+ + INTENSITY_BOLD + param + INTENSITY_NORMAL
+ + COLOR_DEFAULT,
+ "Missing value for option: " + param
+ );
+ } else {
+ throw new CommandException("Missing value for option: " + param);
+ }
+ }
+ if (option.multiValued()) {
+ List<Object> l = (List<Object>) optionValues.get(option);
+ if (l == null) {
+ l = new ArrayList<Object>();
+ optionValues.put(option, l);
+ }
+ l.add(value);
+ } else {
+ optionValues.put(option, value);
+ }
+ } else {
+ processOptions = false;
+ if (argIndex >= orderedArguments.size()) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + ": too many arguments specified"
+ + INTENSITY_BOLD + param + INTENSITY_NORMAL
+ + COLOR_DEFAULT,
+ "Too many arguments specified"
+ );
+ } else {
+ throw new CommandException("Too many arguments specified");
+ }
+ }
+ Argument argument = orderedArguments.get(argIndex);
+ if (!argument.multiValued()) {
+ argIndex++;
+ }
+ if (argument.multiValued()) {
+ List<Object> l = (List<Object>) argumentValues.get(argument);
+ if (l == null) {
+ l = new ArrayList<Object>();
+ argumentValues.put(argument, l);
+ }
+ l.add(param);
+ } else {
+ argumentValues.put(argument, param);
+ }
+ }
+ }
+ // Check required arguments / options
+ for (Option option : options.keySet()) {
+ if (option.required() && optionValues.get(option) == null) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + ": option "
+ + INTENSITY_BOLD + option.name() + INTENSITY_NORMAL
+ + " is required"
+ + COLOR_DEFAULT,
+ "Option " + option.name() + " is required"
+ );
+ } else {
+ throw new CommandException("Option " + option.name() + " is required");
+ }
+ }
+ }
+ for (Argument argument : orderedArguments) {
+ if (argument.required() && argumentValues.get(argument) == null) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + ": argument "
+ + INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL
+ + " is required"
+ + COLOR_DEFAULT,
+ "Argument " + argument.name() + " is required"
+ );
+ } else {
+ throw new CommandException("Argument " + argument.name() + " is required");
+ }
+ }
+ }
+ // Convert and inject values
+ for (Map.Entry<Option, Object> entry : optionValues.entrySet()) {
+ Field field = options.get(entry.getKey());
+ Object value;
+ try {
+ value = convert(action, session, entry.getValue(), field.getGenericType());
+ } catch (Exception e) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + ": unable to convert option "
+ + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL
+ + " with value '" + entry.getValue() + "' to type "
+ + new GenericType(field.getGenericType()).toString()
+ + COLOR_DEFAULT,
+ "Unable to convert option " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e
+ );
+ } else {
+ throw new CommandException("Unable to convert option " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e);
+ }
+ }
+ field.setAccessible(true);
+ field.set(action, value);
+ }
+ for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) {
+ Field field = arguments.get(entry.getKey());
+ Object value;
+ try {
+ value = convert(action, session, entry.getValue(), field.getGenericType());
+ } catch (Exception e) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+ throw new CommandException(COLOR_RED
+ + "Error executing command "
+ + command.scope() + ":"
+ + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
+ + ": unable to convert argument "
+ + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL
+ + " with value '" + entry.getValue() + "' to type "
+ + new GenericType(field.getGenericType()).toString()
+ + COLOR_DEFAULT,
+ "Unable to convert argument " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e
+ );
+ } else {
+ throw new CommandException("Unable to convert argument " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e);
+ }
+ }
+ field.setAccessible(true);
+ field.set(action, value);
+ }
+ return true;
+ }
+
+ protected void printUsage(CommandSession session, Action action, Map<Option, Field> optionsMap, Map<Argument, Field> argsMap, PrintStream out) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ if (command != null) {
+
+ List<Argument> arguments = new ArrayList<Argument>(argsMap.keySet());
+ Collections.sort(arguments, new Comparator<Argument>() {
+ public int compare(Argument o1, Argument o2) {
+ return Integer.valueOf(o1.index()).compareTo(Integer.valueOf(o2.index()));
+ }
+ });
+ Set<Option> options = new HashSet<Option>(optionsMap.keySet());
+ options.add(HELP);
+ boolean globalScope = NameScoping.isGlobalScope(session, command.scope());
+ if (command != null && (command.description() != null || command.name() != null)) {
+ out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
+ out.print(" ");
+ if (command.name() != null) {
+ if (globalScope) {
+ out.println(INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
+ } else {
+ out.println(command.scope() + ":" + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
+ }
+ out.println();
+ }
+ out.print("\t");
+ out.println(command.description());
+ out.println();
+ }
+ StringBuffer syntax = new StringBuffer();
+ if (command != null) {
+ if (globalScope) {
+ syntax.append(command.name());
+ } else {
+ syntax.append(String.format("%s:%s", command.scope(), command.name()));
+ }
+ }
+ if (options.size() > 0) {
+ syntax.append(" [options]");
+ }
+ if (arguments.size() > 0) {
+ syntax.append(' ');
+ for (Argument argument : arguments) {
+ if (!argument.required()) {
+ syntax.append(String.format("[%s] ", argument.name()));
+ } else {
+ syntax.append(String.format("%s ", argument.name()));
+ }
+ }
+ }
+ int width = getWidth(session);
+ out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(syntax.toString());
+ out.println();
+ if (arguments.size() > 0) {
+ out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL);
+ for (Argument argument : arguments) {
+ out.print(" ");
+ out.println(INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL);
+
+ printFormatted(" ", argument.description(), width, out);
+ if (!argument.required()) {
+ if (argument.valueToShowInHelp() != null && argument.valueToShowInHelp().length() != 0) {
+ try {
+ if (Argument.DEFAULT_STRING.equals(argument.valueToShowInHelp())) {
+ argsMap.get(argument).setAccessible(true);
+ Object o = argsMap.get(argument).get(action);
+ printObjectDefaultsTo(out, o);
+ } else {
+ printDefaultsTo(out, argument.valueToShowInHelp());
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+ }
+ }
+ out.println();
+ }
+ if (options.size() > 0) {
+ out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
+ for (Option option : options) {
+ String opt = option.name();
+ for (String alias : option.aliases()) {
+ opt += ", " + alias;
+ }
+ out.print(" ");
+ out.println(INTENSITY_BOLD + opt + INTENSITY_NORMAL);
+ printFormatted(" ", option.description(), width, out);
+ if (option.valueToShowInHelp() != null && option.valueToShowInHelp().length() != 0) {
+ try {
+ if (Option.DEFAULT_STRING.equals(option.valueToShowInHelp())) {
+ optionsMap.get(option).setAccessible(true);
+ Object o = optionsMap.get(option).get(action);
+ printObjectDefaultsTo(out, o);
+ } else {
+ printDefaultsTo(out, option.valueToShowInHelp());
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+ }
+ out.println();
+ }
+ if (command.detailedDescription().length() > 0) {
+ out.println(INTENSITY_BOLD + "DETAILS" + INTENSITY_NORMAL);
+ String desc = loadDescription(action.getClass(), command.detailedDescription());
+ printFormatted(" ", desc, width, out);
+ }
+ }
+ }
+
+ private void printObjectDefaultsTo(PrintStream out, Object o) {
+ if (o != null
+ && (!(o instanceof Boolean) || ((Boolean) o))
+ && (!(o instanceof Number) || ((Number) o).doubleValue() != 0.0)) {
+ printDefaultsTo(out, o.toString());
+ }
+ }
+
+ private void printDefaultsTo(PrintStream out, String value) {
+ out.print(" (defaults to ");
+ out.print(value);
+ out.println(")");
+ }
+
+ protected String loadDescription(Class clazz, String desc) {
+ if (desc.startsWith("classpath:")) {
+ InputStream is = clazz.getResourceAsStream(desc.substring("classpath:".length()));
+ if (is == null) {
+ is = clazz.getClassLoader().getResourceAsStream(desc.substring("classpath:".length()));
+ }
+ if (is == null) {
+ desc = "Unable to load description from " + desc;
+ } else {
+ try {
+ Reader r = new InputStreamReader(is);
+ StringWriter sw = new StringWriter();
+ int c;
+ while ((c = r.read()) != -1) {
+ sw.append((char) c);
+ }
+ desc = sw.toString();
+ } catch (IOException e) {
+ desc = "Unable to load description from " + desc;
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ return desc;
+ }
+
+ // TODO move this to a helper class?
+ public static void printFormatted(String prefix, String str, int termWidth, PrintStream out) {
+ printFormatted(prefix, str, termWidth, out, true);
+ }
+
+ public static void printFormatted(String prefix, String str, int termWidth, PrintStream out, boolean prefixFirstLine) {
+ int pfxLen = length(prefix);
+ int maxwidth = termWidth - pfxLen;
+ Pattern wrap = Pattern.compile("(\\S\\S{" + maxwidth + ",}|.{1," + maxwidth + "})(\\s+|$)");
+ int cur = 0;
+ while (cur >= 0) {
+ int lst = str.indexOf('\n', cur);
+ String s = (lst >= 0) ? str.substring(cur, lst) : str.substring(cur);
+ if (s.length() == 0) {
+ out.println();
+ } else {
+ Matcher m = wrap.matcher(s);
+ while (m.find()) {
+ if (cur > 0 || prefixFirstLine) {
+ out.print(prefix);
+ }
+ out.println(m.group());
+ }
+ }
+ if (lst >= 0) {
+ cur = lst + 1;
+ } else {
+ break;
+ }
+ }
+ }
+
+ public static int length(String str) {
+ return str.length();
+ }
+
+ protected Object convert(Action action, CommandSession session, Object value, Type toType) throws Exception {
+ if (toType == String.class) {
+ return value != null ? value.toString() : null;
+ }
+ return new DefaultConverter(action.getClass().getClassLoader()).convert(value, toType);
+ }
+
+ private int getWidth(CommandSession session) {
+ Object cols = session.get("COLUMNS");
+ return (cols != null && cols instanceof Integer) ? (Integer)cols : 80;
+ }
+}
[02/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
deleted file mode 100644
index 23f5447..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
+++ /dev/null
@@ -1,103 +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.console.completer;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.CommandSessionHolder;
-import org.apache.karaf.shell.console.Completer;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-
-/**
- * Completes command names
- */
-public class CommandNamesCompleter implements Completer {
-
- public static final String COMMANDS = ".commands";
-
- private CommandSession session;
- private final Set<String> commands = new CopyOnWriteArraySet<String>();
-
- public CommandNamesCompleter() {
- this(CommandSessionHolder.getSession());
- }
-
- public CommandNamesCompleter(CommandSession session) {
- this.session = session;
-
- try {
- new CommandTracker();
- } catch (Throwable t) {
- // Ignore in case we're not in OSGi
- }
- }
-
-
- public int complete(String buffer, int cursor, List<String> candidates) {
- if (session == null) {
- session = CommandSessionHolder.getSession();
- }
- checkData();
- int res = new StringsCompleter(commands).complete(buffer, cursor, candidates);
- Collections.sort(candidates);
- return res;
- }
-
- @SuppressWarnings("unchecked")
- protected void checkData() {
- if (commands.isEmpty()) {
- Set<String> names = new HashSet<String>((Set<String>) session.get(COMMANDS));
- for (String name : names) {
- commands.add(name);
- if (name.indexOf(':') > 0) {
- commands.add(name.substring(0, name.indexOf(':')));
- }
- }
- }
- }
-
- private class CommandTracker {
- public CommandTracker() throws Exception {
- BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
- if (context == null) {
- throw new IllegalStateException("Bundle is stopped");
- }
- ServiceListener listener = new ServiceListener() {
- public void serviceChanged(ServiceEvent event) {
- commands.clear();
- }
- };
- context.addServiceListener(listener,
- String.format("(&(%s=*)(%s=*))",
- CommandProcessor.COMMAND_SCOPE,
- CommandProcessor.COMMAND_FUNCTION));
- }
- }
-
-}
-
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
deleted file mode 100644
index ba95b0c..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
+++ /dev/null
@@ -1,321 +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.console.completer;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.felix.gogo.runtime.CommandProxy;
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.CommandWithAction;
-import org.apache.karaf.shell.console.CommandSessionHolder;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.SessionProperties;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Like the {@link org.apache.karaf.shell.console.completer.CommandsCompleter} but does not use OSGi but is
- * instead used from the non-OSGi {@link org.apache.karaf.shell.console.impl.Main}
- */
-public class CommandsCompleter implements Completer {
-
- public static final String COMMANDS = ".commands";
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CommandsCompleter.class);
-
- private CommandSession session;
- private final Map<String, Completer> globalCompleters = new HashMap<String, Completer>();
- private final Map<String, Completer> localCompleters = new HashMap<String, Completer>();
- private final Set<String> commands = new HashSet<String>();
-
- public CommandsCompleter() {
- this(CommandSessionHolder.getSession());
- }
-
- public CommandsCompleter(CommandSession session) {
- this.session = session;
- try {
- new CommandTracker();
- } catch (Throwable t) {
- // Ignore in case we're not in OSGi
- }
- }
-
-
- public int complete(String buffer, int cursor, List<String> candidates) {
- if (session == null) {
- session = CommandSessionHolder.getSession();
- }
-
- List<String> scopes = getCurrentScopes();
- Map<String, Completer>[] allCompleters = checkData();
- sort(allCompleters, scopes);
-
- String subShell = getCurrentSubShell();
- String completion = getCompletionType();
-
- // SUBSHELL mode
- if ("SUBSHELL".equalsIgnoreCase(completion)) {
- if (subShell.isEmpty()) {
- subShell = "*";
- }
- List<Completer> completers = new ArrayList<Completer>();
- for (String name : allCompleters[1].keySet()) {
- if (name.startsWith(subShell)) {
- completers.add(allCompleters[1].get(name));
- }
- }
- if (!subShell.equals("*")) {
- completers.add(new StringsCompleter(new String[] { "exit" }));
- }
- int res = new AggregateCompleter(completers).complete(buffer, cursor, candidates);
- Collections.sort(candidates);
- return res;
- }
-
- if ("FIRST".equalsIgnoreCase(completion)) {
- if (!subShell.isEmpty()) {
- List<Completer> completers = new ArrayList<Completer>();
- for (String name : allCompleters[1].keySet()) {
- if (name.startsWith(subShell)) {
- completers.add(allCompleters[1].get(name));
- }
- }
- int res = new AggregateCompleter(completers).complete(buffer, cursor, candidates);
- if (!candidates.isEmpty()) {
- Collections.sort(candidates);
- return res;
- }
- }
- List<Completer> compl = new ArrayList<Completer>();
- compl.add(new StringsCompleter(getAliases()));
- compl.addAll(allCompleters[0].values());
- int res = new AggregateCompleter(compl).complete(buffer, cursor, candidates);
- Collections.sort(candidates);
- return res;
- }
-
- List<Completer> compl = new ArrayList<Completer>();
- compl.add(new StringsCompleter(getAliases()));
- compl.addAll(allCompleters[0].values());
- int res = new AggregateCompleter(compl).complete(buffer, cursor, candidates);
- Collections.sort(candidates);
- return res;
- }
-
- protected void sort(Map<String, Completer>[] completers, List<String> scopes) {
- ScopeComparator comparator = new ScopeComparator(scopes);
- for (int i = 0; i < completers.length; i++) {
- Map<String, Completer> map = new TreeMap<String, Completer>(comparator);
- map.putAll(completers[i]);
- completers[i] = map;
- }
- }
-
- protected static class ScopeComparator implements Comparator<String> {
- private final List<String> scopes;
- public ScopeComparator(List<String> scopes) {
- this.scopes = scopes;
- }
- @Override
- public int compare(String o1, String o2) {
- String[] p1 = o1.split(":");
- String[] p2 = o2.split(":");
- int p = 0;
- while (p < p1.length && p < p2.length) {
- int i1 = scopes.indexOf(p1[p]);
- int i2 = scopes.indexOf(p2[p]);
- if (i1 < 0) {
- if (i2 < 0) {
- int c = p1[p].compareTo(p2[p]);
- if (c != 0) {
- return c;
- } else {
- p++;
- }
- } else {
- return +1;
- }
- } else if (i2 < 0) {
- return -1;
- } else if (i1 < i2) {
- return -1;
- } else if (i1 > i2) {
- return +1;
- } else {
- p++;
- }
- }
- return 0;
- }
- }
-
- protected List<String> getCurrentScopes() {
- String scopes = (String) session.get("SCOPE");
- return Arrays.asList(scopes.split(":"));
- }
-
- protected String getCurrentSubShell() {
- String s = (String) session.get("SUBSHELL");
- if (s == null) {
- s = "";
- }
- return s;
- }
-
- protected String getCompletionType() {
- String completion = (String) session.get(SessionProperties.COMPLETION_MODE);
- if (completion == null) {
- completion = "GLOBAL";
- }
- return completion;
- }
-
- protected String stripScope(String name) {
- int index = name.indexOf(":");
- return index > 0 ? name.substring(index + 1) : name;
- }
-
- @SuppressWarnings({
- "unchecked", "deprecation"
- })
- protected Map<String, Completer>[] checkData() {
- // Copy the set to avoid concurrent modification exceptions
- // TODO: fix that in gogo instead
- Set<String> names;
- boolean update;
- synchronized (this) {
- names = new HashSet<String>((Set<String>) session.get(COMMANDS));
- update = !names.equals(commands);
- }
- if (update) {
- // get command aliases
- Set<String> commands = new HashSet<String>();
- Map<String, Completer> global = new HashMap<String, Completer>();
- Map<String, Completer> local = new HashMap<String, Completer>();
-
- // add argument completers for each command
- for (String command : names) {
- String rawCommand = stripScope(command);
- Function function = (Function) session.get(command);
- function = unProxy(function);
- if (function instanceof CommandWithAction) {
- try {
- global.put(command, new ArgumentCompleter(session, (CommandWithAction) function, command));
- local.put(command, new ArgumentCompleter(session, (CommandWithAction) function, rawCommand));
- } catch (Throwable t) {
- LOGGER.debug("Unable to create completers for command '" + command + "'", t);
- }
- }
- else if (function instanceof org.apache.felix.gogo.commands.CommandWithAction) {
- try {
- global.put(command, new OldArgumentCompleter(session, (org.apache.felix.gogo.commands.CommandWithAction) function, command));
- local.put(command, new OldArgumentCompleter(session, (org.apache.felix.gogo.commands.CommandWithAction) function, rawCommand));
- } catch (Throwable t) {
- LOGGER.debug("Unable to create completers for command '" + command + "'", t);
- }
- }
- commands.add(command);
- }
-
- synchronized (this) {
- this.commands.clear();
- this.globalCompleters.clear();
- this.localCompleters.clear();
- this.commands.addAll(commands);
- this.globalCompleters.putAll(global);
- this.localCompleters.putAll(local);
- }
- }
- synchronized (this) {
- return new Map[] {
- new HashMap<String, Completer>(this.globalCompleters),
- new HashMap<String, Completer>(this.localCompleters)
- };
- }
- }
-
- /**
- * Get the aliases defined in the console session.
- *
- * @return the aliases set
- */
- @SuppressWarnings("unchecked")
- private Set<String> getAliases() {
- Set<String> vars = ((Set<String>) session.get(null));
- Set<String> aliases = new HashSet<String>();
- for (String var : vars) {
- Object content = session.get(var);
- if (content != null && "org.apache.felix.gogo.runtime.Closure".equals(content.getClass().getName())) {
- aliases.add(var);
- }
- }
- return aliases;
- }
-
- public static Function unProxy(Function function) {
- if (function == null || function.getClass() != CommandProxy.class) {
- return function;
- }
- CommandProxy proxy = (CommandProxy)function;
- Object target = proxy.getTarget();
- try {
- return target instanceof Function ? (Function)target : function;
- } finally {
- proxy.ungetTarget();
- }
- }
-
- private class CommandTracker {
- public CommandTracker() throws Exception {
- BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
- if (context == null) {
- throw new IllegalStateException("Bundle is stopped");
- }
- ServiceListener listener = new ServiceListener() {
- public void serviceChanged(ServiceEvent event) {
- synchronized (CommandsCompleter.this) {
- commands.clear();
- }
- }
- };
- context.addServiceListener(listener,
- String.format("(&(%s=*)(%s=*))",
- CommandProcessor.COMMAND_SCOPE,
- CommandProcessor.COMMAND_FUNCTION));
- }
- }
-
-}
-
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
deleted file mode 100644
index dbb3034..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
+++ /dev/null
@@ -1,147 +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.console.completer;
-
-import java.io.File;
-import java.util.List;
-
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.Completer;
-
-/**
- * A file name completer takes the buffer and issues a list of
- * potential completions.
- * <p/>
- * This completer tries to behave as similar as possible to
- * <i>bash</i>'s file name completion (using GNU readline)
- * with the following exceptions:
- * <p/>
- * <ul>
- * <li>Candidates that are directories will end with "/"</li>
- * <li>Wildcard regular expressions are not evaluated or replaced</li>
- * <li>The "~" character can be used to represent the user's home,
- * but it cannot complete to other users' homes, since java does
- * not provide any way of determining that easily</li>
- * </ul>
- *
- * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
- * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
- * @since 2.3
- */
-public class FileCompleter implements Completer
-{
- private static String OS = System.getProperty("os.name").toLowerCase();
-
- // TODO: Handle files with spaces in them
-
- private static final boolean OS_IS_WINDOWS = isWindows();
-
- public FileCompleter(CommandSession session) {
- }
-
- public static boolean isWindows() {
- return (OS.indexOf("win") >= 0);
-
- }
-
- public int complete(String buffer, final int cursor, final List<String> candidates) {
- // buffer can be null
- if (candidates == null) {
- return 0;
- }
-
- if (buffer == null) {
- buffer = "";
- }
-
- if (OS_IS_WINDOWS) {
- buffer = buffer.replace('/', '\\');
- }
-
- String translated = buffer;
-
- File homeDir = getUserHome();
-
- // Special character: ~ maps to the user's home directory
- if (translated.startsWith("~" + separator())) {
- translated = homeDir.getPath() + translated.substring(1);
- }
- else if (translated.startsWith("~")) {
- translated = homeDir.getParentFile().getAbsolutePath();
- }
- else if (!(translated.startsWith(separator()))) {
- String cwd = getUserDir().getAbsolutePath();
- translated = cwd + separator() + translated;
- }
-
- File file = new File(translated);
- final File dir;
-
- if (translated.endsWith(separator())) {
- dir = file;
- }
- else {
- dir = file.getParentFile();
- }
-
- File[] entries = dir == null ? new File[0] : dir.listFiles();
-
- return matchFiles(buffer, translated, entries, candidates);
- }
-
- protected String separator() {
- return File.separator;
- }
-
- protected File getUserHome() {
- return new File(System.getProperty("user.home"));
- }
-
- protected File getUserDir() {
- return new File(".");
- }
-
- protected int matchFiles(final String buffer, final String translated, final File[] files, final List<String> candidates) {
- if (files == null) {
- return -1;
- }
-
- int matches = 0;
-
- // first pass: just count the matches
- for (File file : files) {
- if (file.getAbsolutePath().startsWith(translated)) {
- matches++;
- }
- }
- for (File file : files) {
- if (file.getAbsolutePath().startsWith(translated)) {
- CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
- candidates.add(render(file, name).toString());
- }
- }
-
- final int index = buffer.lastIndexOf(separator());
-
- return index + separator().length();
- }
-
- protected CharSequence render(final File file, final CharSequence name) {
- return name;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
deleted file mode 100644
index 13da2df..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
+++ /dev/null
@@ -1,32 +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.console.completer;
-
-import java.util.List;
-
-import org.apache.karaf.shell.console.Completer;
-
-public class NullCompleter implements Completer {
-
- public static final NullCompleter INSTANCE = new NullCompleter();
-
- public int complete(String buffer, int cursor, List<String> candidates) {
- return -1;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
deleted file mode 100644
index 583d6f8..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
+++ /dev/null
@@ -1,448 +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.console.completer;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.gogo.commands.Argument;
-import org.apache.felix.gogo.commands.CommandWithAction;
-import org.apache.felix.gogo.commands.CompleterValues;
-import org.apache.felix.gogo.commands.Option;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.CommandSessionHolder;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.NameScoping;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OldArgumentCompleter implements Completer {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(OldArgumentCompleter.class);
-
- public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
-
- final Completer commandCompleter;
- final Completer optionsCompleter;
- final List<Completer> argsCompleters;
- final Map<String, Completer> optionalCompleters;
- final CommandWithAction function;
- final Map<Option, Field> fields = new HashMap<Option, Field>();
- final Map<String, Option> options = new HashMap<String, Option>();
- final Map<Integer, Field> arguments = new HashMap<Integer, Field>();
- boolean strict = true;
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public OldArgumentCompleter(CommandSession session, CommandWithAction function, String command) {
- this.function = function;
- // Command name completer
- commandCompleter = new StringsCompleter(getNames(session, command));
- // Build options completer
- for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
- for (Field field : type.getDeclaredFields()) {
- Option option = field.getAnnotation(Option.class);
- if (option != null) {
- fields.put(option, field);
- options.put(option.name(), option);
- String[] aliases = option.aliases();
- if (aliases != null) {
- for (String alias : aliases) {
- options.put(alias, option);
- }
- }
- }
- Argument argument = field.getAnnotation(Argument.class);
- if (argument != null) {
- Integer key = argument.index();
- if (arguments.containsKey(key)) {
- LOGGER.warn("Duplicate @Argument annotations on class " + type.getName() + " for index: " + key + " see: " + field);
- } else {
- arguments.put(key, field);
- }
- }
- }
- }
-// options.put(HelpOption.HELP.name(), HelpOption.HELP);
- optionsCompleter = new StringsCompleter(options.keySet());
- // Build arguments completers
- argsCompleters = new ArrayList<Completer>();
-
- if (function instanceof CompletableFunction) {
- Map<String, Completer> opt;
- try {
- //
- opt = ((CompletableFunction) function).getOptionalCompleters();
- } catch (Throwable t) {
- opt = new HashMap<String, Completer>();
- }
- optionalCompleters = opt;
- List<Completer> fcl = ((CompletableFunction) function).getCompleters();
- if (fcl != null) {
- for (Completer c : fcl) {
- argsCompleters.add(c == null ? NullCompleter.INSTANCE : c);
- }
- } else {
- argsCompleters.add(NullCompleter.INSTANCE);
- }
- } else {
- optionalCompleters = new HashMap<String, Completer>();
- final Map<Integer, Method> methods = new HashMap<Integer, Method>();
- for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
- for (Method method : type.getDeclaredMethods()) {
- CompleterValues completerMethod = method.getAnnotation(CompleterValues.class);
- if (completerMethod != null) {
- int index = completerMethod.index();
- Integer key = index;
- if (index >= arguments.size() || index < 0) {
- LOGGER.warn("Index out of range on @CompleterValues on class " + type.getName() + " for index: " + key + " see: " + method);
- }
- if (methods.containsKey(key)) {
- LOGGER.warn("Duplicate @CompleterMethod annotations on class " + type.getName() + " for index: " + key + " see: " + method);
- } else {
- methods.put(key, method);
- }
- }
- }
- }
- for (int i = 0, size = arguments.size(); i < size; i++) {
- Completer argCompleter = NullCompleter.INSTANCE;
- Method method = methods.get(i);
- if (method != null) {
- // lets invoke the method
- Action action = function.createNewAction();
- try {
- Object value = method.invoke(action);
- if (value instanceof String[]) {
- argCompleter = new StringsCompleter((String[]) value);
- } else if (value instanceof Collection) {
- argCompleter = new StringsCompleter((Collection<String>) value);
- } else {
- LOGGER.warn("Could not use value " + value + " as set of completions!");
- }
- } catch (IllegalAccessException e) {
- LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + e, e);
- } catch (InvocationTargetException e) {
- Throwable target = e.getTargetException();
- if (target == null) {
- target = e;
- }
- LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + target, target);
- } finally {
- try {
- function.releaseAction(action);
- } catch (Exception e) {
- LOGGER.warn("Failed to release action: " + action + ". " + e, e);
- }
- }
- } else {
- Field field = arguments.get(i);
- Class<?> type = field.getType();
- if (type.isAssignableFrom(File.class)) {
- argCompleter = new FileCompleter(session);
- } else if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) {
- argCompleter = new StringsCompleter(new String[] {"false", "true"}, false);
- } else if (type.isAssignableFrom(Enum.class)) {
- Set<String> values = new HashSet<String>();
- for (Object o : EnumSet.allOf((Class<Enum>) type)) {
- values.add(o.toString());
- }
- argCompleter = new StringsCompleter(values, false);
- } else {
- // TODO any other completers we can add?
- }
- }
- argsCompleters.add(argCompleter);
- }
- }
- }
-
- private String[] getNames(CommandSession session, String scopedCommand) {
- String command = NameScoping.getCommandNameWithoutGlobalPrefix(session, scopedCommand);
- String[] s = command.split(":");
- if (s.length == 1) {
- return s;
- } else {
- return new String[] { command, s[1] };
- }
- }
-
- /**
- * If true, a completion at argument index N will only succeed
- * if all the completions from 0-(N-1) also succeed.
- */
- public void setStrict(final boolean strict) {
- this.strict = strict;
- }
-
- /**
- * Returns whether a completion at argument index N will succees
- * if all the completions from arguments 0-(N-1) also succeed.
- */
- public boolean getStrict() {
- return this.strict;
- }
-
- public int complete(final String buffer, final int cursor,
- final List<String> candidates) {
- ArgumentList list = delimit(buffer, cursor);
- int argpos = list.getArgumentPosition();
- int argIndex = list.getCursorArgumentIndex();
-
- //Store the argument list so that it can be used by completers.
- CommandSession commandSession = CommandSessionHolder.getSession();
- if(commandSession != null) {
- commandSession.put(ARGUMENTS_LIST,list);
- }
-
- Completer comp = null;
- String[] args = list.getArguments();
- int index = 0;
- // First argument is command name
- if (index < argIndex) {
- // Verify command name
- if (!verifyCompleter(commandCompleter, args[index])) {
- return -1;
- }
- index++;
- } else {
- comp = commandCompleter;
- }
- // Now, check options
- if (comp == null) {
- while (index < argIndex && args[index].startsWith("-")) {
- if (!verifyCompleter(optionsCompleter, args[index])) {
- return -1;
- }
- Option option = options.get(args[index]);
- if (option == null) {
- return -1;
- }
- Field field = fields.get(option);
- if (field != null && field.getType() != boolean.class && field.getType() != Boolean.class) {
- if (++index == argIndex) {
- comp = NullCompleter.INSTANCE;
- }
- }
- index++;
- }
- if (comp == null && index >= argIndex && index < args.length && args[index].startsWith("-")) {
- comp = optionsCompleter;
- }
- }
- //Now check for if last Option has a completer
- int lastAgurmentIndex = argIndex - 1;
- if (lastAgurmentIndex >= 1) {
- Option lastOption = options.get(args[lastAgurmentIndex]);
- if (lastOption != null) {
-
- Field lastField = fields.get(lastOption);
- if (lastField != null && lastField.getType() != boolean.class && lastField.getType() != Boolean.class) {
- Option option = lastField.getAnnotation(Option.class);
- if (option != null) {
- Completer optionValueCompleter = null;
- String name = option.name();
- if (optionalCompleters != null && name != null) {
- optionValueCompleter = optionalCompleters.get(name);
- if (optionValueCompleter == null) {
- String[] aliases = option.aliases();
- if (aliases.length > 0) {
- for (int i = 0; i < aliases.length && optionValueCompleter == null; i++) {
- optionValueCompleter = optionalCompleters.get(option.aliases()[i]);
- }
- }
- }
- }
- if(optionValueCompleter != null) {
- comp = optionValueCompleter;
- }
- }
- }
- }
- }
-
- // Check arguments
- if (comp == null) {
- int indexArg = 0;
- while (index < argIndex) {
- Completer sub = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
- if (!verifyCompleter(sub, args[index])) {
- return -1;
- }
- index++;
- indexArg++;
- }
- comp = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
- }
-
- int ret = comp.complete(list.getCursorArgument(), argpos, candidates);
-
- if (ret == -1) {
- return -1;
- }
-
- int pos = ret + (list.getBufferPosition() - argpos);
-
- /**
- * Special case: when completing in the middle of a line, and the
- * area under the cursor is a delimiter, then trim any delimiters
- * from the candidates, since we do not need to have an extra
- * delimiter.
- *
- * E.g., if we have a completion for "foo", and we
- * enter "f bar" into the buffer, and move to after the "f"
- * and hit TAB, we want "foo bar" instead of "foo bar".
- */
-
- if ((buffer != null) && (cursor != buffer.length()) && isDelimiter(buffer, cursor)) {
- for (int i = 0; i < candidates.size(); i++) {
- String val = candidates.get(i);
-
- while ((val.length() > 0)
- && isDelimiter(val, val.length() - 1)) {
- val = val.substring(0, val.length() - 1);
- }
-
- candidates.set(i, val);
- }
- }
-
- return pos;
- }
-
- protected boolean verifyCompleter(Completer completer, String argument) {
- List<String> candidates = new ArrayList<String>();
- return completer.complete(argument, argument.length(), candidates) != -1 && !candidates.isEmpty();
- }
-
- public ArgumentList delimit(final String buffer, final int cursor) {
- Parser parser = new Parser(buffer, cursor);
- try {
- List<List<List<String>>> program = parser.program();
- List<String> pipe = program.get(parser.c0).get(parser.c1);
- return new ArgumentList(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor);
- } catch (Throwable t) {
- return new ArgumentList(new String[] { buffer }, 0, cursor, cursor);
- }
- }
-
- /**
- * Returns true if the specified character is a whitespace
- * parameter. Check to ensure that the character is not
- * escaped and returns true from
- * {@link #isDelimiterChar}.
- *
- * @param buffer the complete command buffer
- * @param pos the index of the character in the buffer
- * @return true if the character should be a delimiter
- */
- public boolean isDelimiter(final String buffer, final int pos) {
- return !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
- }
-
- public boolean isEscaped(final String buffer, final int pos) {
- return pos > 0 && buffer.charAt(pos) == '\\' && !isEscaped(buffer, pos - 1);
- }
-
- /**
- * The character is a delimiter if it is whitespace, and the
- * preceeding character is not an escape character.
- */
- public boolean isDelimiterChar(String buffer, int pos) {
- return Character.isWhitespace(buffer.charAt(pos));
- }
-
- /**
- * The result of a delimited buffer.
- */
- public static class ArgumentList {
- private String[] arguments;
- private int cursorArgumentIndex;
- private int argumentPosition;
- private int bufferPosition;
-
- /**
- * @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
- */
- public ArgumentList(String[] arguments, int cursorArgumentIndex,
- int argumentPosition, int bufferPosition) {
- this.arguments = arguments;
- this.cursorArgumentIndex = cursorArgumentIndex;
- this.argumentPosition = argumentPosition;
- this.bufferPosition = bufferPosition;
- }
-
- public void setCursorArgumentIndex(int cursorArgumentIndex) {
- this.cursorArgumentIndex = cursorArgumentIndex;
- }
-
- public int getCursorArgumentIndex() {
- return this.cursorArgumentIndex;
- }
-
- public String getCursorArgument() {
- if ((cursorArgumentIndex < 0)
- || (cursorArgumentIndex >= arguments.length)) {
- return null;
- }
-
- return arguments[cursorArgumentIndex];
- }
-
- public void setArgumentPosition(int argumentPosition) {
- this.argumentPosition = argumentPosition;
- }
-
- public int getArgumentPosition() {
- return this.argumentPosition;
- }
-
- public void setArguments(String[] arguments) {
- this.arguments = arguments;
- }
-
- public String[] getArguments() {
- return this.arguments;
- }
-
- public void setBufferPosition(int bufferPosition) {
- this.bufferPosition = bufferPosition;
- }
-
- public int getBufferPosition() {
- return this.bufferPosition;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/Parser.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
deleted file mode 100644
index dcdab7d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
+++ /dev/null
@@ -1,396 +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.console.completer;
-
-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;
-
- public Parser(String text, int cursor) {
- this.text = text;
- this.cursor = cursor;
- }
-
- 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) {
- 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;
- }
- }
-
- 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/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
deleted file mode 100644
index a3f7c6d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
+++ /dev/null
@@ -1,103 +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.console.completer;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import org.apache.karaf.shell.console.Completer;
-
-/**
- * Completer for a set of strings.
- */
-public class StringsCompleter
- implements Completer
-{
- private final SortedSet<String> strings = new TreeSet<String>();
- private final boolean caseSensitive;
-
- public StringsCompleter() {
- this(true);
- }
-
-
- public StringsCompleter(final boolean caseSensitive) {
- this.caseSensitive = caseSensitive;
- }
-
- public StringsCompleter(final Collection<String> strings) {
- this();
- assert strings != null;
- getStrings().addAll(strings);
- }
-
- public StringsCompleter(final String[] strings, boolean caseSensitive) {
- this(Arrays.asList(strings), caseSensitive);
- }
-
- public StringsCompleter(final Collection<String> strings, boolean caseSensitive) {
- this(caseSensitive);
- assert strings != null;
- getStrings().addAll(strings);
- }
-
- public StringsCompleter(final String[] strings) {
- this(Arrays.asList(strings));
- }
-
- public SortedSet<String> getStrings() {
- return strings;
- }
-
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public int complete(String buffer, final int cursor, final List candidates) {
- // buffer could be null
- assert candidates != null;
-
- if (buffer == null) {
- buffer = "";
- }
- if (!caseSensitive) {
- buffer = buffer.toLowerCase();
- }
-
- // KARAF-421, use getStrings() instead strings field.
- SortedSet<String> matches = getStrings().tailSet(buffer);
-
- for (String match : matches) {
- String s = caseSensitive ? match : match.toLowerCase();
- if (!s.startsWith(buffer)) {
- break;
- }
-
- // noinspection unchecked
- candidates.add(match);
- }
-
- if (candidates.size() == 1) {
- // noinspection unchecked
- candidates.set(0, candidates.get(0) + " ");
- }
-
- return candidates.isEmpty() ? -1 : 0;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/inject/Destroy.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/inject/Destroy.java b/shell/console/src/main/java/org/apache/karaf/shell/inject/Destroy.java
deleted file mode 100644
index 4df9fe3..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/inject/Destroy.java
+++ /dev/null
@@ -1,29 +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.inject;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface Destroy {
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/inject/Init.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/inject/Init.java b/shell/console/src/main/java/org/apache/karaf/shell/inject/Init.java
deleted file mode 100644
index 154b883..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/inject/Init.java
+++ /dev/null
@@ -1,29 +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.inject;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD})
-public @interface Init {
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/inject/Reference.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/inject/Reference.java b/shell/console/src/main/java/org/apache/karaf/shell/inject/Reference.java
deleted file mode 100644
index b74d609..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/inject/Reference.java
+++ /dev/null
@@ -1,29 +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.inject;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-public @interface Reference {
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/inject/Service.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/inject/Service.java b/shell/console/src/main/java/org/apache/karaf/shell/inject/Service.java
deleted file mode 100644
index ff3f3a3..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/inject/Service.java
+++ /dev/null
@@ -1,29 +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.inject;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Service {
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/Context.java b/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
deleted file mode 100644
index e378789..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/Context.java
+++ /dev/null
@@ -1,67 +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.commands.basic;
-
-import org.apache.felix.gogo.runtime.CommandProcessorImpl;
-import org.apache.felix.gogo.runtime.CommandSessionImpl;
-import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
-import org.apache.felix.service.command.CommandSession;
-
-public class Context extends CommandProcessorImpl
-{
- public static final String EMPTY = "";
- CommandSessionImpl session;
- static ThreadIOImpl threadio;
-
- static
- {
- threadio = new ThreadIOImpl();
- threadio.start();
- }
-
- public Context()
- {
- super(threadio);
- addCommand("shell", this, "addCommand");
- addCommand("shell", this, "removeCommand");
- addCommand("shell", this, "eval");
- session = (CommandSessionImpl) createSession(System.in, System.out, System.err);
- }
-
-
- public Object execute(CharSequence source) throws Exception
- {
- return session.execute(source);
- }
-
- public void set(String name, Object value)
- {
- session.put(name, value);
- }
-
- public Object get(String name)
- {
- return session.get(name);
- }
-
- public CommandSession getSession() {
- return session;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java b/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java
deleted file mode 100644
index 77e9b57..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/SimpleSubShell.java
+++ /dev/null
@@ -1,39 +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.commands.basic;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.karaf.shell.console.SubShellAction;
-
-public class SimpleSubShell extends SimpleCommand {
-
- private final String subshell;
-
- public SimpleSubShell(String subshell) {
- super(SubShellAction.class);
- this.subshell = subshell;
- }
-
- @Override
- public Action createNewAction() {
- SubShellAction action = (SubShellAction) super.createNewAction();
- action.setSubShell(subshell);
- return action;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java b/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
deleted file mode 100644
index ce55446..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/commands/basic/TestCommands.java
+++ /dev/null
@@ -1,184 +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.commands.basic;
-
-import java.util.List;
-import java.util.Arrays;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-
-import junit.framework.TestCase;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.CommandException;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.ExitAction;
-
-public class TestCommands extends TestCase {
-
- public void testSubShellScope() throws Exception {
- Context c = new Context();
- c.set("SCOPE", "*");
- c.addCommand("*", new SimpleSubShell("foo"), "foo");
- c.addCommand("*", new SimpleCommand(ExitAction.class), "exit");
-
- String scope = (String) c.get("SCOPE");
- c.execute("foo");
- assertEquals("foo:" + scope, c.get("SCOPE"));
- c.execute("exit");
- assertEquals(scope, c.get("SCOPE"));
- }
-
- public void testPrompt() throws Exception {
- Context c = new Context();
- c.addCommand("echo", this);
- c.set("USER", "test");
- c.set("APPLICATION", "karaf");
- //c.set("SCOPE", "");
- Object p = c.execute("echo \"@|bold ${USER}|@${APPLICATION}:@|bold ${SCOPE}|> \"");
- System.out.println("Prompt: " + p);
- }
-
- public void testCommand() throws Exception {
- Context c = new Context();
- c.addCommand("*", this, "capture");
- c.addCommand("*", new SimpleCommand(MyAction.class), "my-action");
-
- // Test help
- Object help = c.execute("my-action --help | capture");
- assertTrue(help instanceof String);
- assertTrue(((String) help).indexOf("My Action") >= 0);
- assertTrue(((String) help).indexOf("First option") >= 0);
- assertTrue(((String) help).indexOf("Bundle ids") >= 0);
-
- // Test required argument
- try {
- c.execute("my-action");
- fail("Action should have thrown an exception because of a missing argument");
- } catch (CommandException e) {
- // ignore
- }
-
- // Test required argument
- assertEquals(Arrays.asList(3), c.execute("my-action 3"));
-
- // Test required argument
- assertEquals(Arrays.asList(3), c.execute("my-action 3"));
-
- // Test required argument
- assertEquals(Arrays.asList(3, 5), c.execute("my-action 3 5"));
-
- // Test option
- assertEquals(Arrays.asList(4), c.execute("my-action -i 3"));
-
- // Test option alias
- assertEquals(Arrays.asList(4), c.execute("my-action --increment 3"));
- }
-
- public void testCommandTwoArguments() throws Exception {
- Context c = new Context();
- c.addCommand("*", new SimpleCommand(MyActionTwoArguments.class), "my-action-two-arguments");
-
- // test required arguments
- try {
- c.execute("my-action-two-arguments");
- fail("Action should have thrown an exception because of a missing argument");
- } catch (CommandException e) {
- assertEquals("Argument one is required", e.getMessage());
- }
-
- try {
- c.execute("my-action-two-arguments 1");
- fail("Action should have thrown an exception because of a missing argument");
- } catch (CommandException e) {
- assertEquals("Argument two is required", e.getMessage());
- }
-
- c.execute("my-action-two-arguments 1 2");
- }
-
- public String capture() throws IOException {
- StringWriter sw = new StringWriter();
- BufferedReader rdr = new BufferedReader(new InputStreamReader(System.in));
- String s = rdr.readLine();
- while (s != null) {
- sw.write(s);
- s = rdr.readLine();
- }
- return sw.toString();
- }
-
- public CharSequence echo(Object args[]) {
- if (args == null) {
- return "";
- }
-
- StringBuilder sb = new StringBuilder();
- String del = "";
- for (Object arg : args) {
- sb.append(del);
- if (arg != null) {
- sb.append(arg);
- del = " ";
- }
- }
- return sb;
- }
-
- @Command(scope = "test", name = "my-action", description = "My Action")
- public static class MyAction implements Action {
-
- @Option(name = "-i", aliases = {"--increment"}, description = "First option")
- private boolean increment;
-
- @Argument(name = "ids", description = "Bundle ids", required = true, multiValued = true)
- private List<Integer> ids;
-
- public Object execute(CommandSession session) throws Exception {
- if (increment) {
- for (int i = 0; i < ids.size(); i++) {
- ids.set(i, ids.get(i) + 1);
- }
- }
- return ids;
- }
- }
-
- @Command(scope = "test", name = "my-action-two-arguments", description = "My Action with two arguments")
- public static class MyActionTwoArguments implements Action {
-
- @Argument(index = 0, name = "one", description = "one description", required = true, multiValued = false)
- private String one;
-
- @Argument(index = 1, name = "two", description = "two description", required = true, multiValued = false)
- private String two;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
-
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java b/shell/console/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
deleted file mode 100644
index 24762f5..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/commands/meta/TestFormatting.java
+++ /dev/null
@@ -1,35 +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.commands.meta;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-
-import junit.framework.TestCase;
-
-import org.apache.karaf.shell.commands.meta.ActionMetaData;
-
-public class TestFormatting extends TestCase {
-
- public void testFormat() throws Exception {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ActionMetaData.printFormatted(" ", " This is a test with a long paragraph\n\n with an indented paragraph\nAnd another one\n", 20, new PrintStream(baos, true), true);
- System.err.println(baos.toString());
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
----------------------------------------------------------------------
diff --git a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java b/shell/console/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
deleted file mode 100644
index e140ab3..0000000
--- a/shell/console/src/test/java/org/apache/karaf/shell/console/completer/ArgumentCompleterTest.java
+++ /dev/null
@@ -1,145 +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.console.completer;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.basic.SimpleCommand;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.console.Completer;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class ArgumentCompleterTest extends CompleterTestSupport {
-
- @Test
- public void testParser1() throws Exception {
- Parser parser = new Parser("echo foo | cat bar ; ta", 23);
- List<List<List<String>>> p = parser.program();
- assertEquals(1, parser.c0);
- assertEquals(0, parser.c1);
- assertEquals(0, parser.c2);
- assertEquals(2, parser.c3);
- }
-
- @Test
- public void testParser2() throws Exception {
- Parser parser = new Parser("echo foo ; cat bar | ta", 23);
- List<List<List<String>>> p = parser.program();
- assertEquals(1, parser.c0);
- assertEquals(1, parser.c1);
- assertEquals(0, parser.c2);
- assertEquals(2, parser.c3);
- }
-
- @Test
- public void testParser3() throws Exception {
- Parser parser = new Parser("echo foo ; cat bar | ta", 22);
- List<List<List<String>>> p = parser.program();
- assertEquals(1, parser.c0);
- assertEquals(1, parser.c1);
- assertEquals(0, parser.c2);
- assertEquals(1, parser.c3);
- }
-
- @Test
- public void testParser4() throws Exception {
- Parser parser = new Parser("echo foo ; cat bar | ta reta", 27);
- List<List<List<String>>> p = parser.program();
- assertEquals(1, parser.c0);
- assertEquals(1, parser.c1);
- assertEquals(1, parser.c2);
- assertEquals(3, parser.c3);
- }
-
- @Test
- public void testParser5() throws Exception {
- Parser parser = new Parser("echo foo ; cat bar | ta reta", 24);
- List<List<List<String>>> p = parser.program();
- assertEquals(1, parser.c0);
- assertEquals(1, parser.c1);
- assertEquals(1, parser.c2);
- assertEquals(0, parser.c3);
- }
-
- @Test
- public void testCompleteOptions() throws Exception {
- CommandSession session = new DummyCommandSession();
- Completer comp = new ArgumentCompleter(session, new MyFunction(), "my:action");
- assertEquals(Arrays.asList("--check", "--foo", "--help", "--integer", "--string", "-c", "-f","-i","-s"), complete(comp, "action -"));
- assertEquals(Arrays.asList(), complete(comp, "action --foo "));
- assertEquals(Arrays.asList("action "), complete(comp, "acti"));
- assertEquals(Arrays.asList("my:action "), complete(comp, "my:ac"));
- assertEquals(Arrays.asList("--foo "), complete(comp, "action --f"));
- assertEquals(Arrays.asList("--help "), complete(comp, "action --h"));
- assertEquals(Arrays.asList("-c "), complete(comp, "action -c"));
- assertEquals(Arrays.asList("--check "), complete(comp, "action -f 2 --c"));
- assertEquals(Arrays.asList("foo1 "), complete(comp, "action -f 2 --check foo1"));
- assertEquals(Arrays.asList("bar1", "bar2"), complete(comp, "action -f 2 --check foo1 "));
- assertEquals(Arrays.asList("one", "two"), complete(comp, "action -s "));
- assertEquals(Arrays.asList("one", "two"), complete(comp, "action --string "));
- assertEquals(Arrays.asList("two "), complete(comp, "action -s t"));
- assertEquals(Arrays.asList("1", "2"), complete(comp, "action -i "));
- assertEquals(Arrays.asList("1", "2"), complete(comp, "action --integer "));
- assertEquals(Arrays.asList("2 "), complete(comp, "action -i 2"));
- }
-
- public static class MyFunction extends SimpleCommand implements CompletableFunction {
- public MyFunction() {
- super(MyAction.class);
- }
- public List<Completer> getCompleters() {
- return Arrays.<Completer>asList(
- new StringsCompleter(Arrays.asList("foo1", "foo2")),
- new StringsCompleter(Arrays.asList("bar1", "bar2"))
- );
- }
-
- public Map<String,Completer> getOptionalCompleters() {
- Map<String,Completer> completers = new HashMap<String,Completer>();
- completers.put("-s",new StringsCompleter(Arrays.asList("one","two")));
- completers.put("--integer",new StringsCompleter(Arrays.asList("1","2")));
- return completers;
- }
- }
-
- public static class MyAction implements Action {
- @Option(name = "-f", aliases = { "--foo" })
- int f;
-
- @Option(name = "-c", aliases = "--check")
- boolean check;
-
- @Option(name = "-s", aliases = "--string")
- String string;
-
- @Option(name = "-i", aliases = "--integer")
- String integer;
-
- public Object execute(CommandSession session) throws Exception {
- return null;
- }
- }
-
-}
[04/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
deleted file mode 100644
index 3ad8d29..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
+++ /dev/null
@@ -1,223 +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.commands.basic;
-
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_DEFAULT;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_RED;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.CommandException;
-import org.apache.karaf.shell.commands.HelpOption;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.converter.DefaultConverter;
-import org.apache.karaf.shell.commands.converter.GenericType;
-import org.apache.karaf.shell.commands.meta.ActionMetaData;
-import org.apache.karaf.shell.commands.meta.ActionMetaDataFactory;
-import org.apache.karaf.shell.console.NameScoping;
-
-public class DefaultActionPreparator implements ActionPreparator {
-
- public boolean prepare(Action action, CommandSession session, List<Object> params) throws Exception {
- ActionMetaData actionMetaData = new ActionMetaDataFactory().create(action.getClass());
- Map<Option, Field> options = actionMetaData.getOptions();
- Map<Argument, Field> arguments = actionMetaData.getArguments();
- List<Argument> orderedArguments = actionMetaData.getOrderedArguments();
- Command command2 = actionMetaData.getCommand();
-
- if (command2 == null) {
- // to avoid NPE with subshell
- return true;
- }
-
- String commandErrorSt = (command2 != null) ? COLOR_RED
- + "Error executing command " + command2.scope() + ":"
- + INTENSITY_BOLD + command2.name() + INTENSITY_NORMAL
- + COLOR_DEFAULT + ": " : "";
- for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
- Object param = it.next();
- if (HelpOption.HELP.name().equals(param)) {
- int termWidth = getWidth(session);
- boolean globalScope = NameScoping.isGlobalScope(session, actionMetaData.getCommand().scope());
- actionMetaData.printUsage(action, System.out, globalScope, termWidth);
- return false;
- }
- }
-
- // Populate
- Map<Option, Object> optionValues = new HashMap<Option, Object>();
- Map<Argument, Object> argumentValues = new HashMap<Argument, Object>();
- boolean processOptions = true;
- int argIndex = 0;
- for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
- Object param = it.next();
-
- if (processOptions && param instanceof String && ((String) param).startsWith("-")) {
- boolean isKeyValuePair = ((String) param).indexOf('=') != -1;
- String name;
- Object value = null;
- if (isKeyValuePair) {
- name = ((String) param).substring(0, ((String) param).indexOf('='));
- value = ((String) param).substring(((String) param).indexOf('=') + 1);
- } else {
- name = (String) param;
- }
- Option option = null;
- for (Option opt : options.keySet()) {
- if (name.equals(opt.name()) || Arrays.asList(opt.aliases()).contains(name)) {
- option = opt;
- break;
- }
- }
- if (option == null) {
- throw new CommandException(commandErrorSt
- + "undefined option " + INTENSITY_BOLD + param + INTENSITY_NORMAL + "\n"
- + "Try <command> --help' for more information.",
- "Undefined option: " + param);
- }
- Field field = options.get(option);
- if (value == null && (field.getType() == boolean.class || field.getType() == Boolean.class)) {
- value = Boolean.TRUE;
- }
- if (value == null && it.hasNext()) {
- value = it.next();
- }
- if (value == null) {
- throw new CommandException(commandErrorSt
- + "missing value for option " + INTENSITY_BOLD + param + INTENSITY_NORMAL,
- "Missing value for option: " + param
- );
- }
- if (option.multiValued()) {
- @SuppressWarnings("unchecked")
- List<Object> l = (List<Object>) optionValues.get(option);
- if (l == null) {
- l = new ArrayList<Object>();
- optionValues.put(option, l);
- }
- l.add(value);
- } else {
- optionValues.put(option, value);
- }
- } else {
- processOptions = false;
- if (argIndex >= orderedArguments.size()) {
- throw new CommandException(commandErrorSt +
- "too many arguments specified",
- "Too many arguments specified"
- );
- }
- Argument argument = orderedArguments.get(argIndex);
- if (!argument.multiValued()) {
- argIndex++;
- }
- if (argument.multiValued()) {
- @SuppressWarnings("unchecked")
- List<Object> l = (List<Object>) argumentValues.get(argument);
- if (l == null) {
- l = new ArrayList<Object>();
- argumentValues.put(argument, l);
- }
- l.add(param);
- } else {
- argumentValues.put(argument, param);
- }
- }
- }
- // Check required arguments / options
- for (Option option : options.keySet()) {
- if (option.required() && optionValues.get(option) == null) {
- throw new CommandException(commandErrorSt +
- "option " + INTENSITY_BOLD + option.name() + INTENSITY_NORMAL + " is required",
- "Option " + option.name() + " is required"
- );
- }
- }
- for (Argument argument : orderedArguments) {
- if (argument.required() && argumentValues.get(argument) == null) {
- throw new CommandException(commandErrorSt +
- "argument " + INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL + " is required",
- "Argument " + argument.name() + " is required"
- );
- }
- }
-
- // Convert and inject values
- for (Map.Entry<Option, Object> entry : optionValues.entrySet()) {
- Field field = options.get(entry.getKey());
- Object value;
- try {
- value = convert(action, session, entry.getValue(), field.getGenericType());
- } catch (Exception e) {
- throw new CommandException(commandErrorSt +
- "unable to convert option " + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- "Unable to convert option " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e
- );
- }
- field.setAccessible(true);
- field.set(action, value);
- }
- for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) {
- Field field = arguments.get(entry.getKey());
- Object value;
- try {
- value = convert(action, session, entry.getValue(), field.getGenericType());
- } catch (Exception e) {
- throw new CommandException(commandErrorSt +
- "unable to convert argument " + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- "Unable to convert argument " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e
- );
- }
- field.setAccessible(true);
- field.set(action, value);
- }
- return true;
- }
-
- protected Object convert(Action action, CommandSession session, Object value, Type toType) throws Exception {
- if (toType == String.class) {
- return value != null ? value.toString() : null;
- }
- return new DefaultConverter(action.getClass().getClassLoader()).convert(value, toType);
- }
-
- private int getWidth(CommandSession session) {
- Object cols = session.get("COLUMNS");
- return (cols != null && cols instanceof Integer) ? (Integer)cols : 80;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
deleted file mode 100644
index 4ea5dfc..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
+++ /dev/null
@@ -1,82 +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.commands.basic;
-
-import java.util.Hashtable;
-
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.CommandWithAction;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.framework.BundleContext;
-
-/**
- * A very simple {@link Function} which creates {@link Action} based on a class name.
- */
-public class SimpleCommand extends AbstractCommand {
-
- private Class<? extends Action> actionClass;
-
- public SimpleCommand()
- {
- }
-
- public SimpleCommand(Class<? extends Action> actionClass)
- {
- this.actionClass = actionClass;
- }
-
- public Class<? extends Action> getActionClass()
- {
- return actionClass;
- }
-
- public void setActionClass(Class<? extends Action> actionClass)
- {
- this.actionClass = actionClass;
- }
-
- public Action createNewAction() {
- try {
- return actionClass.newInstance();
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static ServiceRegistration export(BundleContext context, Class<? extends Action> actionClass)
- {
- Command cmd = actionClass.getAnnotation(Command.class);
- if (cmd == null)
- {
- throw new IllegalArgumentException("Action class is not annotated with @Command");
- }
- Hashtable<String, String> props = new Hashtable<String, String>();
- props.put("osgi.command.scope", cmd.scope());
- props.put("osgi.command.function", cmd.name());
- SimpleCommand command = new SimpleCommand(actionClass);
- return context.registerService(
- new String[] { Function.class.getName(), CommandWithAction.class.getName() },
- command, props);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
deleted file mode 100644
index 54fe81a..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
+++ /dev/null
@@ -1,401 +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.commands.converter;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Dictionary;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.Hashtable;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.LinkedHashMap;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Queue;
-import java.util.LinkedList;
-import java.util.regex.Pattern;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.math.BigInteger;
-import java.math.BigDecimal;
-import java.io.ByteArrayInputStream;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Array;
-import java.lang.reflect.Type;
-import java.lang.reflect.InvocationTargetException;
-
-public class DefaultConverter
-{
-
- private Object loader;
-
- public DefaultConverter(Object loader) {
- this.loader = loader;
- }
-
- public Object convert(Object source, Type target) throws Exception {
- return convert( source, new GenericType(target));
- }
-
- public Object convert(Object fromValue, ReifiedType type) throws Exception {
- // Discard null values
- if (fromValue == null) {
- return null;
- }
- // If the object is an instance of the type, just return it
- if (isAssignable(fromValue, type)) {
- return fromValue;
- }
- Object value = convertWithConverters(fromValue, type);
- if (value == null) {
- if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
- return convertToNumber((Number) fromValue, toClass(type));
- } else if (fromValue instanceof String) {
- return convertFromString((String) fromValue, toClass(type), loader);
- } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
- return convertToArray(fromValue, type);
- } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
- return convertToMap(fromValue, type);
- } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
- return convertToDictionary(fromValue, type);
- } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
- return convertToCollection(fromValue, type);
- } else {
- throw new Exception("Unable to convert value " + fromValue + " to type " + type);
- }
- }
- return value;
- }
-
- private Object convertWithConverters(Object source, ReifiedType type) throws Exception {
- Object value = null;
-// for (Converter converter : converters) {
-// if (converter.canConvert(source, type)) {
-// value = converter.convert(source, type);
-// if (value != null) {
-// return value;
-// }
-// }
-// }
- return value;
- }
-
- public Object convertToNumber(Number value, Class toType) throws Exception {
- toType = unwrap(toType);
- if (AtomicInteger.class == toType) {
- return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
- } else if (AtomicLong.class == toType) {
- return new AtomicLong((Long) convertToNumber(value, Long.class));
- } else if (Integer.class == toType) {
- return value.intValue();
- } else if (Short.class == toType) {
- return value.shortValue();
- } else if (Long.class == toType) {
- return value.longValue();
- } else if (Float.class == toType) {
- return value.floatValue();
- } else if (Double.class == toType) {
- return value.doubleValue();
- } else if (Byte.class == toType) {
- return value.byteValue();
- } else if (BigInteger.class == toType) {
- return new BigInteger(value.toString());
- } else if (BigDecimal.class == toType) {
- return new BigDecimal(value.toString());
- } else {
- throw new Exception("Unable to convert number " + value + " to " + toType);
- }
- }
-
- public Object convertFromString(String value, Class toType, Object loader) throws Exception {
- toType = unwrap(toType);
- if (ReifiedType.class == toType) {
- try {
- return GenericType.parse(value, loader);
- } catch (ClassNotFoundException e) {
- throw new Exception("Unable to convert", e);
- }
- } else if (Class.class == toType) {
- try {
- return GenericType.parse(value, loader).getRawClass();
- } catch (ClassNotFoundException e) {
- throw new Exception("Unable to convert", e);
- }
- } else if (Locale.class == toType) {
- String[] tokens = value.split("_");
- if (tokens.length == 1) {
- return new Locale(tokens[0]);
- } else if (tokens.length == 2) {
- return new Locale(tokens[0], tokens[1]);
- } else if (tokens.length == 3) {
- return new Locale(tokens[0], tokens[1], tokens[2]);
- } else {
- throw new Exception("Invalid locale string:" + value);
- }
- } else if (Pattern.class == toType) {
- return Pattern.compile(value);
- } else if (Properties.class == toType) {
- Properties props = new Properties();
- ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
- props.load(in);
- return props;
- } else if (Boolean.class == toType) {
- if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
- return Boolean.TRUE;
- } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
- return Boolean.FALSE;
- } else {
- throw new RuntimeException("Invalid boolean value: " + value);
- }
- } else if (Integer.class == toType) {
- return Integer.valueOf(value);
- } else if (Short.class == toType) {
- return Short.valueOf(value);
- } else if (Long.class == toType) {
- return Long.valueOf(value);
- } else if (Float.class == toType) {
- return Float.valueOf(value);
- } else if (Double.class == toType) {
- return Double.valueOf(value);
- } else if (Character.class == toType) {
- if (value.length() == 6 && value.startsWith("\\u")) {
- int code = Integer.parseInt(value.substring(2), 16);
- return (char)code;
- } else if (value.length() == 1) {
- return value.charAt(0);
- } else {
- throw new Exception("Invalid value for character type: " + value);
- }
- } else if (Byte.class == toType) {
- return Byte.valueOf(value);
- } else if (Enum.class.isAssignableFrom(toType)) {
- return Enum.valueOf((Class<Enum>) toType, value);
- } else {
- return createObject(value, toType);
- }
- }
-
- private static Object createObject(String value, Class type) throws Exception {
- if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
- throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
- }
- Constructor constructor = null;
- try {
- constructor = type.getConstructor(String.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Unable to convert to " + type);
- }
- try {
- return constructor.newInstance(value);
- } catch (Exception e) {
- throw new Exception("Unable to convert ", getRealCause(e));
- }
- }
-
- private static Throwable getRealCause(Throwable t) {
- if (t instanceof InvocationTargetException && t.getCause() != null) {
- return t.getCause();
- }
- return t;
- }
-
- private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
- ReifiedType valueType = type.getActualTypeArgument(0);
- Collection newCol = (Collection) getCollection(toClass(type)).newInstance();
- if (obj.getClass().isArray()) {
- for (int i = 0; i < Array.getLength(obj); i++) {
- try {
- newCol.add(convert(Array.get(obj, i), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
- }
- }
- } else {
- for (Object item : (Collection) obj) {
- try {
- newCol.add(convert(item, valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
- }
- }
- }
- return newCol;
- }
-
- private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
- ReifiedType keyType = type.getActualTypeArgument(0);
- ReifiedType valueType = type.getActualTypeArgument(1);
- Dictionary newDic = new Hashtable();
- if (obj instanceof Dictionary) {
- Dictionary dic = (Dictionary) obj;
- for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
- Object key = keyEnum.nextElement();
- try {
- newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- } else {
- for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
- try {
- newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- }
- return newDic;
- }
-
- private Object convertToMap(Object obj, ReifiedType type) throws Exception {
- ReifiedType keyType = type.getActualTypeArgument(0);
- ReifiedType valueType = type.getActualTypeArgument(1);
- Map newMap = (Map) getMap(toClass(type)).newInstance();
- if (obj instanceof Dictionary) {
- Dictionary dic = (Dictionary) obj;
- for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
- Object key = keyEnum.nextElement();
- try {
- newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- } else {
- for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
- try {
- newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- }
- return newMap;
- }
-
- private Object convertToArray(Object obj, ReifiedType type) throws Exception {
- if (obj instanceof Collection) {
- obj = ((Collection) obj).toArray();
- }
- if (!obj.getClass().isArray()) {
- throw new Exception("Unable to convert from " + obj + " to " + type);
- }
- ReifiedType componentType;
- if (type.size() > 0) {
- componentType = type.getActualTypeArgument(0);
- } else {
- componentType = new GenericType(type.getRawClass().getComponentType());
- }
- Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
- for (int i = 0; i < Array.getLength(obj); i++) {
- try {
- Array.set(array, i, convert(Array.get(obj, i), componentType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
- }
- }
- return array;
- }
-
- public static boolean isAssignable(Object source, ReifiedType target) {
- return source == null
- || (target.size() == 0
- && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
- }
-
- private static Class unwrap(Class c) {
- Class u = primitives.get(c);
- return u != null ? u : c;
- }
-
- private static Class getMap(Class type) {
- if (hasDefaultConstructor(type)) {
- return type;
- } else if (SortedMap.class.isAssignableFrom(type)) {
- return TreeMap.class;
- } else if (ConcurrentMap.class.isAssignableFrom(type)) {
- return ConcurrentHashMap.class;
- } else {
- return LinkedHashMap.class;
- }
- }
-
- private static Class getCollection(Class type) {
- if (hasDefaultConstructor(type)) {
- return type;
- } else if (SortedSet.class.isAssignableFrom(type)) {
- return TreeSet.class;
- } else if (Set.class.isAssignableFrom(type)) {
- return LinkedHashSet.class;
- } else if (List.class.isAssignableFrom(type)) {
- return ArrayList.class;
- } else if (Queue.class.isAssignableFrom(type)) {
- return LinkedList.class;
- } else {
- return ArrayList.class;
- }
- }
-
- private static boolean hasDefaultConstructor(Class type) {
- if (!Modifier.isPublic(type.getModifiers())) {
- return false;
- }
- if (Modifier.isAbstract(type.getModifiers())) {
- return false;
- }
- Constructor[] constructors = type.getConstructors();
- for (Constructor constructor : constructors) {
- if (Modifier.isPublic(constructor.getModifiers()) &&
- constructor.getParameterTypes().length == 0) {
- return true;
- }
- }
- return false;
- }
-
- private static final Map<Class, Class> primitives;
- static {
- primitives = new HashMap<Class, Class>();
- primitives.put(byte.class, Byte.class);
- primitives.put(short.class, Short.class);
- primitives.put(char.class, Character.class);
- primitives.put(int.class, Integer.class);
- primitives.put(long.class, Long.class);
- primitives.put(float.class, Float.class);
- primitives.put(double.class, Double.class);
- primitives.put(boolean.class, Boolean.class);
- }
-
- private Class toClass(ReifiedType type) {
- return type.getRawClass();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
deleted file mode 100644
index 2f2b5e0..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
+++ /dev/null
@@ -1,195 +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.commands.converter;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.framework.Bundle;
-
-public class GenericType extends ReifiedType {
-
- private static final GenericType[] EMPTY = new GenericType[0];
-
- private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
-
- static {
- primitiveClasses.put("int", int.class);
- primitiveClasses.put("short", short.class);
- primitiveClasses.put("long", long.class);
- primitiveClasses.put("byte", byte.class);
- primitiveClasses.put("char", char.class);
- primitiveClasses.put("float", float.class);
- primitiveClasses.put("double", double.class);
- primitiveClasses.put("boolean", boolean.class);
- }
-
- private GenericType[] parameters;
-
- public GenericType(Type type) {
- this(getConcreteClass(type), parametersOf(type));
- }
-
- public GenericType(Class clazz, GenericType... parameters) {
- super(clazz);
- this.parameters = parameters;
- }
-
- public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
- type = type.trim();
- // Check if this is an array
- if (type.endsWith("[]")) {
- GenericType t = parse(type.substring(0, type.length() - 2), loader);
- return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
- }
- // Check if this is a generic
- int genericIndex = type.indexOf('<');
- if (genericIndex > 0) {
- if (!type.endsWith(">")) {
- throw new IllegalArgumentException("Can not load type: " + type);
- }
- GenericType base = parse(type.substring(0, genericIndex), loader);
- String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
- GenericType[] types = new GenericType[params.length];
- for (int i = 0; i < params.length; i++) {
- types[i] = parse(params[i], loader);
- }
- return new GenericType(base.getRawClass(), types);
- }
- // Primitive
- if (primitiveClasses.containsKey(type)) {
- return new GenericType(primitiveClasses.get(type));
- }
- // Class
- if (loader instanceof ClassLoader) {
- return new GenericType(((ClassLoader) loader).loadClass(type));
- } else if (loader instanceof Bundle) {
- return new GenericType(((Bundle) loader).loadClass(type));
- } else {
- throw new IllegalArgumentException("Unsupported loader: " + loader);
- }
- }
-
- @Override
- public ReifiedType getActualTypeArgument(int i) {
- if (parameters.length == 0) {
- return super.getActualTypeArgument(i);
- }
- return parameters[i];
- }
-
- @Override
- public int size() {
- return parameters.length;
- }
-
- @Override
- public String toString() {
- Class cl = getRawClass();
- if (cl.isArray()) {
- if (parameters.length > 0) {
- return parameters[0].toString() + "[]";
- } else {
- return cl.getComponentType().getName() + "[]";
- }
- }
- if (parameters.length > 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(cl.getName());
- sb.append("<");
- for (int i = 0; i < parameters.length; i++) {
- if (i > 0) {
- sb.append(",");
- }
- sb.append(parameters[i].toString());
- }
- sb.append(">");
- return sb.toString();
- }
- return cl.getName();
- }
-
- static GenericType[] parametersOf(Type type ) {
- if ( type instanceof Class ) {
- Class clazz = (Class) type;
- if (clazz.isArray()) {
- GenericType t = new GenericType(clazz.getComponentType());
- if (t.size() > 0) {
- return new GenericType[] { t };
- } else {
- return EMPTY;
- }
- } else {
- return EMPTY;
- }
- }
- if ( type instanceof ParameterizedType ) {
- ParameterizedType pt = (ParameterizedType) type;
- Type [] parameters = pt.getActualTypeArguments();
- GenericType[] gts = new GenericType[parameters.length];
- for ( int i =0; i<gts.length; i++) {
- gts[i] = new GenericType(parameters[i]);
- }
- return gts;
- }
- if ( type instanceof GenericArrayType ) {
- return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
- }
- throw new IllegalStateException();
- }
-
- static Class<?> getConcreteClass(Type type) {
- Type ntype = collapse(type);
- if ( ntype instanceof Class )
- return (Class<?>) ntype;
-
- if ( ntype instanceof ParameterizedType )
- return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
-
- throw new RuntimeException("Unknown type " + type );
- }
-
- static Type collapse(Type target) {
- if (target instanceof Class || target instanceof ParameterizedType ) {
- return target;
- } else if (target instanceof TypeVariable) {
- return collapse(((TypeVariable<?>) target).getBounds()[0]);
- } else if (target instanceof GenericArrayType) {
- Type t = collapse(((GenericArrayType) target)
- .getGenericComponentType());
- while ( t instanceof ParameterizedType )
- t = collapse(((ParameterizedType)t).getRawType());
- return Array.newInstance((Class<?>)t, 0).getClass();
- } else if (target instanceof WildcardType) {
- WildcardType wct = (WildcardType) target;
- if (wct.getLowerBounds().length == 0)
- return collapse(wct.getUpperBounds()[0]);
- else
- return collapse(wct.getLowerBounds()[0]);
- }
- throw new RuntimeException("Huh? " + target);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
deleted file mode 100644
index dda4477..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed 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.commands.converter;
-
-/**
- * Provides access to a concrete type and its optional generic type arguments.
- *
- * Java 5 and later support generic types. These types consist of a raw class
- * with type arguments. This class models such a <code>Type</code> class but
- * ensures that the type is <em>reified</em>. Reification means that the Type
- * graph associated with a Java 5 <code>Type</code> instance is traversed
- * until the type becomes a concrete class. In Java 1.4 a class has no
- * arguments. This concrete class implements the Reified Type for Java 1.4.
- *
- * In Java 1.4, this class works with non-generic types. In that cases, a
- * Reified Type provides access to the class and has zero type arguments, though
- * a subclass that provide type arguments should be respected. Blueprint
- * extender implementations can subclass this class and provide access to the
- * generics type graph if used in a conversion. Such a subclass must
- * <em>reify<em> the different Java 5 <code>Type</code> instances into the
- * reified form. That is, a form where the raw Class is available with its optional type arguments as Reified Types.
- *
- * @Immutable
- */
-public class ReifiedType {
- final static ReifiedType ALL = new ReifiedType(Object.class);
-
- private final Class clazz;
-
- /**
- * Create a Reified Type for a raw Java class without any generic arguments.
- * Subclasses can provide the optional generic argument information. Without
- * subclassing, this instance has no type arguments.
- *
- * @param clazz
- * The raw class of the Reified Type.
- */
- public ReifiedType(Class clazz) {
- this.clazz = clazz;
- }
-
- /**
- * Access to the raw class.
- *
- * The raw class represents the concrete class that is associated with a
- * type declaration. This class could have been deduced from the generics
- * type graph of the declaration. For example, in the following example:
- *
- * <pre>
- * Map<String, Object> map;
- * </pre>
- *
- * The raw class is the Map class.
- *
- * @return the collapsed raw class that represents this type.
- */
- public Class getRawClass() {
- return clazz;
- }
-
- /**
- * Access to a type argument.
- *
- * The type argument refers to a argument in a generic type declaration
- * given by index <code>i</code>. This method returns a Reified Type that
- * has Object as class when no generic type information is available. Any
- * object is assignable to Object and therefore no conversion is then
- * necessary, this is compatible with older Javas than 5. For this reason,
- * the implementation in this class always returns the
- * <code>Object<code> class, regardless of the given index.
- *
- * This method should be overridden by a subclass that provides access to
- * the generic information.
- *
- * For example, in the following example:
- *
- * <pre>
- * Map<String, Object> map;
- * </pre>
- *
- * The type argument 0 is <code>String</code>, and type argument 1 is
- * <code>Object</code>.
- *
- * @param i
- * The index of the type argument
- * @return <code>ReifiedType(Object.class)<code>, subclasses must override this and return the generic argument at index <code>i</code>
- */
- public ReifiedType getActualTypeArgument(int i) {
- return ALL;
- }
-
- /**
- * Return the number of type arguments.
- *
- * This method should be overridden by a subclass to support Java 5 types.
- *
- * @return 0, subclasses must override this and return the number of generic
- * arguments
- */
- public int size() {
- return 0;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
deleted file mode 100644
index e0bd11a..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
+++ /dev/null
@@ -1,296 +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.commands.meta;
-
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.HelpOption;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
-import org.apache.karaf.shell.console.Completer;
-
-public class ActionMetaData {
-
- private final Class<? extends Action> actionClass;
- private final Command command;
- private final Map<Option, Field> options;
- private final Map<Argument, Field> arguments;
- List<Argument> orderedArguments;
- private final Completer[] completers;
-
- public ActionMetaData(Class<? extends Action> actionClass, Command command, Map<Option, Field> options, Map<Argument, Field> args,
- List<Argument> orderedArguments, Completer[] completers) {
- super();
- this.actionClass = actionClass;
- this.command = command;
- this.options = options;
- this.arguments = args;
- this.orderedArguments = orderedArguments;
- this.completers = completers;
- }
-
- public Class<? extends Action> getActionClass() {
- return actionClass;
- }
-
- public Command getCommand() {
- return command;
- }
-
- public Map<Option, Field> getOptions() {
- return options;
- }
-
- public Map<Argument, Field> getArguments() {
- return arguments;
- }
-
- public Completer[] getCompleters() {
- return completers;
- }
-
- public List<Argument> getOrderedArguments() {
- return orderedArguments;
- }
-
- public void printUsage(Action action, PrintStream out, boolean globalScope, int termWidth) {
- if (command != null) {
- List<Argument> argumentsSet = new ArrayList<Argument>(arguments.keySet());
- Collections.sort(argumentsSet, new Comparator<Argument>() {
- public int compare(Argument o1, Argument o2) {
- return Integer.valueOf(o1.index()).compareTo(Integer.valueOf(o2.index()));
- }
- });
- Set<Option> optionsSet = new HashSet<Option>(options.keySet());
- optionsSet.add(HelpOption.HELP);
- if (command != null && (command.description() != null || command.name() != null)) {
- out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
- out.print(" ");
- if (command.name() != null) {
- if (globalScope) {
- out.println(INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
- } else {
- out.println(command.scope() + ":" + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
- }
- out.println();
- }
- out.print("\t");
- out.println(command.description());
- out.println();
- }
- StringBuffer syntax = new StringBuffer();
- if (command != null) {
- if (globalScope) {
- syntax.append(command.name());
- } else {
- syntax.append(String.format("%s:%s", command.scope(), command.name()));
- }
- }
- if (options.size() > 0) {
- syntax.append(" [options]");
- }
- if (arguments.size() > 0) {
- syntax.append(' ');
- for (Argument argument : argumentsSet) {
- if (!argument.required()) {
- syntax.append(String.format("[%s] ", argument.name()));
- } else {
- syntax.append(String.format("%s ", argument.name()));
- }
- }
- }
-
- out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
- out.print(" ");
- out.println(syntax.toString());
- out.println();
- if (arguments.size() > 0) {
- out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL);
- for (Argument argument : argumentsSet) {
- out.print(" ");
- out.println(INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL);
- ActionMetaData.printFormatted(" ", argument.description(), termWidth, out, true);
- if (!argument.required()) {
- if (argument.valueToShowInHelp() != null && argument.valueToShowInHelp().length() != 0) {
- if (Argument.DEFAULT_STRING.equals(argument.valueToShowInHelp())) {
- Object o = getDefaultValue(action, argument);
- String defaultValue = getDefaultValueString(o);
- if (defaultValue != null) {
- printDefaultsTo(out, defaultValue);
- }
- } else {
- printDefaultsTo(out, argument.valueToShowInHelp());
- }
- }
- }
- }
- out.println();
- }
- if (options.size() > 0) {
- out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
- for (Option option : optionsSet) {
- String opt = option.name();
- for (String alias : option.aliases()) {
- opt += ", " + alias;
- }
- out.print(" ");
- out.println(INTENSITY_BOLD + opt + INTENSITY_NORMAL);
- ActionMetaData.printFormatted(" ", option.description(), termWidth, out, true);
- if (option.valueToShowInHelp() != null && option.valueToShowInHelp().length() != 0) {
- if (Option.DEFAULT_STRING.equals(option.valueToShowInHelp())) {
- Object o = getDefaultValue(action, option);
- String defaultValue = getDefaultValueString(o);
- if (defaultValue != null) {
- printDefaultsTo(out, defaultValue);
- }
- } else {
- printDefaultsTo(out, option.valueToShowInHelp());
- }
- }
- }
- out.println();
- }
- if (command.detailedDescription().length() > 0) {
- out.println(INTENSITY_BOLD + "DETAILS" + INTENSITY_NORMAL);
- String desc = getDetailedDescription();
- ActionMetaData.printFormatted(" ", desc, termWidth, out, true);
- }
- }
- }
-
- public Object getDefaultValue(Action action, Argument argument) {
- try {
- arguments.get(argument).setAccessible(true);
- return arguments.get(argument).get(action);
- } catch (Exception e) {
- return null;
- }
- }
-
- public Object getDefaultValue(Action action, Option option) {
- try {
- options.get(option).setAccessible(true);
- return options.get(option).get(action);
- } catch (Exception e) {
- return null;
- }
- }
-
- public String getDetailedDescription() {
- String desc = command.detailedDescription();
- return loadDescription(actionClass, desc);
- }
-
- private String loadDescription(Class<?> clazz, String desc) {
- if (desc != null && desc.startsWith("classpath:")) {
- desc = loadClassPathResource(clazz, desc.substring("classpath:".length()));
- }
- return desc;
- }
-
- public String getDefaultValueString(Object o) {
- if (o != null && (!(o instanceof Boolean) || ((Boolean)o))
- && (!(o instanceof Number) || ((Number)o).doubleValue() != 0.0)) {
- return o.toString();
- } else {
- return null;
- }
- }
-
- private void printDefaultsTo(PrintStream out, String value) {
- out.println(" (defaults to " + value + ")");
- }
-
- static void printFormatted(String prefix, String str, int termWidth, PrintStream out, boolean prefixFirstLine) {
- int pfxLen = prefix.length();
- int maxwidth = termWidth - pfxLen;
- Pattern wrap = Pattern.compile("(\\S\\S{" + maxwidth + ",}|.{1," + maxwidth + "})(\\s+|$)");
- int cur = 0;
- while (cur >= 0) {
- int lst = str.indexOf('\n', cur);
- String s = (lst >= 0) ? str.substring(cur, lst) : str.substring(cur);
- if (s.length() == 0) {
- out.println();
- } else {
- Matcher m = wrap.matcher(s);
- while (m.find()) {
- if (cur > 0 || prefixFirstLine) {
- out.print(prefix);
- }
- out.println(m.group());
- }
- }
- if (lst >= 0) {
- cur = lst + 1;
- } else {
- break;
- }
- }
- }
-
- private String loadClassPathResource(Class<?> clazz, String path) {
- InputStream is = clazz.getResourceAsStream(path);
- if (is == null) {
- is = clazz.getClassLoader().getResourceAsStream(path);
- }
- if (is == null) {
- return "Unable to load description from " + path;
- }
-
- try {
- Reader r = new InputStreamReader(is);
- StringWriter sw = new StringWriter();
- int c;
- while ((c = r.read()) != -1) {
- sw.append((char) c);
- }
- return sw.toString();
- } catch (IOException e) {
- return "Unable to load description from " + path;
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
deleted file mode 100644
index 91bc48f..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
+++ /dev/null
@@ -1,251 +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.commands.meta;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-
-public class ActionMetaDataFactory {
-
- public ActionMetaData create(Class<? extends Action> actionClass) {
- Command command = getCommand(actionClass);
- Map<Option, Field> options = new HashMap<Option, Field>();
- Map<Argument, Field> arguments = new HashMap<Argument, Field>();
- List<Argument> orderedArguments = new ArrayList<Argument>();
-
- for (Class<?> type = actionClass; type != null; type = type.getSuperclass()) {
- for (Field field : type.getDeclaredFields()) {
- Option option = field.getAnnotation(Option.class);
- if (option == null) {
- option = getAndConvertDeprecatedOption(field);
- }
- if (option != null) {
- options.put(option, field);
- }
-
- Argument argument = field.getAnnotation(Argument.class);
- if (argument == null) {
- argument = getAndConvertDeprecatedArgument(field);
- }
- if (argument != null) {
- argument = replaceDefaultArgument(field, argument);
- arguments.put(argument, field);
- int index = argument.index();
- while (orderedArguments.size() <= index) {
- orderedArguments.add(null);
- }
- if (orderedArguments.get(index) != null) {
- throw new IllegalArgumentException("Duplicate argument index: " + index + " on Action " + actionClass.getName());
- }
- orderedArguments.set(index, argument);
- }
- }
- }
- assertIndexesAreCorrect(actionClass, orderedArguments);
-
- return new ActionMetaData(actionClass, command, options, arguments, orderedArguments, null);
- }
-
- public Command getCommand(Class<? extends Action> actionClass) {
- Command command = actionClass.getAnnotation(Command.class);
- if (command == null) {
- command = getAndConvertDeprecatedCommand(actionClass);
- }
- return command;
- }
-
- @SuppressWarnings("deprecation")
- public Command getAndConvertDeprecatedCommand(Class<? extends Action> actionClass) {
- final org.apache.felix.gogo.commands.Command oldCommand = actionClass.getAnnotation(org.apache.felix.gogo.commands.Command.class);
- if (oldCommand == null) {
- return null;
- }
- return new Command() {
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return Command.class;
- }
-
- @Override
- public String scope() {
- return oldCommand.scope();
- }
-
- @Override
- public String name() {
- return oldCommand.name();
- }
-
- @Override
- public String detailedDescription() {
- return oldCommand.detailedDescription();
- }
-
- @Override
- public String description() {
- return oldCommand.description();
- }
- };
- }
-
- @SuppressWarnings("deprecation")
- private Option getAndConvertDeprecatedOption(Field field) {
- final org.apache.felix.gogo.commands.Option oldOption = field.getAnnotation(org.apache.felix.gogo.commands.Option.class);
- if (oldOption == null) {
- return null;
- }
- return new Option() {
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return Option.class;
- }
-
- @Override
- public String valueToShowInHelp() {
- return oldOption.valueToShowInHelp();
- }
-
- @Override
- public boolean required() {
- return oldOption.required();
- }
-
- @Override
- public String name() {
- return oldOption.name();
- }
-
- @Override
- public boolean multiValued() {
- return oldOption.multiValued();
- }
-
- @Override
- public String description() {
- return oldOption.description();
- }
-
- @Override
- public String[] aliases() {
- return oldOption.aliases();
- }
- };
- }
-
- @SuppressWarnings("deprecation")
- private Argument getAndConvertDeprecatedArgument(Field field) {
- final org.apache.felix.gogo.commands.Argument oldArgument = field.getAnnotation(org.apache.felix.gogo.commands.Argument.class);
- if (oldArgument == null) {
- return null;
- }
- return new Argument() {
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return Argument.class;
- }
-
- @Override
- public String valueToShowInHelp() {
- return oldArgument.valueToShowInHelp();
- }
-
- @Override
- public boolean required() {
- return oldArgument.required();
- }
-
- @Override
- public String name() {
- return oldArgument.name();
- }
-
- @Override
- public boolean multiValued() {
- return oldArgument.multiValued();
- }
-
- @Override
- public int index() {
- return oldArgument.index();
- }
-
- @Override
- public String description() {
- return oldArgument.description();
- }
- };
- }
-
- private Argument replaceDefaultArgument(Field field, Argument argument) {
- if (Argument.DEFAULT.equals(argument.name())) {
- final Argument delegate = argument;
- final String name = field.getName();
- argument = new Argument() {
- public String name() {
- return name;
- }
-
- public String description() {
- return delegate.description();
- }
-
- public boolean required() {
- return delegate.required();
- }
-
- public int index() {
- return delegate.index();
- }
-
- public boolean multiValued() {
- return delegate.multiValued();
- }
-
- public String valueToShowInHelp() {
- return delegate.valueToShowInHelp();
- }
-
- public Class<? extends Annotation> annotationType() {
- return delegate.annotationType();
- }
- };
- }
- return argument;
- }
-
- private void assertIndexesAreCorrect(Class<? extends Action> actionClass, List<Argument> orderedArguments) {
- for (int i = 0; i < orderedArguments.size(); i++) {
- if (orderedArguments.get(i) == null) {
- throw new IllegalArgumentException("Missing argument for index: " + i + " on Action " + actionClass.getName());
- }
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/AbstractAction.java b/shell/console/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
deleted file mode 100644
index f9990c5..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
+++ /dev/null
@@ -1,50 +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.console;
-
-import org.apache.karaf.shell.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class AbstractAction implements Action {
-
- protected final Logger log = LoggerFactory.getLogger(getClass());
- protected CommandSession session;
-
- public Object execute(CommandSession session) throws Exception {
- this.session = session;
- return doExecute();
- }
-
- protected abstract Object doExecute() throws Exception;
-
- /**
- * This is for long running commands to be interrupted by ctrl-c
- *
- * @throws InterruptedException
- */
- public static void checkInterrupted() throws InterruptedException {
- Thread.yield();
- if (Thread.currentThread().isInterrupted()) {
- throw new InterruptedException();
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java b/shell/console/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
deleted file mode 100644
index d566f48..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
+++ /dev/null
@@ -1,27 +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.console;
-
-import org.osgi.service.blueprint.container.BlueprintContainer;
-
-public interface BlueprintContainerAware {
-
- void setBlueprintContainer(BlueprintContainer blueprintContainer);
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java b/shell/console/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
deleted file mode 100644
index bbd03c5..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
+++ /dev/null
@@ -1,27 +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.console;
-
-import org.osgi.framework.BundleContext;
-
-public interface BundleContextAware {
-
- void setBundleContext(BundleContext bundleContext);
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/CloseShellException.java b/shell/console/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
deleted file mode 100644
index 81cee88..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
+++ /dev/null
@@ -1,27 +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.console;
-
-/**
- * Exception thrown to indicate the console to close.
- */
-@SuppressWarnings("serial")
-public class CloseShellException extends Exception {
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java b/shell/console/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
deleted file mode 100644
index f07554f..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
+++ /dev/null
@@ -1,38 +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.console;
-
-import org.apache.felix.service.command.CommandSession;
-
-public class CommandSessionHolder {
-
- private static final ThreadLocal<CommandSession> session = new ThreadLocal<CommandSession>();
-
- public static CommandSession getSession() {
- return session.get();
- }
-
- public static void setSession(CommandSession commandSession) {
- session.set(commandSession);
- }
-
- public static void unset() {
- session.remove();
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java b/shell/console/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
deleted file mode 100644
index fcb96da..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
+++ /dev/null
@@ -1,31 +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.console;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.service.command.Function;
-
-public interface CompletableFunction extends Function {
-
- List<Completer> getCompleters();
- Map<String, Completer> getOptionalCompleters();
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/Completer.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/Completer.java b/shell/console/src/main/java/org/apache/karaf/shell/console/Completer.java
deleted file mode 100644
index 59f7897..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/Completer.java
+++ /dev/null
@@ -1,27 +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.console;
-
-import java.util.List;
-
-public interface Completer {
-
- int complete(String buffer, int cursor, List<String> candidates);
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/Console.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/Console.java b/shell/console/src/main/java/org/apache/karaf/shell/console/Console.java
deleted file mode 100644
index fcca7ad..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/Console.java
+++ /dev/null
@@ -1,29 +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.console;
-
-import org.apache.felix.service.command.CommandSession;
-
-public interface Console extends Runnable {
-
- CommandSession getSession();
-
- void close(boolean closedByUser);
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/ExitAction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/ExitAction.java b/shell/console/src/main/java/org/apache/karaf/shell/console/ExitAction.java
deleted file mode 100644
index 1449315..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/ExitAction.java
+++ /dev/null
@@ -1,46 +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.console;
-
-import org.apache.karaf.shell.commands.Command;
-
-/**
- * Exit from the current sub-shell and get back to the previous one.
- */
-@Command(scope = "*", name = "exit", description = "Exit from the current shell")
-public class ExitAction extends AbstractAction {
-
- public Object doExecute() throws Exception {
- // get the current sub-shell
- String currentSubShell = (String) session.get("SUBSHELL");
- if (!currentSubShell.isEmpty()) {
- if (currentSubShell.contains(":")) {
- int index = currentSubShell.lastIndexOf(":");
- session.put("SUBSHELL", currentSubShell.substring(0, index));
- } else {
- session.put("SUBSHELL", "");
- }
- String currentScope = (String) session.get("SCOPE");
- int index = currentScope.indexOf(":");
- session.put("SCOPE", currentScope.substring(index + 1));
- }
- return null;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/HelpProvider.java b/shell/console/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
deleted file mode 100644
index 7e3bca7..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
+++ /dev/null
@@ -1,26 +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.console;
-
-import org.apache.felix.service.command.CommandSession;
-
-public interface HelpProvider {
-
- String getHelp(CommandSession session, String path);
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/MultiException.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/MultiException.java b/shell/console/src/main/java/org/apache/karaf/shell/console/MultiException.java
deleted file mode 100644
index 6e6185c..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/MultiException.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.console;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-@SuppressWarnings("serial")
-public class MultiException extends Exception {
-
- private List<Exception> exceptions = new ArrayList<Exception>();
-
- public MultiException(String message) {
- super(message);
- }
-
- public MultiException(String message, List<Exception> exceptions) {
- super(message);
- this.exceptions = exceptions;
- }
-
- public void addException(Exception e) {
- exceptions.add(e);
- }
-
- public void throwIfExceptions() throws MultiException {
- if (!exceptions.isEmpty()) {
- throw this;
- }
- }
-
- public Throwable[] getCauses() {
- return exceptions.toArray(new Throwable[exceptions.size()]);
- }
-
- @Override
- public void printStackTrace()
- {
- super.printStackTrace();
- for (Exception e : exceptions) {
- e.printStackTrace();
- }
- }
-
-
- /* ------------------------------------------------------------------------------- */
- /**
- * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
- */
- @Override
- public void printStackTrace(PrintStream out)
- {
- super.printStackTrace(out);
- for (Exception e : exceptions) {
- e.printStackTrace(out);
- }
- }
-
- @Override
- public void printStackTrace(PrintWriter out)
- {
- super.printStackTrace(out);
- for (Exception e : exceptions) {
- e.printStackTrace(out);
- }
- }
-
- public static void throwIf(String message, List<Exception> exceptions) throws MultiException {
- if (exceptions != null && !exceptions.isEmpty()) {
- StringBuilder sb = new StringBuilder(message);
- sb.append(":");
- for (Exception e : exceptions) {
- sb.append("\n\t");
- sb.append(e.getMessage());
- }
- throw new MultiException(sb.toString(), exceptions);
- }
- }
-}
[03/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/NameScoping.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/NameScoping.java b/shell/console/src/main/java/org/apache/karaf/shell/console/NameScoping.java
deleted file mode 100644
index 355464d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/NameScoping.java
+++ /dev/null
@@ -1,79 +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.console;
-
-import org.apache.felix.service.command.CommandSession;
-
-
-/**
- * A helper class for name scoping
- */
-public class NameScoping {
-
- public static final String MULTI_SCOPE_MODE_KEY = "MULTI_SCOPE_MODE";
-
- /**
- * Returns the name of the command which can omit the global scope prefix if the command starts with the
- * same prefix as the current application
- */
- public static String getCommandNameWithoutGlobalPrefix(CommandSession session, String key) {
- if (!isMultiScopeMode(session)) {
- String globalScope = (String) (session != null ? session.get("APPLICATION") : null);
- if (globalScope != null) {
- String prefix = globalScope + ":";
- if (key.startsWith(prefix)) {
- // TODO we may only want to do this for single-scope mode when outside of OSGi?
- // so we may want to also check for a isMultiScope mode == false
- return key.substring(prefix.length());
- }
- }
- }
- return key;
- }
-
- /**
- * Returns true if the given scope is the global scope so that it can be hidden from help messages
- */
- public static boolean isGlobalScope(CommandSession session, String scope) {
- if (session == null)
- return false;
-
- if (!isMultiScopeMode(session)) {
- String globalScope = (String) session.get("APPLICATION");
- if (globalScope != null) {
- return scope.equals(globalScope);
- }
- }
- return false;
- }
-
- /**
- * Returns true if we are in multi-scope mode (the default) or if we are in single scope mode which means we
- * avoid prefixing commands with their scope
- */
- public static boolean isMultiScopeMode(CommandSession session) {
- if (session == null)
- return false;
-
- Object value = session.get(MULTI_SCOPE_MODE_KEY);
- if (value != null && value.equals("false")) {
- return false;
- }
- return true;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java b/shell/console/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
deleted file mode 100644
index d737865..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
+++ /dev/null
@@ -1,103 +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.console;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.Action;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-
-public abstract class OsgiCommandSupport extends AbstractAction implements Action, BundleContextAware {
-
- protected BundleContext bundleContext;
- protected List<ServiceReference<?>> usedReferences;
-
- @Override
- public Object execute(CommandSession session) throws Exception {
- try {
- return super.execute(session);
- } finally {
- ungetServices();
- }
- }
-
- public BundleContext getBundleContext() {
- Bundle framework = bundleContext.getBundle(0);
- return framework == null? bundleContext: framework.getBundleContext();
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- protected <T> List<T> getAllServices(Class<T> clazz) {
- try {
- return getAllServices(clazz, null);
- } catch (InvalidSyntaxException e) {
- throw new IllegalStateException(e);
- }
- }
-
- protected <T> List<T> getAllServices(Class<T> clazz, String filter) throws InvalidSyntaxException {
- Collection<ServiceReference<T>> references = getBundleContext().getServiceReferences(clazz, filter);
- List<T> services = new ArrayList<T>();
- if (references != null) {
- for (ServiceReference<T> ref : references) {
- T t = getService(clazz, ref);
- services.add(t);
- }
- }
- return services;
- }
-
- protected <T> T getService(Class<T> clazz) {
- ServiceReference<T> sr = getBundleContext().getServiceReference(clazz);
- if (sr != null) {
- return getService(clazz, sr);
- } else {
- return null;
- }
- }
-
- protected <T> T getService(Class<T> clazz, ServiceReference<T> reference) {
- T t = getBundleContext().getService(reference);
- if (t != null) {
- if (usedReferences == null) {
- usedReferences = new ArrayList<ServiceReference<?>>();
- }
- usedReferences.add(reference);
- }
- return t;
- }
-
- protected void ungetServices() {
- if (usedReferences != null) {
- for (ServiceReference<?> ref : usedReferences) {
- getBundleContext().ungetService(ref);
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/SessionProperties.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/SessionProperties.java b/shell/console/src/main/java/org/apache/karaf/shell/console/SessionProperties.java
deleted file mode 100644
index 30f3433..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/SessionProperties.java
+++ /dev/null
@@ -1,28 +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.console;
-
-public class SessionProperties {
-
- public static final String PRINT_STACK_TRACES = "karaf.printStackTraces";
- public static final String LAST_EXCEPTION = "karaf.lastException";
- public static final String IGNORE_INTERRUPTS = "karaf.ignoreInterrupts";
- public static final String COMPLETION_MODE = "karaf.completionMode";
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/SubShell.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/SubShell.java b/shell/console/src/main/java/org/apache/karaf/shell/console/SubShell.java
deleted file mode 100644
index 2de0d20..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/SubShell.java
+++ /dev/null
@@ -1,38 +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.console;
-
-public interface SubShell {
-
- /**
- * Returns the name of the command if used inside a shell
- */
- String getName();
-
- /**
- * Returns the description of the command which is used to generate command line help
- */
- String getDescription();
-
- /**
- * Returns a detailed description of the command
- */
- String getDetailedDescription();
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/SubShellAction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/SubShellAction.java b/shell/console/src/main/java/org/apache/karaf/shell/console/SubShellAction.java
deleted file mode 100644
index 8774927..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/SubShellAction.java
+++ /dev/null
@@ -1,39 +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.console;
-
-
-
-/**
- * Switch to a sub-shell.
- */
-public class SubShellAction extends AbstractAction {
-
- private String subShell;
-
- public Object doExecute() throws Exception {
- session.put("SUBSHELL", subShell);
- session.put("SCOPE", subShell + ":" + session.get("SCOPE"));
- return null;
- }
-
- public void setSubShell(String subShell) {
- this.subShell = subShell;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java
deleted file mode 100644
index 9cd3dda..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java
+++ /dev/null
@@ -1,43 +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.console.commands;
-
-import org.apache.karaf.shell.console.SubShell;
-
-public class AnnotatedSubShell implements SubShell {
-
- public String getName() {
- return getAnnotation().name();
- }
-
- public String getDescription() {
- return getAnnotation().description();
- }
-
- public String getDetailedDescription() {
- return getAnnotation().detailedDescription();
- }
-
- org.apache.felix.gogo.commands.SubShell getAnnotation() {
- org.apache.felix.gogo.commands.SubShell ann = getClass().getAnnotation(org.apache.felix.gogo.commands.SubShell.class);
- if (ann == null) {
- throw new IllegalStateException("The class should be annotated with the org.apache.felix.gogo.commands.SubShell annotation");
- }
- return ann;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
deleted file mode 100644
index 3e40c5a..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
+++ /dev/null
@@ -1,51 +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.console.commands;
-
-import org.apache.karaf.shell.console.SubShell;
-
-public class BasicSubShell implements SubShell {
-
- private String name;
- private String description;
- private String detailedDescription;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getDetailedDescription() {
- return detailedDescription;
- }
-
- public void setDetailedDescription(String detailedDescription) {
- this.detailedDescription = detailedDescription;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
deleted file mode 100644
index 83fa1ec..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
+++ /dev/null
@@ -1,110 +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.console.commands;
-
-import java.lang.reflect.Type;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.basic.AbstractCommand;
-import org.apache.karaf.shell.commands.basic.ActionPreparator;
-import org.apache.karaf.shell.commands.basic.DefaultActionPreparator;
-import org.apache.karaf.shell.console.BlueprintContainerAware;
-import org.apache.karaf.shell.console.BundleContextAware;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.console.Completer;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.blueprint.container.BlueprintContainer;
-import org.osgi.service.blueprint.container.Converter;
-
-public class
- BlueprintCommand extends AbstractCommand implements CompletableFunction
-{
-
- protected BlueprintContainer blueprintContainer;
- protected Converter blueprintConverter;
- protected String actionId;
- protected String shell;
- protected List<Completer> completers;
- protected Map<String,Completer> optionalCompleters;
-
- public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
- this.blueprintContainer = blueprintContainer;
- }
-
- public void setBlueprintConverter(Converter blueprintConverter) {
- this.blueprintConverter = blueprintConverter;
- }
-
- public void setActionId(String actionId) {
- this.actionId = actionId;
- }
-
- public void setShell(String shell) {
- this.shell = shell;
- }
-
- public List<Completer> getCompleters() {
- return completers;
- }
-
- public void setCompleters(List<Completer> completers) {
- this.completers = completers;
- }
-
- public Map<String, Completer> getOptionalCompleters() {
- return optionalCompleters;
- }
-
- public void setOptionalCompleters(Map<String, Completer> optionalCompleters) {
- this.optionalCompleters = optionalCompleters;
- }
-
- @Override
- protected ActionPreparator getPreparator() throws Exception {
- return new BlueprintActionPreparator();
- }
-
- protected class BlueprintActionPreparator extends DefaultActionPreparator {
-
- @Override
- protected Object convert(Action action, CommandSession commandSession, Object o, Type type) throws Exception {
- GenericType t = new GenericType(type);
- if (t.getRawClass() == String.class) {
- return o != null ? o.toString() : null;
- }
- return blueprintConverter.convert(o, t);
- }
-
- }
-
- public Action createNewAction() {
- Action action = (Action) blueprintContainer.getComponentInstance(actionId);
- if (action instanceof BlueprintContainerAware) {
- ((BlueprintContainerAware) action).setBlueprintContainer(blueprintContainer);
- }
- if (action instanceof BundleContextAware) {
- BundleContext context = (BundleContext) blueprintContainer.getComponentInstance("blueprintBundleContext");
- ((BundleContextAware) action).setBundleContext(context);
- }
- return action;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
deleted file mode 100644
index faf7c18..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
+++ /dev/null
@@ -1,195 +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.console.commands;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.framework.Bundle;
-import org.osgi.service.blueprint.container.ReifiedType;
-
-public class GenericType extends ReifiedType {
-
- private static final GenericType[] EMPTY = new GenericType[0];
-
- private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
-
- static {
- primitiveClasses.put("int", int.class);
- primitiveClasses.put("short", short.class);
- primitiveClasses.put("long", long.class);
- primitiveClasses.put("byte", byte.class);
- primitiveClasses.put("char", char.class);
- primitiveClasses.put("float", float.class);
- primitiveClasses.put("double", double.class);
- primitiveClasses.put("boolean", boolean.class);
- }
-
- private GenericType[] parameters;
-
- public GenericType(Type type) {
- this(getConcreteClass(type), parametersOf(type));
- }
-
- public GenericType(Class clazz, GenericType... parameters) {
- super(clazz);
- this.parameters = parameters;
- }
-
- public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
- type = type.trim();
- // Check if this is an array
- if (type.endsWith("[]")) {
- GenericType t = parse(type.substring(0, type.length() - 2), loader);
- return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
- }
- // Check if this is a generic
- int genericIndex = type.indexOf('<');
- if (genericIndex > 0) {
- if (!type.endsWith(">")) {
- throw new IllegalArgumentException("Can not load type: " + type);
- }
- GenericType base = parse(type.substring(0, genericIndex), loader);
- String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
- GenericType[] types = new GenericType[params.length];
- for (int i = 0; i < params.length; i++) {
- types[i] = parse(params[i], loader);
- }
- return new GenericType(base.getRawClass(), types);
- }
- // Primitive
- if (primitiveClasses.containsKey(type)) {
- return new GenericType(primitiveClasses.get(type));
- }
- // Class
- if (loader instanceof ClassLoader) {
- return new GenericType(((ClassLoader) loader).loadClass(type));
- } else if (loader instanceof Bundle) {
- return new GenericType(((Bundle) loader).loadClass(type));
- } else {
- throw new IllegalArgumentException("Unsupported loader: " + loader);
- }
- }
-
- @Override
- public ReifiedType getActualTypeArgument(int i) {
- if (parameters.length == 0) {
- return super.getActualTypeArgument(i);
- }
- return parameters[i];
- }
-
- @Override
- public int size() {
- return parameters.length;
- }
-
- @Override
- public String toString() {
- Class cl = getRawClass();
- if (cl.isArray()) {
- if (parameters.length > 0) {
- return parameters[0].toString() + "[]";
- } else {
- return cl.getComponentType().getName() + "[]";
- }
- }
- if (parameters.length > 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(cl.getName());
- sb.append("<");
- for (int i = 0; i < parameters.length; i++) {
- if (i > 0) {
- sb.append(",");
- }
- sb.append(parameters[i].toString());
- }
- sb.append(">");
- return sb.toString();
- }
- return cl.getName();
- }
-
- static GenericType[] parametersOf(Type type ) {
- if ( type instanceof Class ) {
- Class clazz = (Class) type;
- if (clazz.isArray()) {
- GenericType t = new GenericType(clazz.getComponentType());
- if (t.size() > 0) {
- return new GenericType[] { t };
- } else {
- return EMPTY;
- }
- } else {
- return EMPTY;
- }
- }
- if ( type instanceof ParameterizedType ) {
- ParameterizedType pt = (ParameterizedType) type;
- Type [] parameters = pt.getActualTypeArguments();
- GenericType[] gts = new GenericType[parameters.length];
- for ( int i =0; i<gts.length; i++) {
- gts[i] = new GenericType(parameters[i]);
- }
- return gts;
- }
- if ( type instanceof GenericArrayType ) {
- return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
- }
- throw new IllegalStateException();
- }
-
- static Class<?> getConcreteClass(Type type) {
- Type ntype = collapse(type);
- if ( ntype instanceof Class )
- return (Class<?>) ntype;
-
- if ( ntype instanceof ParameterizedType )
- return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
-
- throw new RuntimeException("Unknown type " + type );
- }
-
- static Type collapse(Type target) {
- if (target instanceof Class || target instanceof ParameterizedType ) {
- return target;
- } else if (target instanceof TypeVariable) {
- return collapse(((TypeVariable<?>) target).getBounds()[0]);
- } else if (target instanceof GenericArrayType) {
- Type t = collapse(((GenericArrayType) target)
- .getGenericComponentType());
- while ( t instanceof ParameterizedType )
- t = collapse(((ParameterizedType)t).getRawType());
- return Array.newInstance((Class<?>)t, 0).getClass();
- } else if (target instanceof WildcardType) {
- WildcardType wct = (WildcardType) target;
- if (wct.getLowerBounds().length == 0)
- return collapse(wct.getUpperBounds()[0]);
- else
- return collapse(wct.getLowerBounds()[0]);
- }
- throw new RuntimeException("Huh? " + target);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
deleted file mode 100644
index 6c3a5b3..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
+++ /dev/null
@@ -1,523 +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.console.commands;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.aries.blueprint.ParserContext;
-import org.apache.aries.blueprint.PassThroughMetadata;
-import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
-import org.apache.aries.blueprint.mutable.MutableCollectionMetadata;
-import org.apache.aries.blueprint.mutable.MutableIdRefMetadata;
-import org.apache.aries.blueprint.mutable.MutablePassThroughMetadata;
-import org.apache.aries.blueprint.mutable.MutableRefMetadata;
-import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
-import org.apache.aries.blueprint.mutable.MutableServiceMetadata;
-import org.apache.aries.blueprint.mutable.MutableValueMetadata;
-import org.apache.felix.gogo.commands.Action;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.SubShellAction;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Destroy;
-import org.apache.karaf.shell.inject.Init;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.osgi.service.blueprint.reflect.BeanArgument;
-import org.osgi.service.blueprint.reflect.BeanMetadata;
-import org.osgi.service.blueprint.reflect.BeanProperty;
-import org.osgi.service.blueprint.reflect.ComponentMetadata;
-import org.osgi.service.blueprint.reflect.IdRefMetadata;
-import org.osgi.service.blueprint.reflect.MapMetadata;
-import org.osgi.service.blueprint.reflect.Metadata;
-import org.osgi.service.blueprint.reflect.NullMetadata;
-import org.osgi.service.blueprint.reflect.RefMetadata;
-import org.osgi.service.blueprint.reflect.ReferenceMetadata;
-import org.osgi.service.blueprint.reflect.ServiceMetadata;
-import org.osgi.service.blueprint.reflect.ValueMetadata;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-
-public class NamespaceHandler implements org.apache.aries.blueprint.NamespaceHandler {
-
- public static final String ID = "id";
- public static final String ACTION = "action";
- public static final String ACTION_ID = "actionId";
- public static final String COMMAND_BUNDLE = "command-bundle";
- public static final String SCAN = "scan";
- public static final String NAME = "name";
- public static final String COMMAND = "command";
- public static final String COMPLETERS = "completers";
- public static final String OPTIONAL_COMPLETERS = "optional-completers";
- public static final String OPTIONAL_COMPLETERS_PROPERTY = "optionalCompleters";
- public static final String BEAN = "bean";
- public static final String REF = "ref";
- public static final String NULL = "null";
- public static final String MAP = "map";
- public static final String BLUEPRINT_CONTAINER = "blueprintContainer";
- public static final String BLUEPRINT_CONVERTER = "blueprintConverter";
-
- public static final String SHELL_NAMESPACE_1_0_0 = "http://karaf.apache.org/xmlns/shell/v1.0.0";
- public static final String SHELL_NAMESPACE_1_1_0 = "http://karaf.apache.org/xmlns/shell/v1.1.0";
- public static final String SHELL_NAMESPACE_1_2_0 = "http://karaf.apache.org/xmlns/shell/v1.2.0";
-
- private int nameCounter = 0;
-
- public URL getSchemaLocation(String namespace) {
- if(SHELL_NAMESPACE_1_0_0.equals(namespace)) {
- return getClass().getResource("karaf-shell-1.0.0.xsd");
- } else if(SHELL_NAMESPACE_1_1_0.equals(namespace)) {
- return getClass().getResource("karaf-shell-1.1.0.xsd");
- } else if(SHELL_NAMESPACE_1_2_0.equals(namespace)) {
- return getClass().getResource("karaf-shell-1.2.0.xsd");
- }
- return getClass().getResource("karaf-shell-1.2.0.xsd");
- }
-
- public Set<Class> getManagedClasses() {
- return new HashSet<Class>(Arrays.asList(
- BlueprintCommand.class
- ));
- }
-
- public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
- throw new ComponentDefinitionException("Bad xml syntax: node decoration is not supported");
- }
-
- public Metadata parse(Element element, ParserContext context) {
- if (nodeNameEquals(element, COMMAND_BUNDLE)) {
- NamedNodeMap attrs = element.getAttributes();
- for (int i = 0; i < attrs.getLength(); i++) {
- Node child = attrs.item(i);
- if (child instanceof Attr) {
- Attr childAttr = (Attr) child;
- parseChildAttr(childAttr, context);
- }
- }
- NodeList children = element.getChildNodes();
- for (int i = 0; i < children.getLength(); i++) {
- Node child = children.item(i);
- if (child instanceof Element) {
- Element childElement = (Element) child;
- parseChildElement(childElement, context);
- }
- }
- registerConverters(context);
- return null;
- } else {
- throw new IllegalStateException("Unexpected element " + element.getNodeName());
- }
- }
-
- private void parseChildAttr(Attr attr, ParserContext context) {
- if (nodeNameEquals(attr, SCAN)) {
- scan(attr, context);
- }
- }
-
- private void scan(Attr attr, ParserContext context) {
- try {
- Bundle bundle = getBundle(context);
- BundleWiring wiring = bundle.adapt(BundleWiring.class);
- for (String pkg : attr.getValue().split(" ")) {
- String name = pkg;
- int options = BundleWiring.LISTRESOURCES_LOCAL;
- name = name.replace('.', '/');
- if (name.endsWith("*")) {
- options |= BundleWiring.LISTRESOURCES_RECURSE;
- name = name.substring(0, name.length() - 1);
- }
- if (!name.startsWith("/")) {
- name = "/" + name;
- }
- if (name.endsWith("/")) {
- name = name.substring(0, name.length() - 1);
- }
- Collection<String> classes = wiring.listResources(name, "*.class", options);
- for (String className : classes) {
- className = className.replace('/', '.').replace(".class", "");
- inspectClass(context, bundle.loadClass(className));
- }
- }
- } catch (ComponentDefinitionException e) {
- throw e;
- } catch (Exception e) {
- throw new ComponentDefinitionException("Unable to scan commands", e);
- }
- }
-
- private void inspectClass(ParserContext context, Class<?> clazz) throws Exception {
- Service reg = clazz.getAnnotation(Service.class);
- if (reg == null) {
- return;
- }
- if (Action.class.isAssignableFrom(clazz)) {
- final Command cmd = clazz.getAnnotation(Command.class);
- if (cmd == null) {
- throw new IllegalArgumentException("Command " + clazz.getName() + " is not annotated with @Command");
- }
- String scope = cmd.scope();
- String function = cmd.name();
- // Create action
- MutableBeanMetadata action = context.createMetadata(MutableBeanMetadata.class);
- action.setId(getName());
- action.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
- action.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
- action.setRuntimeClass(clazz);
- for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
- for (Field field : cl.getDeclaredFields()) {
- if (field.getAnnotation(Reference.class) != null) {
- if (field.getType() == BundleContext.class) {
- action.addProperty(field.getName(), createRef(context, "blueprintBundleContext"));
- } else {
- action.addProperty(field.getName(), createRef(context, createServiceRef(context, field.getType()).getId()));
- }
- }
- }
- for (Method method : cl.getDeclaredMethods()) {
- if (method.getAnnotation(Init.class) != null) {
- if (action.getInitMethod() == null) {
- action.setInitMethod(method.getName());
- }
- }
- if (method.getAnnotation(Destroy.class) != null) {
- if (action.getDestroyMethod() == null) {
- action.setDestroyMethod(method.getName());
- }
- }
- }
- }
- context.getComponentDefinitionRegistry().registerComponentDefinition(action);
- // Create command
- MutableBeanMetadata command = context.createMetadata(MutableBeanMetadata.class);
- command.setRuntimeClass(BlueprintCommand.class);
- command.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
- command.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
- command.addProperty(ACTION_ID, createIdRef(context, action.getId()));
- // Create command service
- MutableServiceMetadata commandService = context.createMetadata(MutableServiceMetadata.class);
- commandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
- commandService.setId(getName());
- commandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
- commandService.setServiceComponent(command);
- commandService.addServiceProperty(createStringValue(context, "osgi.command.scope"),
- createStringValue(context, scope));
- commandService.addServiceProperty(createStringValue(context, "osgi.command.function"),
- createStringValue(context, function));
- context.getComponentDefinitionRegistry().registerComponentDefinition(commandService);
-
- // create the sub-shell action
- createSubShell(context, scope);
- }
- if (Completer.class.isAssignableFrom(clazz)) {
- MutableBeanMetadata completer = context.createMetadata(MutableBeanMetadata.class);
- completer.setId(getName());
- completer.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
- completer.setScope(MutableBeanMetadata.SCOPE_SINGLETON);
- completer.setRuntimeClass(clazz);
- // Create completer
- for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
- for (Field field : cl.getDeclaredFields()) {
- if (field.getAnnotation(Reference.class) != null) {
- if (field.getType() == BundleContext.class) {
- completer.addProperty(field.getName(), createRef(context, "blueprintBundleContext"));
- } else {
- completer.addProperty(field.getName(), createRef(context, createServiceRef(context, field.getType()).getId()));
- }
- }
- }
- for (Method method : cl.getDeclaredMethods()) {
- if (method.getAnnotation(Init.class) != null) {
- if (completer.getInitMethod() == null) {
- completer.setInitMethod(method.getName());
- }
- }
- if (method.getAnnotation(Destroy.class) != null) {
- if (completer.getDestroyMethod() == null) {
- completer.setDestroyMethod(method.getName());
- }
- }
- }
- }
- context.getComponentDefinitionRegistry().registerComponentDefinition(completer);
- // Create completer service
- MutableServiceMetadata completerService = context.createMetadata(MutableServiceMetadata.class);
- completerService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
- completerService.setId(getName());
- completerService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
- completerService.setServiceComponent(createRef(context, completer.getId()));
- context.getComponentDefinitionRegistry().registerComponentDefinition(completerService);
- }
- }
-
- private ComponentMetadata createServiceRef(ParserContext context, Class<?> cls) {
- String id = ".serviceref." + cls.getName();
- ComponentMetadata metadata = context.getComponentDefinitionRegistry().getComponentDefinition(id);
- if (metadata == null) {
- MutableReferenceMetadata m = context.createMetadata(MutableReferenceMetadata.class);
- m.setRuntimeInterface(cls);
- m.setInterface(cls.getName());
- m.setActivation(ReferenceMetadata.ACTIVATION_EAGER);
- m.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
- m.setId(id);
- context.getComponentDefinitionRegistry().registerComponentDefinition(m);
- return m;
- } else {
- return metadata;
- }
- }
-
- private Bundle getBundle(ParserContext context) {
- PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintBundle");
- return (Bundle) ptm.getObject();
- }
-
- private void parseChildElement(Element element, ParserContext context) {
- if (nodeNameEquals(element, COMMAND)) {
- parseCommand(element, context);
- }
- }
-
- private void registerConverters(ParserContext context) {
- String converterName = "." + NumberToStringConverter.class.getName();
- if (!context.getComponentDefinitionRegistry().containsComponentDefinition(converterName)) {
- MutablePassThroughMetadata cnv = context.createMetadata(MutablePassThroughMetadata.class);
- cnv.setId(converterName);
- cnv.setObject(new NumberToStringConverter());
- context.getComponentDefinitionRegistry().registerTypeConverter(cnv);
- }
- }
-
- private void parseCommand(Element element, ParserContext context) {
- MutableBeanMetadata command = context.createMetadata(MutableBeanMetadata.class);
- command.setRuntimeClass(BlueprintCommand.class);
- command.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
- command.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
-
- NodeList children = element.getChildNodes();
- MutableBeanMetadata action = null;
- for (int i = 0; i < children.getLength(); i++) {
- Node child = children.item(i);
- if (child instanceof Element) {
- Element childElement = (Element) child;
- if (nodeNameEquals(childElement, ACTION)) {
- action = parseAction(context, command, childElement);
- action.setId(getName());
- context.getComponentDefinitionRegistry().registerComponentDefinition(action);
- command.addProperty(ACTION_ID, createIdRef(context, action.getId()));
- } else if (nodeNameEquals(childElement, COMPLETERS)) {
- command.addProperty(COMPLETERS, parseCompleters(context, command, childElement));
- } else if (nodeNameEquals(childElement, OPTIONAL_COMPLETERS)) {
- command.addProperty(OPTIONAL_COMPLETERS_PROPERTY, parseOptionalCompleters(context, command, childElement));
- }
- else {
- throw new ComponentDefinitionException("Bad xml syntax: unknown element '" + childElement.getNodeName() + "'");
- }
- }
- }
-
- MutableServiceMetadata commandService = context.createMetadata(MutableServiceMetadata.class);
- commandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
- commandService.setId(getName());
- commandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
- commandService.setServiceComponent(command);
-
- String scope;
- String function;
- if (SHELL_NAMESPACE_1_0_0.equals(element.getNamespaceURI())) {
- String location = element.getAttribute(NAME);
- location = location.replace('/', ':');
- if (location.lastIndexOf(':') >= 0) {
- scope = location.substring(0, location.lastIndexOf(':'));
- function = location.substring(location.lastIndexOf(':') + 1);
- } else {
- scope = "";
- function = location;
- }
- } else {
- try {
- Class actionClass = getBundle(context).loadClass(action.getClassName());
- scope = getScope(actionClass);
- function = getName(actionClass);
- } catch (Throwable e) {
- throw new ComponentDefinitionException("Unable to introspect action " + action.getClassName(), e);
- }
- }
- commandService.addServiceProperty(createStringValue(context, "osgi.command.scope"),
- createStringValue(context, scope));
- commandService.addServiceProperty(createStringValue(context, "osgi.command.function"),
- createStringValue(context, function));
-
- context.getComponentDefinitionRegistry().registerComponentDefinition(commandService);
-
- // create the sub-shell action
- createSubShell(context, scope);
- }
-
- private void createSubShell(ParserContext context, String scope) {
- String subShellName = ".subshell." + scope;
- if (context.getComponentDefinitionRegistry().containsComponentDefinition(subShellName)) {
- return;
- }
- MutableBeanMetadata subShellAction = context.createMetadata(MutableBeanMetadata.class);
- subShellAction.setRuntimeClass(SubShellAction.class);
- subShellAction.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
- subShellAction.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
- subShellAction.setId(getName());
- subShellAction.addProperty("subShell", createStringValue(context, scope));
- context.getComponentDefinitionRegistry().registerComponentDefinition(subShellAction);
- // generate the sub-shell command
- MutableBeanMetadata subShellCommand = context.createMetadata(MutableBeanMetadata.class);
- subShellCommand.setId(getName());
- subShellCommand.setRuntimeClass(BlueprintCommand.class);
- subShellCommand.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
- subShellCommand.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
- subShellCommand.addProperty(ACTION_ID, createIdRef(context, subShellAction.getId()));
- context.getComponentDefinitionRegistry().registerComponentDefinition(subShellCommand);
- // generate the sub-shell OSGi service
- MutableServiceMetadata subShellCommandService = context.createMetadata(MutableServiceMetadata.class);
- subShellCommandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
- subShellCommandService.setId(subShellName);
- subShellCommandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
- subShellCommandService.setServiceComponent(subShellCommand);
- subShellCommandService.addServiceProperty(createStringValue(context, "osgi.command.scope"), createStringValue(context, "*"));
- subShellCommandService.addServiceProperty(createStringValue(context, "osgi.command.function"), createStringValue(context, scope));
- context.getComponentDefinitionRegistry().registerComponentDefinition(subShellCommandService);
- }
-
- private MutableBeanMetadata getInvocationValue(ParserContext context, String method, String className) {
- MutableBeanMetadata scope = context.createMetadata(MutableBeanMetadata.class);
- scope.setRuntimeClass(NamespaceHandler.class);
- scope.setFactoryMethod(method);
- scope.addArgument(createStringValue(context, className), null, 0);
- return scope;
- }
-
- private MutableBeanMetadata parseAction(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
- MutableBeanMetadata action = context.createMetadata(MutableBeanMetadata.class);
- action.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
- action.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
- action.setClassName(element.getAttribute("class"));
- NodeList children = element.getChildNodes();
- for (int i = 0; i < children.getLength(); i++) {
- Node child = children.item(i);
- if (child instanceof Element) {
- Element childElement = (Element) child;
- if (nodeNameEquals(childElement, "argument")) {
- action.addArgument(context.parseElement(BeanArgument.class, enclosingComponent, childElement));
- } else if (nodeNameEquals(childElement, "property")) {
- action.addProperty(context.parseElement(BeanProperty.class, enclosingComponent, childElement));
- }
- }
- }
- return action;
- }
-
- private Metadata parseOptionalCompleters(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
- Metadata metadata = context.parseElement(MapMetadata.class, context.getEnclosingComponent(), (Element) element);
- return metadata;
- }
-
- private Metadata parseCompleters(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
- MutableCollectionMetadata collection = context.createMetadata(MutableCollectionMetadata.class);
- collection.setCollectionClass(List.class);
- NodeList children = element.getChildNodes();
- for (int i = 0; i < children.getLength(); i++) {
- Node child = children.item(i);
- if (child instanceof Element) {
- Metadata metadata;
- if (nodeNameEquals(child, REF)) {
- metadata = context.parseElement(RefMetadata.class, context.getEnclosingComponent(), (Element) child);
- } else if (nodeNameEquals(child, NULL)) {
- metadata = context.parseElement(NullMetadata.class, context.getEnclosingComponent(), (Element) child);
- } else if (nodeNameEquals(child, BEAN)) {
- metadata = context.parseElement(BeanMetadata.class, enclosingComponent, (Element) child);
- } else {
- throw new IllegalStateException("Unexpected element " + child.getNodeName());
- }
- collection.addValue(metadata);
- }
- }
- return collection;
- }
-
- private ValueMetadata createStringValue(ParserContext context, String str) {
- MutableValueMetadata value = context.createMetadata(MutableValueMetadata.class);
- value.setStringValue(str);
- return value;
- }
-
- private RefMetadata createRef(ParserContext context, String id) {
- MutableRefMetadata idref = context.createMetadata(MutableRefMetadata.class);
- idref.setComponentId(id);
- return idref;
- }
-
- private IdRefMetadata createIdRef(ParserContext context, String id) {
- MutableIdRefMetadata idref = context.createMetadata(MutableIdRefMetadata.class);
- idref.setComponentId(id);
- return idref;
- }
-
- public synchronized String getName() {
- return "shell-" + ++nameCounter;
- }
-
- private static boolean nodeNameEquals(Node node, String name) {
- return (name.equals(node.getNodeName()) || name.equals(node.getLocalName()));
- }
-
- public static String getScope(Class<?> action) {
- Command command = action.getAnnotation(Command.class);
- if (command != null) {
- return command.scope();
- }
- org.apache.felix.gogo.commands.Command command2 = action.getAnnotation(org.apache.felix.gogo.commands.Command.class);
- if (command2 != null) {
- return command2.scope();
- }
- return null;
- }
-
- public static String getName(Class<?> action) {
- Command command = action.getAnnotation(Command.class);
- if (command != null) {
- return command.name();
- }
- org.apache.felix.gogo.commands.Command command2 = action.getAnnotation(org.apache.felix.gogo.commands.Command.class);
- if (command2 != null) {
- return command2.name();
- }
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
deleted file mode 100644
index fb68c3a..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
+++ /dev/null
@@ -1,36 +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.console.commands;
-
-import org.osgi.service.blueprint.container.Converter;
-import org.osgi.service.blueprint.container.ReifiedType;
-
-public class NumberToStringConverter implements Converter {
-
- @Override
- public boolean canConvert(Object sourceObject, ReifiedType targetType) {
- return sourceObject != null && sourceObject instanceof Number
- && targetType.getRawClass() == String.class;
- }
-
- @Override
- public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
- return sourceObject.toString();
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
deleted file mode 100644
index dbba436..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
+++ /dev/null
@@ -1,91 +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.console.completer;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Collection;
-
-import org.apache.karaf.shell.console.Completer;
-
-/**
- * Completer which contains multipule completers and aggregates them together.
- */
-public class AggregateCompleter implements Completer
-{
- private final Collection<Completer> completers;
-
- public AggregateCompleter(final Collection<Completer> completers) {
- assert completers != null;
- this.completers = completers;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public int complete(final String buffer, final int cursor, final List candidates) {
- // buffer could be null
- assert candidates != null;
-
- List<Completion> completions = new ArrayList<Completion>(completers.size());
-
- // Run each completer, saving its completion results
- int max = -1;
- for (Completer completer : completers) {
- Completion completion = new Completion(candidates);
- completion.complete(completer, buffer, cursor);
-
- // Compute the max cursor position
- max = Math.max(max, completion.cursor);
-
- completions.add(completion);
- }
-
- // Append candiates from completions which have the same cursor position as max
- for (Completion completion : completions) {
- if (completion.cursor == max) {
- // noinspection unchecked
- candidates.addAll(completion.candidates);
- }
- }
-
- return max;
- }
-
- private class Completion
- {
- public final List<String> candidates;
-
- public int cursor;
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public Completion(final List candidates) {
- assert candidates != null;
-
- // noinspection unchecked
- this.candidates = new LinkedList<String>(candidates);
- }
-
- public void complete(final Completer completer, final String buffer, final int cursor) {
- assert completer != null;
-
- this.cursor = completer.complete(buffer, cursor, candidates);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
deleted file mode 100644
index 745489e..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
+++ /dev/null
@@ -1,567 +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.console.completer;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.CommandWithAction;
-import org.apache.karaf.shell.commands.CompleterValues;
-import org.apache.karaf.shell.commands.HelpOption;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.CommandSessionHolder;
-import org.apache.karaf.shell.console.CompletableFunction;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.NameScoping;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.karaf.shell.console.completer.CommandsCompleter.unProxy;
-
-public class ArgumentCompleter implements Completer {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentCompleter.class);
-
- public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
-
- public static final String COMMANDS = ".commands";
-
- final Completer commandCompleter;
- final Completer optionsCompleter;
- final List<Completer> argsCompleters;
- final Map<String, Completer> optionalCompleters;
- final CommandWithAction function;
- final Map<Option, Field> fields = new HashMap<Option, Field>();
- final Map<String, Option> options = new HashMap<String, Option>();
- final Map<Integer, Field> arguments = new HashMap<Integer, Field>();
- boolean strict = true;
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public ArgumentCompleter(CommandSession session, CommandWithAction function, String command) {
- this.function = function;
- // Command name completer
- commandCompleter = new StringsCompleter(getNames(session, command));
- // Build options completer
- for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
- for (Field field : type.getDeclaredFields()) {
- Option option = field.getAnnotation(Option.class);
- if (option != null) {
- fields.put(option, field);
- options.put(option.name(), option);
- String[] aliases = option.aliases();
- if (aliases != null) {
- for (String alias : aliases) {
- options.put(alias, option);
- }
- }
- }
- Argument argument = field.getAnnotation(Argument.class);
- if (argument != null) {
- Integer key = argument.index();
- if (arguments.containsKey(key)) {
- LOGGER.warn("Duplicate @Argument annotations on class " + type.getName() + " for index: " + key + " see: " + field);
- } else {
- arguments.put(key, field);
- }
- }
- }
- }
- options.put(HelpOption.HELP.name(), HelpOption.HELP);
- optionsCompleter = new StringsCompleter(options.keySet());
-
- // Build arguments completers
- List<Completer> argsCompleters = null;
- Map<String, Completer> optionalCompleters = null;
-
- if (function instanceof CompletableFunction) {
- Map<String, Completer> focl = ((CompletableFunction) function).getOptionalCompleters();
- List<Completer> fcl = ((CompletableFunction) function).getCompleters();
- if (focl != null || fcl != null) {
- argsCompleters = new ArrayList<Completer>();
- if (fcl != null) {
- for (Completer c : fcl) {
- argsCompleters.add(c == null ? NullCompleter.INSTANCE : c);
- }
- }
- optionalCompleters = focl;
- }
- }
- if (argsCompleters == null) {
- final Map<Integer, Object> values = getCompleterValues(function);
- argsCompleters = new ArrayList<Completer>();
- boolean multi = false;
- for (int key = 0; key < arguments.size(); key++) {
- Completer completer = null;
- Field field = arguments.get(key);
- if (field != null) {
- Argument argument = field.getAnnotation(Argument.class);
- multi = (argument != null && argument.multiValued());
- org.apache.karaf.shell.commands.Completer ann = field.getAnnotation(org.apache.karaf.shell.commands.Completer.class);
- if (ann != null) {
- Class clazz = ann.value();
- String[] value = ann.values();
- if (clazz != null) {
- if (value.length > 0 && clazz == StringsCompleter.class) {
- completer = new StringsCompleter(value, ann.caseSensitive());
- } else {
- BundleContext context = FrameworkUtil.getBundle(function.getClass()).getBundleContext();
- completer = new ProxyServiceCompleter(context, clazz);
- }
- }
- } else if (values.containsKey(key)) {
- Object value = values.get(key);
- if (value instanceof String[]) {
- completer = new StringsCompleter((String[]) value);
- } else if (value instanceof Collection) {
- completer = new StringsCompleter((Collection<String>) value);
- } else {
- LOGGER.warn("Could not use value " + value + " as set of completions!");
- }
- } else {
- completer = getDefaultCompleter(session, field);
- }
- }
- if (completer == null) {
- completer = NullCompleter.INSTANCE;
- }
- argsCompleters.add(completer);
- }
- if (argsCompleters.isEmpty() || !multi) {
- argsCompleters.add(NullCompleter.INSTANCE);
- }
- optionalCompleters = new HashMap<String, Completer>();
- for (Option option : fields.keySet()) {
- Completer completer = null;
- Field field = fields.get(option);
- if (field != null) {
- org.apache.karaf.shell.commands.Completer ann = field.getAnnotation(org.apache.karaf.shell.commands.Completer.class);
- if (ann != null) {
- Class clazz = ann.value();
- String[] value = ann.values();
- if (clazz != null) {
- if (value.length > 0 && clazz == StringsCompleter.class) {
- completer = new StringsCompleter(value, ann.caseSensitive());
- } else {
- BundleContext context = FrameworkUtil.getBundle(function.getClass()).getBundleContext();
- completer = new ProxyServiceCompleter(context, clazz);
- }
- }
- }
- }
- if (completer == null) {
- completer = NullCompleter.INSTANCE;
- }
- optionalCompleters.put(option.name(), completer);
- if (option.aliases() != null) {
- for (String alias : option.aliases()) {
- optionalCompleters.put(alias, completer);
- }
- }
- }
- }
- this.argsCompleters = argsCompleters;
- this.optionalCompleters = optionalCompleters;
- }
-
- private Map<Integer, Object> getCompleterValues(CommandWithAction function) {
- final Map<Integer, Object> values = new HashMap<Integer, Object>();
- Action action = null;
- try {
- for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
- for (Method method : type.getDeclaredMethods()) {
- CompleterValues completerMethod = method.getAnnotation(CompleterValues.class);
- if (completerMethod != null) {
- int index = completerMethod.index();
- Integer key = index;
- if (index >= arguments.size() || index < 0) {
- LOGGER.warn("Index out of range on @CompleterValues on class " + type.getName() + " for index: " + key + " see: " + method);
- } else if (values.containsKey(key)) {
- LOGGER.warn("Duplicate @CompleterMethod annotations on class " + type.getName() + " for index: " + key + " see: " + method);
- } else {
- try {
- Object value;
- if (Modifier.isStatic(method.getModifiers())) {
- value = method.invoke(null);
- } else {
- if (action == null) {
- action = function.createNewAction();
- }
- value = method.invoke(action);
- }
- values.put(key, value);
- } catch (IllegalAccessException e) {
- LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + e, e);
- } catch (InvocationTargetException e) {
- Throwable target = e.getTargetException();
- if (target == null) {
- target = e;
- }
- LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + target, target);
- }
- }
- }
- }
- }
- } finally {
- if (action != null) {
- try {
- function.releaseAction(action);
- } catch (Exception e) {
- LOGGER.warn("Failed to release action: " + action + ". " + e, e);
- }
- }
- }
- return values;
- }
-
- private Completer getDefaultCompleter(CommandSession session, Field field) {
- Completer completer = null;
- Class<?> type = field.getType();
- if (type.isAssignableFrom(File.class)) {
- completer = new FileCompleter(session);
- } else if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) {
- completer = new StringsCompleter(new String[] {"false", "true"}, false);
- } else if (type.isAssignableFrom(Enum.class)) {
- Set<String> values = new HashSet<String>();
- for (Object o : EnumSet.allOf((Class<Enum>) type)) {
- values.add(o.toString());
- }
- completer = new StringsCompleter(values, false);
- } else {
- // TODO any other completers we can add?
- }
- return completer;
- }
-
- private String[] getNames(CommandSession session, String scopedCommand) {
- String command = NameScoping.getCommandNameWithoutGlobalPrefix(session, scopedCommand);
- String[] s = command.split(":");
- if (s.length == 1) {
- return s;
- } else {
- return new String[] { command, s[1] };
- }
- }
-
- /**
- * If true, a completion at argument index N will only succeed
- * if all the completions from 0-(N-1) also succeed.
- */
- public void setStrict(final boolean strict) {
- this.strict = strict;
- }
-
- /**
- * Returns whether a completion at argument index N will succees
- * if all the completions from arguments 0-(N-1) also succeed.
- */
- public boolean getStrict() {
- return this.strict;
- }
-
- public int complete(final String buffer, final int cursor,
- final List<String> candidates) {
- ArgumentList list = delimit(buffer, cursor);
- int argpos = list.getArgumentPosition();
- int argIndex = list.getCursorArgumentIndex();
-
- //Store the argument list so that it can be used by completers.
- CommandSession commandSession = CommandSessionHolder.getSession();
- if(commandSession != null) {
- commandSession.put(ARGUMENTS_LIST,list);
- }
-
- Completer comp = null;
- String[] args = list.getArguments();
- int index = 0;
- // First argument is command name
- if (index < argIndex) {
- // Verify command name
- if (!verifyCompleter(commandCompleter, args[index])) {
- return -1;
- }
- // Verify scope if
- // - the command name has no scope
- // - we have a session
- if (!args[index].contains(":") && commandSession != null) {
- Function f1 = unProxy((Function) commandSession.get("*:" + args[index]));
- Function f2 = unProxy(this.function);
- if (f1 != null && f1 != f2) {
- return -1;
- }
- }
- index++;
- } else {
- comp = commandCompleter;
- }
- // Now, check options
- if (comp == null) {
- while (index < argIndex && args[index].startsWith("-")) {
- if (!verifyCompleter(optionsCompleter, args[index])) {
- return -1;
- }
- Option option = options.get(args[index]);
- if (option == null) {
- return -1;
- }
- Field field = fields.get(option);
- if (field != null && field.getType() != boolean.class && field.getType() != Boolean.class) {
- if (++index == argIndex) {
- comp = NullCompleter.INSTANCE;
- }
- }
- index++;
- }
- if (comp == null && index >= argIndex && index < args.length && args[index].startsWith("-")) {
- comp = optionsCompleter;
- }
- }
- //Now check for if last Option has a completer
- int lastAgurmentIndex = argIndex - 1;
- if (lastAgurmentIndex >= 1) {
- Option lastOption = options.get(args[lastAgurmentIndex]);
- if (lastOption != null) {
-
- Field lastField = fields.get(lastOption);
- if (lastField != null && lastField.getType() != boolean.class && lastField.getType() != Boolean.class) {
- Option option = lastField.getAnnotation(Option.class);
- if (option != null) {
- Completer optionValueCompleter = null;
- String name = option.name();
- if (optionalCompleters != null && name != null) {
- optionValueCompleter = optionalCompleters.get(name);
- if (optionValueCompleter == null) {
- String[] aliases = option.aliases();
- if (aliases.length > 0) {
- for (int i = 0; i < aliases.length && optionValueCompleter == null; i++) {
- optionValueCompleter = optionalCompleters.get(option.aliases()[i]);
- }
- }
- }
- }
- if(optionValueCompleter != null) {
- comp = optionValueCompleter;
- }
- }
- }
- }
- }
-
- // Check arguments
- if (comp == null) {
- int indexArg = 0;
- while (index < argIndex) {
- Completer sub = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
- if (!verifyCompleter(sub, args[index])) {
- return -1;
- }
- index++;
- indexArg++;
- }
- comp = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
- }
-
- int ret = comp.complete(list.getCursorArgument(), argpos, candidates);
-
- if (ret == -1) {
- return -1;
- }
-
- int pos = ret + (list.getBufferPosition() - argpos);
-
- /**
- * Special case: when completing in the middle of a line, and the
- * area under the cursor is a delimiter, then trim any delimiters
- * from the candidates, since we do not need to have an extra
- * delimiter.
- *
- * E.g., if we have a completion for "foo", and we
- * enter "f bar" into the buffer, and move to after the "f"
- * and hit TAB, we want "foo bar" instead of "foo bar".
- */
-
- if ((buffer != null) && (cursor != buffer.length()) && isDelimiter(buffer, cursor)) {
- for (int i = 0; i < candidates.size(); i++) {
- String val = candidates.get(i);
-
- while ((val.length() > 0)
- && isDelimiter(val, val.length() - 1)) {
- val = val.substring(0, val.length() - 1);
- }
-
- candidates.set(i, val);
- }
- }
-
- return pos;
- }
-
- protected boolean verifyCompleter(Completer completer, String argument) {
- List<String> candidates = new ArrayList<String>();
- return completer.complete(argument, argument.length(), candidates) != -1 && !candidates.isEmpty();
- }
-
- public ArgumentList delimit(final String buffer, final int cursor) {
- Parser parser = new Parser(buffer, cursor);
- try {
- List<List<List<String>>> program = parser.program();
- List<String> pipe = program.get(parser.c0).get(parser.c1);
- return new ArgumentList(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor);
- } catch (Throwable t) {
- return new ArgumentList(new String[] { buffer }, 0, cursor, cursor);
- }
- }
-
- /**
- * Returns true if the specified character is a whitespace
- * parameter. Check to ensure that the character is not
- * escaped and returns true from
- * {@link #isDelimiterChar}.
- *
- * @param buffer the complete command buffer
- * @param pos the index of the character in the buffer
- * @return true if the character should be a delimiter
- */
- public boolean isDelimiter(final String buffer, final int pos) {
- return !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
- }
-
- public boolean isEscaped(final String buffer, final int pos) {
- return pos > 0 && buffer.charAt(pos) == '\\' && !isEscaped(buffer, pos - 1);
- }
-
- /**
- * The character is a delimiter if it is whitespace, and the
- * preceeding character is not an escape character.
- */
- public boolean isDelimiterChar(String buffer, int pos) {
- return Character.isWhitespace(buffer.charAt(pos));
- }
-
- /**
- * The result of a delimited buffer.
- */
- public static class ArgumentList {
- private String[] arguments;
- private int cursorArgumentIndex;
- private int argumentPosition;
- private int bufferPosition;
-
- /**
- * @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
- */
- public ArgumentList(String[] arguments, int cursorArgumentIndex,
- int argumentPosition, int bufferPosition) {
- this.arguments = arguments;
- this.cursorArgumentIndex = cursorArgumentIndex;
- this.argumentPosition = argumentPosition;
- this.bufferPosition = bufferPosition;
- }
-
- public void setCursorArgumentIndex(int cursorArgumentIndex) {
- this.cursorArgumentIndex = cursorArgumentIndex;
- }
-
- public int getCursorArgumentIndex() {
- return this.cursorArgumentIndex;
- }
-
- public String getCursorArgument() {
- if ((cursorArgumentIndex < 0)
- || (cursorArgumentIndex >= arguments.length)) {
- return null;
- }
-
- return arguments[cursorArgumentIndex];
- }
-
- public void setArgumentPosition(int argumentPosition) {
- this.argumentPosition = argumentPosition;
- }
-
- public int getArgumentPosition() {
- return this.argumentPosition;
- }
-
- public void setArguments(String[] arguments) {
- this.arguments = arguments;
- }
-
- public String[] getArguments() {
- return this.arguments;
- }
-
- public void setBufferPosition(int bufferPosition) {
- this.bufferPosition = bufferPosition;
- }
-
- public int getBufferPosition() {
- return this.bufferPosition;
- }
- }
-
- public static class ProxyServiceCompleter implements Completer {
- private final BundleContext context;
- private final Class<? extends Completer> clazz;
-
- public ProxyServiceCompleter(BundleContext context, Class<? extends Completer> clazz) {
- this.context = context;
- this.clazz = clazz;
- }
-
- @Override
- public int complete(String buffer, int cursor, List<String> candidates) {
- ServiceReference<? extends Completer> ref = context.getServiceReference(clazz);
- if (ref != null) {
- Completer completer = context.getService(ref);
- if (completer != null) {
- try {
- return completer.complete(buffer, cursor, candidates);
- } finally {
- context.ungetService(ref);
- }
- }
- }
- return -1;
- }
- }
-}
[05/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
deleted file mode 100644
index 6b7865e..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/basic/DefaultActionPreparator.java
+++ /dev/null
@@ -1,566 +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.commands.basic;
-
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_DEFAULT;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_RED;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
-import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.Type;
-import java.util.*;
-import java.io.PrintStream;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.felix.gogo.commands.CommandException;
-import org.apache.felix.gogo.commands.Option;
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.gogo.commands.Argument;
-import org.apache.felix.gogo.commands.Command;
-import org.apache.felix.gogo.commands.converter.DefaultConverter;
-import org.apache.felix.gogo.commands.converter.GenericType;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.console.NameScoping;
-
-@Deprecated
-public class DefaultActionPreparator implements ActionPreparator {
-
- public static final Option HELP = new Option() {
- public String name() {
- return "--help";
- }
-
- public String[] aliases() {
- return new String[]{};
- }
-
- public String description() {
- return "Display this help message";
- }
-
- public boolean required() {
- return false;
- }
-
- public boolean multiValued() {
- return false;
- }
-
- public String valueToShowInHelp() {
- return Option.DEFAULT_STRING;
- }
-
- public Class<? extends Annotation> annotationType() {
- return Option.class;
- }
- };
-
- public boolean prepare(Action action, CommandSession session, List<Object> params) throws Exception {
- Map<Option, Field> options = new HashMap<Option, Field>();
- Map<Argument, Field> arguments = new HashMap<Argument, Field>();
- List<Argument> orderedArguments = new ArrayList<Argument>();
- // Introspect
- for (Class type = action.getClass(); type != null; type = type.getSuperclass()) {
- for (Field field : type.getDeclaredFields()) {
- Option option = field.getAnnotation(Option.class);
- if (option != null) {
- options.put(option, field);
- }
- Argument argument = field.getAnnotation(Argument.class);
- if (argument != null) {
- if (Argument.DEFAULT.equals(argument.name())) {
- final Argument delegate = argument;
- final String name = field.getName();
- argument = new Argument() {
- public String name() {
- return name;
- }
-
- public String description() {
- return delegate.description();
- }
-
- public boolean required() {
- return delegate.required();
- }
-
- public int index() {
- return delegate.index();
- }
-
- public boolean multiValued() {
- return delegate.multiValued();
- }
-
- public String valueToShowInHelp() {
- return delegate.valueToShowInHelp();
- }
-
- public Class<? extends Annotation> annotationType() {
- return delegate.annotationType();
- }
- };
- }
- arguments.put(argument, field);
- int index = argument.index();
- while (orderedArguments.size() <= index) {
- orderedArguments.add(null);
- }
- if (orderedArguments.get(index) != null) {
- throw new IllegalArgumentException("Duplicate argument index: " + index);
- }
- orderedArguments.set(index, argument);
- }
- }
- }
- // Check indexes are correct
- for (int i = 0; i < orderedArguments.size(); i++) {
- if (orderedArguments.get(i) == null) {
- throw new IllegalArgumentException("Missing argument for index: " + i);
- }
- }
- // Populate
- Map<Option, Object> optionValues = new HashMap<Option, Object>();
- Map<Argument, Object> argumentValues = new HashMap<Argument, Object>();
- boolean processOptions = true;
- int argIndex = 0;
- for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
- Object param = it.next();
- // Check for help
- if (HELP.name().equals(param) || Arrays.asList(HELP.aliases()).contains(param)) {
- printUsage(session, action, options, arguments, System.out);
- return false;
- }
- if (processOptions && param instanceof String && ((String) param).startsWith("-")) {
- boolean isKeyValuePair = ((String) param).indexOf('=') != -1;
- String name;
- Object value = null;
- if (isKeyValuePair) {
- name = ((String) param).substring(0, ((String) param).indexOf('='));
- value = ((String) param).substring(((String) param).indexOf('=') + 1);
- } else {
- name = (String) param;
- }
- Option option = null;
- for (Option opt : options.keySet()) {
- if (name.equals(opt.name()) || Arrays.asList(opt.aliases()).contains(name)) {
- option = opt;
- break;
- }
- }
- if (option == null) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + " undefined option "
- + INTENSITY_BOLD + param + INTENSITY_NORMAL
- + COLOR_DEFAULT,
- "Undefined option: " + param
- );
- } else {
- throw new CommandException("Undefined option: " + param);
- }
- }
- Field field = options.get(option);
- if (value == null && (field.getType() == boolean.class || field.getType() == Boolean.class)) {
- value = Boolean.TRUE;
- }
- if (value == null && it.hasNext()) {
- value = it.next();
- }
- if (value == null) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + " missing value for option "
- + INTENSITY_BOLD + param + INTENSITY_NORMAL
- + COLOR_DEFAULT,
- "Missing value for option: " + param
- );
- } else {
- throw new CommandException("Missing value for option: " + param);
- }
- }
- if (option.multiValued()) {
- List<Object> l = (List<Object>) optionValues.get(option);
- if (l == null) {
- l = new ArrayList<Object>();
- optionValues.put(option, l);
- }
- l.add(value);
- } else {
- optionValues.put(option, value);
- }
- } else {
- processOptions = false;
- if (argIndex >= orderedArguments.size()) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + ": too many arguments specified"
- + INTENSITY_BOLD + param + INTENSITY_NORMAL
- + COLOR_DEFAULT,
- "Too many arguments specified"
- );
- } else {
- throw new CommandException("Too many arguments specified");
- }
- }
- Argument argument = orderedArguments.get(argIndex);
- if (!argument.multiValued()) {
- argIndex++;
- }
- if (argument.multiValued()) {
- List<Object> l = (List<Object>) argumentValues.get(argument);
- if (l == null) {
- l = new ArrayList<Object>();
- argumentValues.put(argument, l);
- }
- l.add(param);
- } else {
- argumentValues.put(argument, param);
- }
- }
- }
- // Check required arguments / options
- for (Option option : options.keySet()) {
- if (option.required() && optionValues.get(option) == null) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + ": option "
- + INTENSITY_BOLD + option.name() + INTENSITY_NORMAL
- + " is required"
- + COLOR_DEFAULT,
- "Option " + option.name() + " is required"
- );
- } else {
- throw new CommandException("Option " + option.name() + " is required");
- }
- }
- }
- for (Argument argument : orderedArguments) {
- if (argument.required() && argumentValues.get(argument) == null) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + ": argument "
- + INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL
- + " is required"
- + COLOR_DEFAULT,
- "Argument " + argument.name() + " is required"
- );
- } else {
- throw new CommandException("Argument " + argument.name() + " is required");
- }
- }
- }
- // Convert and inject values
- for (Map.Entry<Option, Object> entry : optionValues.entrySet()) {
- Field field = options.get(entry.getKey());
- Object value;
- try {
- value = convert(action, session, entry.getValue(), field.getGenericType());
- } catch (Exception e) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + ": unable to convert option "
- + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL
- + " with value '" + entry.getValue() + "' to type "
- + new GenericType(field.getGenericType()).toString()
- + COLOR_DEFAULT,
- "Unable to convert option " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e
- );
- } else {
- throw new CommandException("Unable to convert option " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e);
- }
- }
- field.setAccessible(true);
- field.set(action, value);
- }
- for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) {
- Field field = arguments.get(entry.getKey());
- Object value;
- try {
- value = convert(action, session, entry.getValue(), field.getGenericType());
- } catch (Exception e) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
- throw new CommandException(COLOR_RED
- + "Error executing command "
- + command.scope() + ":"
- + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL
- + ": unable to convert argument "
- + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL
- + " with value '" + entry.getValue() + "' to type "
- + new GenericType(field.getGenericType()).toString()
- + COLOR_DEFAULT,
- "Unable to convert argument " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e
- );
- } else {
- throw new CommandException("Unable to convert argument " + entry.getKey().name() + " with value '"
- + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
- e);
- }
- }
- field.setAccessible(true);
- field.set(action, value);
- }
- return true;
- }
-
- protected void printUsage(CommandSession session, Action action, Map<Option, Field> optionsMap, Map<Argument, Field> argsMap, PrintStream out) {
- Command command = action.getClass().getAnnotation(Command.class);
- if (command != null) {
-
- List<Argument> arguments = new ArrayList<Argument>(argsMap.keySet());
- Collections.sort(arguments, new Comparator<Argument>() {
- public int compare(Argument o1, Argument o2) {
- return Integer.valueOf(o1.index()).compareTo(Integer.valueOf(o2.index()));
- }
- });
- Set<Option> options = new HashSet<Option>(optionsMap.keySet());
- options.add(HELP);
- boolean globalScope = NameScoping.isGlobalScope(session, command.scope());
- if (command != null && (command.description() != null || command.name() != null)) {
- out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
- out.print(" ");
- if (command.name() != null) {
- if (globalScope) {
- out.println(INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
- } else {
- out.println(command.scope() + ":" + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
- }
- out.println();
- }
- out.print("\t");
- out.println(command.description());
- out.println();
- }
- StringBuffer syntax = new StringBuffer();
- if (command != null) {
- if (globalScope) {
- syntax.append(command.name());
- } else {
- syntax.append(String.format("%s:%s", command.scope(), command.name()));
- }
- }
- if (options.size() > 0) {
- syntax.append(" [options]");
- }
- if (arguments.size() > 0) {
- syntax.append(' ');
- for (Argument argument : arguments) {
- if (!argument.required()) {
- syntax.append(String.format("[%s] ", argument.name()));
- } else {
- syntax.append(String.format("%s ", argument.name()));
- }
- }
- }
- int width = getWidth(session);
- out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
- out.print(" ");
- out.println(syntax.toString());
- out.println();
- if (arguments.size() > 0) {
- out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL);
- for (Argument argument : arguments) {
- out.print(" ");
- out.println(INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL);
-
- printFormatted(" ", argument.description(), width, out);
- if (!argument.required()) {
- if (argument.valueToShowInHelp() != null && argument.valueToShowInHelp().length() != 0) {
- try {
- if (Argument.DEFAULT_STRING.equals(argument.valueToShowInHelp())) {
- argsMap.get(argument).setAccessible(true);
- Object o = argsMap.get(argument).get(action);
- printObjectDefaultsTo(out, o);
- } else {
- printDefaultsTo(out, argument.valueToShowInHelp());
- }
- } catch (Throwable t) {
- // Ignore
- }
- }
- }
- }
- out.println();
- }
- if (options.size() > 0) {
- out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
- for (Option option : options) {
- String opt = option.name();
- for (String alias : option.aliases()) {
- opt += ", " + alias;
- }
- out.print(" ");
- out.println(INTENSITY_BOLD + opt + INTENSITY_NORMAL);
- printFormatted(" ", option.description(), width, out);
- if (option.valueToShowInHelp() != null && option.valueToShowInHelp().length() != 0) {
- try {
- if (Option.DEFAULT_STRING.equals(option.valueToShowInHelp())) {
- optionsMap.get(option).setAccessible(true);
- Object o = optionsMap.get(option).get(action);
- printObjectDefaultsTo(out, o);
- } else {
- printDefaultsTo(out, option.valueToShowInHelp());
- }
- } catch (Throwable t) {
- // Ignore
- }
- }
- }
- out.println();
- }
- if (command.detailedDescription().length() > 0) {
- out.println(INTENSITY_BOLD + "DETAILS" + INTENSITY_NORMAL);
- String desc = loadDescription(action.getClass(), command.detailedDescription());
- printFormatted(" ", desc, width, out);
- }
- }
- }
-
- private void printObjectDefaultsTo(PrintStream out, Object o) {
- if (o != null
- && (!(o instanceof Boolean) || ((Boolean) o))
- && (!(o instanceof Number) || ((Number) o).doubleValue() != 0.0)) {
- printDefaultsTo(out, o.toString());
- }
- }
-
- private void printDefaultsTo(PrintStream out, String value) {
- out.print(" (defaults to ");
- out.print(value);
- out.println(")");
- }
-
- protected String loadDescription(Class clazz, String desc) {
- if (desc.startsWith("classpath:")) {
- InputStream is = clazz.getResourceAsStream(desc.substring("classpath:".length()));
- if (is == null) {
- is = clazz.getClassLoader().getResourceAsStream(desc.substring("classpath:".length()));
- }
- if (is == null) {
- desc = "Unable to load description from " + desc;
- } else {
- try {
- Reader r = new InputStreamReader(is);
- StringWriter sw = new StringWriter();
- int c;
- while ((c = r.read()) != -1) {
- sw.append((char) c);
- }
- desc = sw.toString();
- } catch (IOException e) {
- desc = "Unable to load description from " + desc;
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
- return desc;
- }
-
- // TODO move this to a helper class?
- public static void printFormatted(String prefix, String str, int termWidth, PrintStream out) {
- printFormatted(prefix, str, termWidth, out, true);
- }
-
- public static void printFormatted(String prefix, String str, int termWidth, PrintStream out, boolean prefixFirstLine) {
- int pfxLen = length(prefix);
- int maxwidth = termWidth - pfxLen;
- Pattern wrap = Pattern.compile("(\\S\\S{" + maxwidth + ",}|.{1," + maxwidth + "})(\\s+|$)");
- int cur = 0;
- while (cur >= 0) {
- int lst = str.indexOf('\n', cur);
- String s = (lst >= 0) ? str.substring(cur, lst) : str.substring(cur);
- if (s.length() == 0) {
- out.println();
- } else {
- Matcher m = wrap.matcher(s);
- while (m.find()) {
- if (cur > 0 || prefixFirstLine) {
- out.print(prefix);
- }
- out.println(m.group());
- }
- }
- if (lst >= 0) {
- cur = lst + 1;
- } else {
- break;
- }
- }
- }
-
- public static int length(String str) {
- return str.length();
- }
-
- protected Object convert(Action action, CommandSession session, Object value, Type toType) throws Exception {
- if (toType == String.class) {
- return value != null ? value.toString() : null;
- }
- return new DefaultConverter(action.getClass().getClassLoader()).convert(value, toType);
- }
-
- private int getWidth(CommandSession session) {
- Object cols = session.get("COLUMNS");
- return (cols != null && cols instanceof Integer) ? (Integer)cols : 80;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
deleted file mode 100644
index e7a4424..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
+++ /dev/null
@@ -1,402 +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.commands.converter;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Dictionary;
-import java.util.Locale;
-import java.util.Properties;
-import java.util.Hashtable;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.LinkedHashMap;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.Set;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Queue;
-import java.util.LinkedList;
-import java.util.regex.Pattern;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.math.BigInteger;
-import java.math.BigDecimal;
-import java.io.ByteArrayInputStream;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Array;
-import java.lang.reflect.Type;
-import java.lang.reflect.InvocationTargetException;
-
-@Deprecated
-public class DefaultConverter {
-
- private Object loader;
-
- public DefaultConverter(Object loader) {
- this.loader = loader;
- }
-
- public Object convert(Object source, Type target) throws Exception {
- return convert(source, new GenericType(target));
- }
-
- public Object convert(Object fromValue, ReifiedType type) throws Exception {
- // Discard null values
- if (fromValue == null) {
- return null;
- }
- // If the object is an instance of the type, just return it
- if (isAssignable(fromValue, type)) {
- return fromValue;
- }
- Object value = convertWithConverters(fromValue, type);
- if (value == null) {
- if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
- return convertToNumber((Number) fromValue, toClass(type));
- } else if (fromValue instanceof String) {
- return convertFromString((String) fromValue, toClass(type), loader);
- } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
- return convertToArray(fromValue, type);
- } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
- return convertToMap(fromValue, type);
- } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
- return convertToDictionary(fromValue, type);
- } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
- return convertToCollection(fromValue, type);
- } else {
- throw new Exception("Unable to convert value " + fromValue + " to type " + type);
- }
- }
- return value;
- }
-
- private Object convertWithConverters(Object source, ReifiedType type) throws Exception {
- Object value = null;
-// for (Converter converter : converters) {
-// if (converter.canConvert(source, type)) {
-// value = converter.convert(source, type);
-// if (value != null) {
-// return value;
-// }
-// }
-// }
- return value;
- }
-
- public Object convertToNumber(Number value, Class toType) throws Exception {
- toType = unwrap(toType);
- if (AtomicInteger.class == toType) {
- return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
- } else if (AtomicLong.class == toType) {
- return new AtomicLong((Long) convertToNumber(value, Long.class));
- } else if (Integer.class == toType) {
- return value.intValue();
- } else if (Short.class == toType) {
- return value.shortValue();
- } else if (Long.class == toType) {
- return value.longValue();
- } else if (Float.class == toType) {
- return value.floatValue();
- } else if (Double.class == toType) {
- return value.doubleValue();
- } else if (Byte.class == toType) {
- return value.byteValue();
- } else if (BigInteger.class == toType) {
- return new BigInteger(value.toString());
- } else if (BigDecimal.class == toType) {
- return new BigDecimal(value.toString());
- } else {
- throw new Exception("Unable to convert number " + value + " to " + toType);
- }
- }
-
- public Object convertFromString(String value, Class toType, Object loader) throws Exception {
- toType = unwrap(toType);
- if (ReifiedType.class == toType) {
- try {
- return GenericType.parse(value, loader);
- } catch (ClassNotFoundException e) {
- throw new Exception("Unable to convert", e);
- }
- } else if (Class.class == toType) {
- try {
- return GenericType.parse(value, loader).getRawClass();
- } catch (ClassNotFoundException e) {
- throw new Exception("Unable to convert", e);
- }
- } else if (Locale.class == toType) {
- String[] tokens = value.split("_");
- if (tokens.length == 1) {
- return new Locale(tokens[0]);
- } else if (tokens.length == 2) {
- return new Locale(tokens[0], tokens[1]);
- } else if (tokens.length == 3) {
- return new Locale(tokens[0], tokens[1], tokens[2]);
- } else {
- throw new Exception("Invalid locale string:" + value);
- }
- } else if (Pattern.class == toType) {
- return Pattern.compile(value);
- } else if (Properties.class == toType) {
- Properties props = new Properties();
- ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
- props.load(in);
- return props;
- } else if (Boolean.class == toType) {
- if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
- return Boolean.TRUE;
- } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
- return Boolean.FALSE;
- } else {
- throw new RuntimeException("Invalid boolean value: " + value);
- }
- } else if (Integer.class == toType) {
- return Integer.valueOf(value);
- } else if (Short.class == toType) {
- return Short.valueOf(value);
- } else if (Long.class == toType) {
- return Long.valueOf(value);
- } else if (Float.class == toType) {
- return Float.valueOf(value);
- } else if (Double.class == toType) {
- return Double.valueOf(value);
- } else if (Character.class == toType) {
- if (value.length() == 6 && value.startsWith("\\u")) {
- int code = Integer.parseInt(value.substring(2), 16);
- return (char) code;
- } else if (value.length() == 1) {
- return value.charAt(0);
- } else {
- throw new Exception("Invalid value for character type: " + value);
- }
- } else if (Byte.class == toType) {
- return Byte.valueOf(value);
- } else if (Enum.class.isAssignableFrom(toType)) {
- return Enum.valueOf((Class<Enum>) toType, value);
- } else {
- return createObject(value, toType);
- }
- }
-
- private static Object createObject(String value, Class type) throws Exception {
- if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
- throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
- }
- Constructor constructor = null;
- try {
- constructor = type.getConstructor(String.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Unable to convert to " + type);
- }
- try {
- return constructor.newInstance(value);
- } catch (Exception e) {
- throw new Exception("Unable to convert ", getRealCause(e));
- }
- }
-
- private static Throwable getRealCause(Throwable t) {
- if (t instanceof InvocationTargetException && t.getCause() != null) {
- return t.getCause();
- }
- return t;
- }
-
- private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
- ReifiedType valueType = type.getActualTypeArgument(0);
- Collection newCol = (Collection) getCollection(toClass(type)).newInstance();
- if (obj.getClass().isArray()) {
- for (int i = 0; i < Array.getLength(obj); i++) {
- try {
- newCol.add(convert(Array.get(obj, i), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
- }
- }
- } else {
- for (Object item : (Collection) obj) {
- try {
- newCol.add(convert(item, valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
- }
- }
- }
- return newCol;
- }
-
- private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
- ReifiedType keyType = type.getActualTypeArgument(0);
- ReifiedType valueType = type.getActualTypeArgument(1);
- Dictionary newDic = new Hashtable();
- if (obj instanceof Dictionary) {
- Dictionary dic = (Dictionary) obj;
- for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements(); ) {
- Object key = keyEnum.nextElement();
- try {
- newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- } else {
- for (Map.Entry e : ((Map<Object, Object>) obj).entrySet()) {
- try {
- newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- }
- return newDic;
- }
-
- private Object convertToMap(Object obj, ReifiedType type) throws Exception {
- ReifiedType keyType = type.getActualTypeArgument(0);
- ReifiedType valueType = type.getActualTypeArgument(1);
- Map newMap = (Map) getMap(toClass(type)).newInstance();
- if (obj instanceof Dictionary) {
- Dictionary dic = (Dictionary) obj;
- for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements(); ) {
- Object key = keyEnum.nextElement();
- try {
- newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- } else {
- for (Map.Entry e : ((Map<Object, Object>) obj).entrySet()) {
- try {
- newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
- }
- }
- }
- return newMap;
- }
-
- private Object convertToArray(Object obj, ReifiedType type) throws Exception {
- if (obj instanceof Collection) {
- obj = ((Collection) obj).toArray();
- }
- if (!obj.getClass().isArray()) {
- throw new Exception("Unable to convert from " + obj + " to " + type);
- }
- ReifiedType componentType;
- if (type.size() > 0) {
- componentType = type.getActualTypeArgument(0);
- } else {
- componentType = new GenericType(type.getRawClass().getComponentType());
- }
- Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
- for (int i = 0; i < Array.getLength(obj); i++) {
- try {
- Array.set(array, i, convert(Array.get(obj, i), componentType));
- } catch (Exception t) {
- throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
- }
- }
- return array;
- }
-
- public static boolean isAssignable(Object source, ReifiedType target) {
- return source == null
- || (target.size() == 0
- && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
- }
-
- private static Class unwrap(Class c) {
- Class u = primitives.get(c);
- return u != null ? u : c;
- }
-
- private static Class getMap(Class type) {
- if (hasDefaultConstructor(type)) {
- return type;
- } else if (SortedMap.class.isAssignableFrom(type)) {
- return TreeMap.class;
- } else if (ConcurrentMap.class.isAssignableFrom(type)) {
- return ConcurrentHashMap.class;
- } else {
- return LinkedHashMap.class;
- }
- }
-
- private static Class getCollection(Class type) {
- if (hasDefaultConstructor(type)) {
- return type;
- } else if (SortedSet.class.isAssignableFrom(type)) {
- return TreeSet.class;
- } else if (Set.class.isAssignableFrom(type)) {
- return LinkedHashSet.class;
- } else if (List.class.isAssignableFrom(type)) {
- return ArrayList.class;
- } else if (Queue.class.isAssignableFrom(type)) {
- return LinkedList.class;
- } else {
- return ArrayList.class;
- }
- }
-
- private static boolean hasDefaultConstructor(Class type) {
- if (!Modifier.isPublic(type.getModifiers())) {
- return false;
- }
- if (Modifier.isAbstract(type.getModifiers())) {
- return false;
- }
- Constructor[] constructors = type.getConstructors();
- for (Constructor constructor : constructors) {
- if (Modifier.isPublic(constructor.getModifiers()) &&
- constructor.getParameterTypes().length == 0) {
- return true;
- }
- }
- return false;
- }
-
- private static final Map<Class, Class> primitives;
-
- static {
- primitives = new HashMap<Class, Class>();
- primitives.put(byte.class, Byte.class);
- primitives.put(short.class, Short.class);
- primitives.put(char.class, Character.class);
- primitives.put(int.class, Integer.class);
- primitives.put(long.class, Long.class);
- primitives.put(float.class, Float.class);
- primitives.put(double.class, Double.class);
- primitives.put(boolean.class, Boolean.class);
- }
-
- private Class toClass(ReifiedType type) {
- return type.getRawClass();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
deleted file mode 100644
index dae6651..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
+++ /dev/null
@@ -1,196 +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.commands.converter;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.osgi.framework.Bundle;
-
-@Deprecated
-public class GenericType extends ReifiedType {
-
- private static final GenericType[] EMPTY = new GenericType[0];
-
- private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
-
- static {
- primitiveClasses.put("int", int.class);
- primitiveClasses.put("short", short.class);
- primitiveClasses.put("long", long.class);
- primitiveClasses.put("byte", byte.class);
- primitiveClasses.put("char", char.class);
- primitiveClasses.put("float", float.class);
- primitiveClasses.put("double", double.class);
- primitiveClasses.put("boolean", boolean.class);
- }
-
- private GenericType[] parameters;
-
- public GenericType(Type type) {
- this(getConcreteClass(type), parametersOf(type));
- }
-
- public GenericType(Class clazz, GenericType... parameters) {
- super(clazz);
- this.parameters = parameters;
- }
-
- public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
- type = type.trim();
- // Check if this is an array
- if (type.endsWith("[]")) {
- GenericType t = parse(type.substring(0, type.length() - 2), loader);
- return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
- }
- // Check if this is a generic
- int genericIndex = type.indexOf('<');
- if (genericIndex > 0) {
- if (!type.endsWith(">")) {
- throw new IllegalArgumentException("Can not load type: " + type);
- }
- GenericType base = parse(type.substring(0, genericIndex), loader);
- String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
- GenericType[] types = new GenericType[params.length];
- for (int i = 0; i < params.length; i++) {
- types[i] = parse(params[i], loader);
- }
- return new GenericType(base.getRawClass(), types);
- }
- // Primitive
- if (primitiveClasses.containsKey(type)) {
- return new GenericType(primitiveClasses.get(type));
- }
- // Class
- if (loader instanceof ClassLoader) {
- return new GenericType(((ClassLoader) loader).loadClass(type));
- } else if (loader instanceof Bundle) {
- return new GenericType(((Bundle) loader).loadClass(type));
- } else {
- throw new IllegalArgumentException("Unsupported loader: " + loader);
- }
- }
-
- @Override
- public ReifiedType getActualTypeArgument(int i) {
- if (parameters.length == 0) {
- return super.getActualTypeArgument(i);
- }
- return parameters[i];
- }
-
- @Override
- public int size() {
- return parameters.length;
- }
-
- @Override
- public String toString() {
- Class cl = getRawClass();
- if (cl.isArray()) {
- if (parameters.length > 0) {
- return parameters[0].toString() + "[]";
- } else {
- return cl.getComponentType().getName() + "[]";
- }
- }
- if (parameters.length > 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(cl.getName());
- sb.append("<");
- for (int i = 0; i < parameters.length; i++) {
- if (i > 0) {
- sb.append(",");
- }
- sb.append(parameters[i].toString());
- }
- sb.append(">");
- return sb.toString();
- }
- return cl.getName();
- }
-
- static GenericType[] parametersOf(Type type ) {
- if ( type instanceof Class ) {
- Class clazz = (Class) type;
- if (clazz.isArray()) {
- GenericType t = new GenericType(clazz.getComponentType());
- if (t.size() > 0) {
- return new GenericType[] { t };
- } else {
- return EMPTY;
- }
- } else {
- return EMPTY;
- }
- }
- if ( type instanceof ParameterizedType ) {
- ParameterizedType pt = (ParameterizedType) type;
- Type [] parameters = pt.getActualTypeArguments();
- GenericType[] gts = new GenericType[parameters.length];
- for ( int i =0; i<gts.length; i++) {
- gts[i] = new GenericType(parameters[i]);
- }
- return gts;
- }
- if ( type instanceof GenericArrayType ) {
- return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
- }
- throw new IllegalStateException();
- }
-
- static Class<?> getConcreteClass(Type type) {
- Type ntype = collapse(type);
- if ( ntype instanceof Class )
- return (Class<?>) ntype;
-
- if ( ntype instanceof ParameterizedType )
- return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
-
- throw new RuntimeException("Unknown type " + type );
- }
-
- static Type collapse(Type target) {
- if (target instanceof Class || target instanceof ParameterizedType ) {
- return target;
- } else if (target instanceof TypeVariable) {
- return collapse(((TypeVariable<?>) target).getBounds()[0]);
- } else if (target instanceof GenericArrayType) {
- Type t = collapse(((GenericArrayType) target)
- .getGenericComponentType());
- while ( t instanceof ParameterizedType )
- t = collapse(((ParameterizedType)t).getRawType());
- return Array.newInstance((Class<?>)t, 0).getClass();
- } else if (target instanceof WildcardType) {
- WildcardType wct = (WildcardType) target;
- if (wct.getLowerBounds().length == 0)
- return collapse(wct.getUpperBounds()[0]);
- else
- return collapse(wct.getLowerBounds()[0]);
- }
- throw new RuntimeException("Huh? " + target);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java b/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
deleted file mode 100644
index bc835d9..0000000
--- a/shell/console/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
- *
- * Licensed 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.commands.converter;
-
-/**
- * Provides access to a concrete type and its optional generic type arguments.
- *
- * Java 5 and later support generic types. These types consist of a raw class
- * with type arguments. This class models such a <code>Type</code> class but
- * ensures that the type is <em>reified</em>. Reification means that the Type
- * graph associated with a Java 5 <code>Type</code> instance is traversed
- * until the type becomes a concrete class. In Java 1.4 a class has no
- * arguments. This concrete class implements the Reified Type for Java 1.4.
- *
- * In Java 1.4, this class works with non-generic types. In that cases, a
- * Reified Type provides access to the class and has zero type arguments, though
- * a subclass that provide type arguments should be respected. Blueprint
- * extender implementations can subclass this class and provide access to the
- * generics type graph if used in a conversion. Such a subclass must
- * <em>reify<em> the different Java 5 <code>Type</code> instances into the
- * reified form. That is, a form where the raw Class is available with its optional type arguments as Reified Types.
- *
- * @Immutable
- */
-@Deprecated
-public class ReifiedType {
-
- final static ReifiedType ALL = new ReifiedType(Object.class);
-
- private final Class clazz;
-
- /**
- * Create a Reified Type for a raw Java class without any generic arguments.
- * Subclasses can provide the optional generic argument information. Without
- * subclassing, this instance has no type arguments.
- *
- * @param clazz
- * The raw class of the Reified Type.
- */
- public ReifiedType(Class clazz) {
- this.clazz = clazz;
- }
-
- /**
- * Access to the raw class.
- *
- * The raw class represents the concrete class that is associated with a
- * type declaration. This class could have been deduced from the generics
- * type graph of the declaration. For example, in the following example:
- *
- * <pre>
- * Map<String, Object> map;
- * </pre>
- *
- * The raw class is the Map class.
- *
- * @return the collapsed raw class that represents this type.
- */
- public Class getRawClass() {
- return clazz;
- }
-
- /**
- * Access to a type argument.
- *
- * The type argument refers to a argument in a generic type declaration
- * given by index <code>i</code>. This method returns a Reified Type that
- * has Object as class when no generic type information is available. Any
- * object is assignable to Object and therefore no conversion is then
- * necessary, this is compatible with older Javas than 5. For this reason,
- * the implementation in this class always returns the
- * <code>Object<code> class, regardless of the given index.
- *
- * This method should be overridden by a subclass that provides access to
- * the generic information.
- *
- * For example, in the following example:
- *
- * <pre>
- * Map<String, Object> map;
- * </pre>
- *
- * The type argument 0 is <code>String</code>, and type argument 1 is
- * <code>Object</code>.
- *
- * @param i
- * The index of the type argument
- * @return <code>ReifiedType(Object.class)<code>, subclasses must override this and return the generic argument at index <code>i</code>
- */
- public ReifiedType getActualTypeArgument(int i) {
- return ALL;
- }
-
- /**
- * Return the number of type arguments.
- *
- * This method should be overridden by a subclass to support Java 5 types.
- *
- * @return 0, subclasses must override this and return the number of generic
- * arguments
- */
- public int size() {
- return 0;
- }
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/Action.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/Action.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/Action.java
deleted file mode 100644
index c3421e3..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/Action.java
+++ /dev/null
@@ -1,40 +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.commands;
-
-import org.apache.felix.service.command.CommandSession;
-
-/**
- * An action allows to easily execute commands in karaf.
- * It can be assumed that each action is only accessed by a single thread at a time.
- *
- * An Action is always part of an AbstractCommand. The AbstractCommand makes sure
- * the single threaded assumption above is true. Before the call to the execute method
- * the action is checked for annotated fields (@Argument, @Option). These fields
- * are populated from the command arguments before the action is called.
- *
- * Any class implementing Action must have a no argument constructor. This
- * is necessary so the help generator can instantiate the class and get the
- * default values.
- */
-public interface Action extends org.apache.felix.gogo.commands.Action {
-
- Object execute(CommandSession session) throws Exception;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/Argument.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/Argument.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/Argument.java
deleted file mode 100644
index eced53d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/Argument.java
+++ /dev/null
@@ -1,48 +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.commands;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-/**
- * Represents a positional argument on a command line (as opposed to an optional named {@link Option}
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-public @interface Argument
-{
- public static final String DEFAULT_STRING= "DEFAULT";
-
- String DEFAULT = "##default";
-
- String name() default DEFAULT;
-
- String description() default "";
-
- boolean required() default false;
-
- int index() default 0;
-
- boolean multiValued() default false;
-
- String valueToShowInHelp() default DEFAULT_STRING;
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/Command.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/Command.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/Command.java
deleted file mode 100644
index 490785d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/Command.java
+++ /dev/null
@@ -1,53 +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.commands;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.annotation.ElementType;
-
-/**
- * Used to denote a class represents a command which is executable within a shell/scope or as a
- * command line process.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Command
-{
- /**
- * Returns the scope or sub shell of the command
- */
- String scope();
-
- /**
- * REturns the name of the command if used inside a shell
- */
- String name();
-
- /**
- * Returns the description of the command which is used to generate command line help
- */
- String description() default "";
-
- /**
- * Returns a detailed description of the command
- */
- String detailedDescription() default "";
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandException.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandException.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandException.java
deleted file mode 100644
index 1ffa25d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandException.java
+++ /dev/null
@@ -1,64 +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.commands;
-
-import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
-
-
-/**
- * Base class for exceptions thrown when executing commands.
- */
-@SuppressWarnings("serial")
-public class CommandException extends Exception {
-
- private String help;
-
- public CommandException() {
- }
-
- public CommandException(String message) {
- super(message);
- }
-
- public CommandException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public CommandException(Throwable cause) {
- super(cause);
- }
-
- public CommandException(String help, String message) {
- super(message);
- this.help = help;
- }
-
- public CommandException(String help, String message, Throwable cause) {
- super(message, cause);
- this.help = help;
- }
-
- public String getNiceHelp() {
- return help != null ? help
- : SimpleAnsi.COLOR_RED + "Error executing command: "
- + getMessage() != null ? getMessage() : getClass().getName()
- + SimpleAnsi.COLOR_DEFAULT;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
deleted file mode 100644
index 9209eb1..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
+++ /dev/null
@@ -1,31 +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.commands;
-
-import org.apache.felix.service.command.Function;
-
-public interface CommandWithAction extends Function {
-
- Class<? extends org.apache.felix.gogo.commands.Action> getActionClass();
-
- org.apache.felix.gogo.commands.Action createNewAction();
-
- void releaseAction(org.apache.felix.gogo.commands.Action action) throws Exception;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/Completer.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/Completer.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/Completer.java
deleted file mode 100644
index ece3e1d..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/Completer.java
+++ /dev/null
@@ -1,34 +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.commands;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-public @interface Completer {
-
- Class<? extends org.apache.karaf.shell.console.Completer> value();
-
- String[] values() default { };
-
- boolean caseSensitive() default false;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
deleted file mode 100644
index 4463d35..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
+++ /dev/null
@@ -1,37 +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.commands;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Represents a method which can return a List or Array of values used for a
- * {@link org.apache.karaf.shell.console.Completer}
- * which is associated with the index of an
- * {@link Argument}
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.METHOD, ElementType.FIELD})
-public @interface CompleterValues
-{
- int index() default 0;
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/HelpOption.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
deleted file mode 100644
index b5a0fa5..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
+++ /dev/null
@@ -1,54 +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.commands;
-
-import java.lang.annotation.Annotation;
-
-public class HelpOption {
-
- public static final Option HELP = new Option() {
- public String name() {
- return "--help";
- }
-
- public String[] aliases() {
- return new String[]{};
- }
-
- public String description() {
- return "Display this help message";
- }
-
- public boolean required() {
- return false;
- }
-
- public boolean multiValued() {
- return false;
- }
-
- public String valueToShowInHelp() {
- return Option.DEFAULT_STRING;
- }
-
- public Class<? extends Annotation> annotationType() {
- return Option.class;
- }
- };
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
deleted file mode 100644
index e253af1..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
+++ /dev/null
@@ -1,30 +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.commands;
-
-import java.util.Properties;
-
-/**
- * A bundle can publish a service with this interface to offer some informations for the shell:info command
- */
-public interface InfoProvider {
-
- public String getName();
-
- public Properties getProperties();
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/Option.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/Option.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/Option.java
deleted file mode 100644
index b0a9e9c..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/Option.java
+++ /dev/null
@@ -1,46 +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.commands;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Used to mark an optional named command line option who's name typically starts with "--"
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
-public @interface Option
-{
- public static final String DEFAULT_STRING= "DEFAULT";
-
- String name();
-
- String[] aliases() default {};
-
- String description() default "";
-
- boolean required() default false;
-
- boolean multiValued() default false;
-
- String valueToShowInHelp() default DEFAULT_STRING;
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java
deleted file mode 100644
index 8437949..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java
+++ /dev/null
@@ -1,30 +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.commands.ansi;
-
-import org.fusesource.jansi.Ansi;
-import org.fusesource.jansi.Ansi.Color;
-
-public class SimpleAnsi {
- public static String COLOR_RED = Ansi.ansi().fg(Color.RED).toString();
- public static String COLOR_DEFAULT = Ansi.ansi().fg(Color.DEFAULT).toString();
-
- public static String INTENSITY_BOLD = Ansi.ansi().bold().toString();
- public static String INTENSITY_NORMAL = Ansi.ansi().boldOff().toString();
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
deleted file mode 100644
index 41d4a51..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
+++ /dev/null
@@ -1,62 +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.commands.basic;
-
-import java.util.List;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.CommandWithAction;
-
-public abstract class AbstractCommand implements CommandWithAction {
-
- public Object execute(CommandSession session, List<Object> arguments) throws Exception {
- Action action = createNewAction();
- try {
- if (getPreparator().prepare(action, session, arguments)) {
- return action.execute(session);
- } else {
- return null;
- }
- } finally {
- releaseAction(action);
- }
- }
-
- public Class<? extends Action> getActionClass() {
- return createNewAction().getClass();
- }
-
- public abstract Action createNewAction();
-
- /**
- * Release the used Action.
- * This method has to be overridden for pool based Actions.
- * @param action Action that was executed
- * @throws Exception if something went wrong during the Action release
- */
- public void releaseAction(Action action) throws Exception {
- // Do nothing by default (stateful)
- }
-
- protected ActionPreparator getPreparator() throws Exception {
- return new DefaultActionPreparator();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java b/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
deleted file mode 100644
index a6d2f8f..0000000
--- a/shell/console/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
+++ /dev/null
@@ -1,42 +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.commands.basic;
-
-import java.util.List;
-
-import org.apache.felix.gogo.commands.Action;
-import org.apache.felix.service.command.CommandSession;
-
-public interface ActionPreparator {
-
- /**
- * Check if the arguments are valid for the action and inject the arguments into the fields
- * of the action
- *
- * Using deprecated Action for compatiblity
- *
- * @param action
- * @param session
- * @param arguments
- * @return
- * @throws Exception
- */
- boolean prepare(@SuppressWarnings("deprecation") Action action, CommandSession session, List<Object> arguments) throws Exception;
-
-}
[08/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
new file mode 100644
index 0000000..3e40c5a
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BasicSubShell.java
@@ -0,0 +1,51 @@
+/**
+ *
+ * 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.console.commands;
+
+import org.apache.karaf.shell.console.SubShell;
+
+public class BasicSubShell implements SubShell {
+
+ private String name;
+ private String description;
+ private String detailedDescription;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDetailedDescription() {
+ return detailedDescription;
+ }
+
+ public void setDetailedDescription(String detailedDescription) {
+ this.detailedDescription = detailedDescription;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
new file mode 100644
index 0000000..83fa1ec
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/BlueprintCommand.java
@@ -0,0 +1,110 @@
+/**
+ *
+ * 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.console.commands;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.basic.AbstractCommand;
+import org.apache.karaf.shell.commands.basic.ActionPreparator;
+import org.apache.karaf.shell.commands.basic.DefaultActionPreparator;
+import org.apache.karaf.shell.console.BlueprintContainerAware;
+import org.apache.karaf.shell.console.BundleContextAware;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.blueprint.container.BlueprintContainer;
+import org.osgi.service.blueprint.container.Converter;
+
+public class
+ BlueprintCommand extends AbstractCommand implements CompletableFunction
+{
+
+ protected BlueprintContainer blueprintContainer;
+ protected Converter blueprintConverter;
+ protected String actionId;
+ protected String shell;
+ protected List<Completer> completers;
+ protected Map<String,Completer> optionalCompleters;
+
+ public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
+ this.blueprintContainer = blueprintContainer;
+ }
+
+ public void setBlueprintConverter(Converter blueprintConverter) {
+ this.blueprintConverter = blueprintConverter;
+ }
+
+ public void setActionId(String actionId) {
+ this.actionId = actionId;
+ }
+
+ public void setShell(String shell) {
+ this.shell = shell;
+ }
+
+ public List<Completer> getCompleters() {
+ return completers;
+ }
+
+ public void setCompleters(List<Completer> completers) {
+ this.completers = completers;
+ }
+
+ public Map<String, Completer> getOptionalCompleters() {
+ return optionalCompleters;
+ }
+
+ public void setOptionalCompleters(Map<String, Completer> optionalCompleters) {
+ this.optionalCompleters = optionalCompleters;
+ }
+
+ @Override
+ protected ActionPreparator getPreparator() throws Exception {
+ return new BlueprintActionPreparator();
+ }
+
+ protected class BlueprintActionPreparator extends DefaultActionPreparator {
+
+ @Override
+ protected Object convert(Action action, CommandSession commandSession, Object o, Type type) throws Exception {
+ GenericType t = new GenericType(type);
+ if (t.getRawClass() == String.class) {
+ return o != null ? o.toString() : null;
+ }
+ return blueprintConverter.convert(o, t);
+ }
+
+ }
+
+ public Action createNewAction() {
+ Action action = (Action) blueprintContainer.getComponentInstance(actionId);
+ if (action instanceof BlueprintContainerAware) {
+ ((BlueprintContainerAware) action).setBlueprintContainer(blueprintContainer);
+ }
+ if (action instanceof BundleContextAware) {
+ BundleContext context = (BundleContext) blueprintContainer.getComponentInstance("blueprintBundleContext");
+ ((BundleContextAware) action).setBundleContext(context);
+ }
+ return action;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
new file mode 100644
index 0000000..faf7c18
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/GenericType.java
@@ -0,0 +1,195 @@
+/**
+ *
+ * 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.console.commands;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+public class GenericType extends ReifiedType {
+
+ private static final GenericType[] EMPTY = new GenericType[0];
+
+ private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
+
+ static {
+ primitiveClasses.put("int", int.class);
+ primitiveClasses.put("short", short.class);
+ primitiveClasses.put("long", long.class);
+ primitiveClasses.put("byte", byte.class);
+ primitiveClasses.put("char", char.class);
+ primitiveClasses.put("float", float.class);
+ primitiveClasses.put("double", double.class);
+ primitiveClasses.put("boolean", boolean.class);
+ }
+
+ private GenericType[] parameters;
+
+ public GenericType(Type type) {
+ this(getConcreteClass(type), parametersOf(type));
+ }
+
+ public GenericType(Class clazz, GenericType... parameters) {
+ super(clazz);
+ this.parameters = parameters;
+ }
+
+ public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
+ type = type.trim();
+ // Check if this is an array
+ if (type.endsWith("[]")) {
+ GenericType t = parse(type.substring(0, type.length() - 2), loader);
+ return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
+ }
+ // Check if this is a generic
+ int genericIndex = type.indexOf('<');
+ if (genericIndex > 0) {
+ if (!type.endsWith(">")) {
+ throw new IllegalArgumentException("Can not load type: " + type);
+ }
+ GenericType base = parse(type.substring(0, genericIndex), loader);
+ String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
+ GenericType[] types = new GenericType[params.length];
+ for (int i = 0; i < params.length; i++) {
+ types[i] = parse(params[i], loader);
+ }
+ return new GenericType(base.getRawClass(), types);
+ }
+ // Primitive
+ if (primitiveClasses.containsKey(type)) {
+ return new GenericType(primitiveClasses.get(type));
+ }
+ // Class
+ if (loader instanceof ClassLoader) {
+ return new GenericType(((ClassLoader) loader).loadClass(type));
+ } else if (loader instanceof Bundle) {
+ return new GenericType(((Bundle) loader).loadClass(type));
+ } else {
+ throw new IllegalArgumentException("Unsupported loader: " + loader);
+ }
+ }
+
+ @Override
+ public ReifiedType getActualTypeArgument(int i) {
+ if (parameters.length == 0) {
+ return super.getActualTypeArgument(i);
+ }
+ return parameters[i];
+ }
+
+ @Override
+ public int size() {
+ return parameters.length;
+ }
+
+ @Override
+ public String toString() {
+ Class cl = getRawClass();
+ if (cl.isArray()) {
+ if (parameters.length > 0) {
+ return parameters[0].toString() + "[]";
+ } else {
+ return cl.getComponentType().getName() + "[]";
+ }
+ }
+ if (parameters.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cl.getName());
+ sb.append("<");
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(parameters[i].toString());
+ }
+ sb.append(">");
+ return sb.toString();
+ }
+ return cl.getName();
+ }
+
+ static GenericType[] parametersOf(Type type ) {
+ if ( type instanceof Class ) {
+ Class clazz = (Class) type;
+ if (clazz.isArray()) {
+ GenericType t = new GenericType(clazz.getComponentType());
+ if (t.size() > 0) {
+ return new GenericType[] { t };
+ } else {
+ return EMPTY;
+ }
+ } else {
+ return EMPTY;
+ }
+ }
+ if ( type instanceof ParameterizedType ) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type [] parameters = pt.getActualTypeArguments();
+ GenericType[] gts = new GenericType[parameters.length];
+ for ( int i =0; i<gts.length; i++) {
+ gts[i] = new GenericType(parameters[i]);
+ }
+ return gts;
+ }
+ if ( type instanceof GenericArrayType ) {
+ return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
+ }
+ throw new IllegalStateException();
+ }
+
+ static Class<?> getConcreteClass(Type type) {
+ Type ntype = collapse(type);
+ if ( ntype instanceof Class )
+ return (Class<?>) ntype;
+
+ if ( ntype instanceof ParameterizedType )
+ return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
+
+ throw new RuntimeException("Unknown type " + type );
+ }
+
+ static Type collapse(Type target) {
+ if (target instanceof Class || target instanceof ParameterizedType ) {
+ return target;
+ } else if (target instanceof TypeVariable) {
+ return collapse(((TypeVariable<?>) target).getBounds()[0]);
+ } else if (target instanceof GenericArrayType) {
+ Type t = collapse(((GenericArrayType) target)
+ .getGenericComponentType());
+ while ( t instanceof ParameterizedType )
+ t = collapse(((ParameterizedType)t).getRawType());
+ return Array.newInstance((Class<?>)t, 0).getClass();
+ } else if (target instanceof WildcardType) {
+ WildcardType wct = (WildcardType) target;
+ if (wct.getLowerBounds().length == 0)
+ return collapse(wct.getUpperBounds()[0]);
+ else
+ return collapse(wct.getLowerBounds()[0]);
+ }
+ throw new RuntimeException("Huh? " + target);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
new file mode 100644
index 0000000..6c3a5b3
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NamespaceHandler.java
@@ -0,0 +1,523 @@
+/*
+ * 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.console.commands;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.aries.blueprint.ParserContext;
+import org.apache.aries.blueprint.PassThroughMetadata;
+import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
+import org.apache.aries.blueprint.mutable.MutableCollectionMetadata;
+import org.apache.aries.blueprint.mutable.MutableIdRefMetadata;
+import org.apache.aries.blueprint.mutable.MutablePassThroughMetadata;
+import org.apache.aries.blueprint.mutable.MutableRefMetadata;
+import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
+import org.apache.aries.blueprint.mutable.MutableServiceMetadata;
+import org.apache.aries.blueprint.mutable.MutableValueMetadata;
+import org.apache.felix.gogo.commands.Action;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.SubShellAction;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.inject.Destroy;
+import org.apache.karaf.shell.inject.Init;
+import org.apache.karaf.shell.inject.Reference;
+import org.apache.karaf.shell.inject.Service;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.osgi.service.blueprint.reflect.BeanArgument;
+import org.osgi.service.blueprint.reflect.BeanMetadata;
+import org.osgi.service.blueprint.reflect.BeanProperty;
+import org.osgi.service.blueprint.reflect.ComponentMetadata;
+import org.osgi.service.blueprint.reflect.IdRefMetadata;
+import org.osgi.service.blueprint.reflect.MapMetadata;
+import org.osgi.service.blueprint.reflect.Metadata;
+import org.osgi.service.blueprint.reflect.NullMetadata;
+import org.osgi.service.blueprint.reflect.RefMetadata;
+import org.osgi.service.blueprint.reflect.ReferenceMetadata;
+import org.osgi.service.blueprint.reflect.ServiceMetadata;
+import org.osgi.service.blueprint.reflect.ValueMetadata;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+
+public class NamespaceHandler implements org.apache.aries.blueprint.NamespaceHandler {
+
+ public static final String ID = "id";
+ public static final String ACTION = "action";
+ public static final String ACTION_ID = "actionId";
+ public static final String COMMAND_BUNDLE = "command-bundle";
+ public static final String SCAN = "scan";
+ public static final String NAME = "name";
+ public static final String COMMAND = "command";
+ public static final String COMPLETERS = "completers";
+ public static final String OPTIONAL_COMPLETERS = "optional-completers";
+ public static final String OPTIONAL_COMPLETERS_PROPERTY = "optionalCompleters";
+ public static final String BEAN = "bean";
+ public static final String REF = "ref";
+ public static final String NULL = "null";
+ public static final String MAP = "map";
+ public static final String BLUEPRINT_CONTAINER = "blueprintContainer";
+ public static final String BLUEPRINT_CONVERTER = "blueprintConverter";
+
+ public static final String SHELL_NAMESPACE_1_0_0 = "http://karaf.apache.org/xmlns/shell/v1.0.0";
+ public static final String SHELL_NAMESPACE_1_1_0 = "http://karaf.apache.org/xmlns/shell/v1.1.0";
+ public static final String SHELL_NAMESPACE_1_2_0 = "http://karaf.apache.org/xmlns/shell/v1.2.0";
+
+ private int nameCounter = 0;
+
+ public URL getSchemaLocation(String namespace) {
+ if(SHELL_NAMESPACE_1_0_0.equals(namespace)) {
+ return getClass().getResource("karaf-shell-1.0.0.xsd");
+ } else if(SHELL_NAMESPACE_1_1_0.equals(namespace)) {
+ return getClass().getResource("karaf-shell-1.1.0.xsd");
+ } else if(SHELL_NAMESPACE_1_2_0.equals(namespace)) {
+ return getClass().getResource("karaf-shell-1.2.0.xsd");
+ }
+ return getClass().getResource("karaf-shell-1.2.0.xsd");
+ }
+
+ public Set<Class> getManagedClasses() {
+ return new HashSet<Class>(Arrays.asList(
+ BlueprintCommand.class
+ ));
+ }
+
+ public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
+ throw new ComponentDefinitionException("Bad xml syntax: node decoration is not supported");
+ }
+
+ public Metadata parse(Element element, ParserContext context) {
+ if (nodeNameEquals(element, COMMAND_BUNDLE)) {
+ NamedNodeMap attrs = element.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Node child = attrs.item(i);
+ if (child instanceof Attr) {
+ Attr childAttr = (Attr) child;
+ parseChildAttr(childAttr, context);
+ }
+ }
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child instanceof Element) {
+ Element childElement = (Element) child;
+ parseChildElement(childElement, context);
+ }
+ }
+ registerConverters(context);
+ return null;
+ } else {
+ throw new IllegalStateException("Unexpected element " + element.getNodeName());
+ }
+ }
+
+ private void parseChildAttr(Attr attr, ParserContext context) {
+ if (nodeNameEquals(attr, SCAN)) {
+ scan(attr, context);
+ }
+ }
+
+ private void scan(Attr attr, ParserContext context) {
+ try {
+ Bundle bundle = getBundle(context);
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ for (String pkg : attr.getValue().split(" ")) {
+ String name = pkg;
+ int options = BundleWiring.LISTRESOURCES_LOCAL;
+ name = name.replace('.', '/');
+ if (name.endsWith("*")) {
+ options |= BundleWiring.LISTRESOURCES_RECURSE;
+ name = name.substring(0, name.length() - 1);
+ }
+ if (!name.startsWith("/")) {
+ name = "/" + name;
+ }
+ if (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
+ }
+ Collection<String> classes = wiring.listResources(name, "*.class", options);
+ for (String className : classes) {
+ className = className.replace('/', '.').replace(".class", "");
+ inspectClass(context, bundle.loadClass(className));
+ }
+ }
+ } catch (ComponentDefinitionException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ComponentDefinitionException("Unable to scan commands", e);
+ }
+ }
+
+ private void inspectClass(ParserContext context, Class<?> clazz) throws Exception {
+ Service reg = clazz.getAnnotation(Service.class);
+ if (reg == null) {
+ return;
+ }
+ if (Action.class.isAssignableFrom(clazz)) {
+ final Command cmd = clazz.getAnnotation(Command.class);
+ if (cmd == null) {
+ throw new IllegalArgumentException("Command " + clazz.getName() + " is not annotated with @Command");
+ }
+ String scope = cmd.scope();
+ String function = cmd.name();
+ // Create action
+ MutableBeanMetadata action = context.createMetadata(MutableBeanMetadata.class);
+ action.setId(getName());
+ action.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
+ action.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
+ action.setRuntimeClass(clazz);
+ for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
+ for (Field field : cl.getDeclaredFields()) {
+ if (field.getAnnotation(Reference.class) != null) {
+ if (field.getType() == BundleContext.class) {
+ action.addProperty(field.getName(), createRef(context, "blueprintBundleContext"));
+ } else {
+ action.addProperty(field.getName(), createRef(context, createServiceRef(context, field.getType()).getId()));
+ }
+ }
+ }
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getAnnotation(Init.class) != null) {
+ if (action.getInitMethod() == null) {
+ action.setInitMethod(method.getName());
+ }
+ }
+ if (method.getAnnotation(Destroy.class) != null) {
+ if (action.getDestroyMethod() == null) {
+ action.setDestroyMethod(method.getName());
+ }
+ }
+ }
+ }
+ context.getComponentDefinitionRegistry().registerComponentDefinition(action);
+ // Create command
+ MutableBeanMetadata command = context.createMetadata(MutableBeanMetadata.class);
+ command.setRuntimeClass(BlueprintCommand.class);
+ command.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
+ command.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
+ command.addProperty(ACTION_ID, createIdRef(context, action.getId()));
+ // Create command service
+ MutableServiceMetadata commandService = context.createMetadata(MutableServiceMetadata.class);
+ commandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
+ commandService.setId(getName());
+ commandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
+ commandService.setServiceComponent(command);
+ commandService.addServiceProperty(createStringValue(context, "osgi.command.scope"),
+ createStringValue(context, scope));
+ commandService.addServiceProperty(createStringValue(context, "osgi.command.function"),
+ createStringValue(context, function));
+ context.getComponentDefinitionRegistry().registerComponentDefinition(commandService);
+
+ // create the sub-shell action
+ createSubShell(context, scope);
+ }
+ if (Completer.class.isAssignableFrom(clazz)) {
+ MutableBeanMetadata completer = context.createMetadata(MutableBeanMetadata.class);
+ completer.setId(getName());
+ completer.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
+ completer.setScope(MutableBeanMetadata.SCOPE_SINGLETON);
+ completer.setRuntimeClass(clazz);
+ // Create completer
+ for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
+ for (Field field : cl.getDeclaredFields()) {
+ if (field.getAnnotation(Reference.class) != null) {
+ if (field.getType() == BundleContext.class) {
+ completer.addProperty(field.getName(), createRef(context, "blueprintBundleContext"));
+ } else {
+ completer.addProperty(field.getName(), createRef(context, createServiceRef(context, field.getType()).getId()));
+ }
+ }
+ }
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getAnnotation(Init.class) != null) {
+ if (completer.getInitMethod() == null) {
+ completer.setInitMethod(method.getName());
+ }
+ }
+ if (method.getAnnotation(Destroy.class) != null) {
+ if (completer.getDestroyMethod() == null) {
+ completer.setDestroyMethod(method.getName());
+ }
+ }
+ }
+ }
+ context.getComponentDefinitionRegistry().registerComponentDefinition(completer);
+ // Create completer service
+ MutableServiceMetadata completerService = context.createMetadata(MutableServiceMetadata.class);
+ completerService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
+ completerService.setId(getName());
+ completerService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
+ completerService.setServiceComponent(createRef(context, completer.getId()));
+ context.getComponentDefinitionRegistry().registerComponentDefinition(completerService);
+ }
+ }
+
+ private ComponentMetadata createServiceRef(ParserContext context, Class<?> cls) {
+ String id = ".serviceref." + cls.getName();
+ ComponentMetadata metadata = context.getComponentDefinitionRegistry().getComponentDefinition(id);
+ if (metadata == null) {
+ MutableReferenceMetadata m = context.createMetadata(MutableReferenceMetadata.class);
+ m.setRuntimeInterface(cls);
+ m.setInterface(cls.getName());
+ m.setActivation(ReferenceMetadata.ACTIVATION_EAGER);
+ m.setAvailability(ReferenceMetadata.AVAILABILITY_MANDATORY);
+ m.setId(id);
+ context.getComponentDefinitionRegistry().registerComponentDefinition(m);
+ return m;
+ } else {
+ return metadata;
+ }
+ }
+
+ private Bundle getBundle(ParserContext context) {
+ PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintBundle");
+ return (Bundle) ptm.getObject();
+ }
+
+ private void parseChildElement(Element element, ParserContext context) {
+ if (nodeNameEquals(element, COMMAND)) {
+ parseCommand(element, context);
+ }
+ }
+
+ private void registerConverters(ParserContext context) {
+ String converterName = "." + NumberToStringConverter.class.getName();
+ if (!context.getComponentDefinitionRegistry().containsComponentDefinition(converterName)) {
+ MutablePassThroughMetadata cnv = context.createMetadata(MutablePassThroughMetadata.class);
+ cnv.setId(converterName);
+ cnv.setObject(new NumberToStringConverter());
+ context.getComponentDefinitionRegistry().registerTypeConverter(cnv);
+ }
+ }
+
+ private void parseCommand(Element element, ParserContext context) {
+ MutableBeanMetadata command = context.createMetadata(MutableBeanMetadata.class);
+ command.setRuntimeClass(BlueprintCommand.class);
+ command.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
+ command.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
+
+ NodeList children = element.getChildNodes();
+ MutableBeanMetadata action = null;
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child instanceof Element) {
+ Element childElement = (Element) child;
+ if (nodeNameEquals(childElement, ACTION)) {
+ action = parseAction(context, command, childElement);
+ action.setId(getName());
+ context.getComponentDefinitionRegistry().registerComponentDefinition(action);
+ command.addProperty(ACTION_ID, createIdRef(context, action.getId()));
+ } else if (nodeNameEquals(childElement, COMPLETERS)) {
+ command.addProperty(COMPLETERS, parseCompleters(context, command, childElement));
+ } else if (nodeNameEquals(childElement, OPTIONAL_COMPLETERS)) {
+ command.addProperty(OPTIONAL_COMPLETERS_PROPERTY, parseOptionalCompleters(context, command, childElement));
+ }
+ else {
+ throw new ComponentDefinitionException("Bad xml syntax: unknown element '" + childElement.getNodeName() + "'");
+ }
+ }
+ }
+
+ MutableServiceMetadata commandService = context.createMetadata(MutableServiceMetadata.class);
+ commandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
+ commandService.setId(getName());
+ commandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
+ commandService.setServiceComponent(command);
+
+ String scope;
+ String function;
+ if (SHELL_NAMESPACE_1_0_0.equals(element.getNamespaceURI())) {
+ String location = element.getAttribute(NAME);
+ location = location.replace('/', ':');
+ if (location.lastIndexOf(':') >= 0) {
+ scope = location.substring(0, location.lastIndexOf(':'));
+ function = location.substring(location.lastIndexOf(':') + 1);
+ } else {
+ scope = "";
+ function = location;
+ }
+ } else {
+ try {
+ Class actionClass = getBundle(context).loadClass(action.getClassName());
+ scope = getScope(actionClass);
+ function = getName(actionClass);
+ } catch (Throwable e) {
+ throw new ComponentDefinitionException("Unable to introspect action " + action.getClassName(), e);
+ }
+ }
+ commandService.addServiceProperty(createStringValue(context, "osgi.command.scope"),
+ createStringValue(context, scope));
+ commandService.addServiceProperty(createStringValue(context, "osgi.command.function"),
+ createStringValue(context, function));
+
+ context.getComponentDefinitionRegistry().registerComponentDefinition(commandService);
+
+ // create the sub-shell action
+ createSubShell(context, scope);
+ }
+
+ private void createSubShell(ParserContext context, String scope) {
+ String subShellName = ".subshell." + scope;
+ if (context.getComponentDefinitionRegistry().containsComponentDefinition(subShellName)) {
+ return;
+ }
+ MutableBeanMetadata subShellAction = context.createMetadata(MutableBeanMetadata.class);
+ subShellAction.setRuntimeClass(SubShellAction.class);
+ subShellAction.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
+ subShellAction.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
+ subShellAction.setId(getName());
+ subShellAction.addProperty("subShell", createStringValue(context, scope));
+ context.getComponentDefinitionRegistry().registerComponentDefinition(subShellAction);
+ // generate the sub-shell command
+ MutableBeanMetadata subShellCommand = context.createMetadata(MutableBeanMetadata.class);
+ subShellCommand.setId(getName());
+ subShellCommand.setRuntimeClass(BlueprintCommand.class);
+ subShellCommand.addProperty(BLUEPRINT_CONTAINER, createRef(context, BLUEPRINT_CONTAINER));
+ subShellCommand.addProperty(BLUEPRINT_CONVERTER, createRef(context, BLUEPRINT_CONVERTER));
+ subShellCommand.addProperty(ACTION_ID, createIdRef(context, subShellAction.getId()));
+ context.getComponentDefinitionRegistry().registerComponentDefinition(subShellCommand);
+ // generate the sub-shell OSGi service
+ MutableServiceMetadata subShellCommandService = context.createMetadata(MutableServiceMetadata.class);
+ subShellCommandService.setActivation(MutableServiceMetadata.ACTIVATION_LAZY);
+ subShellCommandService.setId(subShellName);
+ subShellCommandService.setAutoExport(ServiceMetadata.AUTO_EXPORT_ALL_CLASSES);
+ subShellCommandService.setServiceComponent(subShellCommand);
+ subShellCommandService.addServiceProperty(createStringValue(context, "osgi.command.scope"), createStringValue(context, "*"));
+ subShellCommandService.addServiceProperty(createStringValue(context, "osgi.command.function"), createStringValue(context, scope));
+ context.getComponentDefinitionRegistry().registerComponentDefinition(subShellCommandService);
+ }
+
+ private MutableBeanMetadata getInvocationValue(ParserContext context, String method, String className) {
+ MutableBeanMetadata scope = context.createMetadata(MutableBeanMetadata.class);
+ scope.setRuntimeClass(NamespaceHandler.class);
+ scope.setFactoryMethod(method);
+ scope.addArgument(createStringValue(context, className), null, 0);
+ return scope;
+ }
+
+ private MutableBeanMetadata parseAction(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
+ MutableBeanMetadata action = context.createMetadata(MutableBeanMetadata.class);
+ action.setActivation(MutableBeanMetadata.ACTIVATION_LAZY);
+ action.setScope(MutableBeanMetadata.SCOPE_PROTOTYPE);
+ action.setClassName(element.getAttribute("class"));
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child instanceof Element) {
+ Element childElement = (Element) child;
+ if (nodeNameEquals(childElement, "argument")) {
+ action.addArgument(context.parseElement(BeanArgument.class, enclosingComponent, childElement));
+ } else if (nodeNameEquals(childElement, "property")) {
+ action.addProperty(context.parseElement(BeanProperty.class, enclosingComponent, childElement));
+ }
+ }
+ }
+ return action;
+ }
+
+ private Metadata parseOptionalCompleters(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
+ Metadata metadata = context.parseElement(MapMetadata.class, context.getEnclosingComponent(), (Element) element);
+ return metadata;
+ }
+
+ private Metadata parseCompleters(ParserContext context, ComponentMetadata enclosingComponent, Element element) {
+ MutableCollectionMetadata collection = context.createMetadata(MutableCollectionMetadata.class);
+ collection.setCollectionClass(List.class);
+ NodeList children = element.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child instanceof Element) {
+ Metadata metadata;
+ if (nodeNameEquals(child, REF)) {
+ metadata = context.parseElement(RefMetadata.class, context.getEnclosingComponent(), (Element) child);
+ } else if (nodeNameEquals(child, NULL)) {
+ metadata = context.parseElement(NullMetadata.class, context.getEnclosingComponent(), (Element) child);
+ } else if (nodeNameEquals(child, BEAN)) {
+ metadata = context.parseElement(BeanMetadata.class, enclosingComponent, (Element) child);
+ } else {
+ throw new IllegalStateException("Unexpected element " + child.getNodeName());
+ }
+ collection.addValue(metadata);
+ }
+ }
+ return collection;
+ }
+
+ private ValueMetadata createStringValue(ParserContext context, String str) {
+ MutableValueMetadata value = context.createMetadata(MutableValueMetadata.class);
+ value.setStringValue(str);
+ return value;
+ }
+
+ private RefMetadata createRef(ParserContext context, String id) {
+ MutableRefMetadata idref = context.createMetadata(MutableRefMetadata.class);
+ idref.setComponentId(id);
+ return idref;
+ }
+
+ private IdRefMetadata createIdRef(ParserContext context, String id) {
+ MutableIdRefMetadata idref = context.createMetadata(MutableIdRefMetadata.class);
+ idref.setComponentId(id);
+ return idref;
+ }
+
+ public synchronized String getName() {
+ return "shell-" + ++nameCounter;
+ }
+
+ private static boolean nodeNameEquals(Node node, String name) {
+ return (name.equals(node.getNodeName()) || name.equals(node.getLocalName()));
+ }
+
+ public static String getScope(Class<?> action) {
+ Command command = action.getAnnotation(Command.class);
+ if (command != null) {
+ return command.scope();
+ }
+ org.apache.felix.gogo.commands.Command command2 = action.getAnnotation(org.apache.felix.gogo.commands.Command.class);
+ if (command2 != null) {
+ return command2.scope();
+ }
+ return null;
+ }
+
+ public static String getName(Class<?> action) {
+ Command command = action.getAnnotation(Command.class);
+ if (command != null) {
+ return command.name();
+ }
+ org.apache.felix.gogo.commands.Command command2 = action.getAnnotation(org.apache.felix.gogo.commands.Command.class);
+ if (command2 != null) {
+ return command2.name();
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
new file mode 100644
index 0000000..fb68c3a
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/NumberToStringConverter.java
@@ -0,0 +1,36 @@
+/*
+ * 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.console.commands;
+
+import org.osgi.service.blueprint.container.Converter;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+public class NumberToStringConverter implements Converter {
+
+ @Override
+ public boolean canConvert(Object sourceObject, ReifiedType targetType) {
+ return sourceObject != null && sourceObject instanceof Number
+ && targetType.getRawClass() == String.class;
+ }
+
+ @Override
+ public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
+ return sourceObject.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
new file mode 100644
index 0000000..dbba436
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/AggregateCompleter.java
@@ -0,0 +1,91 @@
+/*
+ * 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.console.completer;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Collection;
+
+import org.apache.karaf.shell.console.Completer;
+
+/**
+ * Completer which contains multipule completers and aggregates them together.
+ */
+public class AggregateCompleter implements Completer
+{
+ private final Collection<Completer> completers;
+
+ public AggregateCompleter(final Collection<Completer> completers) {
+ assert completers != null;
+ this.completers = completers;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public int complete(final String buffer, final int cursor, final List candidates) {
+ // buffer could be null
+ assert candidates != null;
+
+ List<Completion> completions = new ArrayList<Completion>(completers.size());
+
+ // Run each completer, saving its completion results
+ int max = -1;
+ for (Completer completer : completers) {
+ Completion completion = new Completion(candidates);
+ completion.complete(completer, buffer, cursor);
+
+ // Compute the max cursor position
+ max = Math.max(max, completion.cursor);
+
+ completions.add(completion);
+ }
+
+ // Append candiates from completions which have the same cursor position as max
+ for (Completion completion : completions) {
+ if (completion.cursor == max) {
+ // noinspection unchecked
+ candidates.addAll(completion.candidates);
+ }
+ }
+
+ return max;
+ }
+
+ private class Completion
+ {
+ public final List<String> candidates;
+
+ public int cursor;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Completion(final List candidates) {
+ assert candidates != null;
+
+ // noinspection unchecked
+ this.candidates = new LinkedList<String>(candidates);
+ }
+
+ public void complete(final Completer completer, final String buffer, final int cursor) {
+ assert completer != null;
+
+ this.cursor = completer.complete(buffer, cursor, candidates);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
new file mode 100644
index 0000000..745489e
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/ArgumentCompleter.java
@@ -0,0 +1,567 @@
+/*
+ * 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.console.completer;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.CommandWithAction;
+import org.apache.karaf.shell.commands.CompleterValues;
+import org.apache.karaf.shell.commands.HelpOption;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.NameScoping;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.karaf.shell.console.completer.CommandsCompleter.unProxy;
+
+public class ArgumentCompleter implements Completer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentCompleter.class);
+
+ public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
+
+ public static final String COMMANDS = ".commands";
+
+ final Completer commandCompleter;
+ final Completer optionsCompleter;
+ final List<Completer> argsCompleters;
+ final Map<String, Completer> optionalCompleters;
+ final CommandWithAction function;
+ final Map<Option, Field> fields = new HashMap<Option, Field>();
+ final Map<String, Option> options = new HashMap<String, Option>();
+ final Map<Integer, Field> arguments = new HashMap<Integer, Field>();
+ boolean strict = true;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public ArgumentCompleter(CommandSession session, CommandWithAction function, String command) {
+ this.function = function;
+ // Command name completer
+ commandCompleter = new StringsCompleter(getNames(session, command));
+ // Build options completer
+ for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
+ for (Field field : type.getDeclaredFields()) {
+ Option option = field.getAnnotation(Option.class);
+ if (option != null) {
+ fields.put(option, field);
+ options.put(option.name(), option);
+ String[] aliases = option.aliases();
+ if (aliases != null) {
+ for (String alias : aliases) {
+ options.put(alias, option);
+ }
+ }
+ }
+ Argument argument = field.getAnnotation(Argument.class);
+ if (argument != null) {
+ Integer key = argument.index();
+ if (arguments.containsKey(key)) {
+ LOGGER.warn("Duplicate @Argument annotations on class " + type.getName() + " for index: " + key + " see: " + field);
+ } else {
+ arguments.put(key, field);
+ }
+ }
+ }
+ }
+ options.put(HelpOption.HELP.name(), HelpOption.HELP);
+ optionsCompleter = new StringsCompleter(options.keySet());
+
+ // Build arguments completers
+ List<Completer> argsCompleters = null;
+ Map<String, Completer> optionalCompleters = null;
+
+ if (function instanceof CompletableFunction) {
+ Map<String, Completer> focl = ((CompletableFunction) function).getOptionalCompleters();
+ List<Completer> fcl = ((CompletableFunction) function).getCompleters();
+ if (focl != null || fcl != null) {
+ argsCompleters = new ArrayList<Completer>();
+ if (fcl != null) {
+ for (Completer c : fcl) {
+ argsCompleters.add(c == null ? NullCompleter.INSTANCE : c);
+ }
+ }
+ optionalCompleters = focl;
+ }
+ }
+ if (argsCompleters == null) {
+ final Map<Integer, Object> values = getCompleterValues(function);
+ argsCompleters = new ArrayList<Completer>();
+ boolean multi = false;
+ for (int key = 0; key < arguments.size(); key++) {
+ Completer completer = null;
+ Field field = arguments.get(key);
+ if (field != null) {
+ Argument argument = field.getAnnotation(Argument.class);
+ multi = (argument != null && argument.multiValued());
+ org.apache.karaf.shell.commands.Completer ann = field.getAnnotation(org.apache.karaf.shell.commands.Completer.class);
+ if (ann != null) {
+ Class clazz = ann.value();
+ String[] value = ann.values();
+ if (clazz != null) {
+ if (value.length > 0 && clazz == StringsCompleter.class) {
+ completer = new StringsCompleter(value, ann.caseSensitive());
+ } else {
+ BundleContext context = FrameworkUtil.getBundle(function.getClass()).getBundleContext();
+ completer = new ProxyServiceCompleter(context, clazz);
+ }
+ }
+ } else if (values.containsKey(key)) {
+ Object value = values.get(key);
+ if (value instanceof String[]) {
+ completer = new StringsCompleter((String[]) value);
+ } else if (value instanceof Collection) {
+ completer = new StringsCompleter((Collection<String>) value);
+ } else {
+ LOGGER.warn("Could not use value " + value + " as set of completions!");
+ }
+ } else {
+ completer = getDefaultCompleter(session, field);
+ }
+ }
+ if (completer == null) {
+ completer = NullCompleter.INSTANCE;
+ }
+ argsCompleters.add(completer);
+ }
+ if (argsCompleters.isEmpty() || !multi) {
+ argsCompleters.add(NullCompleter.INSTANCE);
+ }
+ optionalCompleters = new HashMap<String, Completer>();
+ for (Option option : fields.keySet()) {
+ Completer completer = null;
+ Field field = fields.get(option);
+ if (field != null) {
+ org.apache.karaf.shell.commands.Completer ann = field.getAnnotation(org.apache.karaf.shell.commands.Completer.class);
+ if (ann != null) {
+ Class clazz = ann.value();
+ String[] value = ann.values();
+ if (clazz != null) {
+ if (value.length > 0 && clazz == StringsCompleter.class) {
+ completer = new StringsCompleter(value, ann.caseSensitive());
+ } else {
+ BundleContext context = FrameworkUtil.getBundle(function.getClass()).getBundleContext();
+ completer = new ProxyServiceCompleter(context, clazz);
+ }
+ }
+ }
+ }
+ if (completer == null) {
+ completer = NullCompleter.INSTANCE;
+ }
+ optionalCompleters.put(option.name(), completer);
+ if (option.aliases() != null) {
+ for (String alias : option.aliases()) {
+ optionalCompleters.put(alias, completer);
+ }
+ }
+ }
+ }
+ this.argsCompleters = argsCompleters;
+ this.optionalCompleters = optionalCompleters;
+ }
+
+ private Map<Integer, Object> getCompleterValues(CommandWithAction function) {
+ final Map<Integer, Object> values = new HashMap<Integer, Object>();
+ Action action = null;
+ try {
+ for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
+ for (Method method : type.getDeclaredMethods()) {
+ CompleterValues completerMethod = method.getAnnotation(CompleterValues.class);
+ if (completerMethod != null) {
+ int index = completerMethod.index();
+ Integer key = index;
+ if (index >= arguments.size() || index < 0) {
+ LOGGER.warn("Index out of range on @CompleterValues on class " + type.getName() + " for index: " + key + " see: " + method);
+ } else if (values.containsKey(key)) {
+ LOGGER.warn("Duplicate @CompleterMethod annotations on class " + type.getName() + " for index: " + key + " see: " + method);
+ } else {
+ try {
+ Object value;
+ if (Modifier.isStatic(method.getModifiers())) {
+ value = method.invoke(null);
+ } else {
+ if (action == null) {
+ action = function.createNewAction();
+ }
+ value = method.invoke(action);
+ }
+ values.put(key, value);
+ } catch (IllegalAccessException e) {
+ LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + e, e);
+ } catch (InvocationTargetException e) {
+ Throwable target = e.getTargetException();
+ if (target == null) {
+ target = e;
+ }
+ LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + target, target);
+ }
+ }
+ }
+ }
+ }
+ } finally {
+ if (action != null) {
+ try {
+ function.releaseAction(action);
+ } catch (Exception e) {
+ LOGGER.warn("Failed to release action: " + action + ". " + e, e);
+ }
+ }
+ }
+ return values;
+ }
+
+ private Completer getDefaultCompleter(CommandSession session, Field field) {
+ Completer completer = null;
+ Class<?> type = field.getType();
+ if (type.isAssignableFrom(File.class)) {
+ completer = new FileCompleter(session);
+ } else if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) {
+ completer = new StringsCompleter(new String[] {"false", "true"}, false);
+ } else if (type.isAssignableFrom(Enum.class)) {
+ Set<String> values = new HashSet<String>();
+ for (Object o : EnumSet.allOf((Class<Enum>) type)) {
+ values.add(o.toString());
+ }
+ completer = new StringsCompleter(values, false);
+ } else {
+ // TODO any other completers we can add?
+ }
+ return completer;
+ }
+
+ private String[] getNames(CommandSession session, String scopedCommand) {
+ String command = NameScoping.getCommandNameWithoutGlobalPrefix(session, scopedCommand);
+ String[] s = command.split(":");
+ if (s.length == 1) {
+ return s;
+ } else {
+ return new String[] { command, s[1] };
+ }
+ }
+
+ /**
+ * If true, a completion at argument index N will only succeed
+ * if all the completions from 0-(N-1) also succeed.
+ */
+ public void setStrict(final boolean strict) {
+ this.strict = strict;
+ }
+
+ /**
+ * Returns whether a completion at argument index N will succees
+ * if all the completions from arguments 0-(N-1) also succeed.
+ */
+ public boolean getStrict() {
+ return this.strict;
+ }
+
+ public int complete(final String buffer, final int cursor,
+ final List<String> candidates) {
+ ArgumentList list = delimit(buffer, cursor);
+ int argpos = list.getArgumentPosition();
+ int argIndex = list.getCursorArgumentIndex();
+
+ //Store the argument list so that it can be used by completers.
+ CommandSession commandSession = CommandSessionHolder.getSession();
+ if(commandSession != null) {
+ commandSession.put(ARGUMENTS_LIST,list);
+ }
+
+ Completer comp = null;
+ String[] args = list.getArguments();
+ int index = 0;
+ // First argument is command name
+ if (index < argIndex) {
+ // Verify command name
+ if (!verifyCompleter(commandCompleter, args[index])) {
+ return -1;
+ }
+ // Verify scope if
+ // - the command name has no scope
+ // - we have a session
+ if (!args[index].contains(":") && commandSession != null) {
+ Function f1 = unProxy((Function) commandSession.get("*:" + args[index]));
+ Function f2 = unProxy(this.function);
+ if (f1 != null && f1 != f2) {
+ return -1;
+ }
+ }
+ index++;
+ } else {
+ comp = commandCompleter;
+ }
+ // Now, check options
+ if (comp == null) {
+ while (index < argIndex && args[index].startsWith("-")) {
+ if (!verifyCompleter(optionsCompleter, args[index])) {
+ return -1;
+ }
+ Option option = options.get(args[index]);
+ if (option == null) {
+ return -1;
+ }
+ Field field = fields.get(option);
+ if (field != null && field.getType() != boolean.class && field.getType() != Boolean.class) {
+ if (++index == argIndex) {
+ comp = NullCompleter.INSTANCE;
+ }
+ }
+ index++;
+ }
+ if (comp == null && index >= argIndex && index < args.length && args[index].startsWith("-")) {
+ comp = optionsCompleter;
+ }
+ }
+ //Now check for if last Option has a completer
+ int lastAgurmentIndex = argIndex - 1;
+ if (lastAgurmentIndex >= 1) {
+ Option lastOption = options.get(args[lastAgurmentIndex]);
+ if (lastOption != null) {
+
+ Field lastField = fields.get(lastOption);
+ if (lastField != null && lastField.getType() != boolean.class && lastField.getType() != Boolean.class) {
+ Option option = lastField.getAnnotation(Option.class);
+ if (option != null) {
+ Completer optionValueCompleter = null;
+ String name = option.name();
+ if (optionalCompleters != null && name != null) {
+ optionValueCompleter = optionalCompleters.get(name);
+ if (optionValueCompleter == null) {
+ String[] aliases = option.aliases();
+ if (aliases.length > 0) {
+ for (int i = 0; i < aliases.length && optionValueCompleter == null; i++) {
+ optionValueCompleter = optionalCompleters.get(option.aliases()[i]);
+ }
+ }
+ }
+ }
+ if(optionValueCompleter != null) {
+ comp = optionValueCompleter;
+ }
+ }
+ }
+ }
+ }
+
+ // Check arguments
+ if (comp == null) {
+ int indexArg = 0;
+ while (index < argIndex) {
+ Completer sub = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
+ if (!verifyCompleter(sub, args[index])) {
+ return -1;
+ }
+ index++;
+ indexArg++;
+ }
+ comp = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
+ }
+
+ int ret = comp.complete(list.getCursorArgument(), argpos, candidates);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ int pos = ret + (list.getBufferPosition() - argpos);
+
+ /**
+ * Special case: when completing in the middle of a line, and the
+ * area under the cursor is a delimiter, then trim any delimiters
+ * from the candidates, since we do not need to have an extra
+ * delimiter.
+ *
+ * E.g., if we have a completion for "foo", and we
+ * enter "f bar" into the buffer, and move to after the "f"
+ * and hit TAB, we want "foo bar" instead of "foo bar".
+ */
+
+ if ((buffer != null) && (cursor != buffer.length()) && isDelimiter(buffer, cursor)) {
+ for (int i = 0; i < candidates.size(); i++) {
+ String val = candidates.get(i);
+
+ while ((val.length() > 0)
+ && isDelimiter(val, val.length() - 1)) {
+ val = val.substring(0, val.length() - 1);
+ }
+
+ candidates.set(i, val);
+ }
+ }
+
+ return pos;
+ }
+
+ protected boolean verifyCompleter(Completer completer, String argument) {
+ List<String> candidates = new ArrayList<String>();
+ return completer.complete(argument, argument.length(), candidates) != -1 && !candidates.isEmpty();
+ }
+
+ public ArgumentList delimit(final String buffer, final int cursor) {
+ Parser parser = new Parser(buffer, cursor);
+ try {
+ List<List<List<String>>> program = parser.program();
+ List<String> pipe = program.get(parser.c0).get(parser.c1);
+ return new ArgumentList(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor);
+ } catch (Throwable t) {
+ return new ArgumentList(new String[] { buffer }, 0, cursor, cursor);
+ }
+ }
+
+ /**
+ * Returns true if the specified character is a whitespace
+ * parameter. Check to ensure that the character is not
+ * escaped and returns true from
+ * {@link #isDelimiterChar}.
+ *
+ * @param buffer the complete command buffer
+ * @param pos the index of the character in the buffer
+ * @return true if the character should be a delimiter
+ */
+ public boolean isDelimiter(final String buffer, final int pos) {
+ return !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+ }
+
+ public boolean isEscaped(final String buffer, final int pos) {
+ return pos > 0 && buffer.charAt(pos) == '\\' && !isEscaped(buffer, pos - 1);
+ }
+
+ /**
+ * The character is a delimiter if it is whitespace, and the
+ * preceeding character is not an escape character.
+ */
+ public boolean isDelimiterChar(String buffer, int pos) {
+ return Character.isWhitespace(buffer.charAt(pos));
+ }
+
+ /**
+ * The result of a delimited buffer.
+ */
+ public static class ArgumentList {
+ private String[] arguments;
+ private int cursorArgumentIndex;
+ private int argumentPosition;
+ private int bufferPosition;
+
+ /**
+ * @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
+ */
+ public ArgumentList(String[] arguments, int cursorArgumentIndex,
+ int argumentPosition, int bufferPosition) {
+ this.arguments = arguments;
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ this.argumentPosition = argumentPosition;
+ this.bufferPosition = bufferPosition;
+ }
+
+ public void setCursorArgumentIndex(int cursorArgumentIndex) {
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ }
+
+ public int getCursorArgumentIndex() {
+ return this.cursorArgumentIndex;
+ }
+
+ public String getCursorArgument() {
+ if ((cursorArgumentIndex < 0)
+ || (cursorArgumentIndex >= arguments.length)) {
+ return null;
+ }
+
+ return arguments[cursorArgumentIndex];
+ }
+
+ public void setArgumentPosition(int argumentPosition) {
+ this.argumentPosition = argumentPosition;
+ }
+
+ public int getArgumentPosition() {
+ return this.argumentPosition;
+ }
+
+ public void setArguments(String[] arguments) {
+ this.arguments = arguments;
+ }
+
+ public String[] getArguments() {
+ return this.arguments;
+ }
+
+ public void setBufferPosition(int bufferPosition) {
+ this.bufferPosition = bufferPosition;
+ }
+
+ public int getBufferPosition() {
+ return this.bufferPosition;
+ }
+ }
+
+ public static class ProxyServiceCompleter implements Completer {
+ private final BundleContext context;
+ private final Class<? extends Completer> clazz;
+
+ public ProxyServiceCompleter(BundleContext context, Class<? extends Completer> clazz) {
+ this.context = context;
+ this.clazz = clazz;
+ }
+
+ @Override
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ ServiceReference<? extends Completer> ref = context.getServiceReference(clazz);
+ if (ref != null) {
+ Completer completer = context.getService(ref);
+ if (completer != null) {
+ try {
+ return completer.complete(buffer, cursor, candidates);
+ } finally {
+ context.ungetService(ref);
+ }
+ }
+ }
+ return -1;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
new file mode 100644
index 0000000..23f5447
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandNamesCompleter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.console.completer;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.Completer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+
+/**
+ * Completes command names
+ */
+public class CommandNamesCompleter implements Completer {
+
+ public static final String COMMANDS = ".commands";
+
+ private CommandSession session;
+ private final Set<String> commands = new CopyOnWriteArraySet<String>();
+
+ public CommandNamesCompleter() {
+ this(CommandSessionHolder.getSession());
+ }
+
+ public CommandNamesCompleter(CommandSession session) {
+ this.session = session;
+
+ try {
+ new CommandTracker();
+ } catch (Throwable t) {
+ // Ignore in case we're not in OSGi
+ }
+ }
+
+
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ if (session == null) {
+ session = CommandSessionHolder.getSession();
+ }
+ checkData();
+ int res = new StringsCompleter(commands).complete(buffer, cursor, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void checkData() {
+ if (commands.isEmpty()) {
+ Set<String> names = new HashSet<String>((Set<String>) session.get(COMMANDS));
+ for (String name : names) {
+ commands.add(name);
+ if (name.indexOf(':') > 0) {
+ commands.add(name.substring(0, name.indexOf(':')));
+ }
+ }
+ }
+ }
+
+ private class CommandTracker {
+ public CommandTracker() throws Exception {
+ BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ if (context == null) {
+ throw new IllegalStateException("Bundle is stopped");
+ }
+ ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ commands.clear();
+ }
+ };
+ context.addServiceListener(listener,
+ String.format("(&(%s=*)(%s=*))",
+ CommandProcessor.COMMAND_SCOPE,
+ CommandProcessor.COMMAND_FUNCTION));
+ }
+ }
+
+}
+
[09/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
new file mode 100644
index 0000000..54fe81a
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/DefaultConverter.java
@@ -0,0 +1,401 @@
+/*
+ * 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.commands.converter;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Dictionary;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.LinkedHashMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Queue;
+import java.util.LinkedList;
+import java.util.regex.Pattern;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.math.BigInteger;
+import java.math.BigDecimal;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.lang.reflect.InvocationTargetException;
+
+public class DefaultConverter
+{
+
+ private Object loader;
+
+ public DefaultConverter(Object loader) {
+ this.loader = loader;
+ }
+
+ public Object convert(Object source, Type target) throws Exception {
+ return convert( source, new GenericType(target));
+ }
+
+ public Object convert(Object fromValue, ReifiedType type) throws Exception {
+ // Discard null values
+ if (fromValue == null) {
+ return null;
+ }
+ // If the object is an instance of the type, just return it
+ if (isAssignable(fromValue, type)) {
+ return fromValue;
+ }
+ Object value = convertWithConverters(fromValue, type);
+ if (value == null) {
+ if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
+ return convertToNumber((Number) fromValue, toClass(type));
+ } else if (fromValue instanceof String) {
+ return convertFromString((String) fromValue, toClass(type), loader);
+ } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+ return convertToArray(fromValue, type);
+ } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+ return convertToMap(fromValue, type);
+ } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+ return convertToDictionary(fromValue, type);
+ } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+ return convertToCollection(fromValue, type);
+ } else {
+ throw new Exception("Unable to convert value " + fromValue + " to type " + type);
+ }
+ }
+ return value;
+ }
+
+ private Object convertWithConverters(Object source, ReifiedType type) throws Exception {
+ Object value = null;
+// for (Converter converter : converters) {
+// if (converter.canConvert(source, type)) {
+// value = converter.convert(source, type);
+// if (value != null) {
+// return value;
+// }
+// }
+// }
+ return value;
+ }
+
+ public Object convertToNumber(Number value, Class toType) throws Exception {
+ toType = unwrap(toType);
+ if (AtomicInteger.class == toType) {
+ return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
+ } else if (AtomicLong.class == toType) {
+ return new AtomicLong((Long) convertToNumber(value, Long.class));
+ } else if (Integer.class == toType) {
+ return value.intValue();
+ } else if (Short.class == toType) {
+ return value.shortValue();
+ } else if (Long.class == toType) {
+ return value.longValue();
+ } else if (Float.class == toType) {
+ return value.floatValue();
+ } else if (Double.class == toType) {
+ return value.doubleValue();
+ } else if (Byte.class == toType) {
+ return value.byteValue();
+ } else if (BigInteger.class == toType) {
+ return new BigInteger(value.toString());
+ } else if (BigDecimal.class == toType) {
+ return new BigDecimal(value.toString());
+ } else {
+ throw new Exception("Unable to convert number " + value + " to " + toType);
+ }
+ }
+
+ public Object convertFromString(String value, Class toType, Object loader) throws Exception {
+ toType = unwrap(toType);
+ if (ReifiedType.class == toType) {
+ try {
+ return GenericType.parse(value, loader);
+ } catch (ClassNotFoundException e) {
+ throw new Exception("Unable to convert", e);
+ }
+ } else if (Class.class == toType) {
+ try {
+ return GenericType.parse(value, loader).getRawClass();
+ } catch (ClassNotFoundException e) {
+ throw new Exception("Unable to convert", e);
+ }
+ } else if (Locale.class == toType) {
+ String[] tokens = value.split("_");
+ if (tokens.length == 1) {
+ return new Locale(tokens[0]);
+ } else if (tokens.length == 2) {
+ return new Locale(tokens[0], tokens[1]);
+ } else if (tokens.length == 3) {
+ return new Locale(tokens[0], tokens[1], tokens[2]);
+ } else {
+ throw new Exception("Invalid locale string:" + value);
+ }
+ } else if (Pattern.class == toType) {
+ return Pattern.compile(value);
+ } else if (Properties.class == toType) {
+ Properties props = new Properties();
+ ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
+ props.load(in);
+ return props;
+ } else if (Boolean.class == toType) {
+ if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
+ return Boolean.TRUE;
+ } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
+ return Boolean.FALSE;
+ } else {
+ throw new RuntimeException("Invalid boolean value: " + value);
+ }
+ } else if (Integer.class == toType) {
+ return Integer.valueOf(value);
+ } else if (Short.class == toType) {
+ return Short.valueOf(value);
+ } else if (Long.class == toType) {
+ return Long.valueOf(value);
+ } else if (Float.class == toType) {
+ return Float.valueOf(value);
+ } else if (Double.class == toType) {
+ return Double.valueOf(value);
+ } else if (Character.class == toType) {
+ if (value.length() == 6 && value.startsWith("\\u")) {
+ int code = Integer.parseInt(value.substring(2), 16);
+ return (char)code;
+ } else if (value.length() == 1) {
+ return value.charAt(0);
+ } else {
+ throw new Exception("Invalid value for character type: " + value);
+ }
+ } else if (Byte.class == toType) {
+ return Byte.valueOf(value);
+ } else if (Enum.class.isAssignableFrom(toType)) {
+ return Enum.valueOf((Class<Enum>) toType, value);
+ } else {
+ return createObject(value, toType);
+ }
+ }
+
+ private static Object createObject(String value, Class type) throws Exception {
+ if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
+ throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
+ }
+ Constructor constructor = null;
+ try {
+ constructor = type.getConstructor(String.class);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Unable to convert to " + type);
+ }
+ try {
+ return constructor.newInstance(value);
+ } catch (Exception e) {
+ throw new Exception("Unable to convert ", getRealCause(e));
+ }
+ }
+
+ private static Throwable getRealCause(Throwable t) {
+ if (t instanceof InvocationTargetException && t.getCause() != null) {
+ return t.getCause();
+ }
+ return t;
+ }
+
+ private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
+ ReifiedType valueType = type.getActualTypeArgument(0);
+ Collection newCol = (Collection) getCollection(toClass(type)).newInstance();
+ if (obj.getClass().isArray()) {
+ for (int i = 0; i < Array.getLength(obj); i++) {
+ try {
+ newCol.add(convert(Array.get(obj, i), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+ }
+ }
+ } else {
+ for (Object item : (Collection) obj) {
+ try {
+ newCol.add(convert(item, valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
+ }
+ }
+ }
+ return newCol;
+ }
+
+ private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
+ ReifiedType keyType = type.getActualTypeArgument(0);
+ ReifiedType valueType = type.getActualTypeArgument(1);
+ Dictionary newDic = new Hashtable();
+ if (obj instanceof Dictionary) {
+ Dictionary dic = (Dictionary) obj;
+ for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+ Object key = keyEnum.nextElement();
+ try {
+ newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ } else {
+ for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+ try {
+ newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ }
+ return newDic;
+ }
+
+ private Object convertToMap(Object obj, ReifiedType type) throws Exception {
+ ReifiedType keyType = type.getActualTypeArgument(0);
+ ReifiedType valueType = type.getActualTypeArgument(1);
+ Map newMap = (Map) getMap(toClass(type)).newInstance();
+ if (obj instanceof Dictionary) {
+ Dictionary dic = (Dictionary) obj;
+ for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements();) {
+ Object key = keyEnum.nextElement();
+ try {
+ newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ } else {
+ for (Map.Entry e : ((Map<Object,Object>) obj).entrySet()) {
+ try {
+ newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ }
+ return newMap;
+ }
+
+ private Object convertToArray(Object obj, ReifiedType type) throws Exception {
+ if (obj instanceof Collection) {
+ obj = ((Collection) obj).toArray();
+ }
+ if (!obj.getClass().isArray()) {
+ throw new Exception("Unable to convert from " + obj + " to " + type);
+ }
+ ReifiedType componentType;
+ if (type.size() > 0) {
+ componentType = type.getActualTypeArgument(0);
+ } else {
+ componentType = new GenericType(type.getRawClass().getComponentType());
+ }
+ Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
+ for (int i = 0; i < Array.getLength(obj); i++) {
+ try {
+ Array.set(array, i, convert(Array.get(obj, i), componentType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+ }
+ }
+ return array;
+ }
+
+ public static boolean isAssignable(Object source, ReifiedType target) {
+ return source == null
+ || (target.size() == 0
+ && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
+ }
+
+ private static Class unwrap(Class c) {
+ Class u = primitives.get(c);
+ return u != null ? u : c;
+ }
+
+ private static Class getMap(Class type) {
+ if (hasDefaultConstructor(type)) {
+ return type;
+ } else if (SortedMap.class.isAssignableFrom(type)) {
+ return TreeMap.class;
+ } else if (ConcurrentMap.class.isAssignableFrom(type)) {
+ return ConcurrentHashMap.class;
+ } else {
+ return LinkedHashMap.class;
+ }
+ }
+
+ private static Class getCollection(Class type) {
+ if (hasDefaultConstructor(type)) {
+ return type;
+ } else if (SortedSet.class.isAssignableFrom(type)) {
+ return TreeSet.class;
+ } else if (Set.class.isAssignableFrom(type)) {
+ return LinkedHashSet.class;
+ } else if (List.class.isAssignableFrom(type)) {
+ return ArrayList.class;
+ } else if (Queue.class.isAssignableFrom(type)) {
+ return LinkedList.class;
+ } else {
+ return ArrayList.class;
+ }
+ }
+
+ private static boolean hasDefaultConstructor(Class type) {
+ if (!Modifier.isPublic(type.getModifiers())) {
+ return false;
+ }
+ if (Modifier.isAbstract(type.getModifiers())) {
+ return false;
+ }
+ Constructor[] constructors = type.getConstructors();
+ for (Constructor constructor : constructors) {
+ if (Modifier.isPublic(constructor.getModifiers()) &&
+ constructor.getParameterTypes().length == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final Map<Class, Class> primitives;
+ static {
+ primitives = new HashMap<Class, Class>();
+ primitives.put(byte.class, Byte.class);
+ primitives.put(short.class, Short.class);
+ primitives.put(char.class, Character.class);
+ primitives.put(int.class, Integer.class);
+ primitives.put(long.class, Long.class);
+ primitives.put(float.class, Float.class);
+ primitives.put(double.class, Double.class);
+ primitives.put(boolean.class, Boolean.class);
+ }
+
+ private Class toClass(ReifiedType type) {
+ return type.getRawClass();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
new file mode 100644
index 0000000..2f2b5e0
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/GenericType.java
@@ -0,0 +1,195 @@
+/*
+ * 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.commands.converter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+public class GenericType extends ReifiedType {
+
+ private static final GenericType[] EMPTY = new GenericType[0];
+
+ private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
+
+ static {
+ primitiveClasses.put("int", int.class);
+ primitiveClasses.put("short", short.class);
+ primitiveClasses.put("long", long.class);
+ primitiveClasses.put("byte", byte.class);
+ primitiveClasses.put("char", char.class);
+ primitiveClasses.put("float", float.class);
+ primitiveClasses.put("double", double.class);
+ primitiveClasses.put("boolean", boolean.class);
+ }
+
+ private GenericType[] parameters;
+
+ public GenericType(Type type) {
+ this(getConcreteClass(type), parametersOf(type));
+ }
+
+ public GenericType(Class clazz, GenericType... parameters) {
+ super(clazz);
+ this.parameters = parameters;
+ }
+
+ public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
+ type = type.trim();
+ // Check if this is an array
+ if (type.endsWith("[]")) {
+ GenericType t = parse(type.substring(0, type.length() - 2), loader);
+ return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
+ }
+ // Check if this is a generic
+ int genericIndex = type.indexOf('<');
+ if (genericIndex > 0) {
+ if (!type.endsWith(">")) {
+ throw new IllegalArgumentException("Can not load type: " + type);
+ }
+ GenericType base = parse(type.substring(0, genericIndex), loader);
+ String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
+ GenericType[] types = new GenericType[params.length];
+ for (int i = 0; i < params.length; i++) {
+ types[i] = parse(params[i], loader);
+ }
+ return new GenericType(base.getRawClass(), types);
+ }
+ // Primitive
+ if (primitiveClasses.containsKey(type)) {
+ return new GenericType(primitiveClasses.get(type));
+ }
+ // Class
+ if (loader instanceof ClassLoader) {
+ return new GenericType(((ClassLoader) loader).loadClass(type));
+ } else if (loader instanceof Bundle) {
+ return new GenericType(((Bundle) loader).loadClass(type));
+ } else {
+ throw new IllegalArgumentException("Unsupported loader: " + loader);
+ }
+ }
+
+ @Override
+ public ReifiedType getActualTypeArgument(int i) {
+ if (parameters.length == 0) {
+ return super.getActualTypeArgument(i);
+ }
+ return parameters[i];
+ }
+
+ @Override
+ public int size() {
+ return parameters.length;
+ }
+
+ @Override
+ public String toString() {
+ Class cl = getRawClass();
+ if (cl.isArray()) {
+ if (parameters.length > 0) {
+ return parameters[0].toString() + "[]";
+ } else {
+ return cl.getComponentType().getName() + "[]";
+ }
+ }
+ if (parameters.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cl.getName());
+ sb.append("<");
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(parameters[i].toString());
+ }
+ sb.append(">");
+ return sb.toString();
+ }
+ return cl.getName();
+ }
+
+ static GenericType[] parametersOf(Type type ) {
+ if ( type instanceof Class ) {
+ Class clazz = (Class) type;
+ if (clazz.isArray()) {
+ GenericType t = new GenericType(clazz.getComponentType());
+ if (t.size() > 0) {
+ return new GenericType[] { t };
+ } else {
+ return EMPTY;
+ }
+ } else {
+ return EMPTY;
+ }
+ }
+ if ( type instanceof ParameterizedType ) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type [] parameters = pt.getActualTypeArguments();
+ GenericType[] gts = new GenericType[parameters.length];
+ for ( int i =0; i<gts.length; i++) {
+ gts[i] = new GenericType(parameters[i]);
+ }
+ return gts;
+ }
+ if ( type instanceof GenericArrayType ) {
+ return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
+ }
+ throw new IllegalStateException();
+ }
+
+ static Class<?> getConcreteClass(Type type) {
+ Type ntype = collapse(type);
+ if ( ntype instanceof Class )
+ return (Class<?>) ntype;
+
+ if ( ntype instanceof ParameterizedType )
+ return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
+
+ throw new RuntimeException("Unknown type " + type );
+ }
+
+ static Type collapse(Type target) {
+ if (target instanceof Class || target instanceof ParameterizedType ) {
+ return target;
+ } else if (target instanceof TypeVariable) {
+ return collapse(((TypeVariable<?>) target).getBounds()[0]);
+ } else if (target instanceof GenericArrayType) {
+ Type t = collapse(((GenericArrayType) target)
+ .getGenericComponentType());
+ while ( t instanceof ParameterizedType )
+ t = collapse(((ParameterizedType)t).getRawType());
+ return Array.newInstance((Class<?>)t, 0).getClass();
+ } else if (target instanceof WildcardType) {
+ WildcardType wct = (WildcardType) target;
+ if (wct.getLowerBounds().length == 0)
+ return collapse(wct.getUpperBounds()[0]);
+ else
+ return collapse(wct.getLowerBounds()[0]);
+ }
+ throw new RuntimeException("Huh? " + target);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
new file mode 100644
index 0000000..dda4477
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/converter/ReifiedType.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed 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.commands.converter;
+
+/**
+ * Provides access to a concrete type and its optional generic type arguments.
+ *
+ * Java 5 and later support generic types. These types consist of a raw class
+ * with type arguments. This class models such a <code>Type</code> class but
+ * ensures that the type is <em>reified</em>. Reification means that the Type
+ * graph associated with a Java 5 <code>Type</code> instance is traversed
+ * until the type becomes a concrete class. In Java 1.4 a class has no
+ * arguments. This concrete class implements the Reified Type for Java 1.4.
+ *
+ * In Java 1.4, this class works with non-generic types. In that cases, a
+ * Reified Type provides access to the class and has zero type arguments, though
+ * a subclass that provide type arguments should be respected. Blueprint
+ * extender implementations can subclass this class and provide access to the
+ * generics type graph if used in a conversion. Such a subclass must
+ * <em>reify<em> the different Java 5 <code>Type</code> instances into the
+ * reified form. That is, a form where the raw Class is available with its optional type arguments as Reified Types.
+ *
+ * @Immutable
+ */
+public class ReifiedType {
+ final static ReifiedType ALL = new ReifiedType(Object.class);
+
+ private final Class clazz;
+
+ /**
+ * Create a Reified Type for a raw Java class without any generic arguments.
+ * Subclasses can provide the optional generic argument information. Without
+ * subclassing, this instance has no type arguments.
+ *
+ * @param clazz
+ * The raw class of the Reified Type.
+ */
+ public ReifiedType(Class clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
+ * Access to the raw class.
+ *
+ * The raw class represents the concrete class that is associated with a
+ * type declaration. This class could have been deduced from the generics
+ * type graph of the declaration. For example, in the following example:
+ *
+ * <pre>
+ * Map<String, Object> map;
+ * </pre>
+ *
+ * The raw class is the Map class.
+ *
+ * @return the collapsed raw class that represents this type.
+ */
+ public Class getRawClass() {
+ return clazz;
+ }
+
+ /**
+ * Access to a type argument.
+ *
+ * The type argument refers to a argument in a generic type declaration
+ * given by index <code>i</code>. This method returns a Reified Type that
+ * has Object as class when no generic type information is available. Any
+ * object is assignable to Object and therefore no conversion is then
+ * necessary, this is compatible with older Javas than 5. For this reason,
+ * the implementation in this class always returns the
+ * <code>Object<code> class, regardless of the given index.
+ *
+ * This method should be overridden by a subclass that provides access to
+ * the generic information.
+ *
+ * For example, in the following example:
+ *
+ * <pre>
+ * Map<String, Object> map;
+ * </pre>
+ *
+ * The type argument 0 is <code>String</code>, and type argument 1 is
+ * <code>Object</code>.
+ *
+ * @param i
+ * The index of the type argument
+ * @return <code>ReifiedType(Object.class)<code>, subclasses must override this and return the generic argument at index <code>i</code>
+ */
+ public ReifiedType getActualTypeArgument(int i) {
+ return ALL;
+ }
+
+ /**
+ * Return the number of type arguments.
+ *
+ * This method should be overridden by a subclass to support Java 5 types.
+ *
+ * @return 0, subclasses must override this and return the number of generic
+ * arguments
+ */
+ public int size() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
new file mode 100644
index 0000000..e0bd11a
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaData.java
@@ -0,0 +1,296 @@
+/*
+ * 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.commands.meta;
+
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.HelpOption;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
+import org.apache.karaf.shell.console.Completer;
+
+public class ActionMetaData {
+
+ private final Class<? extends Action> actionClass;
+ private final Command command;
+ private final Map<Option, Field> options;
+ private final Map<Argument, Field> arguments;
+ List<Argument> orderedArguments;
+ private final Completer[] completers;
+
+ public ActionMetaData(Class<? extends Action> actionClass, Command command, Map<Option, Field> options, Map<Argument, Field> args,
+ List<Argument> orderedArguments, Completer[] completers) {
+ super();
+ this.actionClass = actionClass;
+ this.command = command;
+ this.options = options;
+ this.arguments = args;
+ this.orderedArguments = orderedArguments;
+ this.completers = completers;
+ }
+
+ public Class<? extends Action> getActionClass() {
+ return actionClass;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ public Map<Option, Field> getOptions() {
+ return options;
+ }
+
+ public Map<Argument, Field> getArguments() {
+ return arguments;
+ }
+
+ public Completer[] getCompleters() {
+ return completers;
+ }
+
+ public List<Argument> getOrderedArguments() {
+ return orderedArguments;
+ }
+
+ public void printUsage(Action action, PrintStream out, boolean globalScope, int termWidth) {
+ if (command != null) {
+ List<Argument> argumentsSet = new ArrayList<Argument>(arguments.keySet());
+ Collections.sort(argumentsSet, new Comparator<Argument>() {
+ public int compare(Argument o1, Argument o2) {
+ return Integer.valueOf(o1.index()).compareTo(Integer.valueOf(o2.index()));
+ }
+ });
+ Set<Option> optionsSet = new HashSet<Option>(options.keySet());
+ optionsSet.add(HelpOption.HELP);
+ if (command != null && (command.description() != null || command.name() != null)) {
+ out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
+ out.print(" ");
+ if (command.name() != null) {
+ if (globalScope) {
+ out.println(INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
+ } else {
+ out.println(command.scope() + ":" + INTENSITY_BOLD + command.name() + INTENSITY_NORMAL);
+ }
+ out.println();
+ }
+ out.print("\t");
+ out.println(command.description());
+ out.println();
+ }
+ StringBuffer syntax = new StringBuffer();
+ if (command != null) {
+ if (globalScope) {
+ syntax.append(command.name());
+ } else {
+ syntax.append(String.format("%s:%s", command.scope(), command.name()));
+ }
+ }
+ if (options.size() > 0) {
+ syntax.append(" [options]");
+ }
+ if (arguments.size() > 0) {
+ syntax.append(' ');
+ for (Argument argument : argumentsSet) {
+ if (!argument.required()) {
+ syntax.append(String.format("[%s] ", argument.name()));
+ } else {
+ syntax.append(String.format("%s ", argument.name()));
+ }
+ }
+ }
+
+ out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(syntax.toString());
+ out.println();
+ if (arguments.size() > 0) {
+ out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL);
+ for (Argument argument : argumentsSet) {
+ out.print(" ");
+ out.println(INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL);
+ ActionMetaData.printFormatted(" ", argument.description(), termWidth, out, true);
+ if (!argument.required()) {
+ if (argument.valueToShowInHelp() != null && argument.valueToShowInHelp().length() != 0) {
+ if (Argument.DEFAULT_STRING.equals(argument.valueToShowInHelp())) {
+ Object o = getDefaultValue(action, argument);
+ String defaultValue = getDefaultValueString(o);
+ if (defaultValue != null) {
+ printDefaultsTo(out, defaultValue);
+ }
+ } else {
+ printDefaultsTo(out, argument.valueToShowInHelp());
+ }
+ }
+ }
+ }
+ out.println();
+ }
+ if (options.size() > 0) {
+ out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
+ for (Option option : optionsSet) {
+ String opt = option.name();
+ for (String alias : option.aliases()) {
+ opt += ", " + alias;
+ }
+ out.print(" ");
+ out.println(INTENSITY_BOLD + opt + INTENSITY_NORMAL);
+ ActionMetaData.printFormatted(" ", option.description(), termWidth, out, true);
+ if (option.valueToShowInHelp() != null && option.valueToShowInHelp().length() != 0) {
+ if (Option.DEFAULT_STRING.equals(option.valueToShowInHelp())) {
+ Object o = getDefaultValue(action, option);
+ String defaultValue = getDefaultValueString(o);
+ if (defaultValue != null) {
+ printDefaultsTo(out, defaultValue);
+ }
+ } else {
+ printDefaultsTo(out, option.valueToShowInHelp());
+ }
+ }
+ }
+ out.println();
+ }
+ if (command.detailedDescription().length() > 0) {
+ out.println(INTENSITY_BOLD + "DETAILS" + INTENSITY_NORMAL);
+ String desc = getDetailedDescription();
+ ActionMetaData.printFormatted(" ", desc, termWidth, out, true);
+ }
+ }
+ }
+
+ public Object getDefaultValue(Action action, Argument argument) {
+ try {
+ arguments.get(argument).setAccessible(true);
+ return arguments.get(argument).get(action);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public Object getDefaultValue(Action action, Option option) {
+ try {
+ options.get(option).setAccessible(true);
+ return options.get(option).get(action);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public String getDetailedDescription() {
+ String desc = command.detailedDescription();
+ return loadDescription(actionClass, desc);
+ }
+
+ private String loadDescription(Class<?> clazz, String desc) {
+ if (desc != null && desc.startsWith("classpath:")) {
+ desc = loadClassPathResource(clazz, desc.substring("classpath:".length()));
+ }
+ return desc;
+ }
+
+ public String getDefaultValueString(Object o) {
+ if (o != null && (!(o instanceof Boolean) || ((Boolean)o))
+ && (!(o instanceof Number) || ((Number)o).doubleValue() != 0.0)) {
+ return o.toString();
+ } else {
+ return null;
+ }
+ }
+
+ private void printDefaultsTo(PrintStream out, String value) {
+ out.println(" (defaults to " + value + ")");
+ }
+
+ static void printFormatted(String prefix, String str, int termWidth, PrintStream out, boolean prefixFirstLine) {
+ int pfxLen = prefix.length();
+ int maxwidth = termWidth - pfxLen;
+ Pattern wrap = Pattern.compile("(\\S\\S{" + maxwidth + ",}|.{1," + maxwidth + "})(\\s+|$)");
+ int cur = 0;
+ while (cur >= 0) {
+ int lst = str.indexOf('\n', cur);
+ String s = (lst >= 0) ? str.substring(cur, lst) : str.substring(cur);
+ if (s.length() == 0) {
+ out.println();
+ } else {
+ Matcher m = wrap.matcher(s);
+ while (m.find()) {
+ if (cur > 0 || prefixFirstLine) {
+ out.print(prefix);
+ }
+ out.println(m.group());
+ }
+ }
+ if (lst >= 0) {
+ cur = lst + 1;
+ } else {
+ break;
+ }
+ }
+ }
+
+ private String loadClassPathResource(Class<?> clazz, String path) {
+ InputStream is = clazz.getResourceAsStream(path);
+ if (is == null) {
+ is = clazz.getClassLoader().getResourceAsStream(path);
+ }
+ if (is == null) {
+ return "Unable to load description from " + path;
+ }
+
+ try {
+ Reader r = new InputStreamReader(is);
+ StringWriter sw = new StringWriter();
+ int c;
+ while ((c = r.read()) != -1) {
+ sw.append((char) c);
+ }
+ return sw.toString();
+ } catch (IOException e) {
+ return "Unable to load description from " + path;
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
new file mode 100644
index 0000000..91bc48f
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/meta/ActionMetaDataFactory.java
@@ -0,0 +1,251 @@
+/*
+ * 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.commands.meta;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+
+public class ActionMetaDataFactory {
+
+ public ActionMetaData create(Class<? extends Action> actionClass) {
+ Command command = getCommand(actionClass);
+ Map<Option, Field> options = new HashMap<Option, Field>();
+ Map<Argument, Field> arguments = new HashMap<Argument, Field>();
+ List<Argument> orderedArguments = new ArrayList<Argument>();
+
+ for (Class<?> type = actionClass; type != null; type = type.getSuperclass()) {
+ for (Field field : type.getDeclaredFields()) {
+ Option option = field.getAnnotation(Option.class);
+ if (option == null) {
+ option = getAndConvertDeprecatedOption(field);
+ }
+ if (option != null) {
+ options.put(option, field);
+ }
+
+ Argument argument = field.getAnnotation(Argument.class);
+ if (argument == null) {
+ argument = getAndConvertDeprecatedArgument(field);
+ }
+ if (argument != null) {
+ argument = replaceDefaultArgument(field, argument);
+ arguments.put(argument, field);
+ int index = argument.index();
+ while (orderedArguments.size() <= index) {
+ orderedArguments.add(null);
+ }
+ if (orderedArguments.get(index) != null) {
+ throw new IllegalArgumentException("Duplicate argument index: " + index + " on Action " + actionClass.getName());
+ }
+ orderedArguments.set(index, argument);
+ }
+ }
+ }
+ assertIndexesAreCorrect(actionClass, orderedArguments);
+
+ return new ActionMetaData(actionClass, command, options, arguments, orderedArguments, null);
+ }
+
+ public Command getCommand(Class<? extends Action> actionClass) {
+ Command command = actionClass.getAnnotation(Command.class);
+ if (command == null) {
+ command = getAndConvertDeprecatedCommand(actionClass);
+ }
+ return command;
+ }
+
+ @SuppressWarnings("deprecation")
+ public Command getAndConvertDeprecatedCommand(Class<? extends Action> actionClass) {
+ final org.apache.felix.gogo.commands.Command oldCommand = actionClass.getAnnotation(org.apache.felix.gogo.commands.Command.class);
+ if (oldCommand == null) {
+ return null;
+ }
+ return new Command() {
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Command.class;
+ }
+
+ @Override
+ public String scope() {
+ return oldCommand.scope();
+ }
+
+ @Override
+ public String name() {
+ return oldCommand.name();
+ }
+
+ @Override
+ public String detailedDescription() {
+ return oldCommand.detailedDescription();
+ }
+
+ @Override
+ public String description() {
+ return oldCommand.description();
+ }
+ };
+ }
+
+ @SuppressWarnings("deprecation")
+ private Option getAndConvertDeprecatedOption(Field field) {
+ final org.apache.felix.gogo.commands.Option oldOption = field.getAnnotation(org.apache.felix.gogo.commands.Option.class);
+ if (oldOption == null) {
+ return null;
+ }
+ return new Option() {
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Option.class;
+ }
+
+ @Override
+ public String valueToShowInHelp() {
+ return oldOption.valueToShowInHelp();
+ }
+
+ @Override
+ public boolean required() {
+ return oldOption.required();
+ }
+
+ @Override
+ public String name() {
+ return oldOption.name();
+ }
+
+ @Override
+ public boolean multiValued() {
+ return oldOption.multiValued();
+ }
+
+ @Override
+ public String description() {
+ return oldOption.description();
+ }
+
+ @Override
+ public String[] aliases() {
+ return oldOption.aliases();
+ }
+ };
+ }
+
+ @SuppressWarnings("deprecation")
+ private Argument getAndConvertDeprecatedArgument(Field field) {
+ final org.apache.felix.gogo.commands.Argument oldArgument = field.getAnnotation(org.apache.felix.gogo.commands.Argument.class);
+ if (oldArgument == null) {
+ return null;
+ }
+ return new Argument() {
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Argument.class;
+ }
+
+ @Override
+ public String valueToShowInHelp() {
+ return oldArgument.valueToShowInHelp();
+ }
+
+ @Override
+ public boolean required() {
+ return oldArgument.required();
+ }
+
+ @Override
+ public String name() {
+ return oldArgument.name();
+ }
+
+ @Override
+ public boolean multiValued() {
+ return oldArgument.multiValued();
+ }
+
+ @Override
+ public int index() {
+ return oldArgument.index();
+ }
+
+ @Override
+ public String description() {
+ return oldArgument.description();
+ }
+ };
+ }
+
+ private Argument replaceDefaultArgument(Field field, Argument argument) {
+ if (Argument.DEFAULT.equals(argument.name())) {
+ final Argument delegate = argument;
+ final String name = field.getName();
+ argument = new Argument() {
+ public String name() {
+ return name;
+ }
+
+ public String description() {
+ return delegate.description();
+ }
+
+ public boolean required() {
+ return delegate.required();
+ }
+
+ public int index() {
+ return delegate.index();
+ }
+
+ public boolean multiValued() {
+ return delegate.multiValued();
+ }
+
+ public String valueToShowInHelp() {
+ return delegate.valueToShowInHelp();
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return delegate.annotationType();
+ }
+ };
+ }
+ return argument;
+ }
+
+ private void assertIndexesAreCorrect(Class<? extends Action> actionClass, List<Argument> orderedArguments) {
+ for (int i = 0; i < orderedArguments.size(); i++) {
+ if (orderedArguments.get(i) == null) {
+ throw new IllegalArgumentException("Missing argument for index: " + i + " on Action " + actionClass.getName());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/AbstractAction.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
new file mode 100644
index 0000000..f9990c5
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/AbstractAction.java
@@ -0,0 +1,50 @@
+/*
+ * 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.console;
+
+import org.apache.karaf.shell.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractAction implements Action {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected CommandSession session;
+
+ public Object execute(CommandSession session) throws Exception {
+ this.session = session;
+ return doExecute();
+ }
+
+ protected abstract Object doExecute() throws Exception;
+
+ /**
+ * This is for long running commands to be interrupted by ctrl-c
+ *
+ * @throws InterruptedException
+ */
+ public static void checkInterrupted() throws InterruptedException {
+ Thread.yield();
+ if (Thread.currentThread().isInterrupted()) {
+ throw new InterruptedException();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
new file mode 100644
index 0000000..d566f48
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/BlueprintContainerAware.java
@@ -0,0 +1,27 @@
+/*
+ * 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.console;
+
+import org.osgi.service.blueprint.container.BlueprintContainer;
+
+public interface BlueprintContainerAware {
+
+ void setBlueprintContainer(BlueprintContainer blueprintContainer);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
new file mode 100644
index 0000000..bbd03c5
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/BundleContextAware.java
@@ -0,0 +1,27 @@
+/*
+ * 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.console;
+
+import org.osgi.framework.BundleContext;
+
+public interface BundleContextAware {
+
+ void setBundleContext(BundleContext bundleContext);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/CloseShellException.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
new file mode 100644
index 0000000..81cee88
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CloseShellException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.console;
+
+/**
+ * Exception thrown to indicate the console to close.
+ */
+@SuppressWarnings("serial")
+public class CloseShellException extends Exception {
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
new file mode 100644
index 0000000..f07554f
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CommandSessionHolder.java
@@ -0,0 +1,38 @@
+/*
+ * 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.console;
+
+import org.apache.felix.service.command.CommandSession;
+
+public class CommandSessionHolder {
+
+ private static final ThreadLocal<CommandSession> session = new ThreadLocal<CommandSession>();
+
+ public static CommandSession getSession() {
+ return session.get();
+ }
+
+ public static void setSession(CommandSession commandSession) {
+ session.set(commandSession);
+ }
+
+ public static void unset() {
+ session.remove();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
new file mode 100644
index 0000000..fcb96da
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/CompletableFunction.java
@@ -0,0 +1,31 @@
+/*
+ * 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.console;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.service.command.Function;
+
+public interface CompletableFunction extends Function {
+
+ List<Completer> getCompleters();
+ Map<String, Completer> getOptionalCompleters();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/Completer.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/Completer.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/Completer.java
new file mode 100644
index 0000000..59f7897
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/Completer.java
@@ -0,0 +1,27 @@
+/*
+ * 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.console;
+
+import java.util.List;
+
+public interface Completer {
+
+ int complete(String buffer, int cursor, List<String> candidates);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/Console.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/Console.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/Console.java
new file mode 100644
index 0000000..fcca7ad
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/Console.java
@@ -0,0 +1,29 @@
+/*
+ * 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.console;
+
+import org.apache.felix.service.command.CommandSession;
+
+public interface Console extends Runnable {
+
+ CommandSession getSession();
+
+ void close(boolean closedByUser);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/ExitAction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/ExitAction.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/ExitAction.java
new file mode 100644
index 0000000..1449315
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/ExitAction.java
@@ -0,0 +1,46 @@
+/*
+ * 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.console;
+
+import org.apache.karaf.shell.commands.Command;
+
+/**
+ * Exit from the current sub-shell and get back to the previous one.
+ */
+@Command(scope = "*", name = "exit", description = "Exit from the current shell")
+public class ExitAction extends AbstractAction {
+
+ public Object doExecute() throws Exception {
+ // get the current sub-shell
+ String currentSubShell = (String) session.get("SUBSHELL");
+ if (!currentSubShell.isEmpty()) {
+ if (currentSubShell.contains(":")) {
+ int index = currentSubShell.lastIndexOf(":");
+ session.put("SUBSHELL", currentSubShell.substring(0, index));
+ } else {
+ session.put("SUBSHELL", "");
+ }
+ String currentScope = (String) session.get("SCOPE");
+ int index = currentScope.indexOf(":");
+ session.put("SCOPE", currentScope.substring(index + 1));
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/HelpProvider.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
new file mode 100644
index 0000000..7e3bca7
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/HelpProvider.java
@@ -0,0 +1,26 @@
+/**
+ *
+ * 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.console;
+
+import org.apache.felix.service.command.CommandSession;
+
+public interface HelpProvider {
+
+ String getHelp(CommandSession session, String path);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/MultiException.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/MultiException.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/MultiException.java
new file mode 100644
index 0000000..6e6185c
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/MultiException.java
@@ -0,0 +1,95 @@
+/*
+ * 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.console;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+@SuppressWarnings("serial")
+public class MultiException extends Exception {
+
+ private List<Exception> exceptions = new ArrayList<Exception>();
+
+ public MultiException(String message) {
+ super(message);
+ }
+
+ public MultiException(String message, List<Exception> exceptions) {
+ super(message);
+ this.exceptions = exceptions;
+ }
+
+ public void addException(Exception e) {
+ exceptions.add(e);
+ }
+
+ public void throwIfExceptions() throws MultiException {
+ if (!exceptions.isEmpty()) {
+ throw this;
+ }
+ }
+
+ public Throwable[] getCauses() {
+ return exceptions.toArray(new Throwable[exceptions.size()]);
+ }
+
+ @Override
+ public void printStackTrace()
+ {
+ super.printStackTrace();
+ for (Exception e : exceptions) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /* ------------------------------------------------------------------------------- */
+ /**
+ * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
+ */
+ @Override
+ public void printStackTrace(PrintStream out)
+ {
+ super.printStackTrace(out);
+ for (Exception e : exceptions) {
+ e.printStackTrace(out);
+ }
+ }
+
+ @Override
+ public void printStackTrace(PrintWriter out)
+ {
+ super.printStackTrace(out);
+ for (Exception e : exceptions) {
+ e.printStackTrace(out);
+ }
+ }
+
+ public static void throwIf(String message, List<Exception> exceptions) throws MultiException {
+ if (exceptions != null && !exceptions.isEmpty()) {
+ StringBuilder sb = new StringBuilder(message);
+ sb.append(":");
+ for (Exception e : exceptions) {
+ sb.append("\n\t");
+ sb.append(e.getMessage());
+ }
+ throw new MultiException(sb.toString(), exceptions);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/NameScoping.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/NameScoping.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/NameScoping.java
new file mode 100644
index 0000000..355464d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/NameScoping.java
@@ -0,0 +1,79 @@
+/**
+ *
+ * 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.console;
+
+import org.apache.felix.service.command.CommandSession;
+
+
+/**
+ * A helper class for name scoping
+ */
+public class NameScoping {
+
+ public static final String MULTI_SCOPE_MODE_KEY = "MULTI_SCOPE_MODE";
+
+ /**
+ * Returns the name of the command which can omit the global scope prefix if the command starts with the
+ * same prefix as the current application
+ */
+ public static String getCommandNameWithoutGlobalPrefix(CommandSession session, String key) {
+ if (!isMultiScopeMode(session)) {
+ String globalScope = (String) (session != null ? session.get("APPLICATION") : null);
+ if (globalScope != null) {
+ String prefix = globalScope + ":";
+ if (key.startsWith(prefix)) {
+ // TODO we may only want to do this for single-scope mode when outside of OSGi?
+ // so we may want to also check for a isMultiScope mode == false
+ return key.substring(prefix.length());
+ }
+ }
+ }
+ return key;
+ }
+
+ /**
+ * Returns true if the given scope is the global scope so that it can be hidden from help messages
+ */
+ public static boolean isGlobalScope(CommandSession session, String scope) {
+ if (session == null)
+ return false;
+
+ if (!isMultiScopeMode(session)) {
+ String globalScope = (String) session.get("APPLICATION");
+ if (globalScope != null) {
+ return scope.equals(globalScope);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if we are in multi-scope mode (the default) or if we are in single scope mode which means we
+ * avoid prefixing commands with their scope
+ */
+ public static boolean isMultiScopeMode(CommandSession session) {
+ if (session == null)
+ return false;
+
+ Object value = session.get(MULTI_SCOPE_MODE_KEY);
+ if (value != null && value.equals("false")) {
+ return false;
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
new file mode 100644
index 0000000..d737865
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/OsgiCommandSupport.java
@@ -0,0 +1,103 @@
+/*
+ * 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.console;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.Action;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+public abstract class OsgiCommandSupport extends AbstractAction implements Action, BundleContextAware {
+
+ protected BundleContext bundleContext;
+ protected List<ServiceReference<?>> usedReferences;
+
+ @Override
+ public Object execute(CommandSession session) throws Exception {
+ try {
+ return super.execute(session);
+ } finally {
+ ungetServices();
+ }
+ }
+
+ public BundleContext getBundleContext() {
+ Bundle framework = bundleContext.getBundle(0);
+ return framework == null? bundleContext: framework.getBundleContext();
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ protected <T> List<T> getAllServices(Class<T> clazz) {
+ try {
+ return getAllServices(clazz, null);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ protected <T> List<T> getAllServices(Class<T> clazz, String filter) throws InvalidSyntaxException {
+ Collection<ServiceReference<T>> references = getBundleContext().getServiceReferences(clazz, filter);
+ List<T> services = new ArrayList<T>();
+ if (references != null) {
+ for (ServiceReference<T> ref : references) {
+ T t = getService(clazz, ref);
+ services.add(t);
+ }
+ }
+ return services;
+ }
+
+ protected <T> T getService(Class<T> clazz) {
+ ServiceReference<T> sr = getBundleContext().getServiceReference(clazz);
+ if (sr != null) {
+ return getService(clazz, sr);
+ } else {
+ return null;
+ }
+ }
+
+ protected <T> T getService(Class<T> clazz, ServiceReference<T> reference) {
+ T t = getBundleContext().getService(reference);
+ if (t != null) {
+ if (usedReferences == null) {
+ usedReferences = new ArrayList<ServiceReference<?>>();
+ }
+ usedReferences.add(reference);
+ }
+ return t;
+ }
+
+ protected void ungetServices() {
+ if (usedReferences != null) {
+ for (ServiceReference<?> ref : usedReferences) {
+ getBundleContext().ungetService(ref);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/SessionProperties.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/SessionProperties.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SessionProperties.java
new file mode 100644
index 0000000..30f3433
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SessionProperties.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.console;
+
+public class SessionProperties {
+
+ public static final String PRINT_STACK_TRACES = "karaf.printStackTraces";
+ public static final String LAST_EXCEPTION = "karaf.lastException";
+ public static final String IGNORE_INTERRUPTS = "karaf.ignoreInterrupts";
+ public static final String COMPLETION_MODE = "karaf.completionMode";
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShell.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShell.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShell.java
new file mode 100644
index 0000000..2de0d20
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShell.java
@@ -0,0 +1,38 @@
+/*
+ * 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.console;
+
+public interface SubShell {
+
+ /**
+ * Returns the name of the command if used inside a shell
+ */
+ String getName();
+
+ /**
+ * Returns the description of the command which is used to generate command line help
+ */
+ String getDescription();
+
+ /**
+ * Returns a detailed description of the command
+ */
+ String getDetailedDescription();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShellAction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShellAction.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShellAction.java
new file mode 100644
index 0000000..8774927
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/SubShellAction.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.console;
+
+
+
+/**
+ * Switch to a sub-shell.
+ */
+public class SubShellAction extends AbstractAction {
+
+ private String subShell;
+
+ public Object doExecute() throws Exception {
+ session.put("SUBSHELL", subShell);
+ session.put("SCOPE", subShell + ":" + session.get("SCOPE"));
+ return null;
+ }
+
+ public void setSubShell(String subShell) {
+ this.subShell = subShell;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.java
new file mode 100644
index 0000000..9cd3dda
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/commands/AnnotatedSubShell.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.
+ */
+package org.apache.karaf.shell.console.commands;
+
+import org.apache.karaf.shell.console.SubShell;
+
+public class AnnotatedSubShell implements SubShell {
+
+ public String getName() {
+ return getAnnotation().name();
+ }
+
+ public String getDescription() {
+ return getAnnotation().description();
+ }
+
+ public String getDetailedDescription() {
+ return getAnnotation().detailedDescription();
+ }
+
+ org.apache.felix.gogo.commands.SubShell getAnnotation() {
+ org.apache.felix.gogo.commands.SubShell ann = getClass().getAnnotation(org.apache.felix.gogo.commands.SubShell.class);
+ if (ann == null) {
+ throw new IllegalStateException("The class should be annotated with the org.apache.felix.gogo.commands.SubShell annotation");
+ }
+ return ann;
+ }
+}
[10/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
new file mode 100644
index 0000000..e7a4424
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/DefaultConverter.java
@@ -0,0 +1,402 @@
+/*
+ * 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.commands.converter;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Dictionary;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.LinkedHashMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.Set;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Queue;
+import java.util.LinkedList;
+import java.util.regex.Pattern;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.math.BigInteger;
+import java.math.BigDecimal;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.lang.reflect.InvocationTargetException;
+
+@Deprecated
+public class DefaultConverter {
+
+ private Object loader;
+
+ public DefaultConverter(Object loader) {
+ this.loader = loader;
+ }
+
+ public Object convert(Object source, Type target) throws Exception {
+ return convert(source, new GenericType(target));
+ }
+
+ public Object convert(Object fromValue, ReifiedType type) throws Exception {
+ // Discard null values
+ if (fromValue == null) {
+ return null;
+ }
+ // If the object is an instance of the type, just return it
+ if (isAssignable(fromValue, type)) {
+ return fromValue;
+ }
+ Object value = convertWithConverters(fromValue, type);
+ if (value == null) {
+ if (fromValue instanceof Number && Number.class.isAssignableFrom(unwrap(toClass(type)))) {
+ return convertToNumber((Number) fromValue, toClass(type));
+ } else if (fromValue instanceof String) {
+ return convertFromString((String) fromValue, toClass(type), loader);
+ } else if (toClass(type).isArray() && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+ return convertToArray(fromValue, type);
+ } else if (Map.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+ return convertToMap(fromValue, type);
+ } else if (Dictionary.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Map || fromValue instanceof Dictionary)) {
+ return convertToDictionary(fromValue, type);
+ } else if (Collection.class.isAssignableFrom(toClass(type)) && (fromValue instanceof Collection || fromValue.getClass().isArray())) {
+ return convertToCollection(fromValue, type);
+ } else {
+ throw new Exception("Unable to convert value " + fromValue + " to type " + type);
+ }
+ }
+ return value;
+ }
+
+ private Object convertWithConverters(Object source, ReifiedType type) throws Exception {
+ Object value = null;
+// for (Converter converter : converters) {
+// if (converter.canConvert(source, type)) {
+// value = converter.convert(source, type);
+// if (value != null) {
+// return value;
+// }
+// }
+// }
+ return value;
+ }
+
+ public Object convertToNumber(Number value, Class toType) throws Exception {
+ toType = unwrap(toType);
+ if (AtomicInteger.class == toType) {
+ return new AtomicInteger((Integer) convertToNumber(value, Integer.class));
+ } else if (AtomicLong.class == toType) {
+ return new AtomicLong((Long) convertToNumber(value, Long.class));
+ } else if (Integer.class == toType) {
+ return value.intValue();
+ } else if (Short.class == toType) {
+ return value.shortValue();
+ } else if (Long.class == toType) {
+ return value.longValue();
+ } else if (Float.class == toType) {
+ return value.floatValue();
+ } else if (Double.class == toType) {
+ return value.doubleValue();
+ } else if (Byte.class == toType) {
+ return value.byteValue();
+ } else if (BigInteger.class == toType) {
+ return new BigInteger(value.toString());
+ } else if (BigDecimal.class == toType) {
+ return new BigDecimal(value.toString());
+ } else {
+ throw new Exception("Unable to convert number " + value + " to " + toType);
+ }
+ }
+
+ public Object convertFromString(String value, Class toType, Object loader) throws Exception {
+ toType = unwrap(toType);
+ if (ReifiedType.class == toType) {
+ try {
+ return GenericType.parse(value, loader);
+ } catch (ClassNotFoundException e) {
+ throw new Exception("Unable to convert", e);
+ }
+ } else if (Class.class == toType) {
+ try {
+ return GenericType.parse(value, loader).getRawClass();
+ } catch (ClassNotFoundException e) {
+ throw new Exception("Unable to convert", e);
+ }
+ } else if (Locale.class == toType) {
+ String[] tokens = value.split("_");
+ if (tokens.length == 1) {
+ return new Locale(tokens[0]);
+ } else if (tokens.length == 2) {
+ return new Locale(tokens[0], tokens[1]);
+ } else if (tokens.length == 3) {
+ return new Locale(tokens[0], tokens[1], tokens[2]);
+ } else {
+ throw new Exception("Invalid locale string:" + value);
+ }
+ } else if (Pattern.class == toType) {
+ return Pattern.compile(value);
+ } else if (Properties.class == toType) {
+ Properties props = new Properties();
+ ByteArrayInputStream in = new ByteArrayInputStream(value.getBytes("UTF8"));
+ props.load(in);
+ return props;
+ } else if (Boolean.class == toType) {
+ if ("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value)) {
+ return Boolean.TRUE;
+ } else if ("no".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value) || "off".equalsIgnoreCase(value)) {
+ return Boolean.FALSE;
+ } else {
+ throw new RuntimeException("Invalid boolean value: " + value);
+ }
+ } else if (Integer.class == toType) {
+ return Integer.valueOf(value);
+ } else if (Short.class == toType) {
+ return Short.valueOf(value);
+ } else if (Long.class == toType) {
+ return Long.valueOf(value);
+ } else if (Float.class == toType) {
+ return Float.valueOf(value);
+ } else if (Double.class == toType) {
+ return Double.valueOf(value);
+ } else if (Character.class == toType) {
+ if (value.length() == 6 && value.startsWith("\\u")) {
+ int code = Integer.parseInt(value.substring(2), 16);
+ return (char) code;
+ } else if (value.length() == 1) {
+ return value.charAt(0);
+ } else {
+ throw new Exception("Invalid value for character type: " + value);
+ }
+ } else if (Byte.class == toType) {
+ return Byte.valueOf(value);
+ } else if (Enum.class.isAssignableFrom(toType)) {
+ return Enum.valueOf((Class<Enum>) toType, value);
+ } else {
+ return createObject(value, toType);
+ }
+ }
+
+ private static Object createObject(String value, Class type) throws Exception {
+ if (type.isInterface() || Modifier.isAbstract(type.getModifiers())) {
+ throw new Exception("Unable to convert value " + value + " to type " + type + ". Type " + type + " is an interface or an abstract class");
+ }
+ Constructor constructor = null;
+ try {
+ constructor = type.getConstructor(String.class);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Unable to convert to " + type);
+ }
+ try {
+ return constructor.newInstance(value);
+ } catch (Exception e) {
+ throw new Exception("Unable to convert ", getRealCause(e));
+ }
+ }
+
+ private static Throwable getRealCause(Throwable t) {
+ if (t instanceof InvocationTargetException && t.getCause() != null) {
+ return t.getCause();
+ }
+ return t;
+ }
+
+ private Object convertToCollection(Object obj, ReifiedType type) throws Exception {
+ ReifiedType valueType = type.getActualTypeArgument(0);
+ Collection newCol = (Collection) getCollection(toClass(type)).newInstance();
+ if (obj.getClass().isArray()) {
+ for (int i = 0; i < Array.getLength(obj); i++) {
+ try {
+ newCol.add(convert(Array.get(obj, i), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+ }
+ }
+ } else {
+ for (Object item : (Collection) obj) {
+ try {
+ newCol.add(convert(item, valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting collection entry)", t);
+ }
+ }
+ }
+ return newCol;
+ }
+
+ private Object convertToDictionary(Object obj, ReifiedType type) throws Exception {
+ ReifiedType keyType = type.getActualTypeArgument(0);
+ ReifiedType valueType = type.getActualTypeArgument(1);
+ Dictionary newDic = new Hashtable();
+ if (obj instanceof Dictionary) {
+ Dictionary dic = (Dictionary) obj;
+ for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements(); ) {
+ Object key = keyEnum.nextElement();
+ try {
+ newDic.put(convert(key, keyType), convert(dic.get(key), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ } else {
+ for (Map.Entry e : ((Map<Object, Object>) obj).entrySet()) {
+ try {
+ newDic.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ }
+ return newDic;
+ }
+
+ private Object convertToMap(Object obj, ReifiedType type) throws Exception {
+ ReifiedType keyType = type.getActualTypeArgument(0);
+ ReifiedType valueType = type.getActualTypeArgument(1);
+ Map newMap = (Map) getMap(toClass(type)).newInstance();
+ if (obj instanceof Dictionary) {
+ Dictionary dic = (Dictionary) obj;
+ for (Enumeration keyEnum = dic.keys(); keyEnum.hasMoreElements(); ) {
+ Object key = keyEnum.nextElement();
+ try {
+ newMap.put(convert(key, keyType), convert(dic.get(key), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ } else {
+ for (Map.Entry e : ((Map<Object, Object>) obj).entrySet()) {
+ try {
+ newMap.put(convert(e.getKey(), keyType), convert(e.getValue(), valueType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting map entry)", t);
+ }
+ }
+ }
+ return newMap;
+ }
+
+ private Object convertToArray(Object obj, ReifiedType type) throws Exception {
+ if (obj instanceof Collection) {
+ obj = ((Collection) obj).toArray();
+ }
+ if (!obj.getClass().isArray()) {
+ throw new Exception("Unable to convert from " + obj + " to " + type);
+ }
+ ReifiedType componentType;
+ if (type.size() > 0) {
+ componentType = type.getActualTypeArgument(0);
+ } else {
+ componentType = new GenericType(type.getRawClass().getComponentType());
+ }
+ Object array = Array.newInstance(toClass(componentType), Array.getLength(obj));
+ for (int i = 0; i < Array.getLength(obj); i++) {
+ try {
+ Array.set(array, i, convert(Array.get(obj, i), componentType));
+ } catch (Exception t) {
+ throw new Exception("Unable to convert from " + obj + " to " + type + "(error converting array element)", t);
+ }
+ }
+ return array;
+ }
+
+ public static boolean isAssignable(Object source, ReifiedType target) {
+ return source == null
+ || (target.size() == 0
+ && unwrap(target.getRawClass()).isAssignableFrom(unwrap(source.getClass())));
+ }
+
+ private static Class unwrap(Class c) {
+ Class u = primitives.get(c);
+ return u != null ? u : c;
+ }
+
+ private static Class getMap(Class type) {
+ if (hasDefaultConstructor(type)) {
+ return type;
+ } else if (SortedMap.class.isAssignableFrom(type)) {
+ return TreeMap.class;
+ } else if (ConcurrentMap.class.isAssignableFrom(type)) {
+ return ConcurrentHashMap.class;
+ } else {
+ return LinkedHashMap.class;
+ }
+ }
+
+ private static Class getCollection(Class type) {
+ if (hasDefaultConstructor(type)) {
+ return type;
+ } else if (SortedSet.class.isAssignableFrom(type)) {
+ return TreeSet.class;
+ } else if (Set.class.isAssignableFrom(type)) {
+ return LinkedHashSet.class;
+ } else if (List.class.isAssignableFrom(type)) {
+ return ArrayList.class;
+ } else if (Queue.class.isAssignableFrom(type)) {
+ return LinkedList.class;
+ } else {
+ return ArrayList.class;
+ }
+ }
+
+ private static boolean hasDefaultConstructor(Class type) {
+ if (!Modifier.isPublic(type.getModifiers())) {
+ return false;
+ }
+ if (Modifier.isAbstract(type.getModifiers())) {
+ return false;
+ }
+ Constructor[] constructors = type.getConstructors();
+ for (Constructor constructor : constructors) {
+ if (Modifier.isPublic(constructor.getModifiers()) &&
+ constructor.getParameterTypes().length == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final Map<Class, Class> primitives;
+
+ static {
+ primitives = new HashMap<Class, Class>();
+ primitives.put(byte.class, Byte.class);
+ primitives.put(short.class, Short.class);
+ primitives.put(char.class, Character.class);
+ primitives.put(int.class, Integer.class);
+ primitives.put(long.class, Long.class);
+ primitives.put(float.class, Float.class);
+ primitives.put(double.class, Double.class);
+ primitives.put(boolean.class, Boolean.class);
+ }
+
+ private Class toClass(ReifiedType type) {
+ return type.getRawClass();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
new file mode 100644
index 0000000..dae6651
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/GenericType.java
@@ -0,0 +1,196 @@
+/*
+ * 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.commands.converter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+@Deprecated
+public class GenericType extends ReifiedType {
+
+ private static final GenericType[] EMPTY = new GenericType[0];
+
+ private static final Map<String, Class> primitiveClasses = new HashMap<String, Class>();
+
+ static {
+ primitiveClasses.put("int", int.class);
+ primitiveClasses.put("short", short.class);
+ primitiveClasses.put("long", long.class);
+ primitiveClasses.put("byte", byte.class);
+ primitiveClasses.put("char", char.class);
+ primitiveClasses.put("float", float.class);
+ primitiveClasses.put("double", double.class);
+ primitiveClasses.put("boolean", boolean.class);
+ }
+
+ private GenericType[] parameters;
+
+ public GenericType(Type type) {
+ this(getConcreteClass(type), parametersOf(type));
+ }
+
+ public GenericType(Class clazz, GenericType... parameters) {
+ super(clazz);
+ this.parameters = parameters;
+ }
+
+ public static GenericType parse(String type, Object loader) throws ClassNotFoundException, IllegalArgumentException {
+ type = type.trim();
+ // Check if this is an array
+ if (type.endsWith("[]")) {
+ GenericType t = parse(type.substring(0, type.length() - 2), loader);
+ return new GenericType(Array.newInstance(t.getRawClass(), 0).getClass(), t);
+ }
+ // Check if this is a generic
+ int genericIndex = type.indexOf('<');
+ if (genericIndex > 0) {
+ if (!type.endsWith(">")) {
+ throw new IllegalArgumentException("Can not load type: " + type);
+ }
+ GenericType base = parse(type.substring(0, genericIndex), loader);
+ String[] params = type.substring(genericIndex + 1, type.length() - 1).split(",");
+ GenericType[] types = new GenericType[params.length];
+ for (int i = 0; i < params.length; i++) {
+ types[i] = parse(params[i], loader);
+ }
+ return new GenericType(base.getRawClass(), types);
+ }
+ // Primitive
+ if (primitiveClasses.containsKey(type)) {
+ return new GenericType(primitiveClasses.get(type));
+ }
+ // Class
+ if (loader instanceof ClassLoader) {
+ return new GenericType(((ClassLoader) loader).loadClass(type));
+ } else if (loader instanceof Bundle) {
+ return new GenericType(((Bundle) loader).loadClass(type));
+ } else {
+ throw new IllegalArgumentException("Unsupported loader: " + loader);
+ }
+ }
+
+ @Override
+ public ReifiedType getActualTypeArgument(int i) {
+ if (parameters.length == 0) {
+ return super.getActualTypeArgument(i);
+ }
+ return parameters[i];
+ }
+
+ @Override
+ public int size() {
+ return parameters.length;
+ }
+
+ @Override
+ public String toString() {
+ Class cl = getRawClass();
+ if (cl.isArray()) {
+ if (parameters.length > 0) {
+ return parameters[0].toString() + "[]";
+ } else {
+ return cl.getComponentType().getName() + "[]";
+ }
+ }
+ if (parameters.length > 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cl.getName());
+ sb.append("<");
+ for (int i = 0; i < parameters.length; i++) {
+ if (i > 0) {
+ sb.append(",");
+ }
+ sb.append(parameters[i].toString());
+ }
+ sb.append(">");
+ return sb.toString();
+ }
+ return cl.getName();
+ }
+
+ static GenericType[] parametersOf(Type type ) {
+ if ( type instanceof Class ) {
+ Class clazz = (Class) type;
+ if (clazz.isArray()) {
+ GenericType t = new GenericType(clazz.getComponentType());
+ if (t.size() > 0) {
+ return new GenericType[] { t };
+ } else {
+ return EMPTY;
+ }
+ } else {
+ return EMPTY;
+ }
+ }
+ if ( type instanceof ParameterizedType ) {
+ ParameterizedType pt = (ParameterizedType) type;
+ Type [] parameters = pt.getActualTypeArguments();
+ GenericType[] gts = new GenericType[parameters.length];
+ for ( int i =0; i<gts.length; i++) {
+ gts[i] = new GenericType(parameters[i]);
+ }
+ return gts;
+ }
+ if ( type instanceof GenericArrayType ) {
+ return new GenericType[] { new GenericType(((GenericArrayType) type).getGenericComponentType()) };
+ }
+ throw new IllegalStateException();
+ }
+
+ static Class<?> getConcreteClass(Type type) {
+ Type ntype = collapse(type);
+ if ( ntype instanceof Class )
+ return (Class<?>) ntype;
+
+ if ( ntype instanceof ParameterizedType )
+ return getConcreteClass(collapse(((ParameterizedType)ntype).getRawType()));
+
+ throw new RuntimeException("Unknown type " + type );
+ }
+
+ static Type collapse(Type target) {
+ if (target instanceof Class || target instanceof ParameterizedType ) {
+ return target;
+ } else if (target instanceof TypeVariable) {
+ return collapse(((TypeVariable<?>) target).getBounds()[0]);
+ } else if (target instanceof GenericArrayType) {
+ Type t = collapse(((GenericArrayType) target)
+ .getGenericComponentType());
+ while ( t instanceof ParameterizedType )
+ t = collapse(((ParameterizedType)t).getRawType());
+ return Array.newInstance((Class<?>)t, 0).getClass();
+ } else if (target instanceof WildcardType) {
+ WildcardType wct = (WildcardType) target;
+ if (wct.getLowerBounds().length == 0)
+ return collapse(wct.getUpperBounds()[0]);
+ else
+ return collapse(wct.getLowerBounds()[0]);
+ }
+ throw new RuntimeException("Huh? " + target);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
new file mode 100644
index 0000000..bc835d9
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/felix/gogo/commands/converter/ReifiedType.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) OSGi Alliance (2008, 2009). All Rights Reserved.
+ *
+ * Licensed 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.commands.converter;
+
+/**
+ * Provides access to a concrete type and its optional generic type arguments.
+ *
+ * Java 5 and later support generic types. These types consist of a raw class
+ * with type arguments. This class models such a <code>Type</code> class but
+ * ensures that the type is <em>reified</em>. Reification means that the Type
+ * graph associated with a Java 5 <code>Type</code> instance is traversed
+ * until the type becomes a concrete class. In Java 1.4 a class has no
+ * arguments. This concrete class implements the Reified Type for Java 1.4.
+ *
+ * In Java 1.4, this class works with non-generic types. In that cases, a
+ * Reified Type provides access to the class and has zero type arguments, though
+ * a subclass that provide type arguments should be respected. Blueprint
+ * extender implementations can subclass this class and provide access to the
+ * generics type graph if used in a conversion. Such a subclass must
+ * <em>reify<em> the different Java 5 <code>Type</code> instances into the
+ * reified form. That is, a form where the raw Class is available with its optional type arguments as Reified Types.
+ *
+ * @Immutable
+ */
+@Deprecated
+public class ReifiedType {
+
+ final static ReifiedType ALL = new ReifiedType(Object.class);
+
+ private final Class clazz;
+
+ /**
+ * Create a Reified Type for a raw Java class without any generic arguments.
+ * Subclasses can provide the optional generic argument information. Without
+ * subclassing, this instance has no type arguments.
+ *
+ * @param clazz
+ * The raw class of the Reified Type.
+ */
+ public ReifiedType(Class clazz) {
+ this.clazz = clazz;
+ }
+
+ /**
+ * Access to the raw class.
+ *
+ * The raw class represents the concrete class that is associated with a
+ * type declaration. This class could have been deduced from the generics
+ * type graph of the declaration. For example, in the following example:
+ *
+ * <pre>
+ * Map<String, Object> map;
+ * </pre>
+ *
+ * The raw class is the Map class.
+ *
+ * @return the collapsed raw class that represents this type.
+ */
+ public Class getRawClass() {
+ return clazz;
+ }
+
+ /**
+ * Access to a type argument.
+ *
+ * The type argument refers to a argument in a generic type declaration
+ * given by index <code>i</code>. This method returns a Reified Type that
+ * has Object as class when no generic type information is available. Any
+ * object is assignable to Object and therefore no conversion is then
+ * necessary, this is compatible with older Javas than 5. For this reason,
+ * the implementation in this class always returns the
+ * <code>Object<code> class, regardless of the given index.
+ *
+ * This method should be overridden by a subclass that provides access to
+ * the generic information.
+ *
+ * For example, in the following example:
+ *
+ * <pre>
+ * Map<String, Object> map;
+ * </pre>
+ *
+ * The type argument 0 is <code>String</code>, and type argument 1 is
+ * <code>Object</code>.
+ *
+ * @param i
+ * The index of the type argument
+ * @return <code>ReifiedType(Object.class)<code>, subclasses must override this and return the generic argument at index <code>i</code>
+ */
+ public ReifiedType getActualTypeArgument(int i) {
+ return ALL;
+ }
+
+ /**
+ * Return the number of type arguments.
+ *
+ * This method should be overridden by a subclass to support Java 5 types.
+ *
+ * @return 0, subclasses must override this and return the number of generic
+ * arguments
+ */
+ public int size() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Action.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Action.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Action.java
new file mode 100644
index 0000000..c3421e3
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Action.java
@@ -0,0 +1,40 @@
+/*
+ * 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.commands;
+
+import org.apache.felix.service.command.CommandSession;
+
+/**
+ * An action allows to easily execute commands in karaf.
+ * It can be assumed that each action is only accessed by a single thread at a time.
+ *
+ * An Action is always part of an AbstractCommand. The AbstractCommand makes sure
+ * the single threaded assumption above is true. Before the call to the execute method
+ * the action is checked for annotated fields (@Argument, @Option). These fields
+ * are populated from the command arguments before the action is called.
+ *
+ * Any class implementing Action must have a no argument constructor. This
+ * is necessary so the help generator can instantiate the class and get the
+ * default values.
+ */
+public interface Action extends org.apache.felix.gogo.commands.Action {
+
+ Object execute(CommandSession session) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Argument.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Argument.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Argument.java
new file mode 100644
index 0000000..eced53d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Argument.java
@@ -0,0 +1,48 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Represents a positional argument on a command line (as opposed to an optional named {@link Option}
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Argument
+{
+ public static final String DEFAULT_STRING= "DEFAULT";
+
+ String DEFAULT = "##default";
+
+ String name() default DEFAULT;
+
+ String description() default "";
+
+ boolean required() default false;
+
+ int index() default 0;
+
+ boolean multiValued() default false;
+
+ String valueToShowInHelp() default DEFAULT_STRING;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Command.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Command.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Command.java
new file mode 100644
index 0000000..490785d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Command.java
@@ -0,0 +1,53 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+
+/**
+ * Used to denote a class represents a command which is executable within a shell/scope or as a
+ * command line process.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Command
+{
+ /**
+ * Returns the scope or sub shell of the command
+ */
+ String scope();
+
+ /**
+ * REturns the name of the command if used inside a shell
+ */
+ String name();
+
+ /**
+ * Returns the description of the command which is used to generate command line help
+ */
+ String description() default "";
+
+ /**
+ * Returns a detailed description of the command
+ */
+ String detailedDescription() default "";
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandException.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandException.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandException.java
new file mode 100644
index 0000000..1ffa25d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandException.java
@@ -0,0 +1,64 @@
+/*
+ * 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.commands;
+
+import org.apache.karaf.shell.commands.ansi.SimpleAnsi;
+
+
+/**
+ * Base class for exceptions thrown when executing commands.
+ */
+@SuppressWarnings("serial")
+public class CommandException extends Exception {
+
+ private String help;
+
+ public CommandException() {
+ }
+
+ public CommandException(String message) {
+ super(message);
+ }
+
+ public CommandException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public CommandException(Throwable cause) {
+ super(cause);
+ }
+
+ public CommandException(String help, String message) {
+ super(message);
+ this.help = help;
+ }
+
+ public CommandException(String help, String message, Throwable cause) {
+ super(message, cause);
+ this.help = help;
+ }
+
+ public String getNiceHelp() {
+ return help != null ? help
+ : SimpleAnsi.COLOR_RED + "Error executing command: "
+ + getMessage() != null ? getMessage() : getClass().getName()
+ + SimpleAnsi.COLOR_DEFAULT;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
new file mode 100644
index 0000000..9209eb1
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CommandWithAction.java
@@ -0,0 +1,31 @@
+/*
+ * 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.commands;
+
+import org.apache.felix.service.command.Function;
+
+public interface CommandWithAction extends Function {
+
+ Class<? extends org.apache.felix.gogo.commands.Action> getActionClass();
+
+ org.apache.felix.gogo.commands.Action createNewAction();
+
+ void releaseAction(org.apache.felix.gogo.commands.Action action) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Completer.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Completer.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Completer.java
new file mode 100644
index 0000000..ece3e1d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Completer.java
@@ -0,0 +1,34 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Completer {
+
+ Class<? extends org.apache.karaf.shell.console.Completer> value();
+
+ String[] values() default { };
+
+ boolean caseSensitive() default false;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
new file mode 100644
index 0000000..4463d35
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/CompleterValues.java
@@ -0,0 +1,37 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Represents a method which can return a List or Array of values used for a
+ * {@link org.apache.karaf.shell.console.Completer}
+ * which is associated with the index of an
+ * {@link Argument}
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.FIELD})
+public @interface CompleterValues
+{
+ int index() default 0;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/HelpOption.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
new file mode 100644
index 0000000..b5a0fa5
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/HelpOption.java
@@ -0,0 +1,54 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.Annotation;
+
+public class HelpOption {
+
+ public static final Option HELP = new Option() {
+ public String name() {
+ return "--help";
+ }
+
+ public String[] aliases() {
+ return new String[]{};
+ }
+
+ public String description() {
+ return "Display this help message";
+ }
+
+ public boolean required() {
+ return false;
+ }
+
+ public boolean multiValued() {
+ return false;
+ }
+
+ public String valueToShowInHelp() {
+ return Option.DEFAULT_STRING;
+ }
+
+ public Class<? extends Annotation> annotationType() {
+ return Option.class;
+ }
+ };
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
new file mode 100644
index 0000000..e253af1
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
@@ -0,0 +1,30 @@
+/*
+ * 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.commands;
+
+import java.util.Properties;
+
+/**
+ * A bundle can publish a service with this interface to offer some informations for the shell:info command
+ */
+public interface InfoProvider {
+
+ public String getName();
+
+ public Properties getProperties();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Option.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Option.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Option.java
new file mode 100644
index 0000000..b0a9e9c
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/Option.java
@@ -0,0 +1,46 @@
+/*
+ * 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.commands;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Used to mark an optional named command line option who's name typically starts with "--"
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Option
+{
+ public static final String DEFAULT_STRING= "DEFAULT";
+
+ String name();
+
+ String[] aliases() default {};
+
+ String description() default "";
+
+ boolean required() default false;
+
+ boolean multiValued() default false;
+
+ String valueToShowInHelp() default DEFAULT_STRING;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.java
new file mode 100644
index 0000000..1ada311
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/ansi/SimpleAnsi.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.commands.ansi;
+
+
+public class SimpleAnsi {
+ public static String COLOR_RED = "\u001B[31m";
+ public static String COLOR_DEFAULT = "\u001B[39m";
+
+ public static String INTENSITY_BOLD = "\u001B[1m";
+ public static String INTENSITY_NORMAL = "\u001B[0m";
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
new file mode 100644
index 0000000..41d4a51
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/AbstractCommand.java
@@ -0,0 +1,62 @@
+/*
+ * 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.commands.basic;
+
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.CommandWithAction;
+
+public abstract class AbstractCommand implements CommandWithAction {
+
+ public Object execute(CommandSession session, List<Object> arguments) throws Exception {
+ Action action = createNewAction();
+ try {
+ if (getPreparator().prepare(action, session, arguments)) {
+ return action.execute(session);
+ } else {
+ return null;
+ }
+ } finally {
+ releaseAction(action);
+ }
+ }
+
+ public Class<? extends Action> getActionClass() {
+ return createNewAction().getClass();
+ }
+
+ public abstract Action createNewAction();
+
+ /**
+ * Release the used Action.
+ * This method has to be overridden for pool based Actions.
+ * @param action Action that was executed
+ * @throws Exception if something went wrong during the Action release
+ */
+ public void releaseAction(Action action) throws Exception {
+ // Do nothing by default (stateful)
+ }
+
+ protected ActionPreparator getPreparator() throws Exception {
+ return new DefaultActionPreparator();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
new file mode 100644
index 0000000..a6d2f8f
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/ActionPreparator.java
@@ -0,0 +1,42 @@
+/*
+ * 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.commands.basic;
+
+import java.util.List;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+
+public interface ActionPreparator {
+
+ /**
+ * Check if the arguments are valid for the action and inject the arguments into the fields
+ * of the action
+ *
+ * Using deprecated Action for compatiblity
+ *
+ * @param action
+ * @param session
+ * @param arguments
+ * @return
+ * @throws Exception
+ */
+ boolean prepare(@SuppressWarnings("deprecation") Action action, CommandSession session, List<Object> arguments) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
new file mode 100644
index 0000000..3ad8d29
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/DefaultActionPreparator.java
@@ -0,0 +1,223 @@
+/*
+ * 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.commands.basic;
+
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.commands.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.CommandException;
+import org.apache.karaf.shell.commands.HelpOption;
+import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.commands.converter.DefaultConverter;
+import org.apache.karaf.shell.commands.converter.GenericType;
+import org.apache.karaf.shell.commands.meta.ActionMetaData;
+import org.apache.karaf.shell.commands.meta.ActionMetaDataFactory;
+import org.apache.karaf.shell.console.NameScoping;
+
+public class DefaultActionPreparator implements ActionPreparator {
+
+ public boolean prepare(Action action, CommandSession session, List<Object> params) throws Exception {
+ ActionMetaData actionMetaData = new ActionMetaDataFactory().create(action.getClass());
+ Map<Option, Field> options = actionMetaData.getOptions();
+ Map<Argument, Field> arguments = actionMetaData.getArguments();
+ List<Argument> orderedArguments = actionMetaData.getOrderedArguments();
+ Command command2 = actionMetaData.getCommand();
+
+ if (command2 == null) {
+ // to avoid NPE with subshell
+ return true;
+ }
+
+ String commandErrorSt = (command2 != null) ? COLOR_RED
+ + "Error executing command " + command2.scope() + ":"
+ + INTENSITY_BOLD + command2.name() + INTENSITY_NORMAL
+ + COLOR_DEFAULT + ": " : "";
+ for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
+ Object param = it.next();
+ if (HelpOption.HELP.name().equals(param)) {
+ int termWidth = getWidth(session);
+ boolean globalScope = NameScoping.isGlobalScope(session, actionMetaData.getCommand().scope());
+ actionMetaData.printUsage(action, System.out, globalScope, termWidth);
+ return false;
+ }
+ }
+
+ // Populate
+ Map<Option, Object> optionValues = new HashMap<Option, Object>();
+ Map<Argument, Object> argumentValues = new HashMap<Argument, Object>();
+ boolean processOptions = true;
+ int argIndex = 0;
+ for (Iterator<Object> it = params.iterator(); it.hasNext(); ) {
+ Object param = it.next();
+
+ if (processOptions && param instanceof String && ((String) param).startsWith("-")) {
+ boolean isKeyValuePair = ((String) param).indexOf('=') != -1;
+ String name;
+ Object value = null;
+ if (isKeyValuePair) {
+ name = ((String) param).substring(0, ((String) param).indexOf('='));
+ value = ((String) param).substring(((String) param).indexOf('=') + 1);
+ } else {
+ name = (String) param;
+ }
+ Option option = null;
+ for (Option opt : options.keySet()) {
+ if (name.equals(opt.name()) || Arrays.asList(opt.aliases()).contains(name)) {
+ option = opt;
+ break;
+ }
+ }
+ if (option == null) {
+ throw new CommandException(commandErrorSt
+ + "undefined option " + INTENSITY_BOLD + param + INTENSITY_NORMAL + "\n"
+ + "Try <command> --help' for more information.",
+ "Undefined option: " + param);
+ }
+ Field field = options.get(option);
+ if (value == null && (field.getType() == boolean.class || field.getType() == Boolean.class)) {
+ value = Boolean.TRUE;
+ }
+ if (value == null && it.hasNext()) {
+ value = it.next();
+ }
+ if (value == null) {
+ throw new CommandException(commandErrorSt
+ + "missing value for option " + INTENSITY_BOLD + param + INTENSITY_NORMAL,
+ "Missing value for option: " + param
+ );
+ }
+ if (option.multiValued()) {
+ @SuppressWarnings("unchecked")
+ List<Object> l = (List<Object>) optionValues.get(option);
+ if (l == null) {
+ l = new ArrayList<Object>();
+ optionValues.put(option, l);
+ }
+ l.add(value);
+ } else {
+ optionValues.put(option, value);
+ }
+ } else {
+ processOptions = false;
+ if (argIndex >= orderedArguments.size()) {
+ throw new CommandException(commandErrorSt +
+ "too many arguments specified",
+ "Too many arguments specified"
+ );
+ }
+ Argument argument = orderedArguments.get(argIndex);
+ if (!argument.multiValued()) {
+ argIndex++;
+ }
+ if (argument.multiValued()) {
+ @SuppressWarnings("unchecked")
+ List<Object> l = (List<Object>) argumentValues.get(argument);
+ if (l == null) {
+ l = new ArrayList<Object>();
+ argumentValues.put(argument, l);
+ }
+ l.add(param);
+ } else {
+ argumentValues.put(argument, param);
+ }
+ }
+ }
+ // Check required arguments / options
+ for (Option option : options.keySet()) {
+ if (option.required() && optionValues.get(option) == null) {
+ throw new CommandException(commandErrorSt +
+ "option " + INTENSITY_BOLD + option.name() + INTENSITY_NORMAL + " is required",
+ "Option " + option.name() + " is required"
+ );
+ }
+ }
+ for (Argument argument : orderedArguments) {
+ if (argument.required() && argumentValues.get(argument) == null) {
+ throw new CommandException(commandErrorSt +
+ "argument " + INTENSITY_BOLD + argument.name() + INTENSITY_NORMAL + " is required",
+ "Argument " + argument.name() + " is required"
+ );
+ }
+ }
+
+ // Convert and inject values
+ for (Map.Entry<Option, Object> entry : optionValues.entrySet()) {
+ Field field = options.get(entry.getKey());
+ Object value;
+ try {
+ value = convert(action, session, entry.getValue(), field.getGenericType());
+ } catch (Exception e) {
+ throw new CommandException(commandErrorSt +
+ "unable to convert option " + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ "Unable to convert option " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e
+ );
+ }
+ field.setAccessible(true);
+ field.set(action, value);
+ }
+ for (Map.Entry<Argument, Object> entry : argumentValues.entrySet()) {
+ Field field = arguments.get(entry.getKey());
+ Object value;
+ try {
+ value = convert(action, session, entry.getValue(), field.getGenericType());
+ } catch (Exception e) {
+ throw new CommandException(commandErrorSt +
+ "unable to convert argument " + INTENSITY_BOLD + entry.getKey().name() + INTENSITY_NORMAL + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ "Unable to convert argument " + entry.getKey().name() + " with value '"
+ + entry.getValue() + "' to type " + new GenericType(field.getGenericType()).toString(),
+ e
+ );
+ }
+ field.setAccessible(true);
+ field.set(action, value);
+ }
+ return true;
+ }
+
+ protected Object convert(Action action, CommandSession session, Object value, Type toType) throws Exception {
+ if (toType == String.class) {
+ return value != null ? value.toString() : null;
+ }
+ return new DefaultConverter(action.getClass().getClassLoader()).convert(value, toType);
+ }
+
+ private int getWidth(CommandSession session) {
+ Object cols = session.get("COLUMNS");
+ return (cols != null && cols instanceof Integer) ? (Integer)cols : 80;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
new file mode 100644
index 0000000..4ea5dfc
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/commands/basic/SimpleCommand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.commands.basic;
+
+import java.util.Hashtable;
+
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.commands.Action;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.CommandWithAction;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.BundleContext;
+
+/**
+ * A very simple {@link Function} which creates {@link Action} based on a class name.
+ */
+public class SimpleCommand extends AbstractCommand {
+
+ private Class<? extends Action> actionClass;
+
+ public SimpleCommand()
+ {
+ }
+
+ public SimpleCommand(Class<? extends Action> actionClass)
+ {
+ this.actionClass = actionClass;
+ }
+
+ public Class<? extends Action> getActionClass()
+ {
+ return actionClass;
+ }
+
+ public void setActionClass(Class<? extends Action> actionClass)
+ {
+ this.actionClass = actionClass;
+ }
+
+ public Action createNewAction() {
+ try {
+ return actionClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static ServiceRegistration export(BundleContext context, Class<? extends Action> actionClass)
+ {
+ Command cmd = actionClass.getAnnotation(Command.class);
+ if (cmd == null)
+ {
+ throw new IllegalArgumentException("Action class is not annotated with @Command");
+ }
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put("osgi.command.scope", cmd.scope());
+ props.put("osgi.command.function", cmd.name());
+ SimpleCommand command = new SimpleCommand(actionClass);
+ return context.registerService(
+ new String[] { Function.class.getName(), CommandWithAction.class.getName() },
+ command, props);
+ }
+
+}
[07/11] KARAF-2772 Extracting command-api
Posted by cs...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
new file mode 100644
index 0000000..ba95b0c
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/CommandsCompleter.java
@@ -0,0 +1,321 @@
+/*
+ * 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.console.completer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.felix.gogo.runtime.CommandProxy;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.commands.CommandWithAction;
+import org.apache.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.SessionProperties;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Like the {@link org.apache.karaf.shell.console.completer.CommandsCompleter} but does not use OSGi but is
+ * instead used from the non-OSGi {@link org.apache.karaf.shell.console.impl.Main}
+ */
+public class CommandsCompleter implements Completer {
+
+ public static final String COMMANDS = ".commands";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CommandsCompleter.class);
+
+ private CommandSession session;
+ private final Map<String, Completer> globalCompleters = new HashMap<String, Completer>();
+ private final Map<String, Completer> localCompleters = new HashMap<String, Completer>();
+ private final Set<String> commands = new HashSet<String>();
+
+ public CommandsCompleter() {
+ this(CommandSessionHolder.getSession());
+ }
+
+ public CommandsCompleter(CommandSession session) {
+ this.session = session;
+ try {
+ new CommandTracker();
+ } catch (Throwable t) {
+ // Ignore in case we're not in OSGi
+ }
+ }
+
+
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ if (session == null) {
+ session = CommandSessionHolder.getSession();
+ }
+
+ List<String> scopes = getCurrentScopes();
+ Map<String, Completer>[] allCompleters = checkData();
+ sort(allCompleters, scopes);
+
+ String subShell = getCurrentSubShell();
+ String completion = getCompletionType();
+
+ // SUBSHELL mode
+ if ("SUBSHELL".equalsIgnoreCase(completion)) {
+ if (subShell.isEmpty()) {
+ subShell = "*";
+ }
+ List<Completer> completers = new ArrayList<Completer>();
+ for (String name : allCompleters[1].keySet()) {
+ if (name.startsWith(subShell)) {
+ completers.add(allCompleters[1].get(name));
+ }
+ }
+ if (!subShell.equals("*")) {
+ completers.add(new StringsCompleter(new String[] { "exit" }));
+ }
+ int res = new AggregateCompleter(completers).complete(buffer, cursor, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ if ("FIRST".equalsIgnoreCase(completion)) {
+ if (!subShell.isEmpty()) {
+ List<Completer> completers = new ArrayList<Completer>();
+ for (String name : allCompleters[1].keySet()) {
+ if (name.startsWith(subShell)) {
+ completers.add(allCompleters[1].get(name));
+ }
+ }
+ int res = new AggregateCompleter(completers).complete(buffer, cursor, candidates);
+ if (!candidates.isEmpty()) {
+ Collections.sort(candidates);
+ return res;
+ }
+ }
+ List<Completer> compl = new ArrayList<Completer>();
+ compl.add(new StringsCompleter(getAliases()));
+ compl.addAll(allCompleters[0].values());
+ int res = new AggregateCompleter(compl).complete(buffer, cursor, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ List<Completer> compl = new ArrayList<Completer>();
+ compl.add(new StringsCompleter(getAliases()));
+ compl.addAll(allCompleters[0].values());
+ int res = new AggregateCompleter(compl).complete(buffer, cursor, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ protected void sort(Map<String, Completer>[] completers, List<String> scopes) {
+ ScopeComparator comparator = new ScopeComparator(scopes);
+ for (int i = 0; i < completers.length; i++) {
+ Map<String, Completer> map = new TreeMap<String, Completer>(comparator);
+ map.putAll(completers[i]);
+ completers[i] = map;
+ }
+ }
+
+ protected static class ScopeComparator implements Comparator<String> {
+ private final List<String> scopes;
+ public ScopeComparator(List<String> scopes) {
+ this.scopes = scopes;
+ }
+ @Override
+ public int compare(String o1, String o2) {
+ String[] p1 = o1.split(":");
+ String[] p2 = o2.split(":");
+ int p = 0;
+ while (p < p1.length && p < p2.length) {
+ int i1 = scopes.indexOf(p1[p]);
+ int i2 = scopes.indexOf(p2[p]);
+ if (i1 < 0) {
+ if (i2 < 0) {
+ int c = p1[p].compareTo(p2[p]);
+ if (c != 0) {
+ return c;
+ } else {
+ p++;
+ }
+ } else {
+ return +1;
+ }
+ } else if (i2 < 0) {
+ return -1;
+ } else if (i1 < i2) {
+ return -1;
+ } else if (i1 > i2) {
+ return +1;
+ } else {
+ p++;
+ }
+ }
+ return 0;
+ }
+ }
+
+ protected List<String> getCurrentScopes() {
+ String scopes = (String) session.get("SCOPE");
+ return Arrays.asList(scopes.split(":"));
+ }
+
+ protected String getCurrentSubShell() {
+ String s = (String) session.get("SUBSHELL");
+ if (s == null) {
+ s = "";
+ }
+ return s;
+ }
+
+ protected String getCompletionType() {
+ String completion = (String) session.get(SessionProperties.COMPLETION_MODE);
+ if (completion == null) {
+ completion = "GLOBAL";
+ }
+ return completion;
+ }
+
+ protected String stripScope(String name) {
+ int index = name.indexOf(":");
+ return index > 0 ? name.substring(index + 1) : name;
+ }
+
+ @SuppressWarnings({
+ "unchecked", "deprecation"
+ })
+ protected Map<String, Completer>[] checkData() {
+ // Copy the set to avoid concurrent modification exceptions
+ // TODO: fix that in gogo instead
+ Set<String> names;
+ boolean update;
+ synchronized (this) {
+ names = new HashSet<String>((Set<String>) session.get(COMMANDS));
+ update = !names.equals(commands);
+ }
+ if (update) {
+ // get command aliases
+ Set<String> commands = new HashSet<String>();
+ Map<String, Completer> global = new HashMap<String, Completer>();
+ Map<String, Completer> local = new HashMap<String, Completer>();
+
+ // add argument completers for each command
+ for (String command : names) {
+ String rawCommand = stripScope(command);
+ Function function = (Function) session.get(command);
+ function = unProxy(function);
+ if (function instanceof CommandWithAction) {
+ try {
+ global.put(command, new ArgumentCompleter(session, (CommandWithAction) function, command));
+ local.put(command, new ArgumentCompleter(session, (CommandWithAction) function, rawCommand));
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to create completers for command '" + command + "'", t);
+ }
+ }
+ else if (function instanceof org.apache.felix.gogo.commands.CommandWithAction) {
+ try {
+ global.put(command, new OldArgumentCompleter(session, (org.apache.felix.gogo.commands.CommandWithAction) function, command));
+ local.put(command, new OldArgumentCompleter(session, (org.apache.felix.gogo.commands.CommandWithAction) function, rawCommand));
+ } catch (Throwable t) {
+ LOGGER.debug("Unable to create completers for command '" + command + "'", t);
+ }
+ }
+ commands.add(command);
+ }
+
+ synchronized (this) {
+ this.commands.clear();
+ this.globalCompleters.clear();
+ this.localCompleters.clear();
+ this.commands.addAll(commands);
+ this.globalCompleters.putAll(global);
+ this.localCompleters.putAll(local);
+ }
+ }
+ synchronized (this) {
+ return new Map[] {
+ new HashMap<String, Completer>(this.globalCompleters),
+ new HashMap<String, Completer>(this.localCompleters)
+ };
+ }
+ }
+
+ /**
+ * Get the aliases defined in the console session.
+ *
+ * @return the aliases set
+ */
+ @SuppressWarnings("unchecked")
+ private Set<String> getAliases() {
+ Set<String> vars = ((Set<String>) session.get(null));
+ Set<String> aliases = new HashSet<String>();
+ for (String var : vars) {
+ Object content = session.get(var);
+ if (content != null && "org.apache.felix.gogo.runtime.Closure".equals(content.getClass().getName())) {
+ aliases.add(var);
+ }
+ }
+ return aliases;
+ }
+
+ public static Function unProxy(Function function) {
+ if (function == null || function.getClass() != CommandProxy.class) {
+ return function;
+ }
+ CommandProxy proxy = (CommandProxy)function;
+ Object target = proxy.getTarget();
+ try {
+ return target instanceof Function ? (Function)target : function;
+ } finally {
+ proxy.ungetTarget();
+ }
+ }
+
+ private class CommandTracker {
+ public CommandTracker() throws Exception {
+ BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ if (context == null) {
+ throw new IllegalStateException("Bundle is stopped");
+ }
+ ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ synchronized (CommandsCompleter.this) {
+ commands.clear();
+ }
+ }
+ };
+ context.addServiceListener(listener,
+ String.format("(&(%s=*)(%s=*))",
+ CommandProcessor.COMMAND_SCOPE,
+ CommandProcessor.COMMAND_FUNCTION));
+ }
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
new file mode 100644
index 0000000..dbb3034
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/FileCompleter.java
@@ -0,0 +1,147 @@
+/**
+ *
+ * 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.console.completer;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.Completer;
+
+/**
+ * A file name completer takes the buffer and issues a list of
+ * potential completions.
+ * <p/>
+ * This completer tries to behave as similar as possible to
+ * <i>bash</i>'s file name completion (using GNU readline)
+ * with the following exceptions:
+ * <p/>
+ * <ul>
+ * <li>Candidates that are directories will end with "/"</li>
+ * <li>Wildcard regular expressions are not evaluated or replaced</li>
+ * <li>The "~" character can be used to represent the user's home,
+ * but it cannot complete to other users' homes, since java does
+ * not provide any way of determining that easily</li>
+ * </ul>
+ *
+ * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
+ * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
+ * @since 2.3
+ */
+public class FileCompleter implements Completer
+{
+ private static String OS = System.getProperty("os.name").toLowerCase();
+
+ // TODO: Handle files with spaces in them
+
+ private static final boolean OS_IS_WINDOWS = isWindows();
+
+ public FileCompleter(CommandSession session) {
+ }
+
+ public static boolean isWindows() {
+ return (OS.indexOf("win") >= 0);
+
+ }
+
+ public int complete(String buffer, final int cursor, final List<String> candidates) {
+ // buffer can be null
+ if (candidates == null) {
+ return 0;
+ }
+
+ if (buffer == null) {
+ buffer = "";
+ }
+
+ if (OS_IS_WINDOWS) {
+ buffer = buffer.replace('/', '\\');
+ }
+
+ String translated = buffer;
+
+ File homeDir = getUserHome();
+
+ // Special character: ~ maps to the user's home directory
+ if (translated.startsWith("~" + separator())) {
+ translated = homeDir.getPath() + translated.substring(1);
+ }
+ else if (translated.startsWith("~")) {
+ translated = homeDir.getParentFile().getAbsolutePath();
+ }
+ else if (!(translated.startsWith(separator()))) {
+ String cwd = getUserDir().getAbsolutePath();
+ translated = cwd + separator() + translated;
+ }
+
+ File file = new File(translated);
+ final File dir;
+
+ if (translated.endsWith(separator())) {
+ dir = file;
+ }
+ else {
+ dir = file.getParentFile();
+ }
+
+ File[] entries = dir == null ? new File[0] : dir.listFiles();
+
+ return matchFiles(buffer, translated, entries, candidates);
+ }
+
+ protected String separator() {
+ return File.separator;
+ }
+
+ protected File getUserHome() {
+ return new File(System.getProperty("user.home"));
+ }
+
+ protected File getUserDir() {
+ return new File(".");
+ }
+
+ protected int matchFiles(final String buffer, final String translated, final File[] files, final List<String> candidates) {
+ if (files == null) {
+ return -1;
+ }
+
+ int matches = 0;
+
+ // first pass: just count the matches
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ matches++;
+ }
+ }
+ for (File file : files) {
+ if (file.getAbsolutePath().startsWith(translated)) {
+ CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? separator() : " ");
+ candidates.add(render(file, name).toString());
+ }
+ }
+
+ final int index = buffer.lastIndexOf(separator());
+
+ return index + separator().length();
+ }
+
+ protected CharSequence render(final File file, final CharSequence name) {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
new file mode 100644
index 0000000..13da2df
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/NullCompleter.java
@@ -0,0 +1,32 @@
+/*
+ * 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.console.completer;
+
+import java.util.List;
+
+import org.apache.karaf.shell.console.Completer;
+
+public class NullCompleter implements Completer {
+
+ public static final NullCompleter INSTANCE = new NullCompleter();
+
+ public int complete(String buffer, int cursor, List<String> candidates) {
+ return -1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
new file mode 100644
index 0000000..583d6f8
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/OldArgumentCompleter.java
@@ -0,0 +1,448 @@
+/*
+ * 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.console.completer;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.felix.gogo.commands.Action;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.CommandWithAction;
+import org.apache.felix.gogo.commands.CompleterValues;
+import org.apache.felix.gogo.commands.Option;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.NameScoping;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OldArgumentCompleter implements Completer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OldArgumentCompleter.class);
+
+ public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
+
+ final Completer commandCompleter;
+ final Completer optionsCompleter;
+ final List<Completer> argsCompleters;
+ final Map<String, Completer> optionalCompleters;
+ final CommandWithAction function;
+ final Map<Option, Field> fields = new HashMap<Option, Field>();
+ final Map<String, Option> options = new HashMap<String, Option>();
+ final Map<Integer, Field> arguments = new HashMap<Integer, Field>();
+ boolean strict = true;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public OldArgumentCompleter(CommandSession session, CommandWithAction function, String command) {
+ this.function = function;
+ // Command name completer
+ commandCompleter = new StringsCompleter(getNames(session, command));
+ // Build options completer
+ for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
+ for (Field field : type.getDeclaredFields()) {
+ Option option = field.getAnnotation(Option.class);
+ if (option != null) {
+ fields.put(option, field);
+ options.put(option.name(), option);
+ String[] aliases = option.aliases();
+ if (aliases != null) {
+ for (String alias : aliases) {
+ options.put(alias, option);
+ }
+ }
+ }
+ Argument argument = field.getAnnotation(Argument.class);
+ if (argument != null) {
+ Integer key = argument.index();
+ if (arguments.containsKey(key)) {
+ LOGGER.warn("Duplicate @Argument annotations on class " + type.getName() + " for index: " + key + " see: " + field);
+ } else {
+ arguments.put(key, field);
+ }
+ }
+ }
+ }
+// options.put(HelpOption.HELP.name(), HelpOption.HELP);
+ optionsCompleter = new StringsCompleter(options.keySet());
+ // Build arguments completers
+ argsCompleters = new ArrayList<Completer>();
+
+ if (function instanceof CompletableFunction) {
+ Map<String, Completer> opt;
+ try {
+ //
+ opt = ((CompletableFunction) function).getOptionalCompleters();
+ } catch (Throwable t) {
+ opt = new HashMap<String, Completer>();
+ }
+ optionalCompleters = opt;
+ List<Completer> fcl = ((CompletableFunction) function).getCompleters();
+ if (fcl != null) {
+ for (Completer c : fcl) {
+ argsCompleters.add(c == null ? NullCompleter.INSTANCE : c);
+ }
+ } else {
+ argsCompleters.add(NullCompleter.INSTANCE);
+ }
+ } else {
+ optionalCompleters = new HashMap<String, Completer>();
+ final Map<Integer, Method> methods = new HashMap<Integer, Method>();
+ for (Class<?> type = function.getActionClass(); type != null; type = type.getSuperclass()) {
+ for (Method method : type.getDeclaredMethods()) {
+ CompleterValues completerMethod = method.getAnnotation(CompleterValues.class);
+ if (completerMethod != null) {
+ int index = completerMethod.index();
+ Integer key = index;
+ if (index >= arguments.size() || index < 0) {
+ LOGGER.warn("Index out of range on @CompleterValues on class " + type.getName() + " for index: " + key + " see: " + method);
+ }
+ if (methods.containsKey(key)) {
+ LOGGER.warn("Duplicate @CompleterMethod annotations on class " + type.getName() + " for index: " + key + " see: " + method);
+ } else {
+ methods.put(key, method);
+ }
+ }
+ }
+ }
+ for (int i = 0, size = arguments.size(); i < size; i++) {
+ Completer argCompleter = NullCompleter.INSTANCE;
+ Method method = methods.get(i);
+ if (method != null) {
+ // lets invoke the method
+ Action action = function.createNewAction();
+ try {
+ Object value = method.invoke(action);
+ if (value instanceof String[]) {
+ argCompleter = new StringsCompleter((String[]) value);
+ } else if (value instanceof Collection) {
+ argCompleter = new StringsCompleter((Collection<String>) value);
+ } else {
+ LOGGER.warn("Could not use value " + value + " as set of completions!");
+ }
+ } catch (IllegalAccessException e) {
+ LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + e, e);
+ } catch (InvocationTargetException e) {
+ Throwable target = e.getTargetException();
+ if (target == null) {
+ target = e;
+ }
+ LOGGER.warn("Could not invoke @CompleterMethod on " + function + ". " + target, target);
+ } finally {
+ try {
+ function.releaseAction(action);
+ } catch (Exception e) {
+ LOGGER.warn("Failed to release action: " + action + ". " + e, e);
+ }
+ }
+ } else {
+ Field field = arguments.get(i);
+ Class<?> type = field.getType();
+ if (type.isAssignableFrom(File.class)) {
+ argCompleter = new FileCompleter(session);
+ } else if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) {
+ argCompleter = new StringsCompleter(new String[] {"false", "true"}, false);
+ } else if (type.isAssignableFrom(Enum.class)) {
+ Set<String> values = new HashSet<String>();
+ for (Object o : EnumSet.allOf((Class<Enum>) type)) {
+ values.add(o.toString());
+ }
+ argCompleter = new StringsCompleter(values, false);
+ } else {
+ // TODO any other completers we can add?
+ }
+ }
+ argsCompleters.add(argCompleter);
+ }
+ }
+ }
+
+ private String[] getNames(CommandSession session, String scopedCommand) {
+ String command = NameScoping.getCommandNameWithoutGlobalPrefix(session, scopedCommand);
+ String[] s = command.split(":");
+ if (s.length == 1) {
+ return s;
+ } else {
+ return new String[] { command, s[1] };
+ }
+ }
+
+ /**
+ * If true, a completion at argument index N will only succeed
+ * if all the completions from 0-(N-1) also succeed.
+ */
+ public void setStrict(final boolean strict) {
+ this.strict = strict;
+ }
+
+ /**
+ * Returns whether a completion at argument index N will succees
+ * if all the completions from arguments 0-(N-1) also succeed.
+ */
+ public boolean getStrict() {
+ return this.strict;
+ }
+
+ public int complete(final String buffer, final int cursor,
+ final List<String> candidates) {
+ ArgumentList list = delimit(buffer, cursor);
+ int argpos = list.getArgumentPosition();
+ int argIndex = list.getCursorArgumentIndex();
+
+ //Store the argument list so that it can be used by completers.
+ CommandSession commandSession = CommandSessionHolder.getSession();
+ if(commandSession != null) {
+ commandSession.put(ARGUMENTS_LIST,list);
+ }
+
+ Completer comp = null;
+ String[] args = list.getArguments();
+ int index = 0;
+ // First argument is command name
+ if (index < argIndex) {
+ // Verify command name
+ if (!verifyCompleter(commandCompleter, args[index])) {
+ return -1;
+ }
+ index++;
+ } else {
+ comp = commandCompleter;
+ }
+ // Now, check options
+ if (comp == null) {
+ while (index < argIndex && args[index].startsWith("-")) {
+ if (!verifyCompleter(optionsCompleter, args[index])) {
+ return -1;
+ }
+ Option option = options.get(args[index]);
+ if (option == null) {
+ return -1;
+ }
+ Field field = fields.get(option);
+ if (field != null && field.getType() != boolean.class && field.getType() != Boolean.class) {
+ if (++index == argIndex) {
+ comp = NullCompleter.INSTANCE;
+ }
+ }
+ index++;
+ }
+ if (comp == null && index >= argIndex && index < args.length && args[index].startsWith("-")) {
+ comp = optionsCompleter;
+ }
+ }
+ //Now check for if last Option has a completer
+ int lastAgurmentIndex = argIndex - 1;
+ if (lastAgurmentIndex >= 1) {
+ Option lastOption = options.get(args[lastAgurmentIndex]);
+ if (lastOption != null) {
+
+ Field lastField = fields.get(lastOption);
+ if (lastField != null && lastField.getType() != boolean.class && lastField.getType() != Boolean.class) {
+ Option option = lastField.getAnnotation(Option.class);
+ if (option != null) {
+ Completer optionValueCompleter = null;
+ String name = option.name();
+ if (optionalCompleters != null && name != null) {
+ optionValueCompleter = optionalCompleters.get(name);
+ if (optionValueCompleter == null) {
+ String[] aliases = option.aliases();
+ if (aliases.length > 0) {
+ for (int i = 0; i < aliases.length && optionValueCompleter == null; i++) {
+ optionValueCompleter = optionalCompleters.get(option.aliases()[i]);
+ }
+ }
+ }
+ }
+ if(optionValueCompleter != null) {
+ comp = optionValueCompleter;
+ }
+ }
+ }
+ }
+ }
+
+ // Check arguments
+ if (comp == null) {
+ int indexArg = 0;
+ while (index < argIndex) {
+ Completer sub = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
+ if (!verifyCompleter(sub, args[index])) {
+ return -1;
+ }
+ index++;
+ indexArg++;
+ }
+ comp = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
+ }
+
+ int ret = comp.complete(list.getCursorArgument(), argpos, candidates);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ int pos = ret + (list.getBufferPosition() - argpos);
+
+ /**
+ * Special case: when completing in the middle of a line, and the
+ * area under the cursor is a delimiter, then trim any delimiters
+ * from the candidates, since we do not need to have an extra
+ * delimiter.
+ *
+ * E.g., if we have a completion for "foo", and we
+ * enter "f bar" into the buffer, and move to after the "f"
+ * and hit TAB, we want "foo bar" instead of "foo bar".
+ */
+
+ if ((buffer != null) && (cursor != buffer.length()) && isDelimiter(buffer, cursor)) {
+ for (int i = 0; i < candidates.size(); i++) {
+ String val = candidates.get(i);
+
+ while ((val.length() > 0)
+ && isDelimiter(val, val.length() - 1)) {
+ val = val.substring(0, val.length() - 1);
+ }
+
+ candidates.set(i, val);
+ }
+ }
+
+ return pos;
+ }
+
+ protected boolean verifyCompleter(Completer completer, String argument) {
+ List<String> candidates = new ArrayList<String>();
+ return completer.complete(argument, argument.length(), candidates) != -1 && !candidates.isEmpty();
+ }
+
+ public ArgumentList delimit(final String buffer, final int cursor) {
+ Parser parser = new Parser(buffer, cursor);
+ try {
+ List<List<List<String>>> program = parser.program();
+ List<String> pipe = program.get(parser.c0).get(parser.c1);
+ return new ArgumentList(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor);
+ } catch (Throwable t) {
+ return new ArgumentList(new String[] { buffer }, 0, cursor, cursor);
+ }
+ }
+
+ /**
+ * Returns true if the specified character is a whitespace
+ * parameter. Check to ensure that the character is not
+ * escaped and returns true from
+ * {@link #isDelimiterChar}.
+ *
+ * @param buffer the complete command buffer
+ * @param pos the index of the character in the buffer
+ * @return true if the character should be a delimiter
+ */
+ public boolean isDelimiter(final String buffer, final int pos) {
+ return !isEscaped(buffer, pos) && isDelimiterChar(buffer, pos);
+ }
+
+ public boolean isEscaped(final String buffer, final int pos) {
+ return pos > 0 && buffer.charAt(pos) == '\\' && !isEscaped(buffer, pos - 1);
+ }
+
+ /**
+ * The character is a delimiter if it is whitespace, and the
+ * preceeding character is not an escape character.
+ */
+ public boolean isDelimiterChar(String buffer, int pos) {
+ return Character.isWhitespace(buffer.charAt(pos));
+ }
+
+ /**
+ * The result of a delimited buffer.
+ */
+ public static class ArgumentList {
+ private String[] arguments;
+ private int cursorArgumentIndex;
+ private int argumentPosition;
+ private int bufferPosition;
+
+ /**
+ * @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
+ */
+ public ArgumentList(String[] arguments, int cursorArgumentIndex,
+ int argumentPosition, int bufferPosition) {
+ this.arguments = arguments;
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ this.argumentPosition = argumentPosition;
+ this.bufferPosition = bufferPosition;
+ }
+
+ public void setCursorArgumentIndex(int cursorArgumentIndex) {
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ }
+
+ public int getCursorArgumentIndex() {
+ return this.cursorArgumentIndex;
+ }
+
+ public String getCursorArgument() {
+ if ((cursorArgumentIndex < 0)
+ || (cursorArgumentIndex >= arguments.length)) {
+ return null;
+ }
+
+ return arguments[cursorArgumentIndex];
+ }
+
+ public void setArgumentPosition(int argumentPosition) {
+ this.argumentPosition = argumentPosition;
+ }
+
+ public int getArgumentPosition() {
+ return this.argumentPosition;
+ }
+
+ public void setArguments(String[] arguments) {
+ this.arguments = arguments;
+ }
+
+ public String[] getArguments() {
+ return this.arguments;
+ }
+
+ public void setBufferPosition(int bufferPosition) {
+ this.bufferPosition = bufferPosition;
+ }
+
+ public int getBufferPosition() {
+ return this.bufferPosition;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/Parser.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
new file mode 100644
index 0000000..dcdab7d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/Parser.java
@@ -0,0 +1,396 @@
+/*
+ * 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.console.completer;
+
+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;
+
+ public Parser(String text, int cursor) {
+ this.text = text;
+ this.cursor = cursor;
+ }
+
+ 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) {
+ 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;
+ }
+ }
+
+ 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/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
new file mode 100644
index 0000000..a3f7c6d
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/console/completer/StringsCompleter.java
@@ -0,0 +1,103 @@
+/*
+ * 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.console.completer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.karaf.shell.console.Completer;
+
+/**
+ * Completer for a set of strings.
+ */
+public class StringsCompleter
+ implements Completer
+{
+ private final SortedSet<String> strings = new TreeSet<String>();
+ private final boolean caseSensitive;
+
+ public StringsCompleter() {
+ this(true);
+ }
+
+
+ public StringsCompleter(final boolean caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ }
+
+ public StringsCompleter(final Collection<String> strings) {
+ this();
+ assert strings != null;
+ getStrings().addAll(strings);
+ }
+
+ public StringsCompleter(final String[] strings, boolean caseSensitive) {
+ this(Arrays.asList(strings), caseSensitive);
+ }
+
+ public StringsCompleter(final Collection<String> strings, boolean caseSensitive) {
+ this(caseSensitive);
+ assert strings != null;
+ getStrings().addAll(strings);
+ }
+
+ public StringsCompleter(final String[] strings) {
+ this(Arrays.asList(strings));
+ }
+
+ public SortedSet<String> getStrings() {
+ return strings;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public int complete(String buffer, final int cursor, final List candidates) {
+ // buffer could be null
+ assert candidates != null;
+
+ if (buffer == null) {
+ buffer = "";
+ }
+ if (!caseSensitive) {
+ buffer = buffer.toLowerCase();
+ }
+
+ // KARAF-421, use getStrings() instead strings field.
+ SortedSet<String> matches = getStrings().tailSet(buffer);
+
+ for (String match : matches) {
+ String s = caseSensitive ? match : match.toLowerCase();
+ if (!s.startsWith(buffer)) {
+ break;
+ }
+
+ // noinspection unchecked
+ candidates.add(match);
+ }
+
+ if (candidates.size() == 1) {
+ // noinspection unchecked
+ candidates.set(0, candidates.get(0) + " ");
+ }
+
+ return candidates.isEmpty() ? -1 : 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Destroy.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Destroy.java b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Destroy.java
new file mode 100644
index 0000000..4df9fe3
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Destroy.java
@@ -0,0 +1,29 @@
+/*
+ * 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.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Destroy {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Init.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Init.java b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Init.java
new file mode 100644
index 0000000..154b883
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Init.java
@@ -0,0 +1,29 @@
+/*
+ * 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.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Init {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Reference.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Reference.java b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Reference.java
new file mode 100644
index 0000000..b74d609
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Reference.java
@@ -0,0 +1,29 @@
+/*
+ * 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.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Reference {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Service.java
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Service.java b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Service.java
new file mode 100644
index 0000000..ff3f3a3
--- /dev/null
+++ b/shell/command-api/src/main/java/org/apache/karaf/shell/inject/Service.java
@@ -0,0 +1,29 @@
+/*
+ * 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.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Service {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/resources/OSGI-INF/blueprint/shell-namespacehandler.xml
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/resources/OSGI-INF/blueprint/shell-namespacehandler.xml b/shell/command-api/src/main/resources/OSGI-INF/blueprint/shell-namespacehandler.xml
new file mode 100644
index 0000000..b2b5566
--- /dev/null
+++ b/shell/command-api/src/main/resources/OSGI-INF/blueprint/shell-namespacehandler.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <bean id="namespaceHandler" class="org.apache.karaf.shell.console.commands.NamespaceHandler" />
+
+ <service ref="namespaceHandler" interface="org.apache.aries.blueprint.NamespaceHandler">
+ <service-properties>
+ <entry key="osgi.service.blueprint.namespace" value="http://karaf.apache.org/xmlns/shell/v1.0.0" />
+ </service-properties>
+ </service>
+
+ <service ref="namespaceHandler" interface="org.apache.aries.blueprint.NamespaceHandler">
+ <service-properties>
+ <entry key="osgi.service.blueprint.namespace" value="http://karaf.apache.org/xmlns/shell/v1.1.0" />
+ </service-properties>
+ </service>
+
+ <service ref="namespaceHandler" interface="org.apache.aries.blueprint.NamespaceHandler">
+ <service-properties>
+ <entry key="osgi.service.blueprint.namespace" value="http://karaf.apache.org/xmlns/shell/v1.2.0" />
+ </service-properties>
+ </service>
+
+</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/resources/OSGI-INF/bundle.info b/shell/command-api/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..95214e0
--- /dev/null
+++ b/shell/command-api/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,14 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+h1. Description
+
+
+
+h1. See also
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.0.0.xsd
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.0.0.xsd b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.0.0.xsd
new file mode 100644
index 0000000..0e0dafd
--- /dev/null
+++ b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.0.0.xsd
@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<!-- $Rev: 699828 $ $Date: 2008-09-28 16:35:27 +0200 (Sun, 28 Sep 2008) $ -->
+
+<xsd:schema xmlns="http://karaf.apache.org/xmlns/shell/v1.0.0"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ targetNamespace="http://karaf.apache.org/xmlns/shell/v1.0.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
+
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the configuration elements for Apache Karaf commands support.
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="command-bundle">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command bundle.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element ref="command"/>
+ <xsd:element ref="alias"/>
+ <xsd:element ref="link"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="command">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <!--
+ NOTE: Not using an xsd:choice here, as I can't seem to figure out how to get it to properly
+ validate the min/max of the containted elements. W/o the xsd:choice the validation
+ works, though have to define elements in order :-(
+ -->
+ <xsd:element ref="action" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="documenter" minOccurs="0" maxOccurs="1"/>
+ <xsd:choice minOccurs="0" maxOccurs="1">
+ <xsd:element ref="completer"/>
+ <xsd:element ref="completers"/>
+ </xsd:choice>
+ <xsd:element ref="message-source" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="link">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a link command.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="target" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:group name="commandComponentElements">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid elements for command components. This is based on beans:beanElements,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="argument" type="bp:Targument"/>
+ <xsd:element name="property" type="bp:Tproperty"/>
+ <!--
+ NOTE: This seems to cause schema validation problems... not really sure why
+ <xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
+ -->
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:attributeGroup name="commandComponentAttributes">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid attributes for command components. This is based on beans:beanAttributes,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="class" type="xsd:string"/>
+ <xsd:attribute name="depends-on" type="xsd:string"/>
+ <xsd:attribute name="init-method" type="xsd:string"/>
+ <xsd:attribute name="factory-method" type="xsd:string"/>
+ <xsd:attribute name="factory-bean" type="xsd:string"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:attributeGroup>
+
+ <xsd:complexType name="commandComponent" abstract="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Support for command component elements, which are all basically just beans.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:group ref="commandComponentElements"/>
+ <xsd:attributeGroup ref="commandComponentAttributes"/>
+ </xsd:complexType>
+
+ <xsd:element name="action">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command action.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="documenter">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command documenter.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completer">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command completer.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completers">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable command completer with a set of completers.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element name="bean" type="bp:Tbean"/>
+ <xsd:element name="ref" type="bp:Tref"/>
+ <xsd:element name="null" type="bp:Tnull"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="message-source">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command message source.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="alias">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command alias.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="name" type="xsd:string" use="required"/>
+ <xsd:attribute name="alias" type="xsd:string" use="required"/>
+ </xsd:complexType>
+ </xsd:element>
+
+</xsd:schema>
http://git-wip-us.apache.org/repos/asf/karaf/blob/1ee78df9/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.1.0.xsd
----------------------------------------------------------------------
diff --git a/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.1.0.xsd b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.1.0.xsd
new file mode 100644
index 0000000..929cbd2
--- /dev/null
+++ b/shell/command-api/src/main/resources/org/apache/karaf/shell/console/commands/karaf-shell-1.1.0.xsd
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+
+<!-- $Rev: 699828 $ $Date: 2008-09-28 16:35:27 +0200 (Sun, 28 Sep 2008) $ -->
+
+<xsd:schema xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ targetNamespace="http://karaf.apache.org/xmlns/shell/v1.1.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+ <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
+
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the configuration elements for Apache Karaf commands support.
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="command-bundle">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command bundle.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:element ref="command" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="command">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <!--
+ NOTE: Not using an xsd:choice here, as I can't seem to figure out how to get it to properly
+ validate the min/max of the containted elements. W/o the xsd:choice the validation
+ works, though have to define elements in order :-(
+ -->
+ <xsd:element ref="action" minOccurs="1" maxOccurs="1"/>
+ <xsd:element ref="documenter" minOccurs="0" maxOccurs="1"/>
+ <xsd:choice minOccurs="0" maxOccurs="1">
+ <xsd:element ref="completer"/>
+ <xsd:element ref="completers"/>
+ </xsd:choice>
+ <xsd:element ref="optional-completers" minOccurs="0" maxOccurs="1"/>
+ <xsd:element ref="message-source" minOccurs="0" maxOccurs="1"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:group name="commandComponentElements">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid elements for command components. This is based on beans:beanElements,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="argument" type="bp:Targument"/>
+ <xsd:element name="property" type="bp:Tproperty"/>
+ <!--
+ NOTE: This seems to cause schema validation problems... not really sure why
+ <xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/>
+ -->
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:attributeGroup name="commandComponentAttributes">
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines the valid attributes for command components. This is based on beans:beanAttributes,
+ stripping off the bits which are not valid in the command component context.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:attribute name="class" type="xsd:string"/>
+ <xsd:attribute name="depends-on" type="xsd:string"/>
+ <xsd:attribute name="init-method" type="xsd:string"/>
+ <xsd:attribute name="factory-method" type="xsd:string"/>
+ <xsd:attribute name="factory-bean" type="xsd:string"/>
+ <xsd:anyAttribute namespace="##other" processContents="lax"/>
+ </xsd:attributeGroup>
+
+ <xsd:complexType name="commandComponent" abstract="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Support for command component elements, which are all basically just beans.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:group ref="commandComponentElements"/>
+ <xsd:attributeGroup ref="commandComponentAttributes"/>
+ </xsd:complexType>
+
+ <xsd:element name="action">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command action.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="documenter">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command documenter.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completer">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command completer.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="completers">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable command completer with a set of completers.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:sequence>
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
+ <xsd:element name="bean" type="bp:Tbean"/>
+ <xsd:element name="ref" type="bp:Tref"/>
+ <xsd:element name="null" type="bp:Tnull"/>
+ </xsd:choice>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="optional-completers">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a configurable command completer with a set of completers.
+ These completers are used for option value completion.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="bp:TtypedCollection">
+ <xsd:sequence>
+ <xsd:element name="entry" type="bp:TmapEntry" minOccurs="0"
+ maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="key-type" type="bp:Ttype" />
+ </xsd:extension>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="message-source">
+ <xsd:complexType>
+ <xsd:annotation>
+ <xsd:documentation>
+ Defines a command message source.
+ </xsd:documentation>
+ </xsd:annotation>
+ <xsd:complexContent>
+ <xsd:extension base="commandComponent"/>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+</xsd:schema>