You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/03/05 16:08:28 UTC
[06/10] git commit: [KARAF-2805] Add a compatibility layer and switch
to the new console
[KARAF-2805] Add a compatibility layer and switch to the new console
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/2e3c3ef9
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2e3c3ef9
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2e3c3ef9
Branch: refs/heads/master
Commit: 2e3c3ef97965351dcd9e6f7e562d434793f82681
Parents: e7d23be
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Wed Mar 5 15:16:38 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Wed Mar 5 15:37:33 2014 +0100
----------------------------------------------------------------------
assemblies/features/framework/pom.xml | 4 +-
.../apache/karaf/itests/KarafTestSupport.java | 10 +-
.../apache/karaf/itests/SshCommandTestBase.java | 2 +-
shell/console/pom.xml | 15 +-
.../karaf/shell/compat/ArgumentCompleter.java | 479 +++++++++++++++++++
.../karaf/shell/compat/CommandTracker.java | 166 +++++++
.../shell/compat/OldArgumentCompleter.java | 450 +++++++++++++++++
.../OSGI-INF/blueprint/karaf-console.xml | 71 +--
.../src/main/resources/OSGI-INF/bundle.info | 4 +-
9 files changed, 1121 insertions(+), 80 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/assemblies/features/framework/pom.xml
----------------------------------------------------------------------
diff --git a/assemblies/features/framework/pom.xml b/assemblies/features/framework/pom.xml
index 6a26aae..ed48318 100644
--- a/assemblies/features/framework/pom.xml
+++ b/assemblies/features/framework/pom.xml
@@ -159,11 +159,11 @@
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.help</artifactId>
+ <artifactId>org.apache.karaf.shell.console</artifactId>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java b/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
index ccde975..4507d5f 100644
--- a/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
+++ b/itests/src/test/java/org/apache/karaf/itests/KarafTestSupport.java
@@ -51,11 +51,11 @@ import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
import org.apache.karaf.features.BootFinished;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
import org.junit.Assert;
import org.junit.Rule;
import org.ops4j.pax.exam.Configuration;
@@ -161,8 +161,8 @@ public class KarafTestSupport {
String response;
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final PrintStream printStream = new PrintStream(byteArrayOutputStream);
- final CommandProcessor commandProcessor = getOsgiService(CommandProcessor.class);
- final CommandSession commandSession = commandProcessor.createSession(System.in, printStream, System.err);
+ final SessionFactory sessionFactory = getOsgiService(SessionFactory.class);
+ final Session session = sessionFactory.create(System.in, printStream, System.err);
final Callable<String> commandCallable = new Callable<String>() {
@Override
@@ -171,7 +171,7 @@ public class KarafTestSupport {
if (!silent) {
System.err.println(command);
}
- commandSession.execute(command);
+ session.execute(command);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
----------------------------------------------------------------------
diff --git a/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java b/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
index adc1cc0..e687f4c 100644
--- a/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
+++ b/itests/src/test/java/org/apache/karaf/itests/SshCommandTestBase.java
@@ -21,7 +21,7 @@ import java.io.PipedOutputStream;
import java.util.Arrays;
import java.util.HashSet;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.apache.karaf.features.Feature;
import org.apache.sshd.ClientChannel;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/shell/console/pom.xml
----------------------------------------------------------------------
diff --git a/shell/console/pom.xml b/shell/console/pom.xml
index df03dd9..e44682c 100644
--- a/shell/console/pom.xml
+++ b/shell/console/pom.xml
@@ -31,7 +31,7 @@
<artifactId>org.apache.karaf.shell.console</artifactId>
<packaging>bundle</packaging>
<name>Apache Karaf :: Shell :: Console</name>
- <description>This bundle provides OSGi shell integration and console support.</description>
+ <description>This bundle provides compatibility with the previous console.</description>
<properties>
<appendedResourcesDirectory>${basedir}/../../etc/appended-resources</appendedResourcesDirectory>
@@ -65,6 +65,10 @@
<groupId>org.apache.karaf.jaas</groupId>
<artifactId>org.apache.karaf.jaas.boot</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
@@ -132,6 +136,9 @@
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
+ <Fragment-Host>
+ org.apache.karaf.shell.core
+ </Fragment-Host>
<Import-Package>
!org.apache.felix.gogo.runtime.*,
!org.apache.karaf.shell.inject.impl,
@@ -165,15 +172,11 @@
</Export-Package>
<Private-Package>
org.apache.karaf.shell.commands.ansi,
+ org.apache.karaf.shell.compat,
org.apache.karaf.shell.console.impl*,
org.apache.karaf.shell.security.impl*,
org.apache.karaf.shell.inject.impl*,
- org.apache.felix.utils.extender,
- org.apache.felix.utils.manifest
</Private-Package>
- <Bundle-Activator>
- org.apache.felix.gogo.runtime.activator.Activator
- </Bundle-Activator>
<Main-Class>
org.apache.karaf.shell.console.impl.Main
</Main-Class>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/shell/console/src/main/java/org/apache/karaf/shell/compat/ArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/compat/ArgumentCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/compat/ArgumentCompleter.java
new file mode 100644
index 0000000..8f52503
--- /dev/null
+++ b/shell/console/src/main/java/org/apache/karaf/shell/compat/ArgumentCompleter.java
@@ -0,0 +1,479 @@
+/*
+ * 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.compat;
+
+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.CommandSession;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+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.karaf.shell.console.CommandSessionHolder;
+import org.apache.karaf.shell.console.CompletableFunction;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.FileCompleter;
+import org.apache.karaf.shell.console.completer.NullCompleter;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Session;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ArgumentCompleter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentCompleter.class);
+
+ public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
+
+ public static final String COMMANDS = ".commands";
+
+ final String scope;
+ final String name;
+ 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(CommandWithAction function, String scope, String name, boolean scoped) {
+ this.function = function;
+ this.scope = scope;
+ this.name = name;
+ // Command name completer
+ String[] names = scoped ? new String[] { name } : new String[] { name, scope + ":" + name };
+ commandCompleter = new StringsCompleter(names);
+ // 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(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(Field field) {
+ Completer completer = null;
+ Class<?> type = field.getType();
+ if (type.isAssignableFrom(File.class)) {
+ completer = new FileCompleter(null);
+ } 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;
+ }
+
+ /**
+ * 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 Session session, final CommandLine list, final List<String> candidates) {
+ 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 scope
+ if (!Session.SCOPE_GLOBAL.equals(scope) && !session.resolveCommand(args[index]).equals(scope + ":" + name)) {
+ return -1;
+ }
+ // 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".
+ */
+ String buffer = list.getBuffer();
+ int cursor = list.getBufferPosition();
+ 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();
+ }
+
+ /**
+ * 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));
+ }
+
+ 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/2e3c3ef9/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java b/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
new file mode 100644
index 0000000..191735c
--- /dev/null
+++ b/shell/console/src/main/java/org/apache/karaf/shell/compat/CommandTracker.java
@@ -0,0 +1,166 @@
+/*
+ * 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.compat;
+
+import java.util.List;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.CommandWithAction;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class CommandTracker implements ServiceTrackerCustomizer<Object, Object> {
+
+ SessionFactory sessionFactory;
+ BundleContext context;
+ ServiceTracker<?, ?> tracker;
+
+ public void setSessionFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ }
+
+ public void setContext(BundleContext context) {
+ this.context = context;
+ }
+
+ public void init() throws Exception {
+ Filter filter = context.createFilter(String.format("(&(%s=*)(%s=*))",
+ CommandProcessor.COMMAND_SCOPE, CommandProcessor.COMMAND_FUNCTION));
+ this.tracker = new ServiceTracker<Object, Object>(context, filter, this);
+ this.tracker.open();
+ }
+
+ public void destroy() {
+ tracker.close();
+ }
+
+ @Override
+ public Object addingService(final ServiceReference reference) {
+ Object service = context.getService(reference);
+ if (service instanceof CommandWithAction) {
+ final CommandWithAction oldCommand = (CommandWithAction) service;
+ final org.apache.karaf.shell.api.console.Command command = new org.apache.karaf.shell.api.console.Command() {
+ @Override
+ public String getScope() {
+ return reference.getProperty(CommandProcessor.COMMAND_SCOPE).toString();
+ }
+
+ @Override
+ public String getName() {
+ return reference.getProperty(CommandProcessor.COMMAND_FUNCTION).toString();
+ }
+
+ @Override
+ public String getDescription() {
+ final Command cmd = oldCommand.getActionClass().getAnnotation(Command.class);
+ if (cmd != null) {
+ return cmd.description();
+ } else {
+ return getName();
+ }
+ }
+
+ @Override
+ public Completer getCompleter(final boolean scoped) {
+ final ArgumentCompleter completer = new ArgumentCompleter(oldCommand, getScope(), getName(), scoped);
+ return new Completer() {
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ return completer.complete(session, commandLine, candidates);
+ }
+ };
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ // TODO: remove not really nice cast
+ CommandSession commandSession = (CommandSession) session.get(".commandSession");
+ return oldCommand.execute(commandSession, arguments);
+ }
+ };
+ sessionFactory.getRegistry().register(command);
+ return command;
+ } else if (service instanceof org.apache.felix.gogo.commands.CommandWithAction) {
+ final org.apache.felix.gogo.commands.CommandWithAction oldCommand = (org.apache.felix.gogo.commands.CommandWithAction) service;
+ final org.apache.karaf.shell.api.console.Command command = new org.apache.karaf.shell.api.console.Command() {
+ @Override
+ public String getScope() {
+ return reference.getProperty(CommandProcessor.COMMAND_SCOPE).toString();
+ }
+
+ @Override
+ public String getName() {
+ return reference.getProperty(CommandProcessor.COMMAND_FUNCTION).toString();
+ }
+
+ @Override
+ public String getDescription() {
+ final org.apache.felix.gogo.commands.Command cmd = oldCommand.getActionClass().getAnnotation(org.apache.felix.gogo.commands.Command.class);
+ if (cmd != null) {
+ return cmd.description();
+ } else {
+ return getName();
+ }
+ }
+
+ @Override
+ public Completer getCompleter(final boolean scoped) {
+ final OldArgumentCompleter completer = new OldArgumentCompleter(oldCommand, getScope(), getName(), scoped);
+ return new Completer() {
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ return completer.complete(session, commandLine, candidates);
+ }
+ };
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ // TODO: remove not really nice cast
+ CommandSession commandSession = (CommandSession) session.get(".commandSession");
+ return oldCommand.execute(commandSession, arguments);
+ }
+ };
+ sessionFactory.getRegistry().register(command);
+ return command;
+ }
+ return service;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference reference, Object service) {
+ }
+
+ @Override
+ public void removedService(ServiceReference reference, Object service) {
+ if (service instanceof org.apache.karaf.shell.api.console.Command) {
+ sessionFactory.getRegistry().unregister(service);
+ }
+ context.ungetService(reference);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/shell/console/src/main/java/org/apache/karaf/shell/compat/OldArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/console/src/main/java/org/apache/karaf/shell/compat/OldArgumentCompleter.java b/shell/console/src/main/java/org/apache/karaf/shell/compat/OldArgumentCompleter.java
new file mode 100644
index 0000000..407244c
--- /dev/null
+++ b/shell/console/src/main/java/org/apache/karaf/shell/compat/OldArgumentCompleter.java
@@ -0,0 +1,450 @@
+/*
+ * 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.compat;
+
+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.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Session;
+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.apache.karaf.shell.console.completer.FileCompleter;
+import org.apache.karaf.shell.console.completer.NullCompleter;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OldArgumentCompleter {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OldArgumentCompleter.class);
+
+ public static final String ARGUMENTS_LIST = "ARGUMENTS_LIST";
+
+ final String scope;
+ final String name;
+ 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(CommandWithAction function, String scope, String name, boolean scoped) {
+ this.function = function;
+ this.scope = scope;
+ this.name = name;
+ // Command name completer
+ String[] names = scoped ? new String[] { name } : new String[] { name, scope + ":" + name };
+ commandCompleter = new StringsCompleter(names);
+ // 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(null);
+ } 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 Session session, final CommandLine list, final List<String> candidates) {
+ 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 scope
+ if (!Session.SCOPE_GLOBAL.equals(scope) && !session.resolveCommand(args[index]).equals(scope + ":" + name)) {
+ return -1;
+ }
+ // 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".
+ */
+ String buffer = list.getBuffer();
+ int cursor = list.getBufferPosition();
+ 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();
+ }
+
+ /**
+ * 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/2e3c3ef9/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml
----------------------------------------------------------------------
diff --git a/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml b/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml
index f8b8837..6c41a6e 100644
--- a/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml
+++ b/shell/console/src/main/resources/OSGI-INF/blueprint/karaf-console.xml
@@ -17,69 +17,14 @@
limitations under the License.
-->
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0">
-
- <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]">
- <ext:default-properties>
- <ext:property name="karaf.startLocalConsole" value="true"/>
- </ext:default-properties>
- </ext:property-placeholder>
-
- <reference id="commandProcessor" interface="org.apache.felix.service.command.CommandProcessor"/>
- <reference id="threadIO" interface="org.apache.felix.service.threadio.ThreadIO" />
-
- <bean id="consoleFactoryService" class="org.apache.karaf.shell.console.impl.jline.ConsoleFactoryService">
- <argument ref="blueprintBundleContext"/>
- <argument ref="commandProcessor"/>
- <argument ref="threadIO"/>
- </bean>
- <service interface="org.apache.karaf.shell.console.factory.ConsoleFactory" ref="consoleFactoryService"/>
-
- <bean id="consoleFactory" class="org.apache.karaf.shell.console.impl.jline.LocalConsoleManager"
- destroy-method="stop">
- <argument value="$[karaf.startLocalConsole]"/>
- <argument value="$[org.osgi.framework.startlevel.beginning]"/>
- <argument ref="blueprintBundleContext"/>
- <argument ref="terminalFactory"/>
- <argument ref="consoleFactoryService"/>
- </bean>
-
- <bean id="converters" class="org.apache.karaf.shell.console.impl.Converters">
- <argument ref="blueprintBundleContext"/>
- </bean>
- <service ref="converters" interface="org.apache.felix.service.command.Converter"/>
-
- <bean id="terminalFactory" class="org.apache.karaf.shell.console.impl.jline.TerminalFactory"
- destroy-method="destroy"/>
-
- <service>
- <interfaces>
- <value>org.apache.felix.service.command.Function</value>
- <value>org.apache.karaf.shell.console.CompletableFunction</value>
- </interfaces>
- <service-properties>
- <entry key="osgi.command.scope" value="*"/>
- <entry key="osgi.command.function" value="exit"/>
- </service-properties>
- <bean class="org.apache.karaf.shell.console.commands.BlueprintCommand">
- <property name="blueprintContainer" ref="blueprintContainer"/>
- <property name="blueprintConverter" ref="blueprintConverter"/>
- <property name="actionId" value="exit"/>
- </bean>
- </service>
-
- <bean id="exit" class="org.apache.karaf.shell.console.ExitAction" activation="lazy" scope="prototype"/>
-
- <!-- Get a reference to the Configuration Admin Service -->
- <reference id="configAdmin" interface="org.osgi.service.cm.ConfigurationAdmin"/>
-
- <!-- For role-based security on the shell commands -->
- <bean id="secureCommandConfigTransformer"
- class="org.apache.karaf.shell.security.impl.SecuredCommandConfigTransformer"
- init-method="init">
- <property name="configAdmin" ref="configAdmin"/>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+ <bean id="commandTracker" class="org.apache.karaf.shell.compat.CommandTracker"
+ init-method="init" destroy-method="destroy">
+ <property name="context" ref="blueprintBundleContext" />
+ <property name="sessionFactory">
+ <reference interface="org.apache.karaf.shell.api.console.SessionFactory" />
+ </property>
</bean>
- <service ref="secureCommandConfigTransformer" interface="org.osgi.service.cm.ConfigurationListener"/>
</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e3c3ef9/shell/console/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/shell/console/src/main/resources/OSGI-INF/bundle.info b/shell/console/src/main/resources/OSGI-INF/bundle.info
index 4d4296e..23fcee4 100644
--- a/shell/console/src/main/resources/OSGI-INF/bundle.info
+++ b/shell/console/src/main/resources/OSGI-INF/bundle.info
@@ -9,8 +9,6 @@ Maven URL:
h1. Description
-This bundle provides the integration of Apache Felix Gogo, shell, and console.
-
-It provides the default Karaf branding including the default welcome message.
+This bundle provides the compatibility layer with Karaf 2.x and 3.x console.
h1. See also