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:23 UTC
[01/10] [KARAF-2805] Clean console and commands model
Repository: karaf
Updated Branches:
refs/heads/master bd56b49b0 -> 2e2b9324d
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/AggregateCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/AggregateCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/AggregateCompleter.java
new file mode 100644
index 0000000..580f4d2
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/AggregateCompleter.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.karaf.shell.support.completers;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+
+/**
+ * Completer which contains multiple 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 Session session, final CommandLine commandLine, 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(session, completer, commandLine);
+
+ // Compute the max cursor position
+ if (completion.cursor > max) {
+ completions.clear();
+ completions.add(completion);
+ max = completion.cursor;
+ } else if (completion.cursor == max) {
+ completions.add(completion);
+ }
+ }
+
+ // Append candidates from completions which have the same cursor position as max
+ for (Completion completion : completions) {
+ // 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 Session session, final Completer completer, final CommandLine commandLine) {
+ assert completer != null;
+
+ this.cursor = completer.complete(session, commandLine, candidates);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandNamesCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandNamesCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandNamesCompleter.java
new file mode 100644
index 0000000..3f41fe1
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandNamesCompleter.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.support.completers;
+
+import org.apache.karaf.shell.api.console.Completer;
+
+/**
+ * Marker class. An instance of this class is published by the console.
+ */
+public abstract class CommandNamesCompleter implements Completer {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandsCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandsCompleter.java
new file mode 100644
index 0000000..756c276
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/CommandsCompleter.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.support.completers;
+
+import org.apache.karaf.shell.api.console.Completer;
+
+/**
+ * Marker class. An instance of this class is published by the console.
+ */
+public abstract class CommandsCompleter implements Completer {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/FileCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/FileCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/FileCompleter.java
new file mode 100644
index 0000000..20a812f
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/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.support.completers;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+
+/**
+ * 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 static boolean isWindows() {
+ return (OS.indexOf("win") >= 0);
+
+ }
+
+ public int complete(final Session session, CommandLine commandLine, final List<String> candidates) {
+ // buffer can be null
+ if (candidates == null) {
+ return 0;
+ }
+
+ String buffer = commandLine.getBuffer();
+ 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/NullCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/NullCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/NullCompleter.java
new file mode 100644
index 0000000..4347fe3
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/NullCompleter.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.support.completers;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+public class NullCompleter implements Completer {
+
+ public static final NullCompleter INSTANCE = new NullCompleter();
+
+ public int complete(final Session session, CommandLine commandLine, List<String> candidates) {
+ return -1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/completers/StringsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/completers/StringsCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/StringsCompleter.java
new file mode 100644
index 0000000..1317095
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/completers/StringsCompleter.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.support.completers;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+
+/**
+ * Completer for a set of strings.
+ */
+public class StringsCompleter
+ implements Completer
+{
+ private final SortedSet<String> strings;
+ private final boolean caseSensitive;
+
+ public StringsCompleter() {
+ this(true);
+ }
+
+ public StringsCompleter(final boolean caseSensitive) {
+ this.strings = new TreeSet<String>(new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return caseSensitive ? o1.compareTo(o2) : o1.compareToIgnoreCase(o2);
+ }
+ });
+ 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(final Session session, final CommandLine commandLine, final List<String> candidates) {
+ // buffer could be null
+ assert candidates != null;
+
+ String buffer = commandLine.getBuffer();
+ 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/converter/DefaultConverter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/converter/DefaultConverter.java b/shell/core/src/main/java/org/apache/karaf/shell/support/converter/DefaultConverter.java
new file mode 100644
index 0000000..cc75c1e
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/converter/DefaultConverter.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.support.converter;
+
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+
+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 (String.class.isAssignableFrom(toClass(type))) {
+ return fromValue.toString();
+ } else 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/converter/GenericType.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/converter/GenericType.java b/shell/core/src/main/java/org/apache/karaf/shell/support/converter/GenericType.java
new file mode 100644
index 0000000..13e3bbe
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/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.support.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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/converter/ReifiedType.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/converter/ReifiedType.java b/shell/core/src/main/java/org/apache/karaf/shell/support/converter/ReifiedType.java
new file mode 100644
index 0000000..6f89857
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/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.support.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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/AnsiColumn.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/AnsiColumn.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/AnsiColumn.java
new file mode 100644
index 0000000..4d5b0e7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/AnsiColumn.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.support.table;
+
+import org.fusesource.jansi.Ansi;
+
+/**
+ * Colored support for column.
+ */
+public class AnsiColumn extends Col {
+
+ private Ansi.Color color;
+ private boolean bold;
+
+ public AnsiColumn(String header, Ansi.Color color, boolean bold) {
+ super(header);
+ this.color = color;
+ this.bold = bold;
+ }
+
+ @Override
+ public String getContent(String content) {
+ String in = super.getContent(content);
+
+ Ansi ansi = Ansi.ansi();
+ ansi.fg(color);
+
+ if (bold)
+ ansi.a(Ansi.Attribute.INTENSITY_BOLD);
+
+ ansi.a(in);
+
+ if (bold)
+ ansi.a(Ansi.Attribute.INTENSITY_BOLD_OFF);
+
+ ansi.fg(Ansi.Color.DEFAULT);
+
+ return ansi.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/Col.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/Col.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/Col.java
new file mode 100644
index 0000000..e3cc51d
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/Col.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.support.table;
+
+/**
+ * Column definition.
+ */
+public class Col {
+
+ /**
+ * Column header.
+ */
+ private String header;
+
+ /**
+ * Maximum size of this column. The default -1 means the column
+ * may grow indefinitely
+ */
+ int maxSize = -1;
+
+ int size = 0;
+
+ /**
+ * Alignment
+ */
+ private HAlign align = HAlign.left;
+
+ public Col(String header) {
+ this.header = header;
+ }
+
+ public Col align(HAlign align) {
+ this.align = align;
+ return this;
+ }
+
+ public Col alignLeft() {
+ this.align = HAlign.left;
+ return this;
+ }
+
+ public Col alignRight() {
+ this.align = HAlign.right;
+ return this;
+ }
+
+ public Col alignCenter() {
+ this.align = HAlign.center;
+ return this;
+ }
+
+ public Col maxSize(int maxSize) {
+ this.maxSize = maxSize;
+ return this;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ protected void updateSize(int cellSize) {
+ if (this.size <= cellSize) {
+ this.size = getClippedSize(cellSize);
+ }
+ }
+
+ private int getClippedSize(int cellSize) {
+ return this.maxSize == -1 ? cellSize : Math.min(cellSize, this.maxSize);
+ }
+
+ String format(Object cellData) {
+ if (cellData == null) {
+ cellData = "";
+ }
+ String fullContent = String.format("%s", cellData);
+ if (fullContent.length() == 0) {
+ return "";
+ }
+ String finalContent = fullContent.substring(0, getClippedSize(fullContent.length()));
+ updateSize(finalContent.length());
+ return finalContent;
+ }
+
+ String getHeader() {
+ return header;
+ }
+
+ String getContent(String content) {
+ return this.align.position(cut(content, this.size), this.size);
+ }
+
+ private String cut(String content, int size) {
+ if (content.length() <= size) {
+ return content;
+ } else {
+ return content.substring(0, Math.max(0, size - 1));
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/HAlign.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/HAlign.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/HAlign.java
new file mode 100644
index 0000000..9869a2c
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/HAlign.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.support.table;
+
+import static org.apache.karaf.shell.support.table.StringUtil.length;
+import static org.apache.karaf.shell.support.table.StringUtil.repeat;
+
+/**
+ * Enumeration type which contains all possible horizontal alignments.
+ */
+public enum HAlign {
+
+ /**
+ * Center align.
+ */
+ center {
+ @Override
+ public String position(String text, int colWidth) {
+ int width = colWidth - length(text);
+ text = repeat(" ", width / 2) + text + repeat(" ", width / 2);
+ if (length(text) < colWidth) {
+ // if colWidth is odd we add space at the end.
+ text += " ";
+ }
+ return text;
+ }
+ },
+
+ /**
+ * Left align.
+ */
+ left {
+ @Override
+ public String position(String text, int colWidth) {
+ return text + repeat(" ", colWidth - length(text));
+ }
+ },
+
+ /**
+ * Right align.
+ */
+ right {
+ @Override
+ public String position(String text, int colWidth) {
+ return repeat(" ", colWidth - length(text)) + text;
+ }
+ };
+
+ /**
+ * Calculate text position.
+ *
+ * @param text Text
+ * @param colWidth
+ * @return
+ */
+ public abstract String position(String text, int colWidth);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/Row.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/Row.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/Row.java
new file mode 100644
index 0000000..771eb25
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/Row.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.support.table;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Row {
+ private List<Object> data;
+ private List<String> content;
+
+ Row() {
+ data = new ArrayList<Object>();
+ content = new ArrayList<String>();
+ }
+
+ Row(List<Col> cols) {
+ this();
+ for (Col col : cols) {
+ data.add(col.getHeader());
+ }
+ }
+
+ public void addContent(Object ... cellDataAr) {
+ data.addAll(Arrays.asList(cellDataAr));
+ }
+
+ void formatContent(List<Col> cols) {
+ content.clear();
+ int c = 0;
+ for (Col col : cols) {
+ content.add(col.format(data.get(c)));
+ c++;
+ }
+ }
+
+ String getContent(List<Col> cols, String separator) {
+ StringBuilder st = new StringBuilder();
+ int c = 0;
+ if (cols.size() != content.size()) {
+ throw new RuntimeException("Number of columns and number of content elements do not match");
+ }
+
+ for (Col col : cols) {
+ st.append(col.getContent(content.get(c)));
+ if (c + 1 < cols.size()) {
+ st.append(separator);
+ }
+ c++;
+ }
+
+ return st.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/ShellTable.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/ShellTable.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/ShellTable.java
new file mode 100644
index 0000000..257014f
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/ShellTable.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.support.table;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ShellTable {
+
+ private List<Col> cols = new ArrayList<Col>();
+ private List<Row> rows = new ArrayList<Row>();
+ boolean showHeaders = true;
+ private String separator = " | ";
+ private int size;
+ private String emptyTableText;
+
+ public ShellTable() {
+
+ }
+
+ public ShellTable noHeaders() {
+ this.showHeaders = false;
+ return this;
+ }
+
+ public ShellTable separator(String separator) {
+ this.separator = separator;
+ return this;
+ }
+
+ public ShellTable size(int size) {
+ this.size = size;
+ return this;
+ }
+
+ public ShellTable column(Col colunmn) {
+ cols.add(colunmn);
+ return this;
+ }
+
+ public Col column(String header) {
+ Col col = new Col(header);
+ cols.add(col);
+ return col;
+ }
+
+ public Row addRow() {
+ Row row = new Row();
+ rows.add(row);
+ return row;
+ }
+
+ /**
+ * Set text to display if there are no rows in the table
+ * @param text
+ * @return
+ */
+ public ShellTable emptyTableText(String text) {
+ this.emptyTableText = text;
+ return this;
+ }
+
+ public void print(PrintStream out) {
+ print(out, true);
+ }
+
+ public void print(PrintStream out, boolean format) {
+
+ // "normal" table rendering, with borders
+ Row headerRow = new Row(cols);
+ headerRow.formatContent(cols);
+ for (Row row : rows) {
+ row.formatContent(cols);
+ }
+
+ if (size > 0) {
+ tryGrowToMaxSize();
+ }
+
+ if (format && showHeaders) {
+ String headerLine = headerRow.getContent(cols, separator);
+ out.println(headerLine);
+ for (Col col : cols) {
+ out.print(underline(col.getSize()));
+ }
+ out.println(underline((cols.size() - 1) * 3));
+ }
+
+ for (Row row : rows) {
+ if (!format) {
+ if (separator == null || separator.equals(" | "))
+ out.println(row.getContent(cols, "\t"));
+ else out.println(row.getContent(cols, separator));
+ } else {
+ out.println(row.getContent(cols, separator));
+ }
+ }
+
+ if (format && rows.size() == 0 && emptyTableText != null) {
+ out.println(emptyTableText);
+ }
+ }
+
+ private void tryGrowToMaxSize() {
+ int currentSize = 0;
+ for (Col col : cols) {
+ currentSize += col.size + separator.length();
+ }
+ currentSize -= separator.length();
+ int sizeToGrow = size - currentSize;
+
+ for (Col col : cols) {
+ if (col.maxSize == -1) {
+ col.size = Math.max(0, col.size + sizeToGrow);
+ return;
+ }
+ }
+
+ }
+
+ private String underline(int length) {
+ char[] exmarks = new char[length];
+ Arrays.fill(exmarks, '-');
+ return new String(exmarks);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/table/StringUtil.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/table/StringUtil.java b/shell/core/src/main/java/org/apache/karaf/shell/support/table/StringUtil.java
new file mode 100644
index 0000000..b1f3ab5
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/table/StringUtil.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.support.table;
+
+class StringUtil {
+
+ /**
+ * Returns length of the string.
+ *
+ * @param string String.
+ * @return Length.
+ */
+ public static int length(String string) {
+ return string == null ? 0 : string.length();
+ }
+
+ /**
+ * Utility method to repeat string.
+ *
+ * @param string String to repeat.
+ * @param times Number of times.
+ * @return Repeat string.
+ */
+ public static String repeat(String string, int times) {
+ if (times <= 0) {
+ return "";
+ }
+ else if (times % 2 == 0) {
+ return repeat(string+string, times/2);
+ }
+ else {
+ return string + repeat(string+string, times/2);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/resources/OSGI-INF/bundle.info
----------------------------------------------------------------------
diff --git a/shell/core/src/main/resources/OSGI-INF/bundle.info b/shell/core/src/main/resources/OSGI-INF/bundle.info
new file mode 100644
index 0000000..4d4296e
--- /dev/null
+++ b/shell/core/src/main/resources/OSGI-INF/bundle.info
@@ -0,0 +1,16 @@
+h1. Synopsis
+
+${project.name}
+
+${project.description}
+
+Maven URL:
+[mvn:${project.groupId}/${project.artifactId}/${project.version}]
+
+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.
+
+h1. See also
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/pom.xml
----------------------------------------------------------------------
diff --git a/shell/pom.xml b/shell/pom.xml
index d8dc873..1ab6361 100644
--- a/shell/pom.xml
+++ b/shell/pom.xml
@@ -35,6 +35,7 @@
<modules>
<module>commands</module>
+ <module>core</module>
<module>console</module>
<module>ssh</module>
<module>help</module>
[10/10] git commit: [KARAF-2805] Migrate shell, ssh, wrapper, kar,
instance,
features and bundle to the new API and switch the bin/shell script to use the
new console
Posted by gn...@apache.org.
[KARAF-2805] Migrate shell, ssh, wrapper, kar, instance, features and bundle to the new API and switch the bin/shell script to use 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/2e2b9324
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/2e2b9324
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/2e2b9324
Branch: refs/heads/master
Commit: 2e2b9324d4a65076b119239edc8920185914dc60
Parents: 2e3c3ef
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Wed Mar 5 15:42:44 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Wed Mar 5 15:53:17 2014 +0100
----------------------------------------------------------------------
.../main/filtered-resources/resources/bin/shell | 4 +-
.../filtered-resources/resources/bin/shell.bat | 4 +-
bundle/command/pom.xml | 3 +-
.../karaf/bundle/command/BundleCommand.java | 16 +-
.../command/BundleCommandWithConfirmation.java | 4 +-
.../karaf/bundle/command/BundlesCommand.java | 23 +-
.../command/BundlesCommandWithConfirmation.java | 4 +-
.../karaf/bundle/command/Capabilities.java | 8 +-
.../apache/karaf/bundle/command/Classes.java | 12 +-
.../org/apache/karaf/bundle/command/Diag.java | 6 +-
.../karaf/bundle/command/DynamicImport.java | 5 +-
.../apache/karaf/bundle/command/FindClass.java | 29 +-
.../apache/karaf/bundle/command/Headers.java | 18 +-
.../org/apache/karaf/bundle/command/Info.java | 6 +-
.../apache/karaf/bundle/command/Install.java | 24 +-
.../bundle/command/ListBundleServices.java | 21 +-
.../karaf/bundle/command/ListBundles.java | 23 +-
.../apache/karaf/bundle/command/LoadTest.java | 29 +-
.../apache/karaf/bundle/command/Refresh.java | 6 +-
.../karaf/bundle/command/Requirements.java | 8 +-
.../apache/karaf/bundle/command/Resolve.java | 6 +-
.../apache/karaf/bundle/command/Restart.java | 6 +-
.../karaf/bundle/command/ShowBundleTree.java | 8 +-
.../org/apache/karaf/bundle/command/Start.java | 4 +-
.../apache/karaf/bundle/command/StartLevel.java | 15 +-
.../org/apache/karaf/bundle/command/Stop.java | 6 +-
.../apache/karaf/bundle/command/Uninstall.java | 4 +-
.../org/apache/karaf/bundle/command/Update.java | 6 +-
.../org/apache/karaf/bundle/command/Watch.java | 17 +-
.../OSGI-INF/blueprint/shell-bundles.xml | 25 --
.../karaf/bundle/command/ListServicesTest.java | 6 +-
features/command/pom.xml | 14 +-
.../command/FeaturesCommandSupport.java | 11 +-
.../features/command/InfoFeatureCommand.java | 16 +-
.../features/command/InstallFeatureCommand.java | 14 +-
.../command/ListFeatureVersionsCommand.java | 12 +-
.../features/command/ListFeaturesCommand.java | 6 +-
.../karaf/features/command/RepoAddCommand.java | 12 +-
.../karaf/features/command/RepoListCommand.java | 8 +-
.../features/command/RepoRefreshCommand.java | 8 +-
.../features/command/RepoRemoveCommand.java | 14 +-
.../command/UninstallFeatureCommand.java | 18 +-
.../command/completers/AllFeatureCompleter.java | 2 +-
.../completers/AvailableFeatureCompleter.java | 2 +-
.../completers/AvailableRepoNameCompleter.java | 15 +-
.../completers/FeatureCompleterSupport.java | 12 +-
.../completers/InstalledFeatureCompleter.java | 2 +-
.../completers/InstalledRepoNameCompleter.java | 14 +-
.../completers/InstalledRepoUriCompleter.java | 14 +-
.../OSGI-INF/blueprint/features-command.xml | 27 --
instance/command/pom.xml | 6 +-
.../instance/command/ChangeOptsCommand.java | 10 +-
.../command/ChangeRmiRegistryPortCommand.java | 10 +-
.../command/ChangeRmiServerPortCommand.java | 10 +-
.../instance/command/ChangeSshPortCommand.java | 10 +-
.../karaf/instance/command/CloneCommand.java | 12 +-
.../karaf/instance/command/ConnectCommand.java | 17 +-
.../karaf/instance/command/CreateCommand.java | 14 +-
.../karaf/instance/command/DestroyCommand.java | 10 +-
.../command/InstanceCommandSupport.java | 12 +-
.../karaf/instance/command/ListCommand.java | 6 +-
.../karaf/instance/command/RenameCommand.java | 12 +-
.../karaf/instance/command/StartCommand.java | 12 +-
.../karaf/instance/command/StatusCommand.java | 11 +-
.../karaf/instance/command/StopCommand.java | 10 +-
.../command/completers/InstanceCompleter.java | 14 +-
.../org/apache/karaf/instance/main/Execute.java | 21 +-
.../services/org/apache/karaf/shell/commands | 30 +++
.../OSGI-INF/blueprint/instance-command.xml | 26 --
instance/core/pom.xml | 2 +-
.../core/internal/InstanceServiceImpl.java | 7 +
kar/command/pom.xml | 3 +-
.../karaf/kar/command/CreateKarCommand.java | 25 +-
.../karaf/kar/command/InstallKarCommand.java | 22 +-
.../karaf/kar/command/KarCommandSupport.java | 38 ---
.../karaf/kar/command/ListKarCommand.java | 21 +-
.../karaf/kar/command/UninstallKarCommand.java | 23 +-
.../kar/command/completers/KarCompleter.java | 26 +-
.../OSGI-INF/blueprint/kar-command.xml | 23 --
shell/commands/pom.xml | 5 +-
.../karaf/shell/commands/InfoProvider.java | 30 +++
.../karaf/shell/commands/impl/AliasAction.java | 18 +-
.../karaf/shell/commands/impl/CatAction.java | 19 +-
.../karaf/shell/commands/impl/ClearAction.java | 15 +-
.../shell/commands/impl/CompletionAction.java | 36 +--
.../karaf/shell/commands/impl/DateAction.java | 15 +-
.../karaf/shell/commands/impl/EachAction.java | 19 +-
.../karaf/shell/commands/impl/EchoAction.java | 15 +-
.../karaf/shell/commands/impl/EditAction.java | 40 ++-
.../shell/commands/impl/ExecuteAction.java | 17 +-
.../karaf/shell/commands/impl/GrepAction.java | 16 +-
.../karaf/shell/commands/impl/HeadAction.java | 19 +-
.../shell/commands/impl/HistoryAction.java | 30 ++-
.../karaf/shell/commands/impl/IfAction.java | 19 +-
.../karaf/shell/commands/impl/InfoAction.java | 45 +++-
.../karaf/shell/commands/impl/JavaAction.java | 19 +-
.../karaf/shell/commands/impl/LogoutAction.java | 24 +-
.../karaf/shell/commands/impl/MoreAction.java | 56 ++--
.../karaf/shell/commands/impl/NewAction.java | 20 +-
.../commands/impl/PrintStackTracesAction.java | 21 +-
.../karaf/shell/commands/impl/PrintfAction.java | 14 +-
.../karaf/shell/commands/impl/SleepAction.java | 19 +-
.../karaf/shell/commands/impl/SortAction.java | 20 +-
.../karaf/shell/commands/impl/SourceAction.java | 24 +-
.../karaf/shell/commands/impl/TacAction.java | 18 +-
.../karaf/shell/commands/impl/TailAction.java | 20 +-
.../shell/commands/impl/ThreadsAction.java | 15 +-
.../karaf/shell/commands/impl/WatchAction.java | 64 ++---
.../karaf/shell/commands/impl/WcAction.java | 15 +-
.../services/org/apache/karaf/shell/commands | 10 +-
.../OSGI-INF/blueprint/shell-commands.xml | 4 +-
.../karaf/shell/commands/impl/GrepTest.java | 5 +-
.../karaf/shell/commands/impl/ThreadsTest.java | 8 +-
shell/ssh/pom.xml | 14 +-
.../org/apache/karaf/shell/ssh/Activator.java | 268 +++++++++++++++++++
.../apache/karaf/shell/ssh/ActivatorNoOsgi.java | 33 +++
.../karaf/shell/ssh/KarafAgentFactory.java | 18 +-
.../karaf/shell/ssh/KarafJaasAuthenticator.java | 7 +
.../apache/karaf/shell/ssh/ShellCommand.java | 22 +-
.../karaf/shell/ssh/ShellCommandFactory.java | 10 +-
.../karaf/shell/ssh/ShellFactoryImpl.java | 39 +--
.../org/apache/karaf/shell/ssh/SshAction.java | 50 ++--
.../apache/karaf/shell/ssh/SshServerAction.java | 33 +--
.../karaf/shell/ssh/SshServerFactory.java | 77 ------
.../org/apache/karaf/shell/ssh/SshTerminal.java | 30 ++-
.../shell/ssh/UserAuthFactoriesFactory.java | 33 +--
.../shell/ssh/util/SingleServiceTracker.java | 171 ++++++++++++
.../services/org/apache/karaf/shell/commands | 17 ++
.../resources/OSGI-INF/blueprint/shell-ssh.xml | 149 -----------
wrapper/command/pom.xml | 12 +-
.../apache/karaf/wrapper/commands/Install.java | 38 ++-
.../services/org/apache/karaf/shell/commands | 1 +
.../OSGI-INF/blueprint/wrapper-commands.xml | 26 --
wrapper/core/pom.xml | 2 +-
134 files changed, 1568 insertions(+), 1236 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
----------------------------------------------------------------------
diff --git a/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell b/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
index 7f66eaa..bb62d23 100755
--- a/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
+++ b/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell
@@ -272,7 +272,7 @@ setupDefaults() {
fi
# Setup classpath
- CLASSPATH="$KARAF_HOME/system/org/apache/karaf/shell/org.apache.karaf.shell.console/${project.version}/org.apache.karaf.shell.console-${project.version}.jar"
+ CLASSPATH="$KARAF_HOME/system/org/apache/karaf/shell/org.apache.karaf.shell.core/${project.version}/org.apache.karaf.shell.core-${project.version}.jar"
CLASSPATH="$CLASSPATH:$KARAF_HOME/system/org/ops4j/pax/logging/pax-logging-api/${pax.logging.version}/pax-logging-api-${pax.logging.version}.jar"
CLASSPATH="$CLASSPATH:$KARAF_HOME/system/jline/jline/${jline.version}/jline-${jline.version}.jar"
@@ -331,7 +331,7 @@ run() {
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
fi
- exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Dkaraf.etc="$KARAF_ETC" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.shell.console.impl.Main --classpath="$KARAF_HOME/system" "$@"
+ exec "$JAVA" $JAVA_OPTS -Dkaraf.instances="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Dkaraf.etc="$KARAF_ETC" -Djava.io.tmpdir="$KARAF_DATA/tmp" -Djava.util.logging.config.file="$KARAF_BASE/etc/java.util.logging.properties" $KARAF_OPTS $OPTS -classpath "$CLASSPATH" org.apache.karaf.shell.impl.console.standalone.Main --classpath="$KARAF_HOME/system" "$@"
}
main() {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
----------------------------------------------------------------------
diff --git a/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat b/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
index c4734f8..69b7a72 100644
--- a/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
+++ b/assemblies/features/framework/src/main/filtered-resources/resources/bin/shell.bat
@@ -121,7 +121,7 @@ if "%KARAF_DEBUG%" == "" goto :KARAF_DEBUG_END
call :warn Enabling Java debug options: %JAVA_DEBUG_OPTS%
:KARAF_DEBUG_END
-set CLASSPATH=%KARAF_HOME%\system\org\apache\karaf\shell\org.apache.karaf.shell.console\${project.version}\org.apache.karaf.shell.console-${project.version}.jar
+set CLASSPATH=%KARAF_HOME%\system\org\apache\karaf\shell\org.apache.karaf.shell.core\${project.version}\org.apache.karaf.shell.core-${project.version}.jar
set CLASSPATH=%CLASSPATH%;%KARAF_HOME%\system\org\ops4j\pax\logging\pax-logging-api\${pax.logging.version}\pax-logging-api-${pax.logging.version}.jar
set CLASSPATH=%CLASSPATH%;%KARAF_HOME%\system\jline\jline\${jline.version}\jline-${jline.version}.jar
@@ -129,7 +129,7 @@ set CLASSPATH=%CLASSPATH%;%KARAF_HOME%\system\jline\jline\${jline.version}\jline
if "%SHIFT%" == "true" SET ARGS=%2 %3 %4 %5 %6 %7 %8
if not "%SHIFT%" == "true" SET ARGS=%1 %2 %3 %4 %5 %6 %7 %8
rem Execute the Java Virtual Machine
- "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Dkaraf.etc="%KARAF_ETC%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" %KARAF_OPTS% org.apache.karaf.shell.console.impl.Main --classpath="%KARAF_HOME%\system" %ARGS%
+ "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.instances="%KARAF_HOME%\instances" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Dkaraf.etc="%KARAF_ETC%" -Djava.io.tmpdir="%KARAF_DATA%\tmp" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" %KARAF_OPTS% org.apache.karaf.shell.impl.console.standalone.Main --classpath="%KARAF_HOME%\system" %ARGS%
rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/pom.xml
----------------------------------------------------------------------
diff --git a/bundle/command/pom.xml b/bundle/command/pom.xml
index ebfa147..d6bd26a 100644
--- a/bundle/command/pom.xml
+++ b/bundle/command/pom.xml
@@ -44,7 +44,7 @@
</dependency>
<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.bundle</groupId>
@@ -107,6 +107,7 @@
org.apache.felix.utils.version;-split-package:=merge-first,
org.apache.felix.utils.manifest;-split-package:=merge-first
</Private-Package>
+ <Karaf-Commands>org.apache.karaf.bundle.command.*</Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommand.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommand.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommand.java
index 9aa6c89..dce0ca8 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommand.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommand.java
@@ -17,16 +17,17 @@
package org.apache.karaf.bundle.command;
import org.apache.karaf.bundle.core.BundleService;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
/**
* Unique bundle command.
*/
-public abstract class BundleCommand extends OsgiCommandSupport {
+public abstract class BundleCommand implements Action {
@Argument(index = 0, name = "id", description = "The bundle ID or name or name/version", required = true, multiValued = false)
String id;
@@ -36,11 +37,14 @@ public abstract class BundleCommand extends OsgiCommandSupport {
@Reference
BundleService bundleService;
+ @Reference
+ BundleContext bundleContext;
+
public BundleCommand(boolean defaultAllBundles) {
this.defaultAllBundles = defaultAllBundles;
}
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
return doExecute(true);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommandWithConfirmation.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommandWithConfirmation.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommandWithConfirmation.java
index 66c324c..c07a357 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommandWithConfirmation.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundleCommandWithConfirmation.java
@@ -16,7 +16,7 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.api.action.Option;
/**
* Unique bundle command with confirmation while accessing system bundle.
@@ -30,7 +30,7 @@ public abstract class BundleCommandWithConfirmation extends BundleCommand {
super(true);
}
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
return doExecute(force);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommand.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommand.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommand.java
index 6a421fe..ff4dd53 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommand.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommand.java
@@ -19,13 +19,14 @@ package org.apache.karaf.bundle.command;
import java.util.List;
import org.apache.karaf.bundle.core.BundleService;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
-public abstract class BundlesCommand extends OsgiCommandSupport {
+public abstract class BundlesCommand implements Action {
@Argument(index = 0, name = "ids", description = "The list of bundle (identified by IDs or name or name/version) separated by whitespaces", required = false, multiValued = true)
List<String> ids;
@@ -33,13 +34,21 @@ public abstract class BundlesCommand extends OsgiCommandSupport {
boolean defaultAllBundles = true;
@Reference
+ BundleContext bundleContext;
+
+ @Reference
BundleService bundleService;
public BundlesCommand(boolean defaultAllBundles) {
this.defaultAllBundles = defaultAllBundles;
}
-
- protected Object doExecute() throws Exception {
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public Object execute() throws Exception {
doExecute(true);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommandWithConfirmation.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommandWithConfirmation.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommandWithConfirmation.java
index a6cc62b..271fc42 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommandWithConfirmation.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/BundlesCommandWithConfirmation.java
@@ -19,8 +19,8 @@ package org.apache.karaf.bundle.command;
import java.util.ArrayList;
import java.util.List;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.MultiException;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.support.MultiException;
import org.osgi.framework.Bundle;
/**
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Capabilities.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Capabilities.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Capabilities.java
index 4d8c694..de83a1d 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Capabilities.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Capabilities.java
@@ -22,10 +22,10 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Classes.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Classes.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Classes.java
index 3a9dc03..b0f80ff 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Classes.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Classes.java
@@ -16,15 +16,15 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.wiring.BundleWiring;
-
import java.util.Collection;
import java.util.List;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.wiring.BundleWiring;
+
@Command(scope = "bundle", name = "classes", description = "Displays a list of classes contained in the bundle")
@Service
public class Classes extends BundlesCommand {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Diag.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Diag.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Diag.java
index 0a70d72..1e8e11b 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Diag.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Diag.java
@@ -20,9 +20,9 @@ import java.util.List;
import org.apache.karaf.bundle.core.BundleInfo;
import org.apache.karaf.bundle.core.BundleState;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "diag", description = "Displays diagnostic information why a bundle is not Active")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/DynamicImport.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/DynamicImport.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/DynamicImport.java
index e2e4759..74fc20a 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/DynamicImport.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/DynamicImport.java
@@ -16,9 +16,8 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.bundle.core.BundleService;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
/**
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/FindClass.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/FindClass.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/FindClass.java
index afafd54..4a9fc75 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/FindClass.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/FindClass.java
@@ -17,31 +17,36 @@ package org.apache.karaf.bundle.command;
* limitations under the License.
*/
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
-import org.osgi.framework.wiring.BundleWiring;
-import org.osgi.framework.Bundle;
-
import java.util.Collection;
-import java.util.List;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
@Command(scope = "bundle", name = "find-class", description = "Locates a specified class in any deployed bundle")
@Service
-public class FindClass extends OsgiCommandSupport {
+public class FindClass implements Action {
@Argument(index = 0, name = "className", description = "Class name or partial class name to be found", required = true, multiValued = false)
String className;
- protected Object doExecute() throws Exception {
+ @Reference
+ BundleContext bundleContext;
+
+ @Override
+ public Object execute() throws Exception {
findResource();
return null;
}
protected void findResource() {
- Bundle[] bundles = getBundleContext().getBundles();
+ Bundle[] bundles = bundleContext.getBundles();
String filter = "*" + className + "*";
for (Bundle bundle:bundles){
BundleWiring wiring = bundle.adapt(BundleWiring.class);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Headers.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Headers.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Headers.java
index a173a90..16083ff 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Headers.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Headers.java
@@ -25,18 +25,18 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import jline.Terminal;
-
import org.apache.felix.utils.manifest.Attribute;
import org.apache.felix.utils.manifest.Clause;
import org.apache.felix.utils.manifest.Directive;
import org.apache.felix.utils.manifest.Parser;
import org.apache.felix.utils.version.VersionRange;
import org.apache.felix.utils.version.VersionTable;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.support.ShellUtil;
import org.fusesource.jansi.Ansi;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
@@ -57,6 +57,9 @@ public class Headers extends BundlesCommand {
@Option(name = "--indent", description = "Indentation method")
int indent = -1;
+
+ @Reference
+ Terminal terminal;
public Headers() {
super(true);
@@ -228,8 +231,7 @@ public class Headers extends BundlesCommand {
}
protected int getTermWidth() {
- Terminal term = (Terminal) session.get(".jline.terminal");
- return term != null ? term.getWidth() : 80;
+ return terminal.getWidth();
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Info.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Info.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Info.java
index 904c9d6..451ec87 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Info.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Info.java
@@ -25,9 +25,9 @@ import java.util.List;
import org.apache.karaf.bundle.command.wikidoc.AnsiPrintingWikiVisitor;
import org.apache.karaf.bundle.command.wikidoc.WikiParser;
import org.apache.karaf.bundle.command.wikidoc.WikiVisitor;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "info", description = "Displays detailed information of a given bundles.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Install.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Install.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Install.java
index 15604cc..11fba89 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Install.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Install.java
@@ -19,17 +19,19 @@ package org.apache.karaf.bundle.command;
import java.util.ArrayList;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.MultiException;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.MultiException;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
@Command(scope = "bundle", name = "install", description = "Installs one or more bundles.")
@Service
-public class Install extends OsgiCommandSupport {
+public class Install implements Action {
@Argument(index = 0, name = "urls", description = "Bundle URLs separated by whitespaces", required = true, multiValued = true)
List<String> urls;
@@ -37,12 +39,16 @@ public class Install extends OsgiCommandSupport {
@Option(name = "-s", aliases={"--start"}, description="Starts the bundles after installation", required = false, multiValued = false)
boolean start;
- protected Object doExecute() throws Exception {
+ @Reference
+ BundleContext bundleContext;
+
+ @Override
+ public Object execute() throws Exception {
List<Exception> exceptions = new ArrayList<Exception>();
List<Bundle> bundles = new ArrayList<Bundle>();
for (String url : urls) {
try {
- bundles.add(getBundleContext().installBundle(url, null));
+ bundles.add(bundleContext.installBundle(url, null));
} catch (Exception e) {
exceptions.add(new Exception("Unable to install bundle " + url, e));
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundleServices.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundleServices.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundleServices.java
index b813c52..28f8264 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundleServices.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundleServices.java
@@ -16,14 +16,15 @@
*/
package org.apache.karaf.bundle.command;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -40,6 +41,11 @@ public class ListBundleServices extends BundlesCommand {
@Option(name = "-p", aliases = {}, description = "Shows the properties of the services", required = false, multiValued = false)
boolean showProperties = false;
+
+ Set<String> hidden = new HashSet<String>(Arrays.asList(new String[] {
+ "org.apache.felix.service.command.Function",
+ "org.apache.karaf.shell.console.Completer"
+ }));
public ListBundleServices() {
super(true);
@@ -94,8 +100,7 @@ public class ListBundleServices extends BundlesCommand {
private boolean isCommandOrCompleter(String[] objectClasses) {
for (String objectClass : objectClasses) {
- if (objectClass.equals(Function.class.getName())
- || objectClass.equals(Completer.class.getName())) {
+ if (hidden.contains(objectClass)) {
return true;
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundles.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundles.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundles.java
index 1cc87ef..4ab0af9 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundles.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ListBundles.java
@@ -19,18 +19,19 @@ package org.apache.karaf.bundle.command;
import org.apache.karaf.bundle.core.BundleInfo;
import org.apache.karaf.bundle.core.BundleService;
import org.apache.karaf.bundle.core.BundleState;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
import org.osgi.framework.startlevel.FrameworkStartLevel;
@Command(scope = "bundle", name = "list", description = "Lists all installed bundles.")
@Service
-public class ListBundles extends OsgiCommandSupport {
+public class ListBundles implements Action {
@Option(name = "-l", aliases = {}, description = "Show the locations", required = false, multiValued = false)
boolean showLoc;
@@ -48,14 +49,18 @@ public class ListBundles extends OsgiCommandSupport {
boolean noFormat;
@Reference
+ BundleContext bundleContext;
+
+ @Reference
private BundleService bundleService;
public void setBundleService(BundleService bundleService) {
this.bundleService = bundleService;
}
- protected Object doExecute() throws Exception {
- Bundle[] bundles = getBundleContext().getBundles();
+ @Override
+ public Object execute() throws Exception {
+ Bundle[] bundles = bundleContext.getBundles();
if (bundles == null) {
System.out.println("There are no installed bundles.");
return null;
@@ -64,7 +69,7 @@ public class ListBundles extends OsgiCommandSupport {
determineBundleLevelThreshold();
// Display active start level.
- FrameworkStartLevel fsl = getBundleContext().getBundle(0).adapt(FrameworkStartLevel.class);
+ FrameworkStartLevel fsl = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class);
if (fsl != null) {
System.out.println("START LEVEL " + fsl.getStartLevel() + " , List Threshold: " + bundleLevelThreshold);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/LoadTest.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/LoadTest.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/LoadTest.java
index 6c8d6c3..7ca43b2 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/LoadTest.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/LoadTest.java
@@ -24,12 +24,12 @@ import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
-import jline.console.ConsoleReader;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkEvent;
@@ -38,7 +38,7 @@ import org.osgi.framework.wiring.FrameworkWiring;
@Command(scope = "bundle", name = "load-test", description = "Load test bundle lifecycle")
@Service
-public class LoadTest extends OsgiCommandSupport {
+public class LoadTest implements Action {
@Option(name = "--threads", description = "number of concurrent threads")
int threads = 2;
@@ -55,12 +55,18 @@ public class LoadTest extends OsgiCommandSupport {
@Option(name = "--excludes", description = "List of bundles (ids or symbolic names) to exclude")
List<String> excludes = Arrays.asList("0", "org.ops4j.pax.url.mvn", "org.ops4j.pax.logging.pax-logging-api", "org.ops4j.pax.logging.pax-logging-service");
+ @Reference
+ Session session;
+
+ @Reference
+ BundleContext bundleContext;
+
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
if (!confirm(session)) {
return null;
}
- final BundleContext bundleContext = getBundleContext().getBundle(0).getBundleContext();
+ final BundleContext bundleContext = this.bundleContext.getBundle(0).getBundleContext();
final FrameworkWiring wiring = bundleContext.getBundle().adapt(FrameworkWiring.class);
final CountDownLatch latch = new CountDownLatch(threads);
final Bundle[] bundles = bundleContext.getBundles();
@@ -159,11 +165,10 @@ public class LoadTest extends OsgiCommandSupport {
return null;
}
- private boolean confirm(CommandSession session) throws IOException {
+ private boolean confirm(Session session) throws IOException {
for (;;) {
- ConsoleReader reader = (ConsoleReader) session.get(".jline.reader");
String msg = "You are about to perform a start/stop/refresh load test on bundles.\nDo you wish to continue (yes/no): ";
- String str = reader.readLine(msg);
+ String str = session.readLine(msg, null);
if ("yes".equalsIgnoreCase(str)) {
return true;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Refresh.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Refresh.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Refresh.java
index bfd0c2d..53adaeb 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Refresh.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Refresh.java
@@ -18,8 +18,8 @@ package org.apache.karaf.bundle.command;
import java.util.List;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.wiring.FrameworkWiring;
@@ -32,7 +32,7 @@ public class Refresh extends BundlesCommandWithConfirmation {
}
protected void doExecute(List<Bundle> bundles) throws Exception {
- FrameworkWiring wiring = getBundleContext().getBundle(0).adapt(FrameworkWiring.class);
+ FrameworkWiring wiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class);
wiring.refreshBundles(bundles == null || bundles.isEmpty() ? null : bundles);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Requirements.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Requirements.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Requirements.java
index 3fdc004..c87d4d4 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Requirements.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Requirements.java
@@ -22,10 +22,10 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.ShellUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Resolve.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Resolve.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Resolve.java
index d72cfce..720f118 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Resolve.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Resolve.java
@@ -18,8 +18,8 @@ package org.apache.karaf.bundle.command;
import java.util.List;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.wiring.FrameworkWiring;
@@ -32,7 +32,7 @@ public class Resolve extends BundlesCommand {
}
protected void doExecute(List<Bundle> bundles) throws Exception {
- FrameworkWiring wiring = getBundleContext().getBundle(0).adapt(FrameworkWiring.class);
+ FrameworkWiring wiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class);
wiring.resolveBundles(bundles == null || bundles.isEmpty() ? null : bundles);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Restart.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Restart.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Restart.java
index 16d9b02..95d5dfe 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Restart.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Restart.java
@@ -19,9 +19,9 @@ package org.apache.karaf.bundle.command;
import java.util.ArrayList;
import java.util.List;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.MultiException;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.MultiException;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "restart", description = "Restarts bundles.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
index 1e44a4d..a83ce39 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/ShowBundleTree.java
@@ -16,8 +16,6 @@
*/
package org.apache.karaf.bundle.command;
-import static java.lang.String.format;
-
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -31,8 +29,8 @@ import org.apache.felix.utils.version.VersionRange;
import org.apache.felix.utils.version.VersionTable;
import org.apache.karaf.bundle.command.bundletree.Node;
import org.apache.karaf.bundle.command.bundletree.Tree;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.wiring.BundleCapability;
@@ -43,6 +41,8 @@ import org.osgi.framework.wiring.BundleWiring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static java.lang.String.format;
+
/**
* Command for showing the full tree of bundles that have been used to resolve
* a given bundle.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Start.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Start.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Start.java
index c3f1882..48e90fa 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Start.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Start.java
@@ -16,8 +16,8 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "start", description = "Starts bundles.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/StartLevel.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/StartLevel.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/StartLevel.java
index 117f21a..30bec0f 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/StartLevel.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/StartLevel.java
@@ -16,10 +16,11 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import jline.console.ConsoleReader;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.startlevel.BundleStartLevel;
@@ -30,6 +31,9 @@ public class StartLevel extends BundleCommandWithConfirmation {
@Argument(index = 1, name = "startLevel", description = "The bundle's new start level", required = false, multiValued = false)
Integer level;
+ @Reference
+ Session session;
+
protected void doExecute(Bundle bundle) throws Exception {
// Get package instance service.
BundleStartLevel bsl = bundle.adapt(BundleStartLevel.class);
@@ -42,9 +46,8 @@ public class StartLevel extends BundleCommandWithConfirmation {
}
else if ((level < 50) && (bsl.getStartLevel() > 50) && !force){
for (;;) {
- ConsoleReader reader = (ConsoleReader) session.get(".jline.reader");
String msg = "You are about to designate bundle as a system bundle. Do you wish to continue (yes/no): ";
- String str = reader.readLine(msg);
+ String str = session.readLine(msg, null);
if ("yes".equalsIgnoreCase(str)) {
bsl.setStartLevel(level);
break;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Stop.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Stop.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Stop.java
index c5408bc..0b0fed2 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Stop.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Stop.java
@@ -16,9 +16,9 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "stop", description = "Stop bundles.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Uninstall.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Uninstall.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Uninstall.java
index 04f15f2..67b5b14 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Uninstall.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Uninstall.java
@@ -16,8 +16,8 @@
*/
package org.apache.karaf.bundle.command;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "uninstall", description = "Uninstall bundles.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Update.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Update.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Update.java
index b19bed7..71ae74d 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Update.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Update.java
@@ -19,9 +19,9 @@ package org.apache.karaf.bundle.command;
import java.io.InputStream;
import java.net.URL;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
@Command(scope = "bundle", name = "update", description = "Update bundle.")
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/java/org/apache/karaf/bundle/command/Watch.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Watch.java b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Watch.java
index 715455b..9203f59 100644
--- a/bundle/command/src/main/java/org/apache/karaf/bundle/command/Watch.java
+++ b/bundle/command/src/main/java/org/apache/karaf/bundle/command/Watch.java
@@ -19,19 +19,18 @@ package org.apache.karaf.bundle.command;
import java.util.List;
import org.apache.karaf.bundle.core.BundleWatcher;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
@Command(scope = "bundle", name = "watch", description = "Watches and updates bundles", detailedDescription = "Watches the local maven repo for changes in snapshot jars and redploys changed jars")
@Service
-public class Watch extends OsgiCommandSupport {
+public class Watch implements Action {
@Argument(index = 0, name = "urls", description = "The bundle IDs or URLs", required = false, multiValued = true)
List<String> urls;
@@ -59,7 +58,7 @@ public class Watch extends OsgiCommandSupport {
}
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
if (start && stop) {
System.err.println("Please use only one of --start and --stop options!");
return null;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/main/resources/OSGI-INF/blueprint/shell-bundles.xml
----------------------------------------------------------------------
diff --git a/bundle/command/src/main/resources/OSGI-INF/blueprint/shell-bundles.xml b/bundle/command/src/main/resources/OSGI-INF/blueprint/shell-bundles.xml
deleted file mode 100644
index 327becd..0000000
--- a/bundle/command/src/main/resources/OSGI-INF/blueprint/shell-bundles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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">
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
- scan="org.apache.karaf.bundle.command.*" />
-
-</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
----------------------------------------------------------------------
diff --git a/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java b/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
index 4ddfbba..2c25a44 100644
--- a/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
+++ b/bundle/command/src/test/java/org/apache/karaf/bundle/command/ListServicesTest.java
@@ -38,7 +38,7 @@ public class ListServicesTest {
@Test
public void listAllShort() throws Exception {
System.out.println("listAllShort");
- listServices.doExecute();
+ listServices.execute();
}
@@ -46,7 +46,7 @@ public class ListServicesTest {
public void listAllLong() throws Exception {
System.out.println("listAllLong");
listServices.ids = Arrays.asList(new String[]{"1", "2"});
- listServices.doExecute();
+ listServices.execute();
}
@Test
@@ -54,7 +54,7 @@ public class ListServicesTest {
System.out.println("listAllLongServicesUse");
listServices.ids = Arrays.asList(new String[]{"1", "2"});
listServices.inUse = true;
- listServices.doExecute();
+ listServices.execute();
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/pom.xml
----------------------------------------------------------------------
diff --git a/features/command/pom.xml b/features/command/pom.xml
index 112d988..debe123 100644
--- a/features/command/pom.xml
+++ b/features/command/pom.xml
@@ -59,7 +59,7 @@
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
</dependencies>
@@ -85,17 +85,7 @@
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Import-Package>
- javax.management,
- javax.management.loading,
- org.apache.aries.blueprint,
- org.osgi.service.blueprint.container,
- org.osgi.service.blueprint.reflect,
- org.apache.felix.service.command,
- org.apache.karaf.shell.commands,
- org.apache.karaf.shell.console,
- *
- </Import-Package>
+ <Karaf-Commands>org.apache.karaf.features.command.*</Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
index caa8dfa..076650d 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/FeaturesCommandSupport.java
@@ -17,17 +17,18 @@
package org.apache.karaf.features.command;
import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
-public abstract class FeaturesCommandSupport extends OsgiCommandSupport {
+public abstract class FeaturesCommandSupport implements Action {
@Reference
private FeaturesService featuresService;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (featuresService == null) {
- featuresService = getService(FeaturesService.class);
+ throw new IllegalStateException("FeaturesService not found");
}
doExecute(featuresService);
return null;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
index c030953..7084a6e 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InfoFeatureCommand.java
@@ -21,18 +21,18 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import org.apache.karaf.features.Conditional;
-import org.apache.karaf.features.command.completers.AllFeatureCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
import org.apache.karaf.features.ConfigFileInfo;
import org.apache.karaf.features.Dependency;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.features.command.completers.AllFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "info", description = "Shows information about selected feature.")
@Service
@@ -43,7 +43,7 @@ public class InfoFeatureCommand extends FeaturesCommandSupport {
private static final String CONDITIONAL_CONTENT = "Conditional(%s)";
@Argument(index = 0, name = "name", description = "The name of the feature", required = true, multiValued = false)
- @Completer(AllFeatureCompleter.class)
+ @Completion(AllFeatureCompleter.class)
private String name;
@Argument(index = 1, name = "version", description = "The version of the feature", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
index 6323a23..e47edf0 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/InstallFeatureCommand.java
@@ -19,13 +19,13 @@ package org.apache.karaf.features.command;
import java.util.EnumSet;
import java.util.List;
-import org.apache.karaf.features.command.completers.AvailableFeatureCompleter;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.features.command.completers.AvailableFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "install", description = "Installs a feature with the specified name and version.")
@Service
@@ -34,7 +34,7 @@ public class InstallFeatureCommand extends FeaturesCommandSupport {
private static String DEFAULT_VERSION = "0.0.0";
@Argument(index = 0, name = "feature", description = "The name and version of the features to install. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
- @Completer(AvailableFeatureCompleter.class)
+ @Completion(AvailableFeatureCompleter.class)
List<String> features;
@Option(name = "-c", aliases = "--no-clean", description = "Do not uninstall bundles on failure", required = false, multiValued = false)
boolean noClean;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
index f3f042e..792825c 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeatureVersionsCommand.java
@@ -22,19 +22,19 @@ import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
import org.apache.karaf.features.command.completers.AllFeatureCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "version-list", description = "Lists all versions of a feature available from the currently available repositories.")
@Service
public class ListFeatureVersionsCommand extends FeaturesCommandSupport {
@Argument(index = 0, name = "feature", description = "Name of feature.", required = true, multiValued = false)
- @Completer(AllFeatureCompleter.class)
+ @Completion(AllFeatureCompleter.class)
String feature;
@Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
index 0a699c9..0cb6d3c 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/ListFeaturesCommand.java
@@ -24,10 +24,10 @@ import java.util.List;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "list", description = "Lists all existing features available from the defined repositories.")
@Service
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
index 0594228..16faf42 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoAddCommand.java
@@ -20,18 +20,18 @@ import java.net.URI;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.command.completers.AvailableRepoNameCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "repo-add", description = "Add a features repository")
@Service
public class RepoAddCommand extends FeaturesCommandSupport {
@Argument(index = 0, name = "name/url", description = "Shortcut name of the features repository or the full URL", required = true, multiValued = false)
- @Completer(AvailableRepoNameCompleter.class)
+ @Completion(AvailableRepoNameCompleter.class)
private String nameOrUrl;
@Argument(index = 1, name = "version", description = "The version of the features repository if using features repository name as first argument. It should be empty if using the URL", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
index b71f866..af180bd 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoListCommand.java
@@ -21,11 +21,11 @@ import java.util.List;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.MultiException;
-import org.apache.karaf.shell.inject.Service;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.MultiException;
@Command(scope = "feature", name = "repo-list", description = "Displays a list of all defined repositories.")
@Service
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
index 6930a93..8c7ed79 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRefreshCommand.java
@@ -23,14 +23,14 @@ import java.util.List;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
@Command(scope = "feature", name = "repo-refresh", description = "Refresh a features repository")
public class RepoRefreshCommand extends FeaturesCommandSupport {
@Argument(index = 0, name = "Feature name or uri", description = "Shortcut name of the feature repository or the full URI", required = false, multiValued = false)
- @Completer(InstalledRepoUriCompleter.class)
+ @Completion(InstalledRepoUriCompleter.class)
private String nameOrUrl;
@Argument(index = 1, name = "Feature version", description = "The version of the feature if using the feature name. Should be empty if using the uri", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
index 4c14f66..0710b72 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/RepoRemoveCommand.java
@@ -18,21 +18,21 @@ package org.apache.karaf.features.command;
import java.net.URI;
-import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "feature", name = "repo-remove", description = "Removes the specified repository features service.")
@Service
public class RepoRemoveCommand extends FeaturesCommandSupport {
@Argument(index = 0, name = "repository", description = "Name or url of the repository to remove.", required = true, multiValued = false)
- @Completer(InstalledRepoNameCompleter.class)
+ @Completion(InstalledRepoNameCompleter.class)
private String repository;
@Option(name = "-u", aliases = { "--uninstall-all" }, description = "Uninstall all features from the repository", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
index e22d2f3..b56eac6 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/UninstallFeatureCommand.java
@@ -16,23 +16,23 @@
*/
package org.apache.karaf.features.command;
-import org.apache.karaf.features.command.completers.InstalledFeatureCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
-
import java.util.EnumSet;
import java.util.List;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.command.completers.InstalledFeatureCompleter;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
@Command(scope = "feature", name = "uninstall", description = "Uninstalls a feature with the specified name and version.")
@Service
public class UninstallFeatureCommand extends FeaturesCommandSupport {
@Argument(index = 0, name = "features", description = "The name and version of the features to uninstall. A feature id looks like name/version. The version is optional.", required = true, multiValued = true)
- @Completer(InstalledFeatureCompleter.class)
+ @Completion(InstalledFeatureCompleter.class)
List<String> features;
@Option(name = "-r", aliases = "--no-auto-refresh", description = "Do not automatically refresh bundles", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
index 08fba41..7444b95 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AllFeatureCompleter.java
@@ -17,7 +17,7 @@
package org.apache.karaf.features.command.completers;
import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* {@link org.apache.karaf.shell.console.Completer} for available features.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
index 22ec700..79cd280 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableFeatureCompleter.java
@@ -17,7 +17,7 @@
package org.apache.karaf.features.command.completers;
import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* {@link org.apache.karaf.shell.console.Completer} for features not installed yet.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
index 7797715..acefe77 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/AvailableRepoNameCompleter.java
@@ -20,11 +20,12 @@ import java.util.Arrays;
import java.util.List;
import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.features.internal.FeatureFinder;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* Shows the list of feature repos that can be installed with their short name
@@ -39,9 +40,9 @@ public class AvailableRepoNameCompleter implements Completer {
this.featuresService = featuresService;
}
- public int complete(final String buffer, final int cursor, @SuppressWarnings("rawtypes") final List candidates) {
+ public int complete(Session session, CommandLine commandLine, final List<String> candidates) {
StringsCompleter delegate = new StringsCompleter(Arrays.asList(featuresService.getRepositoryNames()));
- return delegate.complete(buffer, cursor, candidates);
+ return delegate.complete(session, commandLine, candidates);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
index 3dd1e2b..d01e5af 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/FeatureCompleterSupport.java
@@ -20,9 +20,11 @@ import java.util.List;
import org.apache.karaf.features.Feature;
import org.apache.karaf.features.FeaturesService;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.inject.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* Base completer for feature commands.
@@ -39,7 +41,7 @@ public abstract class FeatureCompleterSupport implements Completer {
this.featuresService = featuresService;
}
- public int complete(final String buffer, final int cursor, @SuppressWarnings("rawtypes") final List candidates) {
+ public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
StringsCompleter delegate = new StringsCompleter();
try {
for (Feature feature : featuresService.listFeatures()) {
@@ -50,7 +52,7 @@ public abstract class FeatureCompleterSupport implements Completer {
} catch (Exception e) {
// Ignore
}
- return delegate.complete(buffer, cursor, candidates);
+ return delegate.complete(session, commandLine, candidates);
}
/**
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledFeatureCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledFeatureCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledFeatureCompleter.java
index e61940f..4c937db 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledFeatureCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledFeatureCompleter.java
@@ -17,7 +17,7 @@
package org.apache.karaf.features.command.completers;
import org.apache.karaf.features.Feature;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* {@link org.apache.karaf.shell.console.Completer} for installed features.
[07/10] [KARAF-2805] Migrate shell, ssh, wrapper, kar, instance,
features and bundle to the new API and switch the bin/shell script to
use the new console
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshTerminal.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshTerminal.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshTerminal.java
index 9961c3c..fa24169 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshTerminal.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshTerminal.java
@@ -18,26 +18,18 @@
*/
package org.apache.karaf.shell.ssh;
-import jline.TerminalSupport;
+import org.apache.karaf.shell.api.console.Terminal;
import org.apache.sshd.server.Environment;
-public class SshTerminal extends TerminalSupport {
+public class SshTerminal implements Terminal {
private Environment environment;
public SshTerminal(Environment environment) {
- super(true);
- setAnsiSupported(true);
this.environment = environment;
}
- public void init() throws Exception {
- }
-
- public void restore() throws Exception {
- }
-
@Override
public int getWidth() {
int width = 0;
@@ -46,7 +38,7 @@ public class SshTerminal extends TerminalSupport {
} catch (Throwable t) {
// Ignore
}
- return width > 0 ? width : super.getWidth();
+ return width > 0 ? width : 80;
}
@Override
@@ -57,7 +49,21 @@ public class SshTerminal extends TerminalSupport {
} catch (Throwable t) {
// Ignore
}
- return height > 0 ? height : super.getHeight();
+ return height > 0 ? height : 24;
+ }
+
+ @Override
+ public boolean isAnsiSupported() {
+ return true;
+ }
+
+ @Override
+ public boolean isEchoEnabled() {
+ return true;
}
+ @Override
+ public void setEchoEnabled(boolean enabled) {
+ // TODO: how to disable echo over ssh ?
+ }
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
index ae49e61..94d71a3 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/UserAuthFactoriesFactory.java
@@ -23,8 +23,6 @@ import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthKeyboardInteractive;
import org.apache.sshd.server.auth.UserAuthPassword;
import org.apache.sshd.server.auth.UserAuthPublicKey;
-import org.osgi.service.blueprint.container.ComponentDefinitionException;
-import org.osgi.service.blueprint.container.ReifiedType;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
@@ -34,7 +32,7 @@ import java.util.Set;
/**
* <p>A factory for user authentication factories to set on
- * {@link SshServer#setUserAuthFactories(java.util.List)} based on a
+ * {@link org.apache.sshd.SshServer#setUserAuthFactories(java.util.List)} based on a
* comma-separated list of authentication methods.</p>
*
* <p>Currently, the following methods are supported:</p>
@@ -55,33 +53,6 @@ public class UserAuthFactoriesFactory {
private Set<String> methodSet;
private List<NamedFactory<UserAuth>> factories;
- public static Converter getConverter() {
- return new Converter();
- }
-
- /**
- * This blueprint type converter silently converts instances of
- * <code>Class X implements NameFactory</code>
- * to the reified type <code>cNameFactory</code>
- * and therefore helps blueprint to set the returned factories on
- * {@link SshServerAction#setUserAuthFactories(List)} without complaining
- * about type conversion errors.
- */
- public static class Converter implements org.osgi.service.blueprint.container.Converter {
-
- public boolean canConvert(Object sourceObject, ReifiedType targetType) {
- return NamedFactory.class.isAssignableFrom(sourceObject.getClass())
- && UserAuth.class.equals(((ParameterizedType) sourceObject.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0])
- && NamedFactory.class.equals(targetType.getRawClass())
- && UserAuth.class.equals(targetType.getActualTypeArgument(0).getRawClass());
- }
-
- public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
- return sourceObject;
- }
-
- }
-
public void setAuthMethods(String methods) {
this.methodSet = new HashSet<String>();
this.factories = new ArrayList<NamedFactory<UserAuth>>();
@@ -94,7 +65,7 @@ public class UserAuthFactoriesFactory {
} else if (PUBLICKEY_METHOD.equals(am)) {
this.factories.add(new UserAuthPublicKey.Factory());
} else {
- throw new ComponentDefinitionException("Invalid authentication method " + am + " specified");
+ throw new IllegalArgumentException("Invalid authentication method " + am + " specified");
}
this.methodSet.add(am);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
new file mode 100644
index 0000000..c883dc0
--- /dev/null
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
@@ -0,0 +1,171 @@
+/*
+ * 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.ssh.util;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+//This is from aries util
+public final class SingleServiceTracker<T> {
+ public static interface SingleServiceListener {
+ public void serviceFound();
+
+ public void serviceLost();
+
+ public void serviceReplaced();
+ }
+
+ private final BundleContext ctx;
+ private final String className;
+ private final AtomicReference<T> service = new AtomicReference<T>();
+ private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
+ private final AtomicBoolean open = new AtomicBoolean(false);
+ private final SingleServiceListener serviceListener;
+ private String filterString;
+ private Filter filter;
+
+ private final ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ if (open.get()) {
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ ServiceReference deadRef = event.getServiceReference();
+ if (deadRef.equals(ref.get())) {
+ findMatchingReference(deadRef);
+ }
+ } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
+ findMatchingReference(null);
+ }
+ }
+ }
+ };
+
+ public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
+ ctx = context;
+ this.className = clazz.getName();
+ serviceListener = sl;
+ }
+
+ public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
+ this(context, clazz, sl);
+ this.filterString = filterString;
+ if (filterString != null) filter = context.createFilter(filterString);
+ }
+
+ public T getService() {
+ return service.get();
+ }
+
+ public ServiceReference getServiceReference() {
+ return ref.get();
+ }
+
+ public void open() {
+ if (open.compareAndSet(false, true)) {
+ try {
+ String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
+ if (filter != null) filterString = "(&" + filterString + filter + ')';
+ ctx.addServiceListener(listener, filterString);
+ findMatchingReference(null);
+ } catch (InvalidSyntaxException e) {
+ // this can never happen. (famous last words :)
+ }
+ }
+ }
+
+ private void findMatchingReference(ServiceReference original) {
+ boolean clear = true;
+ ServiceReference ref = ctx.getServiceReference(className);
+ if (ref != null && (filter == null || filter.match(ref))) {
+ @SuppressWarnings("unchecked")
+ T service = (T) ctx.getService(ref);
+ if (service != null) {
+ clear = false;
+
+ // We do the unget out of the lock so we don't exit this class while holding a lock.
+ if (!!!update(original, ref, service)) {
+ ctx.ungetService(ref);
+ }
+ }
+ } else if (original == null) {
+ clear = false;
+ }
+
+ if (clear) {
+ update(original, null, null);
+ }
+ }
+
+ private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
+ boolean result = false;
+ int foundLostReplaced = -1;
+
+ // Make sure we don't try to get a lock on null
+ Object lock;
+
+ // we have to choose our lock.
+ if (newRef != null) lock = newRef;
+ else if (deadRef != null) lock = deadRef;
+ else lock = this;
+
+ // This lock is here to ensure that no two threads can set the ref and service
+ // at the same time.
+ synchronized (lock) {
+ if (open.get()) {
+ result = this.ref.compareAndSet(deadRef, newRef);
+ if (result) {
+ this.service.set(service);
+
+ if (deadRef == null && newRef != null) foundLostReplaced = 0;
+ if (deadRef != null && newRef == null) foundLostReplaced = 1;
+ if (deadRef != null && newRef != null) foundLostReplaced = 2;
+ }
+ }
+ }
+
+ if (serviceListener != null) {
+ if (foundLostReplaced == 0) serviceListener.serviceFound();
+ else if (foundLostReplaced == 1) serviceListener.serviceLost();
+ else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
+ }
+
+ return result;
+ }
+
+ public void close() {
+ if (open.compareAndSet(true, false)) {
+ ctx.removeServiceListener(listener);
+
+ synchronized (this) {
+ ServiceReference deadRef = ref.getAndSet(null);
+ service.set(null);
+ if (deadRef != null) ctx.ungetService(deadRef);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/resources/META-INF/services/org/apache/karaf/shell/commands b/shell/ssh/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
new file mode 100644
index 0000000..44d0683
--- /dev/null
+++ b/shell/ssh/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
@@ -0,0 +1,17 @@
+##---------------------------------------------------------------------------
+## 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.
+##---------------------------------------------------------------------------
+org.apache.karaf.shell.ssh.ActivatorNoOsgi
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml b/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml
deleted file mode 100644
index 7a58288..0000000
--- a/shell/ssh/src/main/resources/OSGI-INF/blueprint/shell-ssh.xml
+++ /dev/null
@@ -1,149 +0,0 @@
-<?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"
- xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0"
- xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
- default-activation="lazy">
-
- <type-converters>
- <bean class="org.apache.karaf.shell.ssh.ShellFactoryImpl" factory-method="getConverter" />
- <bean class="org.apache.karaf.shell.ssh.UserAuthFactoriesFactory" factory-method="getConverter" />
- </type-converters>
-
- <reference id="consoleFactory" interface="org.apache.karaf.shell.console.factory.ConsoleFactory" />
-
- <ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]">
- <ext:default-properties>
- <ext:property name="karaf.startRemoteShell" value="true" />
- </ext:default-properties>
- </ext:property-placeholder>
-
- <cm:property-placeholder persistent-id="org.apache.karaf.shell" update-strategy="reload">
- <cm:default-properties>
- <cm:property name="sshPort" value="8101"/>
- <cm:property name="sshHost" value="0.0.0.0"/>
- <cm:property name="sshIdleTimeout" value="1800000"/>
- <cm:property name="sshRealm" value="karaf"/>
- <cm:property name="hostKey" value="$[karaf.base]/etc/host.key"/>
- <cm:property name="authorizedKeys" value="$[karaf.base]/etc/authorized_keys"/>
- <cm:property name="authMethods" value="keyboard-interactive,password,publickey"/>
- <cm:property name="keySize" value="1024"/>
- <cm:property name="algorithm" value="DSA"/>
- <cm:property name="macs" value="hmac-sha1" />
- <cm:property name="ciphers" value="aes256-ctr,aes192-ctr,aes128-ctr,arcfour256" />
- </cm:default-properties>
- </cm:property-placeholder>
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
- <command>
- <action class="org.apache.karaf.shell.ssh.SshAction">
- <property name="sshClientFactory" ref="sshClientFactory" />
- </action>
- </command>
- <command>
- <action class="org.apache.karaf.shell.ssh.SshServerAction">
- <property name="sshServerId">
- <bp:idref component-id="sshServer"/>
- </property>
- </action>
- </command>
- </command-bundle>
-
- <bean id="sshClientFactory" class="org.apache.karaf.shell.ssh.SshClientFactory">
- <argument ref="agentFactory" />
- <argument value="$[user.home]/.sshkaraf/known_hosts"/>
- </bean>
-
- <bean id="userAuthFactoriesFactory" class="org.apache.karaf.shell.ssh.UserAuthFactoriesFactory">
- <property name="authMethods" value="${authMethods}"/>
- </bean>
-
- <bean id="sshServer" class="org.apache.sshd.SshServer" factory-method="setUpDefaultServer" scope="prototype">
- <property name="port" value="${sshPort}"/>
- <property name="host" value="${sshHost}"/>
- <property name="macFactories">
- <bean class="org.apache.karaf.shell.ssh.SshUtils" factory-method="buildMacs">
- <argument value="${macs}" />
- </bean>
- </property>
- <property name="cipherFactories">
- <bean class="org.apache.karaf.shell.ssh.SshUtils" factory-method="buildCiphers">
- <argument value="${ciphers}" />
- </bean>
- </property>
- <property name="shellFactory">
- <bean class="org.apache.karaf.shell.ssh.ShellFactoryImpl">
- <argument ref="consoleFactory"/>
- </bean>
- </property>
- <property name="commandFactory">
- <bean class="org.apache.sshd.server.command.ScpCommandFactory">
- <argument>
- <bean class="org.apache.karaf.shell.ssh.ShellCommandFactory">
- <property name="commandProcessor" ref="commandProcessor"/>
- </bean>
- </argument>
- </bean>
- </property>
- <property name="subsystemFactories">
- <list>
- <bean class="org.apache.sshd.server.sftp.SftpSubsystem.Factory"/>
- </list>
- </property>
- <property name="keyPairProvider" ref="keyPairProvider"/>
- <property name="passwordAuthenticator" ref="authenticator"/>
- <property name="publickeyAuthenticator" ref="authenticator"/>
- <property name="fileSystemFactory">
- <bean class="org.apache.karaf.shell.ssh.KarafFileSystemFactory"/>
- </property>
- <property name="userAuthFactories">
- <bean factory-ref="userAuthFactoriesFactory" factory-method="getFactories"/>
- </property>
- <property name="agentFactory" ref="agentFactory" />
- </bean>
-
- <bean id="agentFactory" class="org.apache.karaf.shell.ssh.KarafAgentFactory">
- <property name="bundleContext" ref="blueprintBundleContext" />
- </bean>
- <reference-list id="commandSessions" interface="org.apache.felix.service.command.CommandSession" availability="optional" activation="eager">
- <reference-listener ref="agentFactory" bind-method="registerCommandSession" unbind-method="unregisterCommandSession" />
- </reference-list>
-
- <bean id="keyPairProvider" class="org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider">
- <property name="path" value="${hostKey}"/>
- <property name="keySize" value="${keySize}"/>
- <property name="algorithm" value="${algorithm}"/>
- </bean>
-
- <bean id="authenticator" class="org.apache.karaf.shell.ssh.KarafJaasAuthenticator">
- <property name="realm" value="${sshRealm}"/>
- </bean>
-
- <bean id="sshServerFactory" class="org.apache.karaf.shell.ssh.SshServerFactory" init-method="start"
- destroy-method="stop" activation="eager">
- <argument ref="sshServer"/>
- <property name="start" value="$[karaf.startRemoteShell]"/>
- <property name="idleTimeout" value="${sshIdleTimeout}"/>
- </bean>
-
- <reference id="commandProcessor" interface="org.apache.felix.service.command.CommandProcessor"/>
-
-</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/wrapper/command/pom.xml
----------------------------------------------------------------------
diff --git a/wrapper/command/pom.xml b/wrapper/command/pom.xml
index d70ff8c..a8d2fca 100644
--- a/wrapper/command/pom.xml
+++ b/wrapper/command/pom.xml
@@ -86,17 +86,11 @@
org.apache.karaf.wrapper,
javax.management,
javax.management.loading,
- org.apache.aries.blueprint,
- org.osgi.service.blueprint.container,
- org.osgi.service.blueprint.reflect,
- org.apache.felix.service.command,
- org.apache.karaf.shell.commands,
- org.apache.karaf.shell.console,
*
</Import-Package>
- <Private-Package>
- org.apache.karaf.wrapper.internal
- </Private-Package>
+ <Karaf-Commands>
+ org.apache.karaf.wrapper.commands
+ </Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/wrapper/command/src/main/java/org/apache/karaf/wrapper/commands/Install.java
----------------------------------------------------------------------
diff --git a/wrapper/command/src/main/java/org/apache/karaf/wrapper/commands/Install.java b/wrapper/command/src/main/java/org/apache/karaf/wrapper/commands/Install.java
index 14c921a..346f6f1 100644
--- a/wrapper/command/src/main/java/org/apache/karaf/wrapper/commands/Install.java
+++ b/wrapper/command/src/main/java/org/apache/karaf/wrapper/commands/Install.java
@@ -18,21 +18,22 @@ package org.apache.karaf.wrapper.commands;
import java.io.File;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.wrapper.WrapperService;
-import org.apache.karaf.wrapper.internal.WrapperServiceImpl;
-import org.fusesource.jansi.Ansi;
+
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL;
/**
* Installs the Karaf instance as a service in your operating system.
*/
@Command(scope = "wrapper", name = "install", description = "Install the container as a system service in the OS.")
@Service
-public class Install extends AbstractAction {
+public class Install implements Action {
@Option(name = "-n", aliases = { "--name" }, description = "The service name that will be used when installing the service. (Default: karaf)", required = false, multiValued = false)
private String name = "karaf";
@@ -47,13 +48,10 @@ public class Install extends AbstractAction {
private String startType = "AUTO_START";
@Reference
- private WrapperService wrapperService = new WrapperServiceImpl();
-
- public void setWrapperService(WrapperService wrapperService) {
- this.wrapperService = wrapperService;
- }
+ private WrapperService wrapperService;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
File[] wrapperPaths = wrapperService.install(name, displayName, description, startType);
String os = System.getProperty("os.name", "Unknown");
@@ -67,7 +65,7 @@ public class Install extends AbstractAction {
System.out.println("");
if (os.startsWith("Win")) {
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("MS Windows system detected:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "MS Windows system detected:" + INTENSITY_NORMAL);
System.out.println("To install the service, run: ");
System.out.println(" C:> " + serviceFile.getPath() + " install");
System.out.println("");
@@ -82,7 +80,7 @@ public class Install extends AbstractAction {
System.out.println("");
} else if (os.startsWith("Mac OS X")) {
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("Mac OS X system detected:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "Mac OS X system detected:" + INTENSITY_NORMAL);
System.out.println("to add bin/org.apache.karaf.KARAF as user service move this file into ~/Library/LaunchAgents/");
System.out.println("> mv bin/org.apache.karaf.KARAF.plist ~/Library/LaunchAgents/");
System.out.println("");
@@ -110,7 +108,7 @@ public class Install extends AbstractAction {
if (redhatRelease.exists()) {
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("RedHat/Fedora/CentOS Linux system detected:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "RedHat/Fedora/CentOS Linux system detected:" + INTENSITY_NORMAL);
System.out.println(" To install the service:");
System.out.println(" $ ln -s " + serviceFile.getPath() + " /etc/init.d/");
System.out.println(" $ chkconfig " + serviceFile.getName() + " --add");
@@ -132,7 +130,7 @@ public class Install extends AbstractAction {
System.out.println(" $ rm /etc/init.d/" + serviceFile.getPath());
} else if (debianVersion.exists()) {
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("Ubuntu/Debian Linux system detected:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "Ubuntu/Debian Linux system detected:" + INTENSITY_NORMAL);
System.out.println(" To install the service:");
System.out.println(" $ ln -s " + serviceFile.getPath() + " /etc/init.d/");
System.out.println("");
@@ -152,7 +150,7 @@ public class Install extends AbstractAction {
System.out.println(" $ rm /etc/init.d/" + serviceFile.getName());
} else {
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("On Redhat/Fedora/CentOS Systems:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "On Redhat/Fedora/CentOS Systems:" + INTENSITY_NORMAL);
System.out.println(" To install the service:");
System.out.println(" $ ln -s "+serviceFile.getPath()+" /etc/init.d/");
System.out.println(" $ chkconfig "+serviceFile.getName()+" --add");
@@ -174,7 +172,7 @@ public class Install extends AbstractAction {
System.out.println(" $ rm /etc/init.d/"+serviceFile.getName());
System.out.println("");
- System.out.println(Ansi.ansi().a(Ansi.Attribute.INTENSITY_BOLD).a("On Ubuntu/Debian Systems:").a(Ansi.Attribute.RESET).toString());
+ System.out.println(INTENSITY_BOLD + "On Ubuntu/Debian Systems:" + INTENSITY_NORMAL);
System.out.println(" To install the service:");
System.out.println(" $ ln -s "+serviceFile.getPath()+" /etc/init.d/");
System.out.println("");
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/wrapper/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
----------------------------------------------------------------------
diff --git a/wrapper/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands b/wrapper/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
index d89d5da..73b329d 100644
--- a/wrapper/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
+++ b/wrapper/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
@@ -14,4 +14,5 @@
## See the License for the specific language governing permissions and
## limitations under the License.
##---------------------------------------------------------------------------
+org.apache.karaf.wrapper.internal.WrapperServiceImpl
org.apache.karaf.wrapper.commands.Install
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/wrapper/command/src/main/resources/OSGI-INF/blueprint/wrapper-commands.xml
----------------------------------------------------------------------
diff --git a/wrapper/command/src/main/resources/OSGI-INF/blueprint/wrapper-commands.xml b/wrapper/command/src/main/resources/OSGI-INF/blueprint/wrapper-commands.xml
deleted file mode 100644
index f29e8a0..0000000
--- a/wrapper/command/src/main/resources/OSGI-INF/blueprint/wrapper-commands.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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"
- default-activation="lazy">
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
- scan="org.apache.karaf.wrapper.commands.*" />
-
-</blueprint>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/wrapper/core/pom.xml
----------------------------------------------------------------------
diff --git a/wrapper/core/pom.xml b/wrapper/core/pom.xml
index 982433a..f6f51d1 100644
--- a/wrapper/core/pom.xml
+++ b/wrapper/core/pom.xml
@@ -51,7 +51,7 @@
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
<dependency>
<groupId>tanukisoft</groupId>
[09/10] [KARAF-2805] Migrate shell, ssh, wrapper, kar, instance,
features and bundle to the new API and switch the bin/shell script to
use the new console
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
index cb43813..94e4cf7 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoNameCompleter.java
@@ -20,10 +20,12 @@ import java.util.List;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* {@link Completer} for Feature Repository URLs.
@@ -41,7 +43,7 @@ public class InstalledRepoNameCompleter implements Completer {
this.featuresService = featuresService;
}
- public int complete(final String buffer, final int cursor, @SuppressWarnings("rawtypes") final List candidates) {
+ public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
StringsCompleter delegate = new StringsCompleter();
try {
for (Repository repository : featuresService.listRepositories()) {
@@ -50,7 +52,7 @@ public class InstalledRepoNameCompleter implements Completer {
} catch (Exception e) {
// Ignore
}
- return delegate.complete(buffer, cursor, candidates);
+ return delegate.complete(session, commandLine, candidates);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
----------------------------------------------------------------------
diff --git a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
index 9a80e12..7a760c2 100644
--- a/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
+++ b/features/command/src/main/java/org/apache/karaf/features/command/completers/InstalledRepoUriCompleter.java
@@ -18,12 +18,14 @@ package org.apache.karaf.features.command.completers;
import java.util.List;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.console.Completer;
import org.apache.karaf.features.FeaturesService;
import org.apache.karaf.features.Repository;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* {@link Completer} for Feature Repository URLs.
@@ -42,7 +44,7 @@ public class InstalledRepoUriCompleter implements Completer {
this.featuresService = featuresService;
}
- public int complete(final String buffer, final int cursor, @SuppressWarnings("rawtypes") final List candidates) {
+ public int complete(Session session, final CommandLine commandLine, final List<String> candidates) {
StringsCompleter delegate = new StringsCompleter();
try {
for (Repository repository : featuresService.listRepositories()) {
@@ -51,7 +53,7 @@ public class InstalledRepoUriCompleter implements Completer {
} catch (Exception e) {
// Ignore
}
- return delegate.complete(buffer, cursor, candidates);
+ return delegate.complete(session, commandLine, candidates);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml
----------------------------------------------------------------------
diff --git a/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml b/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml
deleted file mode 100644
index 8053312..0000000
--- a/features/command/src/main/resources/OSGI-INF/blueprint/features-command.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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" default-activation="lazy">
-
- <!-- Commands -->
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
- scan="org.apache.karaf.features.command.*" />
-
-</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/pom.xml
----------------------------------------------------------------------
diff --git a/instance/command/pom.xml b/instance/command/pom.xml
index 2c75801..52058cd 100644
--- a/instance/command/pom.xml
+++ b/instance/command/pom.xml
@@ -68,7 +68,7 @@
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
<dependency>
@@ -120,7 +120,8 @@
as Execute.java accesses the InstanceServiceImpl and jansi
(but only outside OSGi) -->
<Import-Package>
- !org.apache.karaf.instance.core.internal,
+ !org.apache.karaf.shell.impl.action.command,
+ !org.apache.karaf.instance.core.internal,
!org.fusesource.jansi,
*
</Import-Package>
@@ -129,6 +130,7 @@
org.apache.karaf.instance.command,
org.apache.karaf.instance.command.completers
</Private-Package>
+ <Karaf-Commands>org.apache.karaf.instance.command.*</Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
index e2faee1..c526c07 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeOptsCommand.java
@@ -17,17 +17,17 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "opts-change", description = "Changes the Java options of an existing container instance.")
@Service
public class ChangeOptsCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description="The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
@Argument(index = 1, name = "javaOpts", description = "The new Java options to set", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
index 148bc93..de5bfaf 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiRegistryPortCommand.java
@@ -17,17 +17,17 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "rmi-registry-port-change", description = "Changes the RMI registry port (used by management layer) of an existing container instance.")
@Service
public class ChangeRmiRegistryPortCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
@Argument(index = 1, name = "port", description = "The new RMI registry port to set", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
index 3b6fdc4..0ac2cf7 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeRmiServerPortCommand.java
@@ -17,17 +17,17 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "rmi-server-port-change", description = "Changes the RMI server port (used by management layer) of an existing instance.")
@Service
public class ChangeRmiServerPortCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
@Argument(index = 1, name = "port", description = "The new RMI server port to set", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
index 01df8ae..17ad26c 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ChangeSshPortCommand.java
@@ -17,17 +17,17 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "ssh-port-change", description = "Changes the secure shell port of an existing container instance.")
@Service
public class ChangeSshPortCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description="The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
@Argument(index = 1, name = "port", description = "The new secure shell port to set", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/CloneCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
index e5626e0..e4f28c5 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/CloneCommand.java
@@ -17,12 +17,12 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.instance.core.InstanceSettings;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* Clone an existing instance.
@@ -50,7 +50,7 @@ public class CloneCommand extends InstanceCommandSupport {
boolean verbose = false;
@Argument(index = 0, name = "name", description = "The name of the source container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
String name;
@Argument(index = 1, name = "cloneName", description = "The name of the cloned container instance", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
index 294c348..c81a3eb 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ConnectCommand.java
@@ -21,11 +21,13 @@ package org.apache.karaf.instance.command;
import java.util.List;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
@Command(scope = "instance", name = "connect", description = "Connects to an existing container instance.")
@Service
@@ -38,12 +40,15 @@ public class ConnectCommand extends InstanceCommandSupport {
private String password;
@Argument(index = 0, name="name", description="The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
@Argument(index = 1, name = "command", description = "Optional command to execute", required = false, multiValued = true)
private List<String> command;
+ @Reference
+ Session session;
+
protected Object doExecute() throws Exception {
String cmdStr = "";
if (command != null) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/CreateCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
index af3aebd..0dcc3ac 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/CreateCommand.java
@@ -20,12 +20,12 @@ import java.util.List;
import org.apache.karaf.features.command.completers.AllFeatureCompleter;
import org.apache.karaf.features.command.completers.InstalledRepoUriCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.instance.core.InstanceSettings;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* Creates a new instance.
@@ -51,12 +51,12 @@ public class CreateCommand extends InstanceCommandSupport
@Option(name = "-f", aliases = {"--feature"},
description = "Initial features. This option can be specified multiple times to enable multiple initial features", required = false, multiValued = true)
- @Completer(AllFeatureCompleter.class)
+ @Completion(AllFeatureCompleter.class)
List<String> features;
@Option(name = "-furl", aliases = {"--featureURL"},
description = "Additional feature descriptor URLs. This option can be specified multiple times to add multiple URLs", required = false, multiValued = true)
- @Completer(InstalledRepoUriCompleter.class)
+ @Completion(InstalledRepoUriCompleter.class)
List<String> featureURLs;
@Option(name = "-v", aliases = {"--verbose"}, description = "Display actions performed by the command (disabled by default)", required = false, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
index dbb1659..fb2964f 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/DestroyCommand.java
@@ -17,10 +17,10 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* Destroy an existing instance.
@@ -30,7 +30,7 @@ import org.apache.karaf.shell.inject.Service;
public class DestroyCommand extends InstanceCommandSupport
{
@Argument(index = 0, name = "name", description= "The name of the container instance to destroy", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
protected Object doExecute() throws Exception {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java b/instance/command/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
index b320b3c..3b0b535 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/InstanceCommandSupport.java
@@ -18,10 +18,10 @@ package org.apache.karaf.instance.command;
import org.apache.karaf.instance.core.Instance;
import org.apache.karaf.instance.core.InstanceService;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
-public abstract class InstanceCommandSupport extends OsgiCommandSupport {
+public abstract class InstanceCommandSupport implements Action {
@Reference
private InstanceService instanceService;
@@ -42,4 +42,10 @@ public abstract class InstanceCommandSupport extends OsgiCommandSupport {
return i;
}
+ @Override
+ public Object execute() throws Exception {
+ return doExecute();
+ }
+
+ protected abstract Object doExecute() throws Exception;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/ListCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/ListCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/ListCommand.java
index b15f8b1..368259a 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/ListCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/ListCommand.java
@@ -17,10 +17,10 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.core.Instance;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "list", description = "Lists all existing container instances.")
@Service
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/RenameCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
index 872d954..ef68400 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/RenameCommand.java
@@ -17,11 +17,11 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "rename", description = "Rename an existing container instance.")
@Service
@@ -31,7 +31,7 @@ public class RenameCommand extends InstanceCommandSupport {
boolean verbose = false;
@Argument(index = 0, name = "name", description = "The name of the container instance to rename", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
String instance = null;
@Argument(index = 1, name = "new-name", description = "The new name of the container instance", required = true, multiValued = false)
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/StartCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/StartCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/StartCommand.java
index 9b6e464..8c52d5e 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/StartCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/StartCommand.java
@@ -17,12 +17,12 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
import org.apache.karaf.instance.core.Instance;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "start", description = "Start an existing container instance.")
@Service
@@ -38,7 +38,7 @@ public class StartCommand extends InstanceCommandSupport {
private boolean wait;
@Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
static final String DEBUG_OPTS = " -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005";
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/StatusCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
index 760dffb..82100e1 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/StatusCommand.java
@@ -18,18 +18,17 @@ package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
import org.apache.karaf.instance.core.Instance;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "status", description = "Check the current status of an instance.")
@Service
public class StatusCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description = "The name of the instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String name;
protected Object doExecute() throws Exception {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/StopCommand.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/StopCommand.java b/instance/command/src/main/java/org/apache/karaf/instance/command/StopCommand.java
index 4d540b2..6c8de10 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/StopCommand.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/StopCommand.java
@@ -17,17 +17,17 @@
package org.apache.karaf.instance.command;
import org.apache.karaf.instance.command.completers.InstanceCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "instance", name = "stop", description = "Stop an existing container instance.")
@Service
public class StopCommand extends InstanceCommandSupport {
@Argument(index = 0, name = "name", description = "The name of the container instance", required = true, multiValued = false)
- @Completer(InstanceCompleter.class)
+ @Completion(InstanceCompleter.class)
private String instance = null;
protected Object doExecute() throws Exception {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java b/instance/command/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
index 5d8cc71..4468374 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/command/completers/InstanceCompleter.java
@@ -20,10 +20,12 @@ import java.util.List;
import org.apache.karaf.instance.core.Instance;
import org.apache.karaf.instance.core.InstanceService;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* Displays a list of configured server instances for the instance commands.
@@ -39,12 +41,12 @@ public class InstanceCompleter implements Completer {
this.instanceService = instanceService;
}
- public int complete(String buffer, int cursor, List candidates) {
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
StringsCompleter delegate = new StringsCompleter();
for (Instance instance : instanceService.getInstances()) {
delegate.getStrings().add(instance.getName());
}
- return delegate.complete(buffer, cursor, candidates);
+ return delegate.complete(session, commandLine, candidates);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/java/org/apache/karaf/instance/main/Execute.java
----------------------------------------------------------------------
diff --git a/instance/command/src/main/java/org/apache/karaf/instance/main/Execute.java b/instance/command/src/main/java/org/apache/karaf/instance/main/Execute.java
index 1556cef..591873e 100644
--- a/instance/command/src/main/java/org/apache/karaf/instance/main/Execute.java
+++ b/instance/command/src/main/java/org/apache/karaf/instance/main/Execute.java
@@ -23,12 +23,23 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import org.apache.karaf.instance.command.*;
-import org.apache.karaf.shell.commands.Action;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.basic.DefaultActionPreparator;
+import org.apache.karaf.instance.command.ChangeOptsCommand;
+import org.apache.karaf.instance.command.ChangeRmiRegistryPortCommand;
+import org.apache.karaf.instance.command.ChangeRmiServerPortCommand;
import org.apache.karaf.instance.command.ChangeSshPortCommand;
+import org.apache.karaf.instance.command.CloneCommand;
+import org.apache.karaf.instance.command.CreateCommand;
+import org.apache.karaf.instance.command.DestroyCommand;
+import org.apache.karaf.instance.command.InstanceCommandSupport;
+import org.apache.karaf.instance.command.ListCommand;
+import org.apache.karaf.instance.command.RenameCommand;
+import org.apache.karaf.instance.command.StartCommand;
+import org.apache.karaf.instance.command.StatusCommand;
+import org.apache.karaf.instance.command.StopCommand;
import org.apache.karaf.instance.core.internal.InstanceServiceImpl;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.impl.action.command.DefaultActionPreparator;
import org.fusesource.jansi.AnsiConsole;
public class Execute {
@@ -136,7 +147,7 @@ public class Execute {
InstanceServiceImpl instanceService = new InstanceServiceImpl();
instanceService.setStorageLocation(storageFile);
command.setInstanceService(instanceService);
- command.execute(null);
+ command.execute();
}
private static void listCommands() {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
----------------------------------------------------------------------
diff --git a/instance/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands b/instance/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
new file mode 100644
index 0000000..92245c7
--- /dev/null
+++ b/instance/command/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
@@ -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.
+##---------------------------------------------------------------------------
+org.apache.karaf.instance.core.internal.InstanceServiceImpl
+org.apache.karaf.instance.command.ChangeOptsCommand
+org.apache.karaf.instance.command.ChangeRmiRegistryPortCommand
+org.apache.karaf.instance.command.ChangeRmiServerPortCommand
+org.apache.karaf.instance.command.ChangeSshPortCommand
+org.apache.karaf.instance.command.CloneCommand
+org.apache.karaf.instance.command.ConnectCommand
+org.apache.karaf.instance.command.CreateCommand
+org.apache.karaf.instance.command.DestroyCommand
+org.apache.karaf.instance.command.ListCommand
+org.apache.karaf.instance.command.RenameCommand
+org.apache.karaf.instance.command.StartCommand
+org.apache.karaf.instance.command.StatusCommand
+org.apache.karaf.instance.command.StopCommand
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/command/src/main/resources/OSGI-INF/blueprint/instance-command.xml
----------------------------------------------------------------------
diff --git a/instance/command/src/main/resources/OSGI-INF/blueprint/instance-command.xml b/instance/command/src/main/resources/OSGI-INF/blueprint/instance-command.xml
deleted file mode 100644
index 4bb3520..0000000
--- a/instance/command/src/main/resources/OSGI-INF/blueprint/instance-command.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?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"
- default-activation="lazy">
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
- scan="org.apache.karaf.instance.command.*" />
-
-</blueprint>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/core/pom.xml
----------------------------------------------------------------------
diff --git a/instance/core/pom.xml b/instance/core/pom.xml
index 80ae6b0..be13f18 100644
--- a/instance/core/pom.xml
+++ b/instance/core/pom.xml
@@ -59,7 +59,7 @@
<dependency>
<groupId>org.apache.karaf.shell</groupId>
- <artifactId>org.apache.karaf.shell.console</artifactId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java
----------------------------------------------------------------------
diff --git a/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java b/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java
index 32326ba..ae03fd9 100644
--- a/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java
+++ b/instance/core/src/main/java/org/apache/karaf/instance/core/internal/InstanceServiceImpl.java
@@ -94,6 +94,13 @@ public class InstanceServiceImpl implements InstanceService {
Map<String, InstanceState> instances;
}
+ public InstanceServiceImpl() {
+ String prop = System.getProperty("karaf.instances");
+ if (prop != null) {
+ storageLocation = new File(prop);
+ }
+ }
+
public File getStorageLocation() {
return storageLocation;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/pom.xml
----------------------------------------------------------------------
diff --git a/kar/command/pom.xml b/kar/command/pom.xml
index 1830ba8..67d18f5 100644
--- a/kar/command/pom.xml
+++ b/kar/command/pom.xml
@@ -50,7 +50,7 @@
</dependency>
<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>
@@ -89,6 +89,7 @@
<configuration>
<instructions>
<Export-Package>!*</Export-Package>
+ <Karaf-Commands>org.apache.karaf.kar.command.*</Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/CreateKarCommand.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/CreateKarCommand.java b/kar/command/src/main/java/org/apache/karaf/kar/command/CreateKarCommand.java
index dbc34a6..a93706c 100644
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/CreateKarCommand.java
+++ b/kar/command/src/main/java/org/apache/karaf/kar/command/CreateKarCommand.java
@@ -19,24 +19,31 @@ package org.apache.karaf.kar.command;
import java.util.List;
import org.apache.karaf.features.command.completers.InstalledRepoNameCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.kar.KarService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "kar", name = "create", description = "Create a kar file for a list of feature repos")
@Service
-public class CreateKarCommand extends KarCommandSupport {
+public class CreateKarCommand implements Action {
@Argument(index = 0, name = "repoName", description = "Repository name. The kar will contain all features of the named repository by default", required = true, multiValued = false)
- @Completer(InstalledRepoNameCompleter.class)
+ @Completion(InstalledRepoNameCompleter.class)
private String repoName;
@Argument(index = 1, name = "features", description = "Names of the features to include. If set then only these features will be added", required = false, multiValued = true)
private List<String> features;
-
- public Object doExecute() throws Exception {
- this.getKarService().create(repoName, features, System.out);
+
+ @Reference
+ private KarService karService;
+
+ @Override
+ public Object execute() throws Exception {
+ karService.create(repoName, features, System.out);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java b/kar/command/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java
index 1053e74..806367a 100644
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java
+++ b/kar/command/src/main/java/org/apache/karaf/kar/command/InstallKarCommand.java
@@ -16,21 +16,27 @@
*/
package org.apache.karaf.kar.command;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.kar.KarService;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import java.net.URI;
@Command(scope = "kar", name = "install", description = "Installs a KAR file.")
@Service
-public class InstallKarCommand extends KarCommandSupport {
-
+public class InstallKarCommand implements Action {
+
@Argument(index = 0, name = "url", description = "The URL of the KAR file to install.", required = true, multiValued = false)
private String url;
-
- public Object doExecute() throws Exception {
- this.getKarService().install(new URI(url));
+
+ @Reference
+ private KarService karService;
+
+ public Object execute() throws Exception {
+ karService.install(new URI(url));
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/KarCommandSupport.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/KarCommandSupport.java b/kar/command/src/main/java/org/apache/karaf/kar/command/KarCommandSupport.java
deleted file mode 100644
index 3af6622..0000000
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/KarCommandSupport.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.kar.command;
-
-import org.apache.karaf.kar.KarService;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Reference;
-
-public abstract class KarCommandSupport extends OsgiCommandSupport {
-
- @Reference
- private KarService karService;
-
- public KarService getKarService() {
- return this.karService;
- }
-
- public void setKarService(KarService karService) {
- this.karService = karService;
- }
-
- public abstract Object doExecute() throws Exception;
-
-}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/ListKarCommand.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/ListKarCommand.java b/kar/command/src/main/java/org/apache/karaf/kar/command/ListKarCommand.java
index e1b59bb..853a743 100644
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/ListKarCommand.java
+++ b/kar/command/src/main/java/org/apache/karaf/kar/command/ListKarCommand.java
@@ -16,24 +16,31 @@
*/
package org.apache.karaf.kar.command;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.kar.KarService;
import org.apache.karaf.shell.table.ShellTable;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "kar", name = "list", description = "List the installed KAR files.")
@Service
-public class ListKarCommand extends KarCommandSupport {
+public class ListKarCommand implements Action {
@Option(name = "--no-format", description = "Disable table rendered output", required = false, multiValued = false)
boolean noFormat;
-
- public Object doExecute() throws Exception {
+
+ @Reference
+ private KarService karService;
+
+ @Override
+ public Object execute() throws Exception {
ShellTable table = new ShellTable();
table.column("KAR Name");
- for (String karName : this.getKarService().list()) {
+ for (String karName : karService.list()) {
table.addRow().addContent(karName);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java b/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
index ce5664d..506bdb3 100644
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
+++ b/kar/command/src/main/java/org/apache/karaf/kar/command/UninstallKarCommand.java
@@ -16,22 +16,29 @@
*/
package org.apache.karaf.kar.command;
+import org.apache.karaf.kar.KarService;
import org.apache.karaf.kar.command.completers.KarCompleter;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Completer;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "kar", name = "uninstall", description = "Uninstall a KAR file.")
@Service
-public class UninstallKarCommand extends KarCommandSupport {
+public class UninstallKarCommand implements Action {
@Argument(index = 0, name = "name", description = "The name of the KAR file to uninstall.", required = true, multiValued = false)
- @Completer(KarCompleter.class)
+ @Completion(KarCompleter.class)
private String name;
- public Object doExecute() throws Exception {
- this.getKarService().uninstall(name);
+ @Reference
+ private KarService karService;
+
+ @Override
+ public Object execute() throws Exception {
+ karService.uninstall(name);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
----------------------------------------------------------------------
diff --git a/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java b/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
index 460a21b..539cfaf 100644
--- a/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
+++ b/kar/command/src/main/java/org/apache/karaf/kar/command/completers/KarCompleter.java
@@ -16,14 +16,16 @@
*/
package org.apache.karaf.kar.command.completers;
-import org.apache.karaf.kar.KarService;
-import org.apache.karaf.shell.console.Completer;
-import org.apache.karaf.shell.console.completer.StringsCompleter;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
-
import java.util.List;
+import org.apache.karaf.kar.KarService;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
/**
* Completer on all installed KAR files.
*/
@@ -33,7 +35,7 @@ public class KarCompleter implements Completer {
@Reference
private KarService karService;
- public int complete(String buffer, int cursor, @SuppressWarnings("rawtypes") List candidates) {
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
StringsCompleter delegate = new StringsCompleter();
try {
for (String karName : karService.list()) {
@@ -42,15 +44,7 @@ public class KarCompleter implements Completer {
} catch (Exception e) {
// ignore
}
- return delegate.complete(buffer, cursor, candidates);
- }
-
- public void setKarService(KarService karService) {
- this.karService = karService;
- }
-
- public KarService getKarService() {
- return this.karService;
+ return delegate.complete(session, commandLine, candidates);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/kar/command/src/main/resources/OSGI-INF/blueprint/kar-command.xml
----------------------------------------------------------------------
diff --git a/kar/command/src/main/resources/OSGI-INF/blueprint/kar-command.xml b/kar/command/src/main/resources/OSGI-INF/blueprint/kar-command.xml
deleted file mode 100644
index 53d56d7..0000000
--- a/kar/command/src/main/resources/OSGI-INF/blueprint/kar-command.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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" default-activation="lazy">
-
- <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
- scan="org.apache.karaf.kar.command.*" />
-
-</blueprint>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/pom.xml
----------------------------------------------------------------------
diff --git a/shell/commands/pom.xml b/shell/commands/pom.xml
index 15fb8c7..6609cd5 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.core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
@@ -113,6 +113,9 @@
org.apache.karaf.util;-split-package:=merge-first,
org.apache.karaf.shell.commands.impl*
</Private-Package>
+ <Karaf-Commands>
+ org.apache.karaf.shell.commands.impl
+ </Karaf-Commands>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/InfoProvider.java
new file mode 100644
index 0000000..a69f824
--- /dev/null
+++ b/shell/commands/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/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/AliasAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/AliasAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/AliasAction.java
index 298c98d..21db405 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/AliasAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/AliasAction.java
@@ -16,19 +16,25 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "shell", name = "alias", description = "Create an alias to a command")
@Service
-public class AliasAction extends AbstractAction {
+public class AliasAction implements Action {
@Argument(index = 0, name = "command", description = "The command to alias, e.g. 'ldn = { log:display -n $args }'", required = true, multiValued = false)
private String alias;
- protected Object doExecute() throws Exception {
+ @Reference
+ private Session session;
+
+ @Override
+ public Object execute() throws Exception {
session.execute(alias);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CatAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CatAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CatAction.java
index 18ca32b..41ec0a6 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CatAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CatAction.java
@@ -28,18 +28,22 @@ import java.net.MalformedURLException;
import java.util.Collections;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Concatenate and print files and/or URLs.
*/
@Command(scope = "shell", name = "cat", description = "Displays the content of a file or URL.")
@Service
-public class CatAction extends AbstractAction {
+public class CatAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Option(name = "-n", aliases = {}, description = "Number the output lines, starting at 1.", required = false, multiValued = false)
private boolean displayLineNumbers;
@@ -50,7 +54,8 @@ public class CatAction extends AbstractAction {
@Argument(index = 0, name = "paths or urls", description = "A list of file paths or urls to display separated by whitespace (use - for STDIN)", required = false, multiValued = true)
private List<String> paths;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (stdin) {
paths = Collections.singletonList("-");
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ClearAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ClearAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ClearAction.java
index ac660eb..805ec25 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ClearAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ClearAction.java
@@ -16,23 +16,24 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* A command to clear the console buffer
*/
@Command(scope = "shell", name = "clear", description = "Clears the console buffer.")
@Service
-public class ClearAction extends AbstractAction {
+public class ClearAction implements Action {
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
System.out.print("\33[2J");
System.out.flush();
System.out.print("\33[1;1H");
System.out.flush();
- return null;
- }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CompletionAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CompletionAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CompletionAction.java
index 2639039..614d2b1 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CompletionAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/CompletionAction.java
@@ -16,36 +16,38 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.console.SessionProperties;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
/**
* Command to change the completion mode while using the shell console.
*/
@Command(scope = "shell", name = "completion", description = "Display or change the completion mode on the current console session.")
@Service
-public class CompletionAction extends AbstractAction {
+public class CompletionAction implements Action {
@Argument(index = 0, name = "mode", description = "The completion mode to set. The valid completion modes are: global, first, subshell.", required = false, multiValued = false)
+ @Completion(value = StringsCompleter.class, values = { "global", "first", "subshell" })
String mode;
- protected Object doExecute() throws Exception {
- if (mode == null) {
- System.out.println(session.get(SessionProperties.COMPLETION_MODE));
- return null;
- }
+ @Reference
+ Session session;
- if (!mode.equalsIgnoreCase("global") && !mode.equalsIgnoreCase("first") && !mode.equalsIgnoreCase("subshell")) {
+ @Override
+ public Object execute() throws Exception {
+ if (mode == null) {
+ System.out.println(session.get(Session.COMPLETION_MODE));
+ } else if (!mode.equalsIgnoreCase("global") && !mode.equalsIgnoreCase("first") && !mode.equalsIgnoreCase("subshell")) {
System.err.println("The completion mode is not correct. The valid modes are: global, first, subshell. See documentation for details.");
- return null;
+ } else {
+ session.put(Session.COMPLETION_MODE, mode.toLowerCase());
}
-
- mode = mode.toUpperCase();
-
- session.put(SessionProperties.COMPLETION_MODE, mode);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/DateAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/DateAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/DateAction.java
index e448fd7..c201ab0 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/DateAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/DateAction.java
@@ -16,11 +16,11 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@@ -28,7 +28,7 @@ import java.util.Date;
@Command(scope = "shell", name = "date", description = "Display the current time in the given FORMAT")
@Service
-public class DateAction extends AbstractAction {
+public class DateAction implements Action {
@Option(name = "-d", aliases = { "--date" }, description = "Display time described, not now", multiValued = false, required = false)
private String date;
@@ -36,7 +36,8 @@ public class DateAction extends AbstractAction {
@Argument(index = 0, name = "format", description = "Output format", multiValued = false, required = false)
private String format;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
Date d;
if (date == null || date.equalsIgnoreCase("now")) {
d = new Date();
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EachAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EachAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EachAction.java
index a115939..0de344e 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EachAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EachAction.java
@@ -19,18 +19,20 @@ package org.apache.karaf.shell.commands.impl;
import java.util.Collection;
import java.util.Collections;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Function;
+import org.apache.karaf.shell.api.console.Session;
/**
* Execute a closure on a list of arguments.
*/
@Command(scope = "shell", name = "each", description = "Execute a closure on a list of arguments.")
@Service
-public class EachAction extends AbstractAction {
+public class EachAction implements Action {
@Argument(name = "values", index = 0, multiValued = false, required = true, description = "The collection of arguments to iterate on")
Collection<Object> values;
@@ -38,8 +40,11 @@ public class EachAction extends AbstractAction {
@Argument(name = "function", index = 1, multiValued = false, required = true, description = "The function to execute")
Function function;
+ @Reference
+ Session session;
+
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
for (Object v : values) {
function.execute(session, Collections.singletonList(v));
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EchoAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EchoAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EchoAction.java
index 4eda5d3..433e2a9 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EchoAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EchoAction.java
@@ -18,15 +18,15 @@ package org.apache.karaf.shell.commands.impl;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "shell", name = "echo", description="Echoes or prints arguments to STDOUT.")
@Service
-public class EchoAction extends AbstractAction
+public class EchoAction implements Action
{
@Option(name = "-n", aliases = {}, description = "Do not print the trailing newline character", required = false, multiValued = false)
private boolean noTrailingNewline = false;
@@ -34,7 +34,8 @@ public class EchoAction extends AbstractAction
@Argument(index = 0, name = "arguments", description="Arguments to display separated by whitespaces", required = false, multiValued = true)
private List<String> args;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (args != null) {
boolean first = true;
for (String arg : args) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java
index dc2d90c..77b9a09 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/EditAction.java
@@ -27,19 +27,20 @@ import java.net.URLConnection;
import java.util.UUID;
import java.util.regex.Pattern;
-import jline.Terminal;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Reference;
-import org.apache.karaf.shell.inject.Service;
+import jline.TerminalSupport;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.util.StreamUtils;
import org.jledit.ConsoleEditor;
import org.jledit.EditorFactory;
@Command(scope = "shell", name = "edit", description = "Calls a text editor.")
@Service
-public class EditAction extends AbstractAction {
+public class EditAction implements Action {
private final Pattern URL_PATTERN = Pattern.compile("[^: ]+:[^ ]+");
@@ -49,8 +50,11 @@ public class EditAction extends AbstractAction {
@Reference
private EditorFactory editorFactory;
+ @Reference
+ Terminal terminal;
+
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
URLConnection connection = null;
InputStream is = null;
OutputStream os = null;
@@ -137,6 +141,7 @@ public class EditAction extends AbstractAction {
if (os != null) {
StreamUtils.close(os);
}
+
return null;
}
@@ -146,13 +151,22 @@ public class EditAction extends AbstractAction {
* @return
* @throws Exception
*/
- private Terminal getTerminal() throws Exception {
- Object terminalObject = session.get(".jline.terminal");
- if (terminalObject instanceof Terminal) {
- return (Terminal) terminalObject;
+ private jline.Terminal getTerminal() throws Exception {
+ try {
+ return (jline.Terminal) terminal.getClass().getMethod("getTerminal").invoke(terminal);
+ } catch (Throwable t) {
+ return new TerminalSupport(true) {
+ @Override
+ public int getWidth() {
+ return terminal.getWidth();
+ }
+ @Override
+ public int getHeight() {
+ return terminal.getHeight();
+ }
+ };
}
- throw new IllegalStateException("Could not get Terminal from CommandSession.");
}
/**
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ExecuteAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ExecuteAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ExecuteAction.java
index 677f3de..0afe73d 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ExecuteAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ExecuteAction.java
@@ -18,23 +18,28 @@ package org.apache.karaf.shell.commands.impl;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.util.process.PumpStreamHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Execute system processes.
*/
@Command(scope = "shell", name = "exec", description = "Executes system processes.")
@Service
-public class ExecuteAction extends AbstractAction {
+public class ExecuteAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Argument(index = 0, name = "command", description = "Execution command with arguments", required = true, multiValued = true)
private List<String> args;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
ProcessBuilder builder = new ProcessBuilder(args);
PumpStreamHandler handler = new PumpStreamHandler(System.in, System.out, System.err, "Command" + args.toString());
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java
index 8ed0f76..573714e 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/GrepAction.java
@@ -26,17 +26,17 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.fusesource.jansi.Ansi;
@Command(scope = "shell", name="grep", description="Prints lines matching the given pattern.", detailedDescription="classpath:grep.txt")
@Service
-public class GrepAction extends AbstractAction {
+public class GrepAction implements Action {
public static enum ColorOption {
never,
@@ -82,8 +82,8 @@ public class GrepAction extends AbstractAction {
@Option(name = "-C", aliases = { "--context" }, description = "Print NUM lines of output context. Places a line containing -- between contiguous groups of matches.", required = false, multiValued = false)
private int context = 0;
-
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (after < 0) {
after = context;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HeadAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HeadAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HeadAction.java
index 9a05935..ad144d4 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HeadAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HeadAction.java
@@ -25,25 +25,30 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Command(scope = "shell", name = "head", description = "Displays the first lines of a file.")
@Service
-public class HeadAction extends AbstractAction {
+public class HeadAction implements Action {
private static final int DEFAULT_NUMBER_OF_LINES = 10;
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
@Option(name = "-n", aliases = {}, description = "The number of lines to display, starting at 1.", required = false, multiValued = false)
private int numberOfLines;
@Argument(index = 0, name = "paths or urls", description = "A list of file paths or urls to display separated by whitespaces.", required = false, multiValued = true)
private List<String> paths;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
//If no paths provided assume standar input
if (paths == null || paths.size() == 0) {
if (log.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HistoryAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HistoryAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HistoryAction.java
index 6c7dae6..09ddeb1 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HistoryAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/HistoryAction.java
@@ -16,11 +16,12 @@
*/
package org.apache.karaf.shell.commands.impl;
-import jline.console.history.History;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.History;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.fusesource.jansi.Ansi;
/**
@@ -28,28 +29,29 @@ import org.fusesource.jansi.Ansi;
*/
@Command(scope = "shell", name="history", description="Prints command history.")
@Service
-public class HistoryAction extends AbstractAction {
+public class HistoryAction implements Action {
@Option(name = "-c", aliases = { "--clear" }, description = "Clears the shell command history.", required = false, multiValued = false)
private boolean clear;
-
- @Override
- protected Object doExecute() throws Exception {
- History history = (History) session.get(".jline.history");
+ @Reference
+ History history;
+
+ @Override
+ public Object execute() throws Exception {
if (history != null && clear) {
history.clear();
}
-
- for (History.Entry element : history) {
+ for (int index = history.first(); index <= history.last(); index++) {
System.out.println(
Ansi.ansi()
.a(" ")
- .a(Ansi.Attribute.INTENSITY_BOLD).render("%3d", element.index()).a(Ansi.Attribute.INTENSITY_BOLD_OFF)
+ .a(Ansi.Attribute.INTENSITY_BOLD).render("%3d", index).a(Ansi.Attribute.INTENSITY_BOLD_OFF)
.a(" ")
- .a(element.value())
+ .a(history.get(index))
.toString());
}
return null;
}
+
}
[04/10] [KARAF-2805] Clean console and commands model
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
new file mode 100644
index 0000000..9cd0343
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
@@ -0,0 +1,481 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.command;
+
+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.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+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.Iterator;
+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.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.converter.DefaultConverter;
+import org.apache.karaf.shell.support.converter.GenericType;
+import org.apache.karaf.shell.support.CommandException;
+import org.apache.karaf.shell.support.NameScoping;
+
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+public class DefaultActionPreparator {
+
+ public boolean prepare(Action action, Session session, List<Object> params) throws Exception {
+
+ Command command = action.getClass().getAnnotation(Command.class);
+ 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 = 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) {
+ 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 " + action.getClass().getName());
+ }
+ orderedArguments.set(index, argument);
+ }
+ }
+ }
+ assertIndexesAreCorrect(action.getClass(), orderedArguments);
+
+ String commandErrorSt = COLOR_RED + "Error executing command " + command.scope() + ":" + INTENSITY_BOLD + command.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 = session.getTerminal() != null ? session.getTerminal().getWidth() : 80;
+ boolean globalScope = NameScoping.isGlobalScope(session, command.scope());
+ printUsage(action, options, arguments, 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, 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, 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, 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 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());
+ }
+ }
+ }
+
+ public void printUsage(Action action, Map<Option, Field> options, Map<Argument, Field> arguments, PrintStream out, boolean globalScope, int termWidth) {
+ Command command = action.getClass().getAnnotation(Command.class);
+ 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);
+ 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, arguments.get(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);
+ 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, options.get(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 = loadDescription(action.getClass(), command.detailedDescription());
+ printFormatted(" ", desc, termWidth, out, true);
+ }
+ }
+ }
+
+ public Object getDefaultValue(Action action, Field field) {
+ try {
+ field.setAccessible(true);
+ return field.get(action);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
new file mode 100644
index 0000000..ec0b1a8
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.command;
+
+import java.lang.annotation.Annotation;
+
+import org.apache.karaf.shell.api.action.Option;
+
+
+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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
new file mode 100644
index 0000000..611ecab
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ManagerImpl.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.command;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Destroy;
+import org.apache.karaf.shell.api.action.lifecycle.Init;
+import org.apache.karaf.shell.api.action.lifecycle.Manager;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.support.converter.GenericType;
+
+public class ManagerImpl implements Manager {
+
+ private final Registry dependencies;
+ private final Registry registrations;
+ private final Map<Class<?>, Object> instances = new HashMap<Class<?>, Object>();
+ private final boolean allowCustomServices;
+
+ public ManagerImpl(Registry dependencies, Registry registrations) {
+ this(dependencies, registrations, false);
+ }
+
+ public ManagerImpl(Registry dependencies, Registry registrations, boolean allowCustomServices) {
+ this.dependencies = dependencies;
+ this.registrations = registrations;
+ this.allowCustomServices = allowCustomServices;
+ }
+
+ public <T> T instantiate(Class<? extends T> clazz) throws Exception {
+ return instantiate(clazz, dependencies);
+ }
+
+ public <T> T instantiate(Class<? extends T> clazz, Registry registry) throws Exception {
+ if (!allowCustomServices) {
+ Service reg = clazz.getAnnotation(Service.class);
+ if (reg == null) {
+ throw new IllegalArgumentException("Class " + clazz.getName() + " is not annotated with @Service");
+ }
+ }
+ T instance = clazz.newInstance();
+ // Inject services
+ for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
+ for (Field field : cl.getDeclaredFields()) {
+ if (field.getAnnotation(Reference.class) != null) {
+ GenericType type = new GenericType(field.getGenericType());
+ Object value;
+ if (type.getRawClass() == List.class) {
+ value = registry.getServices(type.getActualTypeArgument(0).getRawClass());
+ if (value == null && registry != this.dependencies) {
+ value = this.dependencies.getServices(type.getActualTypeArgument(0).getRawClass());
+ }
+ } else {
+ value = registry.getService(type.getRawClass());
+ if (value == null && registry != this.dependencies) {
+ value = this.dependencies.getService(type.getRawClass());
+ }
+ }
+ if (!allowCustomServices && value == null) {
+ throw new RuntimeException("No service matching " + field.getType().getName());
+ }
+ field.setAccessible(true);
+ field.set(instance, value);
+ }
+ }
+ }
+ for (Method method : clazz.getDeclaredMethods()) {
+ Init ann = method.getAnnotation(Init.class);
+ if (ann != null && method.getParameterTypes().length == 0 && method.getReturnType() == void.class) {
+ method.setAccessible(true);
+ method.invoke(instance);
+ }
+ }
+ return instance;
+ }
+
+ public void release(Object instance) throws Exception {
+ Class<?> clazz = instance.getClass();
+ if (!allowCustomServices) {
+ Service reg = clazz.getAnnotation(Service.class);
+ if (reg == null) {
+ throw new IllegalArgumentException("Class " + clazz.getName() + " is not annotated with @Service");
+ }
+ }
+ for (Method method : clazz.getDeclaredMethods()) {
+ Destroy ann = method.getAnnotation(Destroy.class);
+ if (ann != null && method.getParameterTypes().length == 0 && method.getReturnType() == void.class) {
+ method.setAccessible(true);
+ method.invoke(instance);
+ }
+ }
+ }
+
+ @Override
+ public void register(Class<?> clazz) {
+ if (!allowCustomServices) {
+ Service reg = clazz.getAnnotation(Service.class);
+ if (reg == null ) {
+ throw new IllegalArgumentException("Class " + clazz.getName() + " is not annotated with @Service");
+ }
+ }
+ 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");
+ }
+ Object command = new ActionCommand(this, (Class<? extends Action>) clazz);
+ registrations.register(command);
+ }
+ if (allowCustomServices || Completer.class.isAssignableFrom(clazz)) {
+ try {
+ // Create completer
+ Object completer = instantiate(clazz);
+ synchronized (instances) {
+ instances.put(clazz, completer);
+ }
+ registrations.register(completer);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ public void unregister(Class<?> clazz) {
+ Object object;
+ synchronized (instances) {
+ object = instances.remove(clazz);
+ }
+ if (object != null) {
+ registrations.unregister(object);
+ if (object instanceof Completer) {
+ try {
+ release(object);
+ } catch (Exception e) {
+ // TODO: log exception
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtender.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtender.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtender.java
new file mode 100644
index 0000000..25bcae7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtender.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.osgi;
+
+import org.apache.felix.utils.extender.AbstractExtender;
+import org.apache.felix.utils.extender.Extension;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Bundle extender scanning for command classes.
+ */
+public class CommandExtender extends AbstractExtender {
+
+ public static final String KARAF_COMMANDS = "Karaf-Commands";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CommandExtender.class);
+
+ //
+ // Adapt BundleActivator to make it blueprint friendly
+ //
+
+ private Registry registry;
+
+ public CommandExtender(Registry registry) {
+ this.registry = registry;
+ this.registry.register(new ManagerImpl(this.registry, this.registry));
+ }
+
+ //
+ // Extender implementation
+ //
+
+ @Override
+ protected Extension doCreateExtension(Bundle bundle) throws Exception {
+ if (bundle.getHeaders().get(KARAF_COMMANDS) != null) {
+ return new CommandExtension(bundle, registry);
+ }
+ return null;
+ }
+
+ @Override
+ protected void debug(Bundle bundle, String msg) {
+ StringBuilder buf = new StringBuilder();
+ if ( bundle != null )
+ {
+ buf.append( bundle.getSymbolicName() );
+ buf.append( " (" );
+ buf.append( bundle.getBundleId() );
+ buf.append( "): " );
+ }
+ buf.append(msg);
+ LOGGER.debug(buf.toString());
+ }
+
+ @Override
+ protected void warn(Bundle bundle, String msg, Throwable t) {
+ StringBuilder buf = new StringBuilder();
+ if ( bundle != null )
+ {
+ buf.append( bundle.getSymbolicName() );
+ buf.append( " (" );
+ buf.append( bundle.getBundleId() );
+ buf.append( "): " );
+ }
+ buf.append(msg);
+ LOGGER.warn(buf.toString(), t);
+ }
+
+ @Override
+ protected void error(String msg, Throwable t) {
+ LOGGER.error(msg, t);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtension.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtension.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtension.java
new file mode 100644
index 0000000..b1a953b
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/CommandExtension.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.osgi;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.felix.utils.extender.Extension;
+import org.apache.felix.utils.manifest.Clause;
+import org.apache.felix.utils.manifest.Parser;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.History;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.apache.karaf.shell.support.converter.GenericType;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.wiring.BundleWiring;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Commands extension
+ */
+public class CommandExtension implements Extension, Satisfiable {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(CommandExtension.class);
+
+ private final Bundle bundle;
+ private final ManagerImpl manager;
+ private final Registry registry;
+ private final CountDownLatch started;
+ private final MultiServiceTracker tracker;
+ private final List<Satisfiable> satisfiables = new ArrayList<Satisfiable>();
+
+
+ public CommandExtension(Bundle bundle, Registry registry) {
+ this.bundle = bundle;
+ this.registry = new RegistryImpl(registry);
+ this.registry.register(bundle.getBundleContext());
+ this.manager = new ManagerImpl(this.registry, registry);
+ this.registry.register(this.manager);
+ this.started = new CountDownLatch(1);
+ this.tracker = new MultiServiceTracker(bundle.getBundleContext(), this);
+ }
+
+ @Override
+ public void found() {
+ for (Satisfiable s : satisfiables) {
+ s.found();
+ }
+ }
+
+ @Override
+ public void updated() {
+ for (Satisfiable s : satisfiables) {
+ s.updated();
+ }
+ }
+
+ @Override
+ public void lost() {
+ for (Satisfiable s : satisfiables) {
+ s.lost();
+ }
+ }
+
+ public void start() throws Exception {
+ try {
+ String header = bundle.getHeaders().get(CommandExtender.KARAF_COMMANDS);
+ Clause[] clauses = Parser.parseHeader(header);
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ for (Clause clause : clauses) {
+ String name = clause.getName();
+ 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(bundle.loadClass(className));
+ }
+ }
+ tracker.open();
+ if (!tracker.isSatisfied()) {
+ LOGGER.info("Command registration delayed. Missing dependencies: " + tracker.getMissingServices());
+ }
+ } finally {
+ started.countDown();
+ }
+ }
+
+ public void destroy() {
+ try {
+ started.await(5000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ LOGGER.warn("The wait for bundle being started before destruction has been interrupted.", e);
+ }
+ tracker.close();
+ }
+
+ private void inspectClass(final Class<?> clazz) throws Exception {
+ Service reg = clazz.getAnnotation(Service.class);
+ if (reg == null) {
+ return;
+ }
+ // Create trackers
+ for (Class<?> cl = clazz; cl != Object.class; cl = cl.getSuperclass()) {
+ for (Field field : cl.getDeclaredFields()) {
+ if (field.getAnnotation(Reference.class) != null) {
+ GenericType type = new GenericType(field.getType());
+ Class clazzRef = type.getRawClass() == List.class ? type.getActualTypeArgument(0).getRawClass() : type.getRawClass();
+ if (clazzRef != BundleContext.class
+ && clazzRef != Session.class
+ && clazzRef != Terminal.class
+ && clazzRef != History.class
+ && clazzRef != Registry.class
+ && clazzRef != SessionFactory.class
+ && !registry.hasService(clazzRef)) {
+ track(clazzRef);
+ }
+ }
+ }
+ }
+ satisfiables.add(new AutoRegister(clazz));
+ }
+
+ protected void track(final Class clazzRef) {
+ tracker.track(clazzRef);
+ registry.register(new Callable() {
+ @Override
+ public Object call() throws Exception {
+ return tracker.getService(clazzRef);
+ }
+ }, clazzRef);
+ }
+
+ public class AutoRegister implements Satisfiable {
+
+ private final Class<?> clazz;
+
+ public AutoRegister(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public void found() {
+ try {
+ manager.register(clazz);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to create service " + clazz.getName(), e);
+ }
+ }
+
+ @Override
+ public void updated() {
+ lost();
+ found();
+ }
+
+ @Override
+ public void lost() {
+ manager.unregister(clazz);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/MultiServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/MultiServiceTracker.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/MultiServiceTracker.java
new file mode 100644
index 0000000..a762957
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/MultiServiceTracker.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.osgi;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Track multiple services by their type
+ */
+public class MultiServiceTracker implements Satisfiable {
+
+ private final BundleContext bundleContext;
+ private final Satisfiable satisfiable;
+ private final ConcurrentMap<Class, SingleServiceTracker> trackers = new ConcurrentHashMap<Class, SingleServiceTracker>();
+ private final AtomicInteger count = new AtomicInteger(-1);
+
+ public MultiServiceTracker(BundleContext bundleContext, Satisfiable satisfiable) {
+ this.bundleContext = bundleContext;
+ this.satisfiable = satisfiable;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void track(Class service) {
+ if (trackers.get(service) == null) {
+ SingleServiceTracker tracker = new SingleServiceTracker(bundleContext, service, this);
+ trackers.putIfAbsent(service, tracker);
+ }
+ }
+
+ public <T> T getService(Class<T> clazz) {
+ SingleServiceTracker tracker = trackers.get(clazz);
+ return tracker != null ? clazz.cast(tracker.getService()) : null;
+ }
+
+ public void open() {
+ for (SingleServiceTracker tracker : trackers.values()) {
+ tracker.open();
+ }
+ found();
+ }
+
+ public void close() {
+ lost();
+ for (SingleServiceTracker tracker : trackers.values()) {
+ tracker.close();
+ }
+ }
+
+ public boolean isSatisfied() {
+ return count.get() == trackers.size();
+ }
+
+ public List<String> getMissingServices() {
+ List<String> missing = new ArrayList<String>();
+ for (SingleServiceTracker tracker : trackers.values()) {
+ if (!tracker.isSatisfied()) {
+ missing.add(tracker.getClassName());
+ }
+ }
+ return missing;
+ }
+
+ @Override
+ public void found() {
+ if (count.incrementAndGet() == trackers.size()) {
+ satisfiable.found();
+ }
+ }
+
+ @Override
+ public void updated() {
+ if (count.get() == trackers.size()) {
+ satisfiable.updated();
+ }
+ }
+
+ @Override
+ public void lost() {
+ if (count.getAndDecrement() == trackers.size()) {
+ satisfiable.lost();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/RegistryImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/RegistryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/RegistryImpl.java
new file mode 100644
index 0000000..38b56ed
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/RegistryImpl.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.osgi;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Registry;
+
+public class RegistryImpl implements Registry {
+
+ private final Registry parent;
+ private final Map<Object, Object> services = new LinkedHashMap<Object, Object>();
+
+ public RegistryImpl(Registry parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public List<Command> getCommands() {
+ return getServices(Command.class);
+ }
+
+ @Override
+ public <T> void register(Callable<T> factory, Class<T> clazz) {
+ synchronized (services) {
+ services.put(factory, new Factory<T>(clazz, factory));
+ }
+ }
+
+ @Override
+ public void register(Object service) {
+ synchronized (services) {
+ services.put(service, service);
+ }
+ }
+
+ @Override
+ public void unregister(Object service) {
+ synchronized (services) {
+ services.remove(service);
+ }
+ }
+
+ @Override
+ public <T> T getService(Class<T> clazz) {
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ try {
+ return clazz.cast(((Factory) service).callable.call());
+ } catch (Exception e) {
+ // TODO: log exception
+ }
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ return clazz.cast(service);
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ return parent.getService(clazz);
+ }
+ return null;
+ }
+
+ @Override
+ public <T> List<T> getServices(Class<T> clazz) {
+ List<T> list = new ArrayList<T>();
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ try {
+ list.add(clazz.cast(((Factory) service).callable.call()));
+ } catch (Exception e) {
+ // TODO: log exception
+ }
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ list.add(clazz.cast(service));
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ list.addAll(parent.getServices(clazz));
+ }
+ return list;
+ }
+
+ @Override
+ public boolean hasService(Class<?> clazz) {
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ return true;
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ return true;
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ return parent.hasService(clazz);
+ }
+ return false;
+ }
+
+ protected boolean isVisible(Object service) {
+ return true;
+ }
+
+ static class Factory<T> {
+
+ final Class<T> clazz;
+ final Callable<T> callable;
+
+ Factory(Class<T> clazz, Callable<T> callable) {
+ this.clazz = clazz;
+ this.callable = callable;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/Satisfiable.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/Satisfiable.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/Satisfiable.java
new file mode 100644
index 0000000..90545aa
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/Satisfiable.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.impl.action.osgi;
+
+/**
+ * Interface to be called with a boolean satisfaction status.
+ */
+public interface Satisfiable {
+
+ void found();
+ void updated();
+ void lost();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/SingleServiceTracker.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/SingleServiceTracker.java
new file mode 100644
index 0000000..039fe48
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/osgi/SingleServiceTracker.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.osgi;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Track a single service by its type.
+ *
+ * @param <T>
+ */
+public final class SingleServiceTracker<T> {
+
+ private final BundleContext ctx;
+ private final String className;
+ private final AtomicReference<T> service = new AtomicReference<T>();
+ private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
+ private final AtomicBoolean open = new AtomicBoolean(false);
+ private final Satisfiable serviceListener;
+ private Filter filter;
+
+ private final ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ if (open.get()) {
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ ServiceReference deadRef = event.getServiceReference();
+ if (deadRef.equals(ref.get())) {
+ findMatchingReference(deadRef);
+ }
+ } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
+ findMatchingReference(null);
+ }
+ }
+ }
+ };
+
+ public SingleServiceTracker(BundleContext context, Class<T> clazz, Satisfiable sl) {
+ ctx = context;
+ this.className = clazz.getName();
+ serviceListener = sl;
+ }
+
+ public T getService() {
+ return service.get();
+ }
+
+ public ServiceReference getServiceReference() {
+ return ref.get();
+ }
+
+ public void open() {
+ if (open.compareAndSet(false, true)) {
+ try {
+ String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
+ if (filter != null) filterString = "(&" + filterString + filter + ')';
+ ctx.addServiceListener(listener, filterString);
+ findMatchingReference(null);
+ } catch (InvalidSyntaxException e) {
+ // this can never happen. (famous last words :)
+ }
+ }
+ }
+
+ private void findMatchingReference(ServiceReference original) {
+ boolean clear = true;
+ ServiceReference ref = ctx.getServiceReference(className);
+ if (ref != null && (filter == null || filter.match(ref))) {
+ @SuppressWarnings("unchecked")
+ T service = (T) ctx.getService(ref);
+ if (service != null) {
+ clear = false;
+
+ // We do the unget out of the lock so we don't exit this class while holding a lock.
+ if (!!!update(original, ref, service)) {
+ ctx.ungetService(ref);
+ }
+ }
+ } else if (original == null) {
+ clear = false;
+ }
+
+ if (clear) {
+ update(original, null, null);
+ }
+ }
+
+ private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
+ boolean result = false;
+ int foundLostReplaced = -1;
+
+ // Make sure we don't try to get a lock on null
+ Object lock;
+
+ // we have to choose our lock.
+ if (newRef != null) lock = newRef;
+ else if (deadRef != null) lock = deadRef;
+ else lock = this;
+
+ // This lock is here to ensure that no two threads can set the ref and service
+ // at the same time.
+ synchronized (lock) {
+ if (open.get()) {
+ result = this.ref.compareAndSet(deadRef, newRef);
+ if (result) {
+ this.service.set(service);
+
+ if (deadRef == null && newRef != null) foundLostReplaced = 0;
+ if (deadRef != null && newRef == null) foundLostReplaced = 1;
+ if (deadRef != null && newRef != null) foundLostReplaced = 2;
+ }
+ }
+ }
+
+ if (serviceListener != null) {
+ if (foundLostReplaced == 0) serviceListener.found();
+ else if (foundLostReplaced == 1) serviceListener.lost();
+ else if (foundLostReplaced == 2) serviceListener.updated();
+ }
+
+ return result;
+ }
+
+ public void close() {
+ if (open.compareAndSet(true, false)) {
+ ctx.removeServiceListener(listener);
+
+ synchronized (this) {
+ ServiceReference deadRef = ref.getAndSet(null);
+ service.set(null);
+ if (deadRef != null) ctx.ungetService(deadRef);
+ }
+ }
+ }
+
+ public boolean isSatisfied() {
+ return service.get() != null;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/Branding.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/Branding.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/Branding.java
new file mode 100644
index 0000000..bae8f2a
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/Branding.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.karaf.shell.api.console.Terminal;
+
+
+public final class Branding {
+
+ private Branding() { }
+
+ public static Properties loadBrandingProperties() {
+ Properties props = new Properties();
+ loadProps(props, "org/apache/karaf/shell/console/branding.properties");
+ loadProps(props, "org/apache/karaf/branding/branding.properties");
+ return props;
+ }
+
+ public static Properties loadBrandingProperties(Terminal terminal) {
+ Properties props = new Properties();
+ if (terminal != null && terminal.getClass().getName().endsWith("SshTerminal")) {
+ //it's a ssh client, so load branding seperately
+ loadProps(props, "org/apache/karaf/shell/console/branding-ssh.properties");
+ } else {
+ loadProps(props, "org/apache/karaf/shell/console/branding.properties");
+ }
+
+ loadProps(props, "org/apache/karaf/branding/branding.properties");
+ return props;
+ }
+
+ protected static void loadProps(Properties props, String resource) {
+ InputStream is = null;
+ try {
+ is = Branding.class.getClassLoader().getResourceAsStream(resource);
+ if (is != null) {
+ props.load(is);
+ }
+ } catch (IOException e) {
+ // ignore
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandNamesCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandNamesCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandNamesCompleter.java
new file mode 100644
index 0000000..377bdcc
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandNamesCompleter.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+public class CommandNamesCompleter extends org.apache.karaf.shell.support.completers.CommandNamesCompleter {
+
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ // TODO: optimize
+ List<Command> list = session.getRegistry().getCommands();
+ Set<String> names = new HashSet<String>();
+ for (Command command : list) {
+ names.add(command.getScope() + ":" + command.getName());
+ names.add(command.getName());
+ }
+ int res = new StringsCompleter(names).complete(session, commandLine, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandWrapper.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandWrapper.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandWrapper.java
new file mode 100644
index 0000000..9488d8f
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandWrapper.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.Closure;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Session;
+
+public class CommandWrapper implements Function {
+
+ private final Command command;
+
+ public CommandWrapper(Command command) {
+ this.command = command;
+ }
+
+ public Command getCommand() {
+ return command;
+ }
+
+ @Override
+ public Object execute(final CommandSession commandSession, List<Object> arguments) throws Exception {
+ // TODO: remove the hack for .session
+ Session session = (Session) commandSession.get(".session");
+ // When need to translate closures to a compatible type for the command
+ for (int i = 0; i < arguments.size(); i++) {
+ Object v = arguments.get(i);
+ if (v instanceof Closure) {
+ final Closure closure = (Closure) v;
+ arguments.set(i, new org.apache.karaf.shell.api.console.Function() {
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ return closure.execute(commandSession, arguments);
+ }
+ });
+ }
+ }
+ return command.execute(session, arguments);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
new file mode 100644
index 0000000..d73af34
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CommandsCompleter.java
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+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.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.support.completers.AggregateCompleter;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+/**
+ * Overall command line completer.
+ */
+public class CommandsCompleter extends org.apache.karaf.shell.support.completers.CommandsCompleter {
+
+ private final SessionFactory factory;
+ private final Map<String, Completer> globalCompleters = new HashMap<String, Completer>();
+ private final Map<String, Completer> localCompleters = new HashMap<String, Completer>();
+ private final List<Command> commands = new ArrayList<Command>();
+
+ public CommandsCompleter(SessionFactory factory) {
+ this.factory = factory;
+ }
+
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ Map<String, Completer>[] allCompleters = checkData();
+
+ List<String> scopes = getCurrentScopes(session);
+ sort(allCompleters, scopes);
+
+ String subShell = getCurrentSubShell(session);
+ String completion = getCompletionType(session);
+
+ // SUBSHELL mode
+ if (Session.COMPLETION_MODE_SUBSHELL.equalsIgnoreCase(completion)) {
+ if (subShell.isEmpty()) {
+ subShell = Session.SCOPE_GLOBAL;
+ }
+ 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(Session.SCOPE_GLOBAL)) {
+ completers.add(new StringsCompleter(new String[] { "exit" }));
+ }
+ int res = new AggregateCompleter(completers).complete(session, commandLine, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ if (Session.COMPLETION_MODE_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(session, commandLine, candidates);
+ if (!candidates.isEmpty()) {
+ Collections.sort(candidates);
+ return res;
+ }
+ }
+ List<Completer> compl = new ArrayList<Completer>();
+ compl.add(new StringsCompleter(getAliases(session)));
+ compl.addAll(allCompleters[0].values());
+ int res = new AggregateCompleter(compl).complete(session, commandLine, candidates);
+ Collections.sort(candidates);
+ return res;
+ }
+
+ List<Completer> compl = new ArrayList<Completer>();
+ compl.add(new StringsCompleter(getAliases(session)));
+ compl.addAll(allCompleters[0].values());
+ int res = new AggregateCompleter(compl).complete(session, commandLine, 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(Session session) {
+ String scopes = (String) session.get(Session.SCOPE);
+ return Arrays.asList(scopes.split(":"));
+ }
+
+ protected String getCurrentSubShell(Session session) {
+ String s = (String) session.get(Session.SUBSHELL);
+ if (s == null) {
+ s = "";
+ }
+ return s;
+ }
+
+ protected String getCompletionType(Session session) {
+ String completion = (String) session.get(Session.COMPLETION_MODE);
+ if (completion == null) {
+ completion = Session.COMPLETION_MODE_GLOBAL;
+ }
+ return completion;
+ }
+
+ protected String stripScope(String name) {
+ int index = name.indexOf(":");
+ return index > 0 ? name.substring(index + 1) : name;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Map<String, Completer>[] checkData() {
+ // Copy the set to avoid concurrent modification exceptions
+ // TODO: fix that in gogo instead
+ Collection<Command> commands;
+ boolean update;
+ synchronized (this) {
+ commands = factory.getRegistry().getCommands();
+ update = !commands.equals(this.commands);
+ }
+ if (update) {
+ // get command aliases
+ Map<String, Completer> global = new HashMap<String, Completer>();
+ Map<String, Completer> local = new HashMap<String, Completer>();
+
+ // add argument completers for each command
+ for (Command command : commands) {
+ String key = command.getScope() + ":" + command.getName();
+ Completer cg = command.getCompleter(false);
+ Completer cl = command.getCompleter(true);
+ if (cg == null) {
+ if (Session.SCOPE_GLOBAL.equals(command.getScope())) {
+ cg = new StringsCompleter(new String[] { command.getName() });
+ } else {
+ cg = new StringsCompleter(new String[] { key, command.getName() });
+ }
+ }
+ if (cl == null) {
+ cl = new StringsCompleter(new String[] { command.getName() });
+ }
+ global.put(key, cg);
+ local.put(key, cl);
+ }
+
+ 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(Session session) {
+ 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;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
new file mode 100644
index 0000000..fb8ebfb
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/CompleterAsCompletor.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.impl.console.parsing.CommandLineImpl;
+
+public class CompleterAsCompletor implements jline.console.completer.Completer {
+
+ private final Session session;
+ private final Completer completer;
+
+ public CompleterAsCompletor(Session session, Completer completer) {
+ this.session = session;
+ this.completer = completer;
+ }
+
+ public int complete(String buffer, int cursor, List candidates) {
+ return completer.complete(session, CommandLineImpl.build(buffer, cursor), candidates);
+ }
+
+}
[03/10] [KARAF-2805] Clean console and commands model
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
new file mode 100644
index 0000000..7988035
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
@@ -0,0 +1,583 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.io.CharArrayWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jline.UnsupportedTerminal;
+import jline.console.ConsoleReader;
+import jline.console.history.MemoryHistory;
+import jline.console.history.PersistentHistory;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Converter;
+import org.apache.felix.service.command.Function;
+import org.apache.felix.service.threadio.ThreadIO;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.History;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.console.parsing.Parser;
+import org.apache.karaf.shell.support.ShellUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConsoleSessionImpl implements Session {
+
+ public static final String SHELL_INIT_SCRIPT = "karaf.shell.init.script";
+ public static final String SHELL_HISTORY_MAXSIZE = "karaf.shell.history.maxSize";
+ public static final String PROMPT = "PROMPT";
+ public static final String DEFAULT_PROMPT = "\u001B[1m${USER}\u001B[0m@${APPLICATION}(${SUBSHELL})> ";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConsoleSessionImpl.class);
+
+ // Input stream
+ final BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1024);
+ final ConsoleInputStream console = new ConsoleInputStream();
+ final Pipe pipe = new Pipe();
+ volatile boolean running;
+ volatile boolean eof;
+
+ final SessionFactory factory;
+ final ThreadIO threadIO;
+ final InputStream in;
+ final PrintStream out;
+ final PrintStream err;
+ private Runnable closeCallback;
+
+ final CommandSession session;
+ final Registry registry;
+ final Terminal terminal;
+ final History history;
+ final ConsoleReader reader;
+
+ private boolean interrupt;
+ private Thread thread;
+
+ public ConsoleSessionImpl(SessionFactory factory,
+ CommandProcessor processor,
+ ThreadIO threadIO,
+ InputStream in,
+ PrintStream out,
+ PrintStream err,
+ Terminal term,
+ String encoding,
+ Runnable closeCallback) {
+ // Arguments
+ this.factory = factory;
+ this.threadIO = threadIO;
+ this.in = in;
+ this.out = out;
+ this.err = err;
+ this.closeCallback = closeCallback;
+
+ // Terminal
+ terminal = term == null ? new JLineTerminal(new UnsupportedTerminal()) : term;
+
+
+ // Console reader
+ try {
+ reader = new ConsoleReader(null,
+ in != null ? console : null,
+ out,
+ terminal instanceof JLineTerminal ? ((JLineTerminal) terminal).getTerminal() : new KarafTerminal(terminal),
+ encoding);
+ } catch (IOException e) {
+ throw new RuntimeException("Error opening console reader", e);
+ }
+
+ // History
+ final File file = getHistoryFile();
+ try {
+ file.getParentFile().mkdirs();
+ reader.setHistory(new KarafFileHistory(file));
+ } catch (Exception e) {
+ LOGGER.error("Can not read history from file " + file + ". Using in memory history", e);
+ }
+ if (reader.getHistory() instanceof MemoryHistory) {
+ String maxSizeStr = System.getProperty(SHELL_HISTORY_MAXSIZE);
+ if (maxSizeStr != null) {
+ ((MemoryHistory) this.reader.getHistory()).setMaxSize(Integer.parseInt(maxSizeStr));
+ }
+ }
+ history = new HistoryWrapper(reader.getHistory());
+
+ // Registry
+ registry = new RegistryImpl(factory.getRegistry());
+ registry.register(factory);
+ registry.register(this);
+ registry.register(registry);
+ registry.register(terminal);
+ registry.register(history);
+
+ // Completers
+ Completer completer = new CommandsCompleter(factory);
+ reader.addCompleter(new CompleterAsCompletor(this, completer));
+ registry.register(completer);
+ registry.register(new CommandNamesCompleter());
+
+ // Session
+ session = processor.createSession(in != null ? console : null, out, err);
+ Properties sysProps = System.getProperties();
+ for (Object key : sysProps.keySet()) {
+ session.put(key.toString(), sysProps.get(key));
+ }
+ session.put(".session", this);
+ session.put(".commandSession", session);
+ session.put(".jline.reader", reader);
+ session.put(".jline.terminal", reader.getTerminal());
+ session.put(".jline.history", reader.getHistory());
+ session.put(Session.SCOPE, "shell:bundle:*");
+ session.put(Session.SUBSHELL, "");
+ session.put(Session.COMPLETION_MODE, loadCompletionMode());
+ session.put("USER", ShellUtil.getCurrentUserName());
+ session.put("APPLICATION", System.getProperty("karaf.name", "root"));
+ session.put("#LINES", new Function() {
+ public Object execute(CommandSession session, List<Object> arguments) throws Exception {
+ return Integer.toString(terminal.getHeight());
+ }
+ });
+ session.put("#COLUMNS", new Function() {
+ public Object execute(CommandSession session, List<Object> arguments) throws Exception {
+ return Integer.toString(terminal.getWidth());
+ }
+ });
+ session.put("pid", getPid());
+ }
+
+ /**
+ * Subclasses can override to use a different history file.
+ *
+ * @return
+ */
+ protected File getHistoryFile() {
+ String defaultHistoryPath = new File(System.getProperty("user.home"), ".karaf/karaf.history").toString();
+ return new File(System.getProperty("karaf.history", defaultHistoryPath));
+ }
+
+ @Override
+ public Terminal getTerminal() {
+ return terminal;
+ }
+
+ public History getHistory() {
+ return history;
+ }
+
+ @Override
+ public Registry getRegistry() {
+ return registry;
+ }
+
+ @Override
+ public SessionFactory getFactory() {
+ return factory;
+ }
+
+ public void close() {
+ if (!running) {
+ return;
+ }
+ if (reader.getHistory() instanceof PersistentHistory) {
+ try {
+ ((PersistentHistory) reader.getHistory()).flush();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ running = false;
+ pipe.interrupt();
+ if (closeCallback != null) {
+ closeCallback.run();
+ }
+ }
+
+ public void run() {
+ try {
+ threadIO.setStreams(session.getKeyboard(), out, err);
+ thread = Thread.currentThread();
+ running = true;
+ pipe.start();
+ Properties brandingProps = Branding.loadBrandingProperties(terminal);
+ welcome(brandingProps);
+ setSessionProperties(brandingProps);
+ String scriptFileName = System.getProperty(SHELL_INIT_SCRIPT);
+ executeScript(scriptFileName);
+ while (running) {
+ try {
+ String command = readAndParseCommand();
+ if (command == null) {
+ break;
+ }
+ //session.getConsole().println("Executing: " + line);
+ Object result = session.execute(command);
+ if (result != null) {
+ session.getConsole().println(session.format(result, Converter.INSPECT));
+ }
+ } catch (InterruptedIOException e) {
+ //System.err.println("^C");
+ // TODO: interrupt current thread
+ } catch (InterruptedException e) {
+ //interrupt current thread
+ } catch (Throwable t) {
+ ShellUtil.logException(this, t);
+ }
+ }
+ close();
+ } finally {
+ try {
+ threadIO.close();
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+ }
+
+ @Override
+ public Object execute(CharSequence commandline) throws Exception {
+ return session.execute(commandline);
+ }
+
+ @Override
+ public Object get(String name) {
+ return session.get(name);
+ }
+
+ @Override
+ public void put(String name, Object value) {
+ session.put(name, value);
+ }
+
+ @Override
+ public InputStream getKeyboard() {
+ return session.getKeyboard();
+ }
+
+ @Override
+ public PrintStream getConsole() {
+ return session.getConsole();
+ }
+
+ @Override
+ public String resolveCommand(String name) {
+ // TODO: optimize
+ if (!name.contains(":")) {
+ String[] scopes = ((String) get(Session.SCOPE)).split(":");
+ List<Command> commands = registry.getCommands();
+ for (String scope : scopes) {
+ for (Command command : commands) {
+ if ((Session.SCOPE_GLOBAL.equals(scope) || command.getScope().equals(scope)) && command.getName().equals(name)) {
+ return command.getScope() + ":" + name;
+ }
+ }
+ }
+ }
+ return name;
+ }
+
+ @Override
+ public String readLine(String prompt, Character mask) throws IOException {
+ return reader.readLine(prompt, mask);
+ }
+
+ private String loadCompletionMode() {
+ String mode;
+ try {
+ File shellCfg = new File(System.getProperty("karaf.etc"), "/org.apache.karaf.shell.cfg");
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(shellCfg));
+ mode = (String) properties.get("completionMode");
+ if (mode == null) {
+ LOGGER.debug("completionMode property is not defined in etc/org.apache.karaf.shell.cfg file. Using default completion mode.");
+ mode = Session.COMPLETION_MODE_GLOBAL;
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Can't read {}/org.apache.karaf.shell.cfg file. The completion is set to default.", System.getProperty("karaf.etc"));
+ mode = Session.COMPLETION_MODE_GLOBAL;
+ }
+ return mode;
+ }
+
+ private String readAndParseCommand() throws IOException {
+ String command = null;
+ boolean loop = true;
+ boolean first = true;
+ while (loop) {
+ checkInterrupt();
+ String line = reader.readLine(first ? getPrompt() : "> ");
+ if (line == null) {
+ break;
+ }
+ if (command == null) {
+ command = line;
+ } else {
+ if (command.charAt(command.length() - 1) == '\\') {
+ command = command.substring(0, command.length() - 1) + line;
+ } else {
+ command += "\n" + line;
+ }
+ }
+ if (reader.getHistory().size() == 0) {
+ reader.getHistory().add(command);
+ } else {
+ // jline doesn't add blank lines to the history so we don't
+ // need to replace the command in jline's console history with
+ // an indented one
+ if (command.length() > 0 && !" ".equals(command)) {
+ reader.getHistory().replace(command);
+ }
+ }
+ if (command.length() > 0 && command.charAt(command.length() - 1) == '\\') {
+ loop = true;
+ first = false;
+ } else {
+ try {
+ Class<?> cl = CommandSession.class.getClassLoader().loadClass("org.apache.felix.gogo.runtime.Parser");
+ Object parser = cl.getConstructor(CharSequence.class).newInstance(command);
+ cl.getMethod("program").invoke(parser);
+ loop = false;
+ } catch (Exception e) {
+ loop = true;
+ first = false;
+ } catch (Throwable t) {
+ // Reflection problem ? just quit
+ loop = false;
+ }
+ }
+ }
+ return command;
+ }
+
+ private void executeScript(String scriptFileName) {
+ if (scriptFileName != null) {
+ Reader r = null;
+ try {
+ File scriptFile = new File(scriptFileName);
+ r = new InputStreamReader(new FileInputStream(scriptFile));
+ CharArrayWriter w = new CharArrayWriter();
+ int n;
+ char[] buf = new char[8192];
+ while ((n = r.read(buf)) > 0) {
+ w.write(buf, 0, n);
+ }
+ session.execute(new String(w.toCharArray()));
+ } catch (Exception e) {
+ LOGGER.debug("Error in initialization script", e);
+ System.err.println("Error in initialization script: " + e.getMessage());
+ } finally {
+ if (r != null) {
+ try {
+ r.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ }
+
+ protected void welcome(Properties brandingProps) {
+ String welcome = brandingProps.getProperty("welcome");
+ if (welcome != null && welcome.length() > 0) {
+ session.getConsole().println(welcome);
+ }
+ }
+
+ protected void setSessionProperties(Properties brandingProps) {
+ for (Map.Entry<Object, Object> entry : brandingProps.entrySet()) {
+ String key = (String) entry.getKey();
+ if (key.startsWith("session.")) {
+ session.put(key.substring("session.".length()), entry.getValue());
+ }
+ }
+ }
+
+ protected String getPrompt() {
+ try {
+ String prompt;
+ try {
+ Object p = session.get(PROMPT);
+ if (p != null) {
+ prompt = p.toString();
+ } else {
+ Properties properties = Branding.loadBrandingProperties(terminal);
+ if (properties.getProperty("prompt") != null) {
+ prompt = properties.getProperty("prompt");
+ // we put the PROMPT in ConsoleSession to avoid to read
+ // the properties file each time.
+ session.put(PROMPT, prompt);
+ } else {
+ prompt = DEFAULT_PROMPT;
+ }
+ }
+ } catch (Throwable t) {
+ prompt = DEFAULT_PROMPT;
+ }
+ Matcher matcher = Pattern.compile("\\$\\{([^}]+)\\}").matcher(prompt);
+ while (matcher.find()) {
+ Object rep = session.get(matcher.group(1));
+ if (rep != null) {
+ prompt = prompt.replace(matcher.group(0), rep.toString());
+ matcher.reset(prompt);
+ }
+ }
+ return prompt;
+ } catch (Throwable t) {
+ return "$ ";
+ }
+ }
+
+ private void checkInterrupt() throws IOException {
+ if (Thread.interrupted() || interrupt) {
+ interrupt = false;
+ throw new InterruptedIOException("Keyboard interruption");
+ }
+ }
+
+ private void interrupt() {
+ interrupt = true;
+ thread.interrupt();
+ }
+
+ private String getPid() {
+ String name = ManagementFactory.getRuntimeMXBean().getName();
+ String[] parts = name.split("@");
+ return parts[0];
+ }
+
+ private class ConsoleInputStream extends InputStream {
+ private int read(boolean wait) throws IOException {
+ if (!running) {
+ return -1;
+ }
+ checkInterrupt();
+ if (eof && queue.isEmpty()) {
+ return -1;
+ }
+ Integer i;
+ if (wait) {
+ try {
+ i = queue.take();
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ checkInterrupt();
+ } else {
+ i = queue.poll();
+ }
+ if (i == null) {
+ return -1;
+ }
+ return i;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return read(true);
+ }
+
+ @Override
+ public int read(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if (off < 0 || len < 0 || len > b.length - off) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ int nb = 1;
+ int i = read(true);
+ if (i < 0) {
+ return -1;
+ }
+ b[off++] = (byte) i;
+ while (nb < len) {
+ i = read(false);
+ if (i < 0) {
+ return nb;
+ }
+ b[off++] = (byte) i;
+ nb++;
+ }
+ return nb;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return queue.size();
+ }
+ }
+
+ private class Pipe extends Thread {
+ public Pipe() {
+ super("Karaf shell pipe thread");
+ setDaemon(true);
+ }
+
+ public void run() {
+ try {
+ while (running) {
+ try {
+ int c = in.read();
+ if (c == -1) {
+ return;
+ } else if (c == 4 && !ShellUtil.getBoolean(ConsoleSessionImpl.this, Session.IGNORE_INTERRUPTS)) {
+ err.println("^D");
+ return;
+ } else if (c == 3 && !ShellUtil.getBoolean(ConsoleSessionImpl.this, Session.IGNORE_INTERRUPTS)) {
+ err.println("^C");
+ reader.getCursorBuffer().clear();
+ ConsoleSessionImpl.this.interrupt();
+ }
+ queue.put(c);
+ } catch (Throwable t) {
+ return;
+ }
+ }
+ } finally {
+ eof = true;
+ try {
+ queue.put(-1);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
new file mode 100644
index 0000000..16e73ca
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HeadlessSessionImpl.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.History;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.support.ShellUtil;
+
+public class HeadlessSessionImpl implements Session {
+
+ final SessionFactory factory;
+ final CommandSession session;
+ final Registry registry;
+
+ public HeadlessSessionImpl(SessionFactory factory, CommandProcessor processor, InputStream in, PrintStream out, PrintStream err) {
+ // Factory
+ this.factory = factory;
+ // Registry
+ registry = new RegistryImpl(factory.getRegistry());
+ registry.register(factory);
+ registry.register(this);
+ registry.register(registry);
+ // Session
+ session = processor.createSession(in, out, err);
+ Properties sysProps = System.getProperties();
+ for (Object key : sysProps.keySet()) {
+ session.put(key.toString(), sysProps.get(key));
+ }
+ session.put(".session", this);
+ session.put(".commandSession", session);
+ session.put(Session.SCOPE, "shell:bundle:*");
+ session.put(Session.SUBSHELL, "");
+ session.put("USER", ShellUtil.getCurrentUserName());
+ session.put("APPLICATION", System.getProperty("karaf.name", "root"));
+ }
+
+ public CommandSession getSession() {
+ return session;
+ }
+
+ @Override
+ public Object execute(CharSequence commandline) throws Exception {
+ return session.execute(commandline);
+ }
+
+ @Override
+ public Object get(String name) {
+ return session.get(name);
+ }
+
+ @Override
+ public void put(String name, Object value) {
+ session.put(name, value);
+ }
+
+ @Override
+ public InputStream getKeyboard() {
+ return session.getKeyboard();
+ }
+
+ @Override
+ public PrintStream getConsole() {
+ return session.getConsole();
+ }
+
+ @Override
+ public String readLine(String prompt, Character mask) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Terminal getTerminal() {
+ return null;
+ }
+
+ @Override
+ public History getHistory() {
+ return null;
+ }
+
+ @Override
+ public Registry getRegistry() {
+ return registry;
+ }
+
+ @Override
+ public SessionFactory getFactory() {
+ return factory;
+ }
+
+ @Override
+ public void run() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String resolveCommand(String name) {
+ // TODO: optimize
+ if (!name.contains(":")) {
+ String[] scopes = ((String) get(Session.SCOPE)).split(":");
+ List<Command> commands = registry.getCommands();
+ for (String scope : scopes) {
+ for (Command command : commands) {
+ if ((Session.SCOPE_GLOBAL.equals(scope) || command.getScope().equals(scope)) && command.getName().equals(name)) {
+ return command.getScope() + ":" + name;
+ }
+ }
+ }
+ }
+ return name;
+ }
+
+ @Override
+ public void close() {
+ session.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HistoryWrapper.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HistoryWrapper.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HistoryWrapper.java
new file mode 100644
index 0000000..6f69991
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/HistoryWrapper.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.impl.console;
+
+import org.apache.karaf.shell.api.console.History;
+
+public class HistoryWrapper implements History {
+
+ private final jline.console.history.History history;
+
+ public HistoryWrapper(jline.console.history.History history) {
+ this.history = history;
+ }
+
+ @Override
+ public void clear() {
+ history.clear();
+ }
+
+ public int first() {
+ return history.iterator().next().index() + 1;
+ }
+
+ public int last() {
+ return first() + history.size() - 1;
+ }
+
+ @Override
+ public CharSequence get(int index) {
+ return history.get(index - 1);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/JLineTerminal.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/JLineTerminal.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/JLineTerminal.java
new file mode 100644
index 0000000..d000885
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/JLineTerminal.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.impl.console;
+
+import org.apache.karaf.shell.api.console.Terminal;
+
+/**
+* Created by gnodet on 27/02/14.
+*/
+public class JLineTerminal implements Terminal {
+
+ private final jline.Terminal terminal;
+
+ public JLineTerminal(jline.Terminal terminal) {
+ this.terminal = terminal;
+ }
+
+ public jline.Terminal getTerminal() {
+ return terminal;
+ }
+
+ @Override
+ public int getWidth() {
+ return terminal.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return terminal.getHeight();
+ }
+
+ @Override
+ public boolean isAnsiSupported() {
+ return terminal.isAnsiSupported();
+ }
+
+ @Override
+ public boolean isEchoEnabled() {
+ return terminal.isEchoEnabled();
+ }
+
+ @Override
+ public void setEchoEnabled(boolean enabled) {
+ terminal.setEchoEnabled(enabled);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafFileHistory.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafFileHistory.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafFileHistory.java
new file mode 100644
index 0000000..aa4d2e4
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafFileHistory.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.impl.console;
+
+import java.io.File;
+import java.io.IOException;
+
+import jline.console.history.FileHistory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Override the FileHistory impl to trap failures due to the
+ * user does not having write access to the history file.
+ */
+public final class KarafFileHistory extends FileHistory {
+
+ static final Logger LOGGER = LoggerFactory.getLogger(KarafFileHistory.class);
+ boolean failed = false;
+
+ public KarafFileHistory(File file) throws IOException {
+ super(file);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ if( !failed ) {
+ try {
+ super.flush();
+ } catch (IOException e) {
+ failed = true;
+ LOGGER.debug("Could not write history file: "+ getFile(), e);
+ }
+ }
+ }
+
+ @Override
+ public void purge() throws IOException {
+ if( !failed ) {
+ try {
+ super.purge();
+ } catch (IOException e) {
+ failed = true;
+ LOGGER.debug("Could not delete history file: "+ getFile(), e);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafTerminal.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafTerminal.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafTerminal.java
new file mode 100644
index 0000000..0c8b0fe
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/KarafTerminal.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import jline.TerminalSupport;
+import org.apache.karaf.shell.api.console.Terminal;
+
+public class KarafTerminal extends TerminalSupport {
+
+ private final Terminal terminal;
+
+ public KarafTerminal(Terminal terminal) {
+ super(true);
+ this.terminal = terminal;
+ }
+
+ @Override
+ public synchronized boolean isAnsiSupported() {
+ return terminal.isAnsiSupported();
+ }
+
+ @Override
+ public int getWidth() {
+ return terminal.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return terminal.getHeight();
+ }
+
+ @Override
+ public synchronized boolean isEchoEnabled() {
+ return terminal.isEchoEnabled();
+ }
+
+ @Override
+ public synchronized void setEchoEnabled(boolean enabled) {
+ terminal.setEchoEnabled(enabled);
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/RegistryImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/RegistryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/RegistryImpl.java
new file mode 100644
index 0000000..43ed27e
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/RegistryImpl.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Registry;
+
+public class RegistryImpl implements Registry {
+
+ private final Registry parent;
+ private final Map<Object, Object> services = new LinkedHashMap<Object, Object>();
+
+ public RegistryImpl(Registry parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public List<Command> getCommands() {
+ return getServices(Command.class);
+ }
+
+ @Override
+ public <T> void register(Callable<T> factory, Class<T> clazz) {
+ synchronized (services) {
+ services.put(factory, new Factory<T>(clazz, factory));
+ }
+ }
+
+ @Override
+ public void register(Object service) {
+ synchronized (services) {
+ services.put(service, service);
+ }
+ }
+
+ @Override
+ public void unregister(Object service) {
+ synchronized (services) {
+ services.remove(service);
+ }
+ }
+
+ @Override
+ public <T> T getService(Class<T> clazz) {
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ try {
+ return clazz.cast(((Factory) service).callable.call());
+ } catch (Exception e) {
+ // TODO: log exception
+ }
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ return clazz.cast(service);
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ return parent.getService(clazz);
+ }
+ return null;
+ }
+
+ @Override
+ public <T> List<T> getServices(Class<T> clazz) {
+ List<T> list = new ArrayList<T>();
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ try {
+ list.add(clazz.cast(((Factory) service).callable.call()));
+ } catch (Exception e) {
+ // TODO: log exception
+ }
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ list.add(clazz.cast(service));
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ list.addAll(parent.getServices(clazz));
+ }
+ return list;
+ }
+
+ @Override
+ public boolean hasService(Class<?> clazz) {
+ synchronized (services) {
+ for (Object service : services.values()) {
+ if (service instanceof Factory) {
+ if (clazz.isAssignableFrom(((Factory) service).clazz)) {
+ if (isVisible(service)) {
+ return true;
+ }
+ }
+ } else if (clazz.isInstance(service)) {
+ if (isVisible(service)) {
+ return true;
+ }
+ }
+ }
+ }
+ if (parent != null) {
+ return parent.hasService(clazz);
+ }
+ return false;
+ }
+
+ protected boolean isVisible(Object service) {
+ return true;
+ }
+
+ static class Factory<T> {
+
+ final Class<T> clazz;
+ final Callable<T> callable;
+
+ Factory(Class<T> clazz, Callable<T> callable) {
+ this.clazz = clazz;
+ this.callable = callable;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
new file mode 100644
index 0000000..2f19499
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/SessionFactoryImpl.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+import org.apache.felix.service.threadio.ThreadIO;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.console.commands.ExitCommand;
+import org.apache.karaf.shell.impl.console.commands.SubShellCommand;
+import org.apache.karaf.shell.impl.console.commands.help.HelpCommand;
+import org.apache.karaf.shell.support.ShellUtil;
+
+public class SessionFactoryImpl extends RegistryImpl implements SessionFactory, Registry {
+
+ final CommandProcessorImpl commandProcessor;
+ final ThreadIO threadIO;
+ final List<Session> sessions = new ArrayList<Session>();
+ final Map<String, SubShellCommand> subshells = new HashMap<String, SubShellCommand>();
+ boolean closed;
+
+ public SessionFactoryImpl(ThreadIO threadIO) {
+ super(null);
+ this.threadIO = threadIO;
+ commandProcessor = new CommandProcessorImpl(threadIO);
+ register(new ExitCommand());
+ new HelpCommand(this);
+ }
+
+ public CommandProcessorImpl getCommandProcessor() {
+ return commandProcessor;
+ }
+
+ @Override
+ public Registry getRegistry() {
+ return this;
+ }
+
+ @Override
+ public void register(Object service) {
+ if (service instanceof Command) {
+ Command command = (Command) service;
+ String scope = command.getScope();
+ String name = command.getName();
+ if (!Session.SCOPE_GLOBAL.equals(scope)) {
+ if (!subshells.containsKey(scope)) {
+ SubShellCommand subShell = new SubShellCommand(scope);
+ subshells.put(scope, subShell);
+ register(subShell);
+ }
+ subshells.get(scope).increment();
+ }
+ commandProcessor.addCommand(scope, wrap(command), name);
+ }
+ super.register(service);
+ }
+
+ protected Function wrap(Command command) {
+ return new CommandWrapper(command);
+ }
+
+ @Override
+ public void unregister(Object service) {
+ super.unregister(service);
+ if (service instanceof Command) {
+ Command command = (Command) service;
+ String scope = command.getScope();
+ String name = command.getName();
+ commandProcessor.removeCommand(scope, name);
+ if (!Session.SCOPE_GLOBAL.equals(scope)) {
+ if (subshells.get(scope).decrement() == 0) {
+ SubShellCommand subShell = subshells.remove(scope);
+ unregister(subShell);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Session create(InputStream in, PrintStream out, PrintStream err, Terminal term, String encoding, Runnable closeCallback) {
+ synchronized (this) {
+ if (closed) {
+ throw new IllegalStateException("SessionFactory has been closed");
+ }
+ final Session session = new ConsoleSessionImpl(this, commandProcessor, threadIO, in, out, err, term, encoding, closeCallback);
+ sessions.add(session);
+ return session;
+ }
+ }
+
+ @Override
+ public Session create(InputStream in, PrintStream out, PrintStream err) {
+ synchronized (this) {
+ if (closed) {
+ throw new IllegalStateException("SessionFactory has been closed");
+ }
+ final Session session = new HeadlessSessionImpl(this, commandProcessor, in, out, err);
+ sessions.add(session);
+ return session;
+ }
+ }
+
+ public void stop() {
+ synchronized (this) {
+ closed = true;
+ for (Session session : sessions) {
+ session.close();
+ }
+ commandProcessor.stop();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/TerminalFactory.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/TerminalFactory.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/TerminalFactory.java
new file mode 100644
index 0000000..bae3a25
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/TerminalFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console;
+
+import jline.NoInterruptUnixTerminal;
+import jline.Terminal;
+
+public class TerminalFactory {
+
+ private Terminal term;
+
+ public synchronized Terminal getTerminal() throws Exception {
+ if (term == null) {
+ init();
+ }
+ return term;
+ }
+
+ public void init() throws Exception {
+ jline.TerminalFactory.registerFlavor(jline.TerminalFactory.Flavor.UNIX, NoInterruptUnixTerminal.class);
+ term = jline.TerminalFactory.create();
+ }
+
+ public synchronized void destroy() throws Exception {
+ if (term != null) {
+ term.restore();
+ term = null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/ExitCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/ExitCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/ExitCommand.java
new file mode 100644
index 0000000..147d403
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/ExitCommand.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.impl.console.commands;
+
+import org.apache.karaf.shell.api.console.Session;
+
+public class ExitCommand extends TopLevelCommand {
+
+ @Override
+ public String getName() {
+ return "exit";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Exit from the current shell";
+ }
+
+ @Override
+ protected void doExecute(Session session) throws Exception {
+ // get the current sub-shell
+ String currentSubShell = (String) session.get(Session.SUBSHELL);
+ if (!currentSubShell.isEmpty()) {
+ if (currentSubShell.contains(":")) {
+ int index = currentSubShell.lastIndexOf(":");
+ session.put(Session.SUBSHELL, currentSubShell.substring(0, index));
+ } else {
+ session.put(Session.SUBSHELL, "");
+ }
+ String currentScope = (String) session.get(Session.SCOPE);
+ int index = currentScope.indexOf(":");
+ session.put(Session.SCOPE, currentScope.substring(index + 1));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/SubShellCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/SubShellCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/SubShellCommand.java
new file mode 100644
index 0000000..d2826f3
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/SubShellCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.commands;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.karaf.shell.api.console.Session;
+
+public class SubShellCommand extends TopLevelCommand {
+
+ private final String name;
+ private final AtomicInteger references = new AtomicInteger();
+
+ public SubShellCommand(String name) {
+ this.name = name;
+ }
+
+ public void increment() {
+ references.incrementAndGet();
+ }
+
+ public int decrement() {
+ return references.decrementAndGet();
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Enter the subshell";
+ }
+
+ @Override
+ protected void doExecute(Session session) throws Exception {
+ session.put(Session.SUBSHELL, name);
+ session.put(Session.SCOPE, name + ":" + session.get(Session.SCOPE));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
new file mode 100644
index 0000000..ad2c729
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/TopLevelCommand.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.commands;
+
+import java.io.PrintStream;
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.CommandException;
+
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+public abstract class TopLevelCommand implements Command {
+
+ @Override
+ public String getScope() {
+ return Session.SCOPE_GLOBAL;
+ }
+
+ @Override
+ public Completer getCompleter(boolean scoped) {
+ return null;
+// return new StringsCompleter(new String[] { getName() });
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ if (arguments.contains("--help")) {
+ printHelp(System.out);
+ return null;
+ }
+ if (!arguments.isEmpty()) {
+ String msg = COLOR_RED
+ + "Error executing command "
+ + INTENSITY_BOLD + getName() + INTENSITY_NORMAL
+ + COLOR_DEFAULT + ": " + "too many arguments specified";
+ throw new CommandException(msg);
+ }
+ doExecute(session);
+ return null;
+ }
+
+ protected void printHelp(PrintStream out) {
+ out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(INTENSITY_BOLD + getName() + INTENSITY_NORMAL);
+ out.println();
+ out.print("\t");
+ out.println(getDescription());
+ out.println();
+ out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(getName() + " [options]");
+ out.println();
+ out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(INTENSITY_BOLD + "--help" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println("Display this help message");
+ out.println();
+ }
+
+ protected abstract void doExecute(Session session) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/CommandListHelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/CommandListHelpProvider.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/CommandListHelpProvider.java
new file mode 100644
index 0000000..9101520
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/CommandListHelpProvider.java
@@ -0,0 +1,117 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.impl.console.commands.help;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.support.NameScoping;
+import org.apache.karaf.shell.support.ansi.SimpleAnsi;
+import org.apache.karaf.shell.support.table.Col;
+import org.apache.karaf.shell.support.table.ShellTable;
+
+public class CommandListHelpProvider implements HelpProvider {
+
+ public String getHelp(Session session, String path) {
+ if (path.indexOf('|') > 0) {
+ if (path.startsWith("command-list|")) {
+ path = path.substring("command-list|".length());
+ } else {
+ return null;
+ }
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ SortedMap<String, String> commands = getCommandDescriptions(session, path);
+ if (commands.isEmpty()) {
+ return null;
+ } else if (commands.size() == 1 && commands.containsKey(path)) {
+ return null;
+ } else {
+ printMethodList(session, new PrintStream(baos), commands);
+ return baos.toString();
+ }
+ }
+
+ private SortedMap<String, String> getCommandDescriptions(Session session, String path) {
+ // TODO: this is not really clean
+
+ List<Command> commands = session.getRegistry().getCommands();
+
+ String subshell = (String) session.get(Session.SUBSHELL);
+ String completionMode = (String) session.get(Session.COMPLETION_MODE);
+
+ SortedMap<String,String> descriptions = new TreeMap<String,String>();
+ for (Command command : commands) {
+
+ String name = command.getScope() + ":" + command.getName();
+
+ if (command != null && !name.startsWith(path)) {
+ continue;
+ }
+
+ if (completionMode != null && completionMode.equalsIgnoreCase(Session.COMPLETION_MODE_SUBSHELL)) {
+ // filter the help only for "global" commands
+ if (subshell == null || subshell.trim().isEmpty()) {
+ if (!name.startsWith(Session.SCOPE_GLOBAL)) {
+ continue;
+ }
+ }
+ }
+
+ if (completionMode != null && (completionMode.equalsIgnoreCase(Session.COMPLETION_MODE_SUBSHELL)
+ || completionMode.equalsIgnoreCase(Session.COMPLETION_MODE_FIRST))) {
+ // filter the help only for commands local to the subshell
+ if (!name.startsWith(subshell)) {
+ continue;
+ }
+ }
+
+ String description = command.getDescription();
+ if (name.startsWith("*:")) {
+ name = name.substring(2);
+ }
+ if (subshell != null && !subshell.trim().isEmpty() && name.startsWith(subshell + ":")) {
+ name = name.substring(subshell.length() + 1);
+ }
+ descriptions.put(name, description);
+ }
+ return descriptions;
+ }
+
+ protected void printMethodList(Session session, PrintStream out, SortedMap<String, String> commands) {
+ Terminal term = session.getTerminal();
+ int termWidth = term != null ? term.getWidth() : 80;
+ out.println(SimpleAnsi.INTENSITY_BOLD + "COMMANDS" + SimpleAnsi.INTENSITY_NORMAL);
+ ShellTable table = new ShellTable().noHeaders().separator(" ").size(termWidth);
+ table.column(new Col("Command").maxSize(35));
+ table.column(new Col("Description"));
+ for (Map.Entry<String,String> entry : commands.entrySet()) {
+ String key = NameScoping.getCommandNameWithoutGlobalPrefix(session, entry.getKey());
+ table.addRow().addContent(key, entry.getValue());
+ }
+ table.print(out, true);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
new file mode 100644
index 0000000..086b83b
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpCommand.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.commands.help;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.karaf.util.properties.InterpolationHelper;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.support.CommandException;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+public class HelpCommand implements Command {
+
+ public HelpCommand(SessionFactory factory) {
+ Registry registry = factory.getRegistry();
+ registry.register(this);
+ registry.register(new SimpleHelpProvider());
+ registry.register(new CommandListHelpProvider());
+ registry.register(new SingleCommandHelpProvider());
+ }
+
+ @Override
+ public String getScope() {
+ return Session.SCOPE_GLOBAL;
+ }
+
+ @Override
+ public String getName() {
+ return "help";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Displays this help or help about a command";
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ if (arguments.contains("--help")) {
+ printHelp(System.out);
+ return null;
+ }
+ if (arguments.size() > 1) {
+ String msg = COLOR_RED
+ + "Error executing command "
+ + INTENSITY_BOLD + getName() + INTENSITY_NORMAL
+ + COLOR_DEFAULT + ": " + "too many arguments specified";
+ throw new CommandException(msg);
+ }
+ String path = arguments.isEmpty() ? null : arguments.get(0) == null ? null : arguments.get(0).toString();
+ String help = getHelp(session, path);
+ if (help != null) {
+ System.out.println(help);
+ }
+ return null;
+ }
+
+ @Override
+ public Completer getCompleter(final boolean scoped) {
+ return new Completer() {
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ String[] args = commandLine.getArguments();
+ int argIndex = commandLine.getCursorArgumentIndex();
+ StringsCompleter completer = new StringsCompleter(Collections.singletonList(getName()));
+ if (argIndex == 0) {
+ return completer.complete(session, new ArgumentCommandLine(args[argIndex], commandLine.getArgumentPosition()), candidates);
+ } else if (!verifyCompleter(session, completer, args[0])) {
+ return -1;
+ }
+ // TODO: use CommandNamesCompleter and better completion wrt parsing etc...
+ completer = new StringsCompleter();
+ for (Command command : session.getRegistry().getCommands()) {
+ if (!Session.SCOPE_GLOBAL.equals(command.getScope())) {
+ completer.getStrings().add(command.getScope() + ":" + command.getName());
+ }
+ completer.getStrings().add(command.getName());
+ }
+ completer.getStrings().add("--help");
+ if (argIndex == 1) {
+ int res;
+ if (argIndex < args.length) {
+ res = completer.complete(session, new ArgumentCommandLine(args[argIndex], commandLine.getArgumentPosition()), candidates);
+ } else {
+ res = completer.complete(session, new ArgumentCommandLine("", 0), candidates);
+ }
+ return res + (commandLine.getBufferPosition() - commandLine.getArgumentPosition());
+ } else if (!verifyCompleter(session, completer, args[1])) {
+ return -1;
+ }
+ return -1;
+ }
+ protected boolean verifyCompleter(Session session, Completer completer, String argument) {
+ List<String> candidates = new ArrayList<String>();
+ return completer.complete(session, new ArgumentCommandLine(argument, argument.length()), candidates) != -1 && !candidates.isEmpty();
+ }
+ };
+ }
+
+ protected void printHelp(PrintStream out) {
+ out.println(INTENSITY_BOLD + "DESCRIPTION" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(INTENSITY_BOLD + getName() + INTENSITY_NORMAL);
+ out.println();
+ out.print("\t");
+ out.println(getDescription());
+ out.println();
+ out.println(INTENSITY_BOLD + "SYNTAX" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(getName() + " [options] [command]");
+ out.println();
+ out.println(INTENSITY_BOLD + "ARGUMENTS" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(INTENSITY_BOLD + "command" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println("Command to display help for");
+ out.println();
+ out.println(INTENSITY_BOLD + "OPTIONS" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println(INTENSITY_BOLD + "--help" + INTENSITY_NORMAL);
+ out.print(" ");
+ out.println("Display this help message");
+ out.println();
+ }
+
+ public String getHelp(final Session session, String path) {
+ if (path == null) {
+ path = "%root%";
+ }
+ Map<String,String> props = new HashMap<String,String>();
+ props.put("data", "${" + path + "}");
+ final List<HelpProvider> providers = session.getRegistry().getServices(HelpProvider.class);
+ InterpolationHelper.performSubstitution(props, new InterpolationHelper.SubstitutionCallback() {
+ public String getValue(final String key) {
+ for (HelpProvider hp : providers) {
+ String result = hp.getHelp(session, key);
+ if (result != null) {
+ return removeNewLine(result);
+ }
+ }
+ return null;
+ }
+ });
+ return props.get("data");
+ }
+
+ private String removeNewLine(String help) {
+ if (help != null && help.endsWith("\n")) {
+ help = help.substring(0, help.length() -1);
+ }
+ return help;
+ }
+
+ static class ArgumentCommandLine implements CommandLine {
+ private final String argument;
+ private final int position;
+
+ ArgumentCommandLine(String argument, int position) {
+ this.argument = argument;
+ this.position = position;
+ }
+
+ @Override
+ public int getCursorArgumentIndex() {
+ return 0;
+ }
+
+ @Override
+ public String getCursorArgument() {
+ return argument;
+ }
+
+ @Override
+ public int getArgumentPosition() {
+ return position;
+ }
+
+ @Override
+ public String[] getArguments() {
+ return new String[] { argument };
+ }
+
+ @Override
+ public int getBufferPosition() {
+ return position;
+ }
+
+ @Override
+ public String getBuffer() {
+ return argument;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpProvider.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpProvider.java
new file mode 100644
index 0000000..ad5e215
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/HelpProvider.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.impl.console.commands.help;
+
+import org.apache.karaf.shell.api.console.Session;
+
+public interface HelpProvider {
+
+ String getHelp(Session session, String path);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SimpleHelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SimpleHelpProvider.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SimpleHelpProvider.java
new file mode 100644
index 0000000..90ad506
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SimpleHelpProvider.java
@@ -0,0 +1,47 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.impl.console.commands.help;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.karaf.shell.api.console.Session;
+
+
+public class SimpleHelpProvider implements HelpProvider {
+
+ private final Map<String, String> help;
+
+ public SimpleHelpProvider() {
+ help = new HashMap<String, String>();
+ help.put("%root%", "${command-list|}");
+ help.put("all", "${command-list|}");
+ }
+
+ public String getHelp(Session session, String path) {
+ if (path.indexOf('|') > 0) {
+ if (path.startsWith("simple|")) {
+ path = path.substring("simple|".length());
+ } else {
+ return null;
+ }
+ }
+ return help.get(path);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SingleCommandHelpProvider.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SingleCommandHelpProvider.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SingleCommandHelpProvider.java
new file mode 100644
index 0000000..dafab98
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/commands/help/SingleCommandHelpProvider.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.impl.console.commands.help;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.karaf.shell.api.console.Session;
+
+public class SingleCommandHelpProvider implements HelpProvider {
+
+ public String getHelp(Session session, String path) {
+ if (path.indexOf('|') > 0) {
+ if (path.startsWith("command|")) {
+ path = path.substring("command|".length());
+ } else {
+ return null;
+ }
+ }
+
+ String resolved = session.resolveCommand(path);
+
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos, true);
+ Session s = session.getFactory().create(null, ps, ps);
+ s.put(Session.SCOPE, session.get(Session.SCOPE));
+ s.put(Session.SUBSHELL, session.get(Session.SUBSHELL));
+ try {
+ s.execute(path + " --help");
+ } catch (Throwable t) {
+ return null;
+ } finally {
+ s.close();
+ }
+ return baos.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Activator.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Activator.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Activator.java
new file mode 100644
index 0000000..921dca3
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Activator.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi;
+
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.impl.action.osgi.CommandExtender;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.impl.console.TerminalFactory;
+import org.apache.karaf.shell.impl.console.osgi.secured.SecuredSessionFactoryImpl;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+ private static final String START_CONSOLE = "karaf.startLocalConsole";
+
+ private ThreadIOImpl threadIO;
+
+ private SessionFactoryImpl sessionFactory;
+ private ServiceRegistration sessionFactoryRegistration;
+
+ private CommandExtender actionExtender;
+
+ private TerminalFactory terminalFactory;
+ private LocalConsoleManager localConsoleManager;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ threadIO = new ThreadIOImpl();
+ threadIO.start();
+
+ sessionFactory = new SecuredSessionFactoryImpl(context, threadIO);
+ sessionFactory.getCommandProcessor().addConverter(new Converters(context));
+ sessionFactory.getCommandProcessor().addConstant(".context", context.getBundle(0).getBundleContext());
+
+ sessionFactory.register(new ManagerImpl(sessionFactory, sessionFactory));
+
+ sessionFactoryRegistration = context.registerService(SessionFactory.class.getName(), sessionFactory, null);
+
+ actionExtender = new CommandExtender(sessionFactory);
+ actionExtender.start(context);
+
+ if (Boolean.parseBoolean(context.getProperty(START_CONSOLE))) {
+ terminalFactory = new TerminalFactory();
+ localConsoleManager = new LocalConsoleManager(context, terminalFactory, sessionFactory);
+ localConsoleManager.start();
+ }
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ sessionFactoryRegistration.unregister();
+ sessionFactory.stop();
+ localConsoleManager.stop();
+ actionExtender.stop(context);
+ threadIO.stop();
+ terminalFactory.destroy();
+ }
+}
[08/10] [KARAF-2805] Migrate shell, ssh, wrapper, kar, instance,
features and bundle to the new API and switch the bin/shell script to
use the new console
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/IfAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/IfAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/IfAction.java
index 6a01233..b7d4585 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/IfAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/IfAction.java
@@ -16,18 +16,20 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.felix.service.command.Function;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Function;
+import org.apache.karaf.shell.api.console.Session;
/**
* Execute a closure on a list of arguments.
*/
@Command(scope = "shell", name = "if", description = "If/Then/Else block.")
@Service
-public class IfAction extends AbstractAction {
+public class IfAction implements Action {
@Argument(name = "condition", index = 0, multiValued = false, required = true, description = "The condition")
Function condition;
@@ -38,8 +40,11 @@ public class IfAction extends AbstractAction {
@Argument(name = "ifFalse", index = 2, multiValued = false, required = false, description = "The function to execute if the condition is false")
Function ifFalse;
+ @Reference
+ Session session;
+
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
Object result = condition.execute(session, null);
if (isTrue(result)) {
return ifTrue.execute(session, null);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java
index 90cf2e8..dfa811d 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/InfoAction.java
@@ -31,26 +31,33 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
+import java.util.concurrent.Callable;
-import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.InfoProvider;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.fusesource.jansi.Ansi;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
@Command(scope = "shell", name = "info", description = "Prints system information.")
@Service
-public class InfoAction extends OsgiCommandSupport {
+public class InfoAction implements Action {
private NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
private NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));
- protected Object doExecute() throws Exception {
+// @Reference
+ List<InfoProvider> infoProviders;
+
+ @Override
+ public Object execute() throws Exception {
int maxNameLen;
RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
@@ -67,8 +74,10 @@ public class InfoAction extends OsgiCommandSupport {
printValue("Karaf version", maxNameLen, System.getProperty("karaf.version"));
printValue("Karaf home", maxNameLen, System.getProperty("karaf.home"));
printValue("Karaf base", maxNameLen, System.getProperty("karaf.base"));
- printValue("OSGi Framework", maxNameLen, bundleContext.getBundle(0).getSymbolicName() + " - " +
- bundleContext.getBundle(0).getVersion());
+ String osgi = getOsgiFramework();
+ if (osgi != null) {
+ printValue("OSGi Framework", maxNameLen, osgi);
+ }
System.out.println();
System.out.println("JVM");
@@ -119,9 +128,7 @@ public class InfoAction extends OsgiCommandSupport {
//Display Information from external information providers.
Map<String, Map<Object, Object>> properties = new HashMap<String, Map<Object, Object>>();
- List<InfoProvider> infoProviders = getAllServices(InfoProvider.class);
if (infoProviders != null) {
-
// dump all properties to Map, KARAF-425
for (InfoProvider provider : infoProviders) {
if (!properties.containsKey(provider.getName())) {
@@ -149,7 +156,6 @@ public class InfoAction extends OsgiCommandSupport {
}
}
}
-
return null;
}
@@ -221,4 +227,21 @@ public class InfoAction extends OsgiCommandSupport {
return sb.toString();
}
+ String getOsgiFramework() {
+ try {
+ Callable<String> call = new Callable<String>() {
+ @Override
+ public String call() throws Exception {
+ BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
+ Bundle sysBundle = context.getBundle(0);
+ return sysBundle.getSymbolicName() + "-" + sysBundle.getVersion();
+ }
+ };
+ return call.call();
+ } catch (Throwable t) {
+ // We're not in OSGi, just safely return null
+ return null;
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/JavaAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/JavaAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/JavaAction.java
index 84e4d62..99f201d 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/JavaAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/JavaAction.java
@@ -19,11 +19,13 @@ package org.apache.karaf.shell.commands.impl;
import java.lang.reflect.Method;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Execute a Java standard application.
@@ -34,7 +36,9 @@ import org.apache.karaf.shell.inject.Service;
*/
@Command(scope = "shell", name = "java", description = "Executes a Java standard application.")
@Service
-public class JavaAction extends AbstractAction {
+public class JavaAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Option(name = "-m", aliases = {"--method"}, description = "Invoke a named method", required = false, multiValued = false)
private String methodName = "main";
@@ -45,7 +49,8 @@ public class JavaAction extends AbstractAction {
@Argument(index = 1, name = "arguments", description="Arguments to pass to the method of the given class", required = false, multiValued = false)
private List<String> args;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
boolean info = log.isInfoEnabled();
Class type = Thread.currentThread().getContextClassLoader().loadClass(className);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LogoutAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LogoutAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LogoutAction.java
index f11437d..3654225 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LogoutAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/LogoutAction.java
@@ -16,18 +16,28 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.console.CloseShellException;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Command(scope = "shell", name = "logout", description = "Disconnects shell from current session.")
@Service
-public class LogoutAction extends AbstractAction {
+public class LogoutAction implements Action {
- protected Object doExecute() throws Exception {
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ @Reference
+ Session session;
+
+ @Override
+ public Object execute() throws Exception {
log.info("Disconnecting from current session...");
- throw new CloseShellException();
+ session.close();
+ return null;
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/MoreAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/MoreAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/MoreAction.java
index ebe1d86..5db87f6 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/MoreAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/MoreAction.java
@@ -24,23 +24,34 @@ import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
-import jline.Terminal;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Command(scope = "shell", name = "more", description = "File pager.")
@Service
-public class MoreAction extends AbstractAction {
+public class MoreAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Option(name = "--lines", description = "stop after N lines")
int lines;
+ @Reference
+ Terminal terminal;
+
+ @Reference
+ Session session;
+
@Override
- protected Object doExecute() throws Exception {
- Terminal term = (Terminal) session.get(".jline.terminal");
- if (term == null || !isTty(System.out)) {
+ public Object execute() throws Exception {
+ if (terminal == null || !isTty(System.out)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = reader.readLine()) != null) {
@@ -49,13 +60,13 @@ public class MoreAction extends AbstractAction {
}
return null;
} else {
- boolean echo = term.isEchoEnabled();
- term.setEchoEnabled(false);
+ boolean echo = terminal.isEchoEnabled();
+ terminal.setEchoEnabled(false);
try {
if (lines == 0) {
- lines = term.getHeight();
+ lines = terminal.getHeight();
}
- LineSplitter reader = new LineSplitter(new BufferedReader(new InputStreamReader(System.in)), term.getWidth());
+ LineSplitter reader = new LineSplitter(new BufferedReader(new InputStreamReader(System.in)), terminal.getWidth());
int count = 0;
int c;
do {
@@ -100,14 +111,13 @@ public class MoreAction extends AbstractAction {
}
}
} while (c != 'q');
- return null;
} catch (InterruptedException ie) {
- log.debug("Interupted by user");
- return null;
+ log.debug("Interrupted by user");
} finally {
- term.setEchoEnabled(echo);
+ terminal.setEchoEnabled(echo);
}
}
+ return null;
}
public static class LineSplitter {
@@ -148,4 +158,16 @@ public class MoreAction extends AbstractAction {
}
}
+ /**
+ * 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/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/NewAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/NewAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/NewAction.java
index 990eee5..c2d2a86 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/NewAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/NewAction.java
@@ -16,14 +16,6 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.converter.DefaultConverter;
-import org.apache.karaf.shell.commands.converter.GenericType;
-import org.apache.karaf.shell.commands.converter.ReifiedType;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
-
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -36,12 +28,20 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.support.converter.DefaultConverter;
+import org.apache.karaf.shell.support.converter.GenericType;
+import org.apache.karaf.shell.support.converter.ReifiedType;
+
/**
* Instantiate a new object
*/
@Command(scope = "shell", name = "new", description = "Creates a new java object.")
@Service
-public class NewAction extends AbstractAction {
+public class NewAction implements Action {
@Argument(name = "class", index = 0, multiValued = false, required = true, description = "The object class")
Class clazz;
@@ -54,7 +54,7 @@ public class NewAction extends AbstractAction {
protected DefaultConverter converter = new DefaultConverter(getClass().getClassLoader());
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
if (args == null) {
args = Collections.emptyList();
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintStackTracesAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintStackTracesAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintStackTracesAction.java
index a07850c..38ca8b5 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintStackTracesAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintStackTracesAction.java
@@ -16,11 +16,12 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.console.SessionProperties;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* Command for showing the full tree of bundles that have been used to resolve
@@ -28,14 +29,18 @@ import org.apache.karaf.shell.inject.Service;
*/
@Command(scope = "shell", name = "stack-traces-print", description = "Prints the full stack trace in the console when the execution of a command throws an exception.")
@Service
-public class PrintStackTracesAction extends AbstractAction {
+public class PrintStackTracesAction implements Action {
@Argument(name = "print", description="Print stack traces or not", required = false, multiValued = false)
boolean print = true;
- protected Object doExecute() throws Exception {
+ @Reference
+ Session session;
+
+ @Override
+ public Object execute() throws Exception {
System.out.println("Printing of stacktraces set to " + print);
- session.put(SessionProperties.PRINT_STACK_TRACES, Boolean.valueOf(print));
+ session.put(Session.PRINT_STACK_TRACES, print);
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintfAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintfAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintfAction.java
index 3761a20..51b02bb 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintfAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/PrintfAction.java
@@ -18,14 +18,14 @@ package org.apache.karaf.shell.commands.impl;
import java.util.Collection;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
@Command(scope = "shell", name = "printf", description = "Formats and prints arguments.")
@Service
-public class PrintfAction extends AbstractAction {
+public class PrintfAction implements Action {
@Argument(index = 0, name = "format", description = "The format pattern to use", required = true, multiValued = false)
private String format;
@@ -33,8 +33,10 @@ public class PrintfAction extends AbstractAction {
@Argument(index = 1, name = "arguments", description = "The arguments for the given format pattern", required = true, multiValued = true)
private Collection<Object> arguments = null;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
System.out.printf(format, arguments.toArray());
return null;
}
+
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SleepAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SleepAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SleepAction.java
index 4f4f0e5..e8b1103 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SleepAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SleepAction.java
@@ -16,15 +16,19 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Command(scope = "shell", name = "sleep", description = "Sleeps for a bit then wakes up.")
@Service
-public class SleepAction extends AbstractAction {
+public class SleepAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Argument(index = 0, name = "duration", description = "The amount of time to sleep. The default time unit is millisecond, use -s option to use second instead.", required = true, multiValued = false)
private long time = -1;
@@ -32,7 +36,8 @@ public class SleepAction extends AbstractAction {
@Option(name = "-s", aliases = { "--second" }, description = "Use a duration time in seconds instead of milliseconds.", required = false, multiValued = false)
private boolean second = false;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (second) {
log.info("Sleeping for {} second(s)", time);
time = time * 1000;
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SortAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SortAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SortAction.java
index 6b383f7..4b9d165 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SortAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SortAction.java
@@ -34,18 +34,22 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Sort lines of text
*/
@Command(scope = "shell", name = "sort", description = "Writes sorted concatenation of all files to standard output.")
@Service
-public class SortAction extends AbstractAction {
+public class SortAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Option(name = "-f", aliases = { "-ignore-case" }, description = "fold lower case to upper case characters", required = false, multiValued = false)
private boolean caseInsensitive;
@@ -71,8 +75,8 @@ public class SortAction extends AbstractAction {
@Argument(index = 0, name = "files", description = "A list of files separated by whitespaces", required = false, multiValued = true)
private List<String> paths;
-
- public Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
if (paths != null && paths.size() > 0) {
List<String> lines = new ArrayList<String>();
for (String filename : paths) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SourceAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SourceAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SourceAction.java
index 8eaaf18..c8bae6f 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SourceAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/SourceAction.java
@@ -28,17 +28,23 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* TODO
*/
@Command(scope = "shell", name = "source", description = "Run a script")
@Service
-public class SourceAction extends AbstractAction {
+public class SourceAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
@Argument(index = 0, name = "script", description = "A URI pointing to the script", required = true, multiValued = false)
private String script;
@@ -46,8 +52,11 @@ public class SourceAction extends AbstractAction {
@Argument(index = 1, name = "args", description = "Arguments for the script", required = false, multiValued = true)
private List<Object> args;
+ @Reference
+ Session session;
+
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
BufferedReader reader = null;
Object arg0 = session.get("0");
try {
@@ -75,7 +84,7 @@ public class SourceAction extends AbstractAction {
session.put( Integer.toString(i+1), args.get(i) );
}
- return session.execute(w.toString());
+ session.execute(w.toString());
} finally {
for (int i = 0; args != null && i < args.size(); i++) {
session.put( Integer.toString(i+1), null );
@@ -89,5 +98,6 @@ public class SourceAction extends AbstractAction {
}
}
}
+ return null;
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TacAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TacAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TacAction.java
index 89fde75..5cf1b20 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TacAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TacAction.java
@@ -25,10 +25,12 @@ import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
/**
* Grab the text from the standard input and return it as a string.
@@ -36,12 +38,16 @@ import org.apache.karaf.shell.inject.Service;
*/
@Command(scope = "shell", name = "tac", description = "Captures the STDIN and returns it as a string. Optionally writes the content to a file.")
@Service
-public class TacAction extends AbstractAction {
+public class TacAction implements Action {
@Option(name = "-f", aliases = {}, description = "Outputs the content to the given file", required = false, multiValued = false)
private File file;
- protected Object doExecute() throws Exception {
+ @Reference
+ Session session;
+
+ @Override
+ public Object execute() throws Exception {
StringWriter sw = new StringWriter();
Writer[] writers;
if (file != null) {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TailAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TailAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TailAction.java
index d9486e2..435816c 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TailAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/TailAction.java
@@ -25,15 +25,19 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
@Command(scope = "shell", name = "tail", description = "Displays the last lines of a file.")
@Service
-public class TailAction extends AbstractAction {
+public class TailAction implements Action {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
private static final int DEFAULT_NUMBER_OF_LINES = 10;
@@ -51,7 +55,8 @@ public class TailAction extends AbstractAction {
@Argument(index = 0, name = "path or url", description = "A file path or url to display.", required = false, multiValued = false)
private String path;
- protected Object doExecute() throws Exception {
+ @Override
+ public Object execute() throws Exception {
//If no paths provided assume standar input
if (path == null || path.trim().length() == 0) {
if (log.isDebugEnabled()) {
@@ -89,7 +94,6 @@ public class TailAction extends AbstractAction {
}
}
}
-
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ThreadsAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ThreadsAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ThreadsAction.java
index e6c77ea..fbf6692 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ThreadsAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/ThreadsAction.java
@@ -27,11 +27,11 @@ import java.util.List;
import java.util.Map;
import java.util.TreeMap;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.karaf.shell.table.ShellTable;
/**
@@ -40,7 +40,7 @@ import org.apache.karaf.shell.table.ShellTable;
*/
@Command(scope = "shell", name = "threads", description = "Prints the current threads (optionally with stacktraces)")
@Service
-public class ThreadsAction extends AbstractAction {
+public class ThreadsAction implements Action {
@Option(name = "--tree" , description = "Display threads as a tree")
boolean tree = false;
@@ -70,7 +70,7 @@ public class ThreadsAction extends AbstractAction {
boolean noFormat;
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
Map<Long, ThreadInfo> threadInfos = new TreeMap<Long, ThreadInfo>();
ThreadMXBean threadsBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] infos;
@@ -118,7 +118,6 @@ public class ThreadsAction extends AbstractAction {
ThreadGroupData data = new ThreadGroupData(group, threadInfos);
data.print();
}
-
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
index 4ec7763..fa75134 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WatchAction.java
@@ -24,18 +24,22 @@ import java.io.PrintStream;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import org.apache.felix.service.command.CommandProcessor;
-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.Completer;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.console.completer.CommandsCompleter;
-import org.apache.karaf.shell.inject.Reference;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.support.ShellUtil;
+import org.apache.karaf.shell.support.completers.CommandsCompleter;
@Command(scope = "shell", name = "watch", description = "Watches & refreshes the output of a command")
-public class WatchAction extends AbstractAction {
+@Service
+public class WatchAction implements Action {
@Option(name = "-n", aliases = {"--interval"}, description = "The interval between executions of the command in seconds", required = false, multiValued = false)
private long interval = 1;
@@ -44,25 +48,27 @@ public class WatchAction extends AbstractAction {
private boolean append = false;
@Argument(index = 0, name = "command", description = "The command to watch / refresh", required = true, multiValued = true)
- @Completer(CommandsCompleter.class)
+ @Completion(CommandsCompleter.class)
private String[] arguments;
@Reference
- CommandProcessor commandProcessor;
+ Session session;
+
+ @Reference
+ SessionFactory sessionFactory;
private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
if (arguments == null || arguments.length == 0) {
System.err.println("Argument expected");
- return null;
} else {
StringBuilder command = new StringBuilder();
- for (String arg:arguments) {
+ for (String arg : arguments) {
command.append(arg).append(" ");
}
- WatchTask watchTask = new WatchTask(commandProcessor, command.toString().trim());
+ WatchTask watchTask = new WatchTask(command.toString().trim());
executorService.scheduleAtFixedRate(watchTask, 0, interval, TimeUnit.SECONDS);
try {
session.getKeyboard().read();
@@ -70,23 +76,21 @@ public class WatchAction extends AbstractAction {
} finally {
executorService.shutdownNow();
watchTask.close();
- return null;
}
}
+ return null;
}
public class WatchTask implements Runnable {
- private final CommandProcessor processor;
private final String command;
- CommandSession session;
+ Session session;
ByteArrayOutputStream byteArrayOutputStream = null;
PrintStream printStream = null;
boolean doDisplay = true;
- public WatchTask(CommandProcessor processor, String command) {
- this.processor = processor;
+ public WatchTask(String command) {
this.command = command;
}
@@ -94,10 +98,15 @@ public class WatchAction extends AbstractAction {
try {
byteArrayOutputStream = new ByteArrayOutputStream();
printStream = new PrintStream(byteArrayOutputStream);
- session = commandProcessor.createSession(null, printStream, printStream);
- session.put("SCOPE", "shell:bundle:*");
+ session = sessionFactory.create(null, printStream, printStream);
+ session.put(Session.SCOPE, WatchAction.this.session.get(Session.SCOPE));
+ session.put(Session.SUBSHELL, WatchAction.this.session.get(Session.SUBSHELL));
String output = "";
- session.execute(command);
+ try {
+ session.execute(command);
+ } catch (Exception e) {
+ ShellUtil.logException(session, e);
+ }
output = byteArrayOutputStream.toString();
if (doDisplay) {
if (!append) {
@@ -130,11 +139,4 @@ public class WatchAction extends AbstractAction {
}
}
- public CommandProcessor getCommandProcessor() {
- return commandProcessor;
- }
-
- public void setCommandProcessor(CommandProcessor commandProcessor) {
- this.commandProcessor = commandProcessor;
- }
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WcAction.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WcAction.java b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WcAction.java
index f87fe48..93e00bc 100644
--- a/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WcAction.java
+++ b/shell/commands/src/main/java/org/apache/karaf/shell/commands/impl/WcAction.java
@@ -16,18 +16,18 @@
*/
package org.apache.karaf.shell.commands.impl;
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.apache.karaf.shell.console.AbstractAction;
-import org.apache.karaf.shell.inject.Service;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import java.io.*;
import java.util.List;
@Command(scope = "shell", name = "wc", description = "Print newline, word, and byte counts for each file.")
@Service
-public class WcAction extends AbstractAction {
+public class WcAction implements Action {
@Option(name = "-l", aliases = { "--lines" }, description = "Print the newline counts.", required = false, multiValued = false)
private boolean lines;
@@ -45,7 +45,7 @@ public class WcAction extends AbstractAction {
private List<File> files;
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
this.setDefaultOptions();
String outputString;
@@ -58,7 +58,6 @@ public class WcAction extends AbstractAction {
}
System.out.println(outputString);
-
return null;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/resources/META-INF/services/org/apache/karaf/shell/commands b/shell/commands/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
index a94c585..8149c3d 100644
--- a/shell/commands/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
+++ b/shell/commands/src/main/resources/META-INF/services/org/apache/karaf/shell/commands
@@ -14,24 +14,32 @@
## See the License for the specific language governing permissions and
## limitations under the License.
##---------------------------------------------------------------------------
+org.jledit.ConcreteEditorFactory
org.apache.karaf.shell.commands.impl.AliasAction
org.apache.karaf.shell.commands.impl.CatAction
org.apache.karaf.shell.commands.impl.ClearAction
+org.apache.karaf.shell.commands.impl.CompletionAction
org.apache.karaf.shell.commands.impl.DateAction
org.apache.karaf.shell.commands.impl.EachAction
org.apache.karaf.shell.commands.impl.EchoAction
+org.apache.karaf.shell.commands.impl.EditAction
org.apache.karaf.shell.commands.impl.ExecuteAction
org.apache.karaf.shell.commands.impl.GrepAction
-org.apache.karaf.shell.commands.impl.HistoryAction
org.apache.karaf.shell.commands.impl.HeadAction
+org.apache.karaf.shell.commands.impl.HistoryAction
org.apache.karaf.shell.commands.impl.IfAction
+org.apache.karaf.shell.commands.impl.InfoAction
org.apache.karaf.shell.commands.impl.JavaAction
org.apache.karaf.shell.commands.impl.LogoutAction
org.apache.karaf.shell.commands.impl.MoreAction
org.apache.karaf.shell.commands.impl.NewAction
org.apache.karaf.shell.commands.impl.PrintfAction
+org.apache.karaf.shell.commands.impl.PrintStackTracesAction
org.apache.karaf.shell.commands.impl.SleepAction
org.apache.karaf.shell.commands.impl.SortAction
+org.apache.karaf.shell.commands.impl.SourceAction
org.apache.karaf.shell.commands.impl.TacAction
org.apache.karaf.shell.commands.impl.TailAction
+org.apache.karaf.shell.commands.impl.ThreadsAction
+org.apache.karaf.shell.commands.impl.WatchAction
org.apache.karaf.shell.commands.impl.WcAction
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml
----------------------------------------------------------------------
diff --git a/shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml b/shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml
index 36c1bae..af2747c 100644
--- a/shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml
+++ b/shell/commands/src/main/resources/OSGI-INF/blueprint/shell-commands.xml
@@ -19,13 +19,15 @@
-->
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" default-activation="lazy">
+ <!--
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.2.0"
scan="org.apache.karaf.shell.commands.impl" />
<bean id="commandCompleter" class="org.apache.karaf.shell.console.completer.CommandsCompleter"/>
<service ref="commandCompleter" auto-export="all-classes"/>
+ -->
- <bean class="org.osgi.util.tracker.BundleTracker" init-method="open"
+ <bean class="org.osgi.util.tracker.BundleTracker" init-method="open"
destroy-method="close">
<argument ref="blueprintBundleContext" />
<argument value="32" />
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java
index eb61a7b..3845b9d 100644
--- a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java
+++ b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/GrepTest.java
@@ -23,8 +23,7 @@ import java.io.InputStream;
import java.util.Arrays;
import junit.framework.TestCase;
-import org.apache.karaf.shell.commands.basic.DefaultActionPreparator;
-import org.apache.karaf.shell.commands.impl.GrepAction;
+import org.apache.karaf.shell.impl.action.command.DefaultActionPreparator;
public class GrepTest extends TestCase {
@@ -37,7 +36,7 @@ public class GrepTest extends TestCase {
GrepAction grep = new GrepAction();
DefaultActionPreparator preparator = new DefaultActionPreparator();
preparator.prepare(grep, null, Arrays.<Object>asList("-C", "100", "2"));
- grep.doExecute();
+ grep.execute();
} finally {
System.setIn(input);
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/ThreadsTest.java
----------------------------------------------------------------------
diff --git a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/ThreadsTest.java b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/ThreadsTest.java
index 5daf61c..98d9aed 100644
--- a/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/ThreadsTest.java
+++ b/shell/commands/src/test/java/org/apache/karaf/shell/commands/impl/ThreadsTest.java
@@ -26,26 +26,26 @@ public class ThreadsTest {
public void testThreadlist() throws Exception {
ThreadsAction action = new ThreadsAction();
action.list = true;
- action.doExecute();
+ action.execute();
}
@Test
public void testThreadInfo() throws Exception {
ThreadsAction action = new ThreadsAction();
action.id = 1L;
- action.doExecute();
+ action.execute();
}
@Test
public void testThreadTree() throws Exception {
ThreadsAction action = new ThreadsAction();
action.tree = true;
- action.doExecute();
+ action.execute();
}
@Test
public void testThreadDump() throws Exception {
ThreadsAction action = new ThreadsAction();
- action.doExecute();
+ action.execute();
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/pom.xml
----------------------------------------------------------------------
diff --git a/shell/ssh/pom.xml b/shell/ssh/pom.xml
index 749e5ca..84135eb 100644
--- a/shell/ssh/pom.xml
+++ b/shell/ssh/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.core</artifactId>
</dependency>
<dependency>
@@ -101,22 +101,12 @@
<configuration>
<instructions>
<Import-Package>
- org.apache.aries.blueprint,
- org.osgi.service.blueprint.container,
- org.osgi.service.blueprint.reflect,
- org.apache.felix.service.command,
- org.apache.karaf.shell.commands,
- org.apache.karaf.shell.console,
- org.apache.mina.util,
- org.apache.sshd.server.keyprovider,
- org.apache.sshd.server.jaas,
- org.apache.sshd.server.sftp,
- !org.apache.sshd.server.sftp.SftpSubsystem,
*
</Import-Package>
<Private-Package>
org.apache.karaf.util
</Private-Package>
+ <Bundle-Activator>org.apache.karaf.shell.ssh.Activator</Bundle-Activator>
</instructions>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
new file mode 100644
index 0000000..a61babc
--- /dev/null
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
@@ -0,0 +1,268 @@
+/*
+ * 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.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.karaf.shell.api.action.lifecycle.Manager;
+import org.apache.karaf.shell.ssh.util.SingleServiceTracker;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.server.sftp.SftpSubsystem;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Activate this bundle
+ */
+public class Activator implements BundleActivator, ManagedService {
+
+ ServiceRegistration registration;
+
+ List<Session> sessions = new CopyOnWriteArrayList<Session>();
+
+ BundleContext bundleContext;
+ SingleServiceTracker<SessionFactory> sessionFactoryTracker;
+ ServiceTracker<Session, Session> sessionTracker;
+ Dictionary<String, ?> configuration;
+
+ final KarafAgentFactory agentFactory = new KarafAgentFactory();
+
+ SessionFactory sessionFactory;
+ SshClientFactory sshClientFactory;
+ final Callable<SshServer> sshServerFactory = new Callable<SshServer>() {
+ @Override
+ public SshServer call() throws Exception {
+ return createSshServer(sessionFactory);
+ }
+ };
+ SshServer server;
+ final List<SshServer> servers = new ArrayList<SshServer>();
+
+
+ public void start(BundleContext context) throws Exception {
+ bundleContext = context;
+
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put(Constants.SERVICE_PID, "org.apache.karaf.shell");
+ registration = bundleContext.registerService(ManagedService.class, this, props);
+
+ sshClientFactory = new SshClientFactory(agentFactory, new File(context.getProperty("user.home"), ".sshkaraf/known_hosts"));
+
+ sessionFactoryTracker = new SingleServiceTracker<SessionFactory>(bundleContext, SessionFactory.class, new SingleServiceTracker.SingleServiceListener() {
+ @Override
+ public void serviceFound() {
+ bindSessionFactory(sessionFactoryTracker.getService());
+ }
+ @Override
+ public void serviceLost() {
+ unbindSessionFactory();
+ }
+ @Override
+ public void serviceReplaced() {
+ serviceLost();
+ serviceFound();
+ }
+ });
+ sessionFactoryTracker.open();
+
+ sessionTracker = new ServiceTracker<Session, Session>(bundleContext, Session.class, null) {
+ @Override
+ public Session addingService(ServiceReference<Session> reference) {
+ Session session = super.addingService(reference);
+ agentFactory.registerSession(session);
+ return session;
+ }
+ @Override
+ public void removedService(ServiceReference<Session> reference, Session session) {
+ agentFactory.unregisterSession(session);
+ super.removedService(reference, session);
+ }
+ };
+ sessionTracker.open();
+
+ }
+
+ private void bindSessionFactory(final SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
+ this.sessionFactory.getRegistry().register(sshServerFactory, SshServer.class);
+ this.sessionFactory.getRegistry().register(sshClientFactory);
+ this.sessionFactory.getRegistry().getService(Manager.class).register(SshServerAction.class);
+ this.sessionFactory.getRegistry().getService(Manager.class).register(SshAction.class);
+ if (Boolean.parseBoolean(Activator.this.bundleContext.getProperty("karaf.startRemoteShell"))) {
+ server = createSshServer(sessionFactory);
+ try {
+ server.start();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void unbindSessionFactory() {
+ this.sessionFactory.getRegistry().getService(Manager.class).unregister(SshAction.class);
+ this.sessionFactory.getRegistry().getService(Manager.class).unregister(SshServerAction.class);
+ this.sessionFactory.getRegistry().unregister(sshClientFactory);
+ this.sessionFactory.getRegistry().unregister(sshServerFactory);
+ SshServer srv = server;
+ server = null;
+ if (srv != null) {
+ try {
+ srv.stop();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void stop(BundleContext context) {
+ registration.unregister();
+ sessionTracker.close();
+ sessionFactoryTracker.close();
+ synchronized (servers) {
+ for (SshServer server : servers) {
+ try {
+ server.stop();
+ } catch (InterruptedException e) {
+ // TODO: log exception
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void updated(Dictionary<String, ?> configuration) throws ConfigurationException {
+ this.configuration = configuration;
+ }
+
+ private int getInt(String key, int def) {
+ Dictionary<String, ?> config = this.configuration;
+ if (config != null) {
+ Object val = config.get(key);
+ if (val instanceof Number) {
+ return ((Number) val).intValue();
+ } else if (val != null) {
+ return Integer.parseInt(val.toString());
+ }
+ }
+ return def;
+ }
+
+ private long getLong(String key, long def) {
+ Dictionary<String, ?> config = this.configuration;
+ if (config != null) {
+ Object val = config.get(key);
+ if (val instanceof Number) {
+ return ((Number) val).longValue();
+ } else if (val != null) {
+ return Long.parseLong(val.toString());
+ }
+ }
+ return def;
+ }
+
+ private String getString(String key, String def) {
+ Dictionary<String, ?> config = this.configuration;
+ if (config != null) {
+ Object val = config.get(key);
+ if (val != null) {
+ return val.toString();
+ }
+ }
+ return def;
+ }
+
+ protected SshServer createSshServer(SessionFactory sessionFactory) {
+ int sshPort = getInt("sshPort", 8181);
+ String sshHost = getString("sshHost", "0.0.0.0");
+ long sshIdleTimeout = getLong("sshIdleTimeout", 1800000);
+ String sshRealm = getString("sshRealm", "karaf");
+ String hostKey = getString("hostKey", System.getProperty("karaf.base") + "/etc/host.key");
+ String authMethods = getString("authMethods", "keyboard-interactive,password,publickey");
+ int keySize = getInt("keySize", 1024);
+ String algorithm = getString("algorithm", "DSA");
+ String macs = getString("macs", "hmac-sha1");
+ String ciphers = getString("ciphers", "aes256-ctr,aes192-ctr,aes128-ctr,arcfour256");
+
+ SimpleGeneratorHostKeyProvider keyPairProvider = new SimpleGeneratorHostKeyProvider();
+ keyPairProvider.setPath(hostKey);
+ keyPairProvider.setKeySize(keySize);
+ keyPairProvider.setAlgorithm(algorithm);
+
+ KarafJaasAuthenticator authenticator = new KarafJaasAuthenticator(sshRealm);
+
+ UserAuthFactoriesFactory authFactoriesFactory = new UserAuthFactoriesFactory();
+ authFactoriesFactory.setAuthMethods(authMethods);
+
+ SshServer server = SshServer.setUpDefaultServer();
+ server.setPort(sshPort);
+ server.setHost(sshHost);
+ server.setMacFactories(SshUtils.buildMacs(macs));
+ server.setCipherFactories(SshUtils.buildCiphers(ciphers));
+ server.setShellFactory(new ShellFactoryImpl(sessionFactory));
+ server.setCommandFactory(new ScpCommandFactory(new ShellCommandFactory(sessionFactory)));
+ server.setSubsystemFactories(Arrays.<NamedFactory<org.apache.sshd.server.Command>>asList(new SftpSubsystem.Factory()));
+ server.setKeyPairProvider(keyPairProvider);
+ server.setPasswordAuthenticator(authenticator);
+ server.setPublickeyAuthenticator(authenticator);
+ server.setFileSystemFactory(new KarafFileSystemFactory());
+ server.setUserAuthFactories(authFactoriesFactory.getFactories());
+ server.setAgentFactory(agentFactory);
+ server.getProperties().put(SshServer.IDLE_TIMEOUT, Long.toString(sshIdleTimeout));
+
+ synchronized (servers) {
+ servers.add(server);
+ }
+ return server;
+ }
+
+ public void bindCommandSession(Session session) {
+ sessions.add(session);
+ if (agentFactory != null) {
+ agentFactory.registerSession(session);
+ }
+ }
+
+ public void unbindCommandSession(Session session) {
+ sessions.remove(session);
+ if (agentFactory != null) {
+ agentFactory.unregisterSession(session);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ActivatorNoOsgi.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ActivatorNoOsgi.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ActivatorNoOsgi.java
new file mode 100644
index 0000000..f71c5ef
--- /dev/null
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ActivatorNoOsgi.java
@@ -0,0 +1,33 @@
+package org.apache.karaf.shell.ssh;
+
+import java.io.File;
+
+import org.apache.karaf.shell.api.action.lifecycle.Destroy;
+import org.apache.karaf.shell.api.action.lifecycle.Init;
+import org.apache.karaf.shell.api.action.lifecycle.Manager;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.console.SessionFactory;
+
+public class ActivatorNoOsgi {
+
+ @Reference
+ SessionFactory sessionFactory;
+
+ KarafAgentFactory agentFactory;
+ SshClientFactory sshClientFactory;
+
+ @Init
+ public void init() {
+ agentFactory = new KarafAgentFactory();
+ sshClientFactory = new SshClientFactory(agentFactory, new File(System.getProperty("user.home"), ".sshkaraf/known_hosts"));
+ sessionFactory.getRegistry().register(sshClientFactory);
+ sessionFactory.getRegistry().getService(Manager.class).register(SshAction.class);
+ }
+
+ @Destroy
+ public void destroy() {
+ sessionFactory.getRegistry().register(sshClientFactory);
+ sessionFactory.getRegistry().getService(Manager.class).register(SshAction.class);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafAgentFactory.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafAgentFactory.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafAgentFactory.java
index 45d1f36..da4d43a 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafAgentFactory.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafAgentFactory.java
@@ -26,7 +26,6 @@ import java.security.KeyPair;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.felix.service.command.CommandSession;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.agent.SshAgentServer;
@@ -38,7 +37,6 @@ import org.apache.sshd.common.Channel;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.Session;
import org.apache.sshd.server.session.ServerSession;
-import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,16 +47,6 @@ public class KarafAgentFactory implements SshAgentFactory {
private final Map<String, AgentServerProxy> proxies = new ConcurrentHashMap<String, AgentServerProxy>();
private final Map<String, SshAgent> locals = new ConcurrentHashMap<String, SshAgent>();
- private BundleContext bundleContext;
-
- public BundleContext getBundleContext() {
- return bundleContext;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
public NamedFactory<Channel> getChannelForwardingFactory() {
return new ChannelAgentForwarding.Factory();
}
@@ -97,11 +85,11 @@ public class KarafAgentFactory implements SshAgentFactory {
};
}
- public void registerCommandSession(CommandSession session) {
+ public void registerSession(org.apache.karaf.shell.api.console.Session session) {
try {
String user = (String) session.get("USER");
SshAgent agent = new AgentImpl();
- URL url = bundleContext.getBundle().getResource("karaf.key");
+ URL url = getClass().getClassLoader().getResource("karaf.key");
InputStream is = url.openStream();
ObjectInputStream r = new ObjectInputStream(is);
KeyPair keyPair = (KeyPair) r.readObject();
@@ -114,7 +102,7 @@ public class KarafAgentFactory implements SshAgentFactory {
}
}
- public void unregisterCommandSession(CommandSession session) {
+ public void unregisterSession(org.apache.karaf.shell.api.console.Session session) {
try {
if (session != null && session.get(SshAgent.SSH_AUTHSOCKET_ENV_NAME) != null) {
String agentId = (String) session.get(SshAgent.SSH_AUTHSOCKET_ENV_NAME);
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafJaasAuthenticator.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafJaasAuthenticator.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafJaasAuthenticator.java
index 0562bb2..6df591a 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafJaasAuthenticator.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/KarafJaasAuthenticator.java
@@ -47,6 +47,13 @@ public class KarafJaasAuthenticator implements PasswordAuthenticator, PublickeyA
private String realm;
+ public KarafJaasAuthenticator() {
+ }
+
+ public KarafJaasAuthenticator(String realm) {
+ this.realm = realm;
+ }
+
public String getRealm() {
return realm;
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommand.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommand.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommand.java
index a825f07..62d8ba6 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommand.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommand.java
@@ -25,12 +25,11 @@ import java.util.Map;
import javax.security.auth.Subject;
-import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
-import org.apache.felix.service.command.Converter;
import org.apache.karaf.jaas.modules.JaasHelper;
-import org.apache.karaf.shell.util.ShellUtil;
import org.apache.karaf.util.StreamUtils;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.support.ShellUtil;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
@@ -57,10 +56,10 @@ public class ShellCommand implements Command, SessionAware {
private OutputStream err;
private ExitCallback callback;
private ServerSession session;
- private CommandProcessor commandProcessor;
+ private SessionFactory sessionFactory;
- public ShellCommand(CommandProcessor commandProcessor, String command) {
- this.commandProcessor = commandProcessor;
+ public ShellCommand(SessionFactory sessionFactory, String command) {
+ this.sessionFactory = sessionFactory;
this.command = command;
}
@@ -86,9 +85,7 @@ public class ShellCommand implements Command, SessionAware {
public void start(final Environment env) throws IOException {
try {
- final CommandSession session = commandProcessor.createSession(in, new PrintStream(out), new PrintStream(err));
- session.put("SCOPE", "shell:osgi:*");
- session.put("APPLICATION", System.getProperty("karaf.name", "root"));
+ final Session session = sessionFactory.create(in, new PrintStream(out), new PrintStream(err));
for (Map.Entry<String,String> e : env.getEnv().entrySet()) {
session.put(e.getKey(), e.getValue());
}
@@ -114,7 +111,8 @@ public class ShellCommand implements Command, SessionAware {
}
if (result != null)
{
- session.getConsole().println(session.format(result, Converter.INSPECT));
+ // TODO: print the result of the command ?
+// session.getConsole().println(session.format(result, Converter.INSPECT));
}
} catch (Throwable t) {
ShellUtil.logException(session, t);
@@ -130,7 +128,7 @@ public class ShellCommand implements Command, SessionAware {
public void destroy() {
}
- private void executeScript(String scriptFileName, CommandSession session) {
+ private void executeScript(String scriptFileName, Session session) {
if (scriptFileName != null) {
Reader r = null;
try {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommandFactory.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommandFactory.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommandFactory.java
index a1de13d..dc1f04e 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommandFactory.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellCommandFactory.java
@@ -18,20 +18,20 @@
*/
package org.apache.karaf.shell.ssh;
-import org.apache.felix.service.command.CommandProcessor;
+import org.apache.karaf.shell.api.console.SessionFactory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.CommandFactory;
public class ShellCommandFactory implements CommandFactory {
- private CommandProcessor commandProcessor;
+ private SessionFactory sessionFactory;
- public void setCommandProcessor(CommandProcessor commandProcessor) {
- this.commandProcessor = commandProcessor;
+ public ShellCommandFactory(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
}
public Command createCommand(String command) {
- return new ShellCommand(commandProcessor, command);
+ return new ShellCommand(sessionFactory, command);
}
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java
index 657193b..a6defed 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/ShellFactoryImpl.java
@@ -29,30 +29,27 @@ import java.util.Map;
import javax.security.auth.Subject;
-import jline.Terminal;
-
-import org.apache.felix.service.command.CommandSession;
import org.apache.karaf.jaas.modules.JaasHelper;
-import org.apache.karaf.shell.console.Console;
-import org.apache.karaf.shell.console.factory.ConsoleFactory;
-import org.apache.karaf.shell.util.ShellUtil;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.support.ShellUtil;
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.apache.sshd.server.SessionAware;
import org.apache.sshd.server.session.ServerSession;
-import org.osgi.service.blueprint.container.ReifiedType;
/**
* SSHD {@link org.apache.sshd.server.Command} factory which provides access to
* Shell.
*/
public class ShellFactoryImpl implements Factory<Command> {
- private ConsoleFactory consoleFactory;
+ private SessionFactory sessionFactory;
- public ShellFactoryImpl(ConsoleFactory consoleFactory) {
- this.consoleFactory = consoleFactory;
+ public ShellFactoryImpl(SessionFactory sessionFactory) {
+ this.sessionFactory = sessionFactory;
}
public Command create() {
@@ -106,15 +103,14 @@ public class ShellFactoryImpl implements Factory<Command> {
if (encoding != null && encoding.indexOf('.') > 0) {
encoding = encoding.substring(encoding.indexOf('.') + 1);
}
- final Console console = consoleFactory.create(in,
+ final Session session = sessionFactory.create(in,
lfToCrLfPrintStream(out), lfToCrLfPrintStream(err), terminal, encoding, destroyCallback);
- final CommandSession session = console.getSession();
for (Map.Entry<String, String> e : env.getEnv().entrySet()) {
session.put(e.getKey(), e.getValue());
}
JaasHelper.doAs(subject, new PrivilegedAction<Object>() {
public Object run() {
- new Thread(console, "Karaf ssh console user " + ShellUtil.getCurrentUserName()).start();
+ new Thread(session, "Karaf ssh console user " + ShellUtil.getCurrentUserName()).start();
return null;
}
});
@@ -158,23 +154,6 @@ public class ShellFactoryImpl implements Factory<Command> {
}
}
- public static Converter getConverter() {
- return new Converter();
- }
-
- public static class Converter implements org.osgi.service.blueprint.container.Converter {
-
- public boolean canConvert(Object sourceObject, ReifiedType targetType) {
- return ShellFactoryImpl.class.isAssignableFrom(sourceObject.getClass())
- && Factory.class.equals(targetType.getRawClass())
- && Command.class.equals(targetType.getActualTypeArgument(0).getRawClass());
- }
-
- public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
- return sourceObject;
- }
- }
-
// TODO: remove this class when sshd use lf->crlf conversion by default
public class LfToCrLfFilterOutputStream extends FilterOutputStream {
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshAction.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshAction.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshAction.java
index ed59460..0f2ae21 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshAction.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshAction.java
@@ -22,14 +22,14 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
-import jline.Terminal;
-
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import jline.console.ConsoleReader;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
-import org.apache.karaf.shell.console.SessionProperties;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.Terminal;
import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
@@ -42,7 +42,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Command(scope = "ssh", name = "ssh", description = "Connects to a remote SSH server")
-public class SshAction extends OsgiCommandSupport {
+@Service
+public class SshAction implements Action {
private final Logger log = LoggerFactory.getLogger(getClass());
@Option(name="-l", aliases={"--username"}, description = "The user name for remote login", required = false, multiValued = false)
@@ -63,9 +64,11 @@ public class SshAction extends OsgiCommandSupport {
@Argument(index = 1, name = "command", description = "Optional command to execute", required = false, multiValued = true)
private List<String> command;
- private ClientSession sshSession;
+ @Reference
+ private Session session;
- private SshClientFactory sshClientFactory;
+ @Reference
+ private SshClientFactory sshClientFactory;
private final static String keyChangedMessage =
" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ \n" +
@@ -85,7 +88,7 @@ public class SshAction extends OsgiCommandSupport {
}
@Override
- protected Object doExecute() throws Exception {
+ public Object execute() throws Exception {
if (hostname.indexOf('@') >= 0) {
if (username == null) {
@@ -104,7 +107,7 @@ public class SshAction extends OsgiCommandSupport {
if (username == null) {
log.debug("Prompting user for login");
if (username == null) {
- username = readLine("Login: ");
+ username = session.readLine("Login: ", null);
}
}
@@ -121,9 +124,9 @@ public class SshAction extends OsgiCommandSupport {
try {
ConnectFuture future = client.connect(hostname, port);
future.await();
- sshSession = future.getSession();
+ ClientSession sshSession = future.getSession();
- Object oldIgnoreInterrupts = this.session.get(SessionProperties.IGNORE_INTERRUPTS);
+ Object oldIgnoreInterrupts = this.session.get(Session.IGNORE_INTERRUPTS);
try {
@@ -145,7 +148,7 @@ public class SshAction extends OsgiCommandSupport {
if (!authed) {
if (password == null) {
log.debug("Prompting user for password");
- password = readLine("Password: ");
+ password = session.readLine("Password: ", '*');
} else {
log.debug("Password provided using command line option");
}
@@ -167,7 +170,7 @@ public class SshAction extends OsgiCommandSupport {
}
System.out.println("Connected");
- this.session.put( SessionProperties.IGNORE_INTERRUPTS, Boolean.TRUE );
+ this.session.put( Session.IGNORE_INTERRUPTS, Boolean.TRUE );
StringBuilder sb = new StringBuilder();
if (command != null) {
@@ -199,7 +202,7 @@ public class SshAction extends OsgiCommandSupport {
channel.open();
channel.waitFor(ClientChannel.CLOSED, 0);
} finally {
- session.put( SessionProperties.IGNORE_INTERRUPTS, oldIgnoreInterrupts );
+ session.put( Session.IGNORE_INTERRUPTS, oldIgnoreInterrupts );
sshSession.close(false);
}
} finally {
@@ -210,17 +213,8 @@ public class SshAction extends OsgiCommandSupport {
}
private int getTermWidth() {
- Terminal term = (Terminal) session.get(".jline.terminal");
+ Terminal term = session.getTerminal();
return term != null ? term.getWidth() : 80;
}
- public String readLine(String msg) throws IOException {
- return readLine(msg, null);
- }
-
- public String readLine(String msg, Character mask) throws IOException {
- ConsoleReader reader = (ConsoleReader) session.get(".jline.reader");
- return reader.readLine(msg, mask);
- }
-
}
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerAction.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerAction.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerAction.java
index e92db70..6b45a0a 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerAction.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerAction.java
@@ -18,17 +18,18 @@
*/
package org.apache.karaf.shell.ssh;
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.apache.sshd.SshServer;
-import org.apache.karaf.shell.console.BlueprintContainerAware;
-import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.osgi.service.blueprint.container.BlueprintContainer;
@Command(scope = "ssh", name = "sshd", description = "Creates a SSH server")
-public class SshServerAction extends OsgiCommandSupport implements BlueprintContainerAware
+@Service
+public class SshServerAction implements Action
{
private final Logger log = LoggerFactory.getLogger(getClass());
@@ -41,29 +42,21 @@ public class SshServerAction extends OsgiCommandSupport implements BlueprintCont
@Option(name = "-i", aliases = { "--idle-timeout" }, description = "The session idle timeout (Default: 1800000ms)", required = false, multiValued = false)
private long idleTimeout = 1800000;
- private BlueprintContainer container;
+ @Reference
+ private SshServer server;
- private String sshServerId;
-
- public void setBlueprintContainer(final BlueprintContainer container) {
- assert container != null;
- this.container = container;
- }
-
- public void setSshServerId(String sshServerId) {
- this.sshServerId = sshServerId;
+ public void setServer(SshServer server) {
+ this.server = server;
}
- protected Object doExecute() throws Exception {
- SshServer server = (SshServer) container.getComponentInstance(sshServerId);
-
+ public Object execute() throws Exception {
log.debug("Created server: {}", server);
// port number
server.setPort(port);
// idle timeout
- server.getProperties().put(SshServer.IDLE_TIMEOUT, new Long(idleTimeout).toString());
+ server.getProperties().put(SshServer.IDLE_TIMEOUT, Long.toString(idleTimeout));
// starting the SSHd server
server.start();
http://git-wip-us.apache.org/repos/asf/karaf/blob/2e2b9324/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerFactory.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerFactory.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerFactory.java
deleted file mode 100644
index 4789669..0000000
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/SshServerFactory.java
+++ /dev/null
@@ -1,77 +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.ssh;
-
-import org.apache.sshd.SshServer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SshServerFactory {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SshServerFactory.class);
-
- private long idleTimeout;
- private boolean start;
-
- private SshServer server;
-
- public SshServerFactory(SshServer server) {
- this.server = server;
- }
-
- public boolean isStart() {
- return start;
- }
-
- public void setStart(boolean start) {
- this.start = start;
- }
-
- public long getIdleTimeout() {
- return idleTimeout;
- }
-
- public void setIdleTimeout(long idleTimeout) {
- this.idleTimeout = idleTimeout;
- }
-
- public void start() {
- if (start) {
- try {
- server.getProperties().put(SshServer.IDLE_TIMEOUT, new Long(idleTimeout).toString());
- server.start();
- } catch (Exception e) {
- LOGGER.info("Error updating SSH server", e);
- }
- }
- }
-
- public void stop() {
- if (start && server != null) {
- try {
- server.stop();
- } catch (Exception e) {
- LOGGER.info("Error stopping SSH server", e);
- } finally {
- server = null;
- }
- }
- }
-
-}
[05/10] git commit: [KARAF-2805] Clean console and commands model
Posted by gn...@apache.org.
[KARAF-2805] Clean console and commands model
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/e7d23bef
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/e7d23bef
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/e7d23bef
Branch: refs/heads/master
Commit: e7d23bef3856780ab07aa813f8feea56572eb2f2
Parents: bd56b49
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Wed Mar 5 14:39:38 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Wed Mar 5 15:10:37 2014 +0100
----------------------------------------------------------------------
pom.xml | 5 +
shell/core/NOTICE | 71 +++
shell/core/pom.xml | 179 ++++++
.../karaf/shell/console/branding-ssh.properties | 34 ++
.../karaf/shell/console/branding.properties | 33 ++
.../apache/karaf/shell/api/action/Action.java | 56 ++
.../apache/karaf/shell/api/action/Argument.java | 73 +++
.../apache/karaf/shell/api/action/Command.java | 61 ++
.../karaf/shell/api/action/Completion.java | 59 ++
.../apache/karaf/shell/api/action/Option.java | 71 +++
.../shell/api/action/lifecycle/Destroy.java | 34 ++
.../karaf/shell/api/action/lifecycle/Init.java | 34 ++
.../shell/api/action/lifecycle/Manager.java | 49 ++
.../shell/api/action/lifecycle/Reference.java | 39 ++
.../shell/api/action/lifecycle/Service.java | 36 ++
.../apache/karaf/shell/api/console/Command.java | 51 ++
.../karaf/shell/api/console/CommandLine.java | 61 ++
.../karaf/shell/api/console/Completer.java | 38 ++
.../karaf/shell/api/console/Function.java | 38 ++
.../apache/karaf/shell/api/console/History.java | 45 ++
.../karaf/shell/api/console/Registry.java | 77 +++
.../apache/karaf/shell/api/console/Session.java | 153 +++++
.../karaf/shell/api/console/SessionFactory.java | 65 +++
.../karaf/shell/api/console/Terminal.java | 51 ++
.../impl/action/command/ActionCommand.java | 109 ++++
.../impl/action/command/ArgumentCompleter.java | 385 ++++++++++++
.../action/command/DefaultActionPreparator.java | 481 +++++++++++++++
.../shell/impl/action/command/HelpOption.java | 57 ++
.../shell/impl/action/command/ManagerImpl.java | 168 ++++++
.../shell/impl/action/osgi/CommandExtender.java | 94 +++
.../impl/action/osgi/CommandExtension.java | 202 +++++++
.../impl/action/osgi/MultiServiceTracker.java | 106 ++++
.../shell/impl/action/osgi/RegistryImpl.java | 159 +++++
.../shell/impl/action/osgi/Satisfiable.java | 30 +
.../impl/action/osgi/SingleServiceTracker.java | 168 ++++++
.../karaf/shell/impl/console/Branding.java | 72 +++
.../impl/console/CommandNamesCompleter.java | 47 ++
.../shell/impl/console/CommandWrapper.java | 61 ++
.../shell/impl/console/CommandsCompleter.java | 256 ++++++++
.../impl/console/CompleterAsCompletor.java | 41 ++
.../shell/impl/console/ConsoleSessionImpl.java | 583 +++++++++++++++++++
.../shell/impl/console/HeadlessSessionImpl.java | 146 +++++
.../shell/impl/console/HistoryWrapper.java | 48 ++
.../karaf/shell/impl/console/JLineTerminal.java | 62 ++
.../shell/impl/console/KarafFileHistory.java | 64 ++
.../karaf/shell/impl/console/KarafTerminal.java | 57 ++
.../karaf/shell/impl/console/RegistryImpl.java | 159 +++++
.../shell/impl/console/SessionFactoryImpl.java | 144 +++++
.../shell/impl/console/TerminalFactory.java | 47 ++
.../impl/console/commands/ExitCommand.java | 51 ++
.../impl/console/commands/SubShellCommand.java | 58 ++
.../impl/console/commands/TopLevelCommand.java | 86 +++
.../commands/help/CommandListHelpProvider.java | 117 ++++
.../impl/console/commands/help/HelpCommand.java | 225 +++++++
.../console/commands/help/HelpProvider.java | 27 +
.../commands/help/SimpleHelpProvider.java | 47 ++
.../help/SingleCommandHelpProvider.java | 54 ++
.../shell/impl/console/osgi/Activator.java | 78 +++
.../shell/impl/console/osgi/Converters.java | 279 +++++++++
.../shell/impl/console/osgi/DelayedStarted.java | 87 +++
.../impl/console/osgi/LocalConsoleManager.java | 133 +++++
.../shell/impl/console/osgi/StreamWrapUtil.java | 91 +++
.../console/osgi/secured/SecuredCommand.java | 85 +++
.../osgi/secured/SecuredSessionFactoryImpl.java | 239 ++++++++
.../osgi/secured/SingleServiceTracker.java | 171 ++++++
.../impl/console/parsing/CommandLineImpl.java | 91 +++
.../shell/impl/console/parsing/Parser.java | 396 +++++++++++++
.../shell/impl/console/standalone/Main.java | 278 +++++++++
.../karaf/shell/support/CommandException.java | 64 ++
.../karaf/shell/support/MultiException.java | 95 +++
.../apache/karaf/shell/support/NameScoping.java | 79 +++
.../apache/karaf/shell/support/ShellUtil.java | 214 +++++++
.../karaf/shell/support/ansi/SimpleAnsi.java | 30 +
.../support/completers/AggregateCompleter.java | 96 +++
.../completers/CommandNamesCompleter.java | 27 +
.../support/completers/CommandsCompleter.java | 27 +
.../shell/support/completers/FileCompleter.java | 147 +++++
.../shell/support/completers/NullCompleter.java | 34 ++
.../support/completers/StringsCompleter.java | 113 ++++
.../support/converter/DefaultConverter.java | 403 +++++++++++++
.../shell/support/converter/GenericType.java | 195 +++++++
.../shell/support/converter/ReifiedType.java | 116 ++++
.../karaf/shell/support/table/AnsiColumn.java | 54 ++
.../apache/karaf/shell/support/table/Col.java | 113 ++++
.../karaf/shell/support/table/HAlign.java | 71 +++
.../apache/karaf/shell/support/table/Row.java | 69 +++
.../karaf/shell/support/table/ShellTable.java | 143 +++++
.../karaf/shell/support/table/StringUtil.java | 48 ++
.../src/main/resources/OSGI-INF/bundle.info | 16 +
shell/pom.xml | 1 +
90 files changed, 9907 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index f505153..032442a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -659,6 +659,11 @@
<artifactId>org.apache.karaf.shell.table</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.karaf.shell</groupId>
+ <artifactId>org.apache.karaf.shell.core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.karaf.jaas</groupId>
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/NOTICE
----------------------------------------------------------------------
diff --git a/shell/core/NOTICE b/shell/core/NOTICE
new file mode 100644
index 0000000..b70f1f9
--- /dev/null
+++ b/shell/core/NOTICE
@@ -0,0 +1,71 @@
+Apache Karaf
+Copyright 2010-2014 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/e7d23bef/shell/core/pom.xml
----------------------------------------------------------------------
diff --git a/shell/core/pom.xml b/shell/core/pom.xml
new file mode 100644
index 0000000..c41b0b2
--- /dev/null
+++ b/shell/core/pom.xml
@@ -0,0 +1,179 @@
+<?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.core</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Karaf :: Shell :: Core</name>
+ <description>This bundle provides OSGi shell integration and console support.</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>jline</groupId>
+ <artifactId>jline</artifactId>
+ </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.karaf.jaas</groupId>
+ <artifactId>org.apache.karaf.jaas.modules</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.jaas</groupId>
+ <artifactId>org.apache.karaf.jaas.boot</artifactId>
+ </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>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.apache.karaf.util</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf.service</groupId>
+ <artifactId>org.apache.karaf.service.guard</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>${project.basedir}/../../client/src/main/key</directory>
+ <filtering>false</filtering>
+ </resource>
+ <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.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <mainClass>Main</mainClass>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ org.osgi.service.event;resolution:=optional,
+ org.apache.karaf.branding;resolution:=optional,
+ *
+ </Import-Package>
+ <Export-Package>
+ org.apache.karaf.shell.api.*;version=${project.version},
+ org.apache.karaf.shell.support.*;version=${project.version},
+ </Export-Package>
+ <Private-Package>
+ org.apache.karaf.service.guard.tools,
+ org.apache.karaf.shell.impl.*,
+ org.apache.karaf.util.properties,
+ org.apache.felix.utils.extender,
+ org.apache.felix.utils.manifest,
+ org.apache.felix.gogo.api,
+ org.apache.felix.gogo.runtime,
+ org.apache.felix.gogo.runtime.threadio,
+ org.apache.felix.service.command,
+ org.apache.felix.service.threadio,
+ </Private-Package>
+ <Bundle-Activator>
+ org.apache.karaf.shell.impl.console.osgi.Activator
+ </Bundle-Activator>
+ <Main-Class>
+ org.apache.karaf.shell.impl.console.standalone.Main
+ </Main-Class>
+ </instructions>
+ <unpackBundle>true</unpackBundle>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties
----------------------------------------------------------------------
diff --git a/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties b/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding-ssh.properties
new file mode 100644
index 0000000..978484b
--- /dev/null
+++ b/shell/core/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/e7d23bef/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties
----------------------------------------------------------------------
diff --git a/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties b/shell/core/src/main/filtered-resources/org/apache/karaf/shell/console/branding.properties
new file mode 100644
index 0000000..3fbcb0a
--- /dev/null
+++ b/shell/core/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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/Action.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Action.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Action.java
new file mode 100644
index 0000000..955c837
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Action.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.api.action;
+
+/**
+ * An action is the default implementation of the commands in karaf.
+ * In OSGi, Actions are discovered using an extender and a new instance
+ * of the class is created when the command is invoked, so that the
+ * implementation does not need to be thread safe.
+ *
+ * Before the call to the execute method the action is checked for
+ * fields annotated with @Reference and injected with services coming
+ * from the SessionFactory's Registry or from the OSGi registry.
+ * Methods annotated with @Init are then called. The next step is to
+ * inject command line parameters into fields annotated with @Option
+ * and @Argument and then call the execute method.
+ *
+ * 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.
+ *
+ * In order to make commands available from the non-OSGi shell,
+ * the commands must be listed in a file available at
+ * META-INF/services/org/apache/karaf/shell/commmands.
+ *
+ * @see org.apache.karaf.shell.api.action.Command
+ * @see org.apache.karaf.shell.api.action.lifecycle.Service
+ */
+public interface Action {
+
+ /**
+ * Execute the action which has been injected with services from the
+ * registry, options and arguments from the command line.
+ *
+ * @return <code>null</code> or the result of the action execution
+ * @throws Exception
+ */
+ Object execute() throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
new file mode 100644
index 0000000..8cb1e51
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.action;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 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";
+
+ /**
+ * Name of the argument.
+ * By default, the field name will be used.
+ */
+ String name() default DEFAULT;
+
+ /**
+ * A textual description of the argument.
+ */
+ String description() default "";
+
+ /**
+ * Whether this argument is mandatory or not.
+ */
+ boolean required() default false;
+
+ /**
+ * Position of the argument in the command line.
+ * When using multiple arguments, the indices must be
+ * starting from 0 and incrementing without any holes.
+ */
+ int index() default 0;
+
+ /**
+ * The last argument can be multi-valued in which case
+ * the field type must be a List.
+ */
+ boolean multiValued() default false;
+
+ /**
+ * The generated help displays default values for arguments.
+ * In case the value displayed in the help to the user should
+ * be different that the default value of the field, one
+ * can use this property to specify the value to display.
+ */
+ String valueToShowInHelp() default DEFAULT_STRING;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/Command.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Command.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Command.java
new file mode 100644
index 0000000..7622b33
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Command.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.action;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Used to denote a class represents a command which is executable
+ * within a shell/scope or as a command line process.
+ *
+ * All classes annotated with @Command should implement the
+ * {@link org.apache.karaf.shell.api.action.Action} interface.
+ */
+@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.
+ * This description will be shown in the help for the command.
+ * Longer descriptions can be externalized using a
+ * <code>classpath:[location]</code> url, in which case the
+ * descrition will be loaded from the bundle at the given location,
+ * relatively to the implementation of the command.
+ */
+ String detailedDescription() default "";
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/Completion.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Completion.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Completion.java
new file mode 100644
index 0000000..d9a3dca
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Completion.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.api.action;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The @Completion annotation can be used on a field annotated with
+ * {@link Option} or {@link Argument} to specify the completion
+ * method to use for this field.
+ *
+ * @see org.apache.karaf.shell.api.console.Completer
+ * @see org.apache.karaf.shell.support.completers.StringsCompleter
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Completion {
+
+ /**
+ * The completer class to use for this field.
+ * The console registry will be used to look for
+ * a completer of this class.
+ *
+ * A special case for simple static completions is to use
+ * {@link org.apache.karaf.shell.support.completers.StringsCompleter},
+ * in which case, the <code>values</code> property will be used
+ * as the list of possible completions.
+ */
+ Class<?> value();
+
+ /**
+ * When using a static completer, returns the possible values.
+ */
+ String[] values() default { };
+
+ /**
+ * When using a static completer, indicates if completion
+ * should be done case sensitive or not.
+ */
+ boolean caseSensitive() default false;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
new file mode 100644
index 0000000..97e7557
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.action;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Used to mark an optional named command line option who's name typically starts with "--" or "-".
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Option
+{
+ public static final String DEFAULT_STRING= "DEFAULT";
+
+ /**
+ * The name of this option. Usually starting with a '-'.
+ */
+ String name();
+
+ /**
+ * Specify a list of aliases for this option.
+ * Useful when using an option with short or long names.
+ */
+ String[] aliases() default {};
+
+ /**
+ * A textual description of the option.
+ */
+ String description() default "";
+
+ /**
+ * Whether this argument is mandatory or not.
+ */
+ boolean required() default false;
+
+ /**
+ * The last argument can be multi-valued in which case
+ * the field type must be a List. On the command line,
+ * multi-valued options are used with specifying the option
+ * multiple times with different values.
+ */
+ boolean multiValued() default false;
+
+ /**
+ * The generated help displays default values for arguments.
+ * In case the value displayed in the help to the user should
+ * be different that the default value of the field, one
+ * can use this property to specify the value to display.
+ */
+ String valueToShowInHelp() default DEFAULT_STRING;
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Destroy.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Destroy.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Destroy.java
new file mode 100644
index 0000000..86199c0
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Destroy.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.api.action.lifecycle;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A class annotated with {@link @Service} can have a method
+ * annotation with <code>@Destroy</code> in which case the annotated
+ * method will be called when the object is destroyed.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Destroy {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Init.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Init.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Init.java
new file mode 100644
index 0000000..d0cd3c0
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Init.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.api.action.lifecycle;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A class annotated with {@link @Service} can have a method
+ * annotation with <code>@Init</code> in which case the annotated
+ * method will be called after a successful injection.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface Init {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Manager.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Manager.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Manager.java
new file mode 100644
index 0000000..2b26e81
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Manager.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.karaf.shell.api.action.lifecycle;
+
+/**
+ * The <code>Manager</code> service can be used to programmatically
+ * register {@link org.apache.karaf.shell.api.action.Action}s or
+ * {@link org.apache.karaf.shell.api.console.Completer}s.
+ *
+ * Registered objects must be annotated with the {@link Service} annotation.
+ *
+ * Objects will be registered in the {@link org.apache.karaf.shell.api.console.Registry}
+ * associated with this <code>Manager</code>.
+ *
+ * @see org.apache.karaf.shell.api.console.Registry
+ * @see org.apache.karaf.shell.api.action.lifecycle.Service
+ */
+public interface Manager {
+
+ /**
+ * Register a service.
+ * If the given class is an {@link org.apache.karaf.shell.api.action.Action},
+ * a {@link org.apache.karaf.shell.api.console.Command} will be created and registered,
+ * else, an instance of the class will be created, injected and registered.
+ */
+ void register(Class<?> clazz);
+
+ /**
+ * Unregister a previously registered class.
+ */
+ void unregister(Class<?> clazz);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Reference.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Reference.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Reference.java
new file mode 100644
index 0000000..4d8a73c
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Reference.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.action.lifecycle;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A class annotated with {@link @Service} can have fields
+ * annotated with <code>@Service</code> in which case matching
+ * services will be retrieved from the
+ * {@link org.apache.karaf.shell.api.console.Registry} and
+ * injected.
+ *
+ * If a field has a {@link java.util.List} type, it will be injected
+ * with a list containing all matching services.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface Reference {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Service.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Service.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Service.java
new file mode 100644
index 0000000..d5d62a3
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/lifecycle/Service.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.api.action.lifecycle;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Classes that need to be managed must be annotated
+ * with <code>@Service</code> annotation.
+ *
+ * Services can either implement {@link org.apache.karaf.shell.api.action.Action}
+ * or {@link org.apache.karaf.shell.api.console.Completer}.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Service {
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.java
new file mode 100644
index 0000000..4bb1db0
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Command.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.api.console;
+
+/**
+ * A <code>Command</code> is a named
+ * {@link org.apache.karaf.shell.api.console.Function}
+ * which also provides completion.
+ */
+public interface Command extends Function {
+
+ /**
+ * Retrieve the scope of this command.
+ */
+ String getScope();
+
+ /**
+ * Retrieve the name of this command.
+ */
+ String getName();
+
+ /**
+ * Retrieve the description of this command.
+ * This short command description will be printed
+ * when using the <code>help</code> command.
+ */
+ String getDescription();
+
+ /**
+ * Retrieve the completer associated with this command.
+ *
+ * @param scoped whether the command is invoked from a subshell or not
+ * @return the {@link Completer} to use
+ */
+ Completer getCompleter(boolean scoped);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/CommandLine.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/CommandLine.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/CommandLine.java
new file mode 100644
index 0000000..2ed7697
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/CommandLine.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.console;
+
+/**
+ * A <code>CommandLine</code> object will be created and
+ * given the {@link org.apache.karaf.shell.api.console.Completer}s to ease
+ * their work. Arguments are separated and the cursor position within the
+ * current argument is given.
+ */
+public interface CommandLine {
+
+ /**
+ * Retrieve the argument index for the cursor position
+ */
+ int getCursorArgumentIndex();
+
+ /**
+ * Retrieve the argument for the cursor position
+ */
+ String getCursorArgument();
+
+ /**
+ * Retrieve the position of the cursor within the argument
+ */
+ int getArgumentPosition();
+
+ /**
+ * List of arguments on the current command.
+ * If the command line contains multiple commands, only the command corresponding
+ * to the cursor position is available.
+ */
+ String[] getArguments();
+
+ /**
+ * Retrieve the position of the cursor within the command line.
+ */
+ int getBufferPosition();
+
+ /**
+ * Retrieve the full buffer.
+ */
+ String getBuffer();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Completer.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Completer.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Completer.java
new file mode 100644
index 0000000..4f9f3d1
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Completer.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.api.console;
+
+import java.util.List;
+
+/**
+ * A <code>Completer</code> is used by the console to complete the command line.
+ */
+public interface Completer {
+
+ /**
+ * populate possible completion candidates.
+ *
+ * @param session the current {@link Session}
+ * @param commandLine the pre-parsed {@link CommandLine}
+ * @param candidates a list to fill with possible completion candidates
+ * @return the index of the{@link CommandLine} for which the completion will be relative
+ */
+ int complete(Session session, CommandLine commandLine, List<String> candidates);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Function.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Function.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Function.java
new file mode 100644
index 0000000..209039f
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Function.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.api.console;
+
+import java.util.List;
+
+/**
+ * This interface represents some code that can be executed in the
+ * {@link Session}.
+ */
+public interface Function {
+
+ /**
+ * Execute this function within the given Session and with the given
+ * arguments.
+ *
+ * @param session the current session
+ * @param arguments the arguments of this function
+ * @return the result
+ * @throws Exception if any exception occurs
+ */
+ Object execute(Session session, List<Object> arguments) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/History.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/History.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/History.java
new file mode 100644
index 0000000..10b1b11
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/History.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.api.console;
+
+/**
+ * Session history.
+ */
+public interface History {
+
+ /**
+ * First available index.
+ */
+ int first();
+
+ /**
+ * Last available index.
+ */
+ int last();
+
+ /**
+ * Command at the given index.
+ * Indices can range from <code>first()</code> to <code>last()</code>.
+ */
+ CharSequence get(int index);
+
+ /**
+ * Clear the history.
+ */
+ void clear();
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Registry.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Registry.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Registry.java
new file mode 100644
index 0000000..b768d69
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Registry.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.api.console;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Service registry.
+ *
+ * The registry can be used to register various services used during injection along
+ * with {@link Command}s.
+ *
+ * @see org.apache.karaf.shell.api.console.SessionFactory
+ * @see org.apache.karaf.shell.api.console.Session
+ */
+public interface Registry {
+
+ /**
+ * Return a list of available commands.
+ */
+ List<Command> getCommands();
+
+ /**
+ * Register a delayed service (or factory).
+ * In cases where instances must be created for each injection,
+ * a {@link Callable} can be registered and each injection will
+ * call it to obtain the actual service implementation.
+ *
+ * @param factory
+ * @param clazz
+ * @param <T>
+ */
+ <T> void register(Callable<T> factory, Class<T> clazz);
+
+ /**
+ * Register a service.
+ */
+ void register(Object service);
+
+ /**
+ * Unregister a service.
+ * If the registration has been done using a factory, the same
+ * factory should be used to unregister.
+ */
+ void unregister(Object service);
+
+ /**
+ * Obtain a service implementing the given class.
+ */
+ <T> T getService(Class<T> clazz);
+
+ /**
+ * Obtain a list of services implementing the given class.
+ */
+ <T> List<T> getServices(Class<T> clazz);
+
+ /**
+ * Check whether the registry has a service of the given class.
+ */
+ boolean hasService(Class<?> clazz);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Session.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Session.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Session.java
new file mode 100644
index 0000000..cf7f795
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Session.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.api.console;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+/**
+ * A <code>Session</code> can be used to execute commands.
+ *
+ * The {@link org.apache.karaf.shell.api.console.Registry} associated
+ * with this <code>Session</code> will contain: <ul>
+ * <li>{@link SessionFactory}</li>
+ * <li>{@link Command}s</li>
+ * <li>{@link Session}</li>
+ * <li>{@link Registry}</li>
+ * <li>{@link History}</li>
+ * <li>{@link Terminal}</li>
+ * </ul>
+ */
+public interface Session extends Runnable {
+
+ //
+ // Session properties
+ //
+ // Property names starting with "karaf." are reserved for karaf
+ //
+
+ String SCOPE = "SCOPE";
+ String SUBSHELL = "SUBSHELL";
+
+ String PRINT_STACK_TRACES = "karaf.printStackTraces";
+ String LAST_EXCEPTION = "karaf.lastException";
+ String IGNORE_INTERRUPTS = "karaf.ignoreInterrupts";
+ String COMPLETION_MODE = "karaf.completionMode";
+
+ String COMPLETION_MODE_GLOBAL = "global";
+ String COMPLETION_MODE_SUBSHELL = "subshell";
+ String COMPLETION_MODE_FIRST = "first";
+
+ String SCOPE_GLOBAL = "*";
+
+ /**
+ * Execute a program in this session.
+ *
+ * @param commandline
+ * @return the result of the execution
+ */
+ Object execute(CharSequence commandline) throws Exception;
+
+ /**
+ * Get the value of a variable.
+ *
+ * @param name
+ * @return
+ */
+ Object get(String name);
+
+ /**
+ * Set the value of a variable.
+ *
+ * @param name Name of the variable.
+ * @param value Value of the variable
+ */
+ void put(String name, Object value);
+
+ /**
+ * Return the input stream that is the first of the pipeline. This stream is
+ * sometimes necessary to communicate directly to the end user. For example,
+ * a "less" or "more" command needs direct input from the keyboard to
+ * control the paging.
+ *
+ * @return InputStream used closest to the user or null if input is from a
+ * file.
+ */
+ InputStream getKeyboard();
+
+ /**
+ * Return the PrintStream for the console. This must always be the stream
+ * "closest" to the user. This stream can be used to post messages that
+ * bypass the piping. If the output is piped to a file, then the object
+ * returned must be null.
+ *
+ * @return
+ */
+ PrintStream getConsole();
+
+ /**
+ * Prompt the user for a line.
+ *
+ * @param prompt
+ * @param mask
+ * @return
+ * @throws java.io.IOException
+ */
+ String readLine(String prompt, final Character mask) throws IOException;
+
+ /**
+ * Retrieve the {@link org.apache.karaf.shell.api.console.Terminal} associated
+ * with this <code>Session</code> or <code>null</code> if this <code>Session</code>
+ * is headless.
+ */
+ Terminal getTerminal();
+
+ /**
+ * Retrieve the {@link org.apache.karaf.shell.api.console.History} associated
+ * with this <code>Session</code> or <code>null</code> if this <code>Session</code>
+ * is headless.
+ */
+ History getHistory();
+
+ /**
+ * Retrieve the {@link org.apache.karaf.shell.api.console.Registry} associated
+ * with this <code>Session</code>.
+ */
+ Registry getRegistry();
+
+ /**
+ * Retrieve the {@link org.apache.karaf.shell.api.console.SessionFactory} associated
+ * with this <code>Session</code>.
+ */
+ SessionFactory getFactory();
+
+ /**
+ * Resolve a command name. If the command name has no specified scope, the fully
+ * qualified command name will be returned, depending on the scopes and current
+ * subshell.
+ */
+ String resolveCommand(String name);
+
+ /**
+ * Close this session. After the session is closed, it will throw
+ * IllegalStateException when it is used.
+ */
+ void close();
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/SessionFactory.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/SessionFactory.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/SessionFactory.java
new file mode 100644
index 0000000..7b02fd6
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/SessionFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.api.console;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+/**
+ * The <code>SessionFactory</code> can be used to create
+ * {@link Session} to execute commands.
+ *
+ * The {@link org.apache.karaf.shell.api.console.Registry} associated
+ * with this <code>SessionFactory</code> will contain: <ul>
+ * <li>{@link SessionFactory}</li>
+ * <li>{@link Registry}</li>
+ * <li>{@link Command}s</li>
+ * </ul>
+ */
+public interface SessionFactory {
+
+ /**
+ * Retrieve the {@link Registry} used by this <code>SessionFactory</code>.
+ */
+ Registry getRegistry();
+
+ /**
+ * Create new interactive session.
+ *
+ * @param in the input stream, can be <code>null</code> if the session is only used to execute a command using {@link Session#execute(CharSequence)}
+ * @param out the output stream
+ * @param err the error stream
+ * @param term the {@link Terminal} to use, may be <code>null</code>
+ * @param encoding the encoding to use for the input stream, may be <code>null</code>
+ * @param closeCallback a callback to be called when the session is closed, may be <code>null</code>
+ * @return the new session
+ */
+ Session create(InputStream in, PrintStream out, PrintStream err, Terminal term, String encoding, Runnable closeCallback);
+
+ /**
+ * Create a new headless session.
+ * Headless session can only be used to execute commands, so that
+ * {@link org.apache.karaf.shell.api.console.Session#run()} can not be used.
+ *
+ * @param in the input stream, can be <code>null</code> if the session is only used to execute a command using {@link Session#execute(CharSequence)}
+ * @param out the output stream
+ * @param err the error stream
+ * @return the new session
+ */
+ Session create(InputStream in, PrintStream out, PrintStream err);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/api/console/Terminal.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/console/Terminal.java b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Terminal.java
new file mode 100644
index 0000000..3549ec7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/console/Terminal.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.api.console;
+
+/**
+ * Session terminal.
+ */
+public interface Terminal {
+
+ /**
+ * Width of the terminal.
+ */
+ int getWidth();
+
+ /**
+ * Height of the terminal.
+ */
+ int getHeight();
+
+ /**
+ * Whether ansi sequences are supported or not.
+ */
+ boolean isAnsiSupported();
+
+ /**
+ * Whether echo is enabled or not.
+ */
+ boolean isEchoEnabled();
+
+ /**
+ * Enable or disable echo.
+ */
+ void setEchoEnabled(boolean enabled);
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
new file mode 100644
index 0000000..4cd58ca
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionCommand.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.command;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+public class ActionCommand implements org.apache.karaf.shell.api.console.Command {
+
+ private final ManagerImpl manager;
+ private final Class<? extends Action> actionClass;
+
+ public ActionCommand(ManagerImpl manager, Class<? extends Action> actionClass) {
+ this.manager = manager;
+ this.actionClass = actionClass;
+ }
+
+ public Class<? extends Action> getActionClass() {
+ return actionClass;
+ }
+
+ @Override
+ public String getScope() {
+ return actionClass.getAnnotation(Command.class).scope();
+ }
+
+ @Override
+ public String getName() {
+ return actionClass.getAnnotation(Command.class).name();
+ }
+
+ @Override
+ public String getDescription() {
+ return actionClass.getAnnotation(Command.class).description();
+ }
+
+ @Override
+ public Completer getCompleter(boolean scoped) {
+ return new ArgumentCompleter(this, scoped);
+ }
+
+ protected Completer getCompleter(Class<?> clazz) {
+ return new DelayedCompleter(clazz);
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ Action action = createNewAction(session);
+ try {
+ if (new DefaultActionPreparator().prepare(action, session, arguments)) {
+ return action.execute();
+ }
+ } finally {
+ releaseAction(action);
+ }
+ return null;
+ }
+
+ protected Action createNewAction(Session session) {
+ try {
+ return manager.instantiate(actionClass, session.getRegistry());
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to creation command action " + actionClass.getName(), e);
+ }
+ }
+
+ protected void releaseAction(Action action) throws Exception {
+ manager.release(action);
+ }
+
+ public static class DelayedCompleter implements Completer {
+ private final Class<?> clazz;
+
+ public DelayedCompleter(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public int complete(Session session, CommandLine commandLine, List<String> candidates) {
+ Object service = session.getRegistry().getService(clazz);
+ if (service instanceof Completer) {
+ return ((Completer) service).complete(session, commandLine, candidates);
+ }
+ return -1;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ArgumentCompleter.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ArgumentCompleter.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ArgumentCompleter.java
new file mode 100644
index 0000000..2868e6f
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ArgumentCompleter.java
@@ -0,0 +1,385 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.action.command;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+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.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.FileCompleter;
+import org.apache.karaf.shell.support.completers.NullCompleter;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ArgumentCompleter implements Completer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ArgumentCompleter.class);
+
+ final ActionCommand command;
+ final Completer commandCompleter;
+ final Completer optionsCompleter;
+ final List<Completer> argsCompleters;
+ final Map<String, Completer> optionalCompleters;
+ 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(ActionCommand command, boolean scoped) {
+ this.command = command;
+ Class<?> actionClass = command.getActionClass();
+ // Command name completer
+ Command cmd = actionClass.getAnnotation(Command.class);
+ String[] names = scoped || Session.SCOPE_GLOBAL.equals(cmd.scope()) ? new String[] { cmd.name() } : new String[] { cmd.name(), cmd.scope() + ":" + cmd.name() };
+ commandCompleter = new StringsCompleter(names);
+ // Build options completer
+ for (Class<?> type = actionClass; 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);
+
+ argsCompleters = new ArrayList<Completer>();
+ optionsCompleter = new StringsCompleter(options.keySet());
+
+ 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());
+ Completion ann = field.getAnnotation(Completion.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 {
+ completer = command.getCompleter(clazz);
+ }
+ }
+ } 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) {
+ Completion ann = field.getAnnotation(Completion.class);
+ if (ann != null) {
+ Class clazz = ann.value();
+ String[] value = ann.values();
+ if (clazz != null) {
+ if (clazz == StringsCompleter.class) {
+ completer = new StringsCompleter(value, ann.caseSensitive());
+ } else {
+ completer = command.getCompleter(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);
+ }
+ }
+ }
+ }
+
+ private Completer getDefaultCompleter(Field field) {
+ Completer completer = null;
+ Class<?> type = field.getType();
+ if (type.isAssignableFrom(File.class)) {
+ completer = new FileCompleter();
+ } 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(Session session, final CommandLine list, final List<String> candidates) {
+ int argpos = list.getArgumentPosition();
+ int argIndex = list.getCursorArgumentIndex();
+
+ 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(command.getScope()) && !session.resolveCommand(args[index]).equals(command.getScope() + ":" + command.getName())) {
+ return -1;
+ }
+ // Verify command name
+ if (!verifyCompleter(session, commandCompleter, args[index])) {
+ return -1;
+ }
+ index++;
+ } else {
+ comp = commandCompleter;
+ }
+ // Now, check options
+ if (comp == null) {
+ while (index < argIndex && args[index].startsWith("-")) {
+ if (!verifyCompleter(session, 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 (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(session, sub, args[index])) {
+ return -1;
+ }
+ index++;
+ indexArg++;
+ }
+ comp = argsCompleters.get(indexArg >= argsCompleters.size() ? argsCompleters.size() - 1 : indexArg);
+ }
+
+ int ret = comp.complete(session, new ArgumentCommandLine(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(Session session, Completer completer, String argument) {
+ List<String> candidates = new ArrayList<String>();
+ return completer.complete(session, new ArgumentCommandLine(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));
+ }
+
+ static class ArgumentCommandLine implements CommandLine {
+ private final String argument;
+ private final int position;
+
+ ArgumentCommandLine(String argument, int position) {
+ this.argument = argument;
+ this.position = position;
+ }
+
+ @Override
+ public int getCursorArgumentIndex() {
+ return 0;
+ }
+
+ @Override
+ public String getCursorArgument() {
+ return argument;
+ }
+
+ @Override
+ public int getArgumentPosition() {
+ return position;
+ }
+
+ @Override
+ public String[] getArguments() {
+ return new String[] { argument };
+ }
+
+ @Override
+ public int getBufferPosition() {
+ return position;
+ }
+
+ @Override
+ public String getBuffer() {
+ return argument;
+ }
+ }
+}
[02/10] [KARAF-2805] Clean console and commands model
Posted by gn...@apache.org.
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Converters.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Converters.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Converters.java
new file mode 100644
index 0000000..87544e7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/Converters.java
@@ -0,0 +1,279 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.Formatter;
+
+import org.apache.felix.service.command.Converter;
+import org.apache.felix.service.command.Function;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.startlevel.BundleStartLevel;
+
+public class Converters implements Converter
+{
+ private final BundleContext context;
+
+ public Converters(BundleContext context)
+ {
+ this.context = context;
+ }
+
+ private CharSequence print(Bundle bundle)
+ {
+ // [ ID ] [STATE ] [ SL ] symname
+ int level = bundle.adapt(BundleStartLevel.class).getStartLevel();
+
+ return String.format("%5d|%-11s|%5d|%s (%s)", bundle.getBundleId(),
+ getState(bundle), level, bundle.getSymbolicName(), bundle.getVersion());
+ }
+
+ private CharSequence print(ServiceReference ref)
+ {
+ StringBuilder sb = new StringBuilder();
+ Formatter f = new Formatter(sb);
+
+ String spid = "";
+ Object pid = ref.getProperty("service.pid");
+ if (pid != null)
+ {
+ spid = pid.toString();
+ }
+
+ f.format("%06d %3s %-40s %s", ref.getProperty("service.id"),
+ ref.getBundle().getBundleId(),
+ getShortNames((String[]) ref.getProperty("objectclass")), spid);
+ return sb;
+ }
+
+ private CharSequence getShortNames(String[] list)
+ {
+ StringBuilder sb = new StringBuilder();
+ String del = "";
+ for (String s : list)
+ {
+ sb.append(del + getShortName(s));
+ del = " | ";
+ }
+ return sb;
+ }
+
+ private CharSequence getShortName(String name)
+ {
+ int n = name.lastIndexOf('.');
+ if (n < 0)
+ {
+ n = 0;
+ }
+ else
+ {
+ n++;
+ }
+ return name.subSequence(n, name.length());
+ }
+
+ private String getState(Bundle bundle)
+ {
+ switch (bundle.getState())
+ {
+ case Bundle.ACTIVE:
+ return "Active";
+
+ case Bundle.INSTALLED:
+ return "Installed";
+
+ case Bundle.RESOLVED:
+ return "Resolved";
+
+ case Bundle.STARTING:
+ return "Starting";
+
+ case Bundle.STOPPING:
+ return "Stopping";
+
+ case Bundle.UNINSTALLED:
+ return "Uninstalled ";
+ }
+ return null;
+ }
+
+ public Bundle bundle(Bundle i)
+ {
+ return i;
+ }
+
+ public Object convert(Class<?> desiredType, final Object in) throws Exception
+ {
+ if (desiredType == Bundle.class)
+ {
+ return convertBundle(in);
+ }
+
+ if (desiredType == ServiceReference.class)
+ {
+ return convertServiceReference(in);
+ }
+
+ if (desiredType == Class.class)
+ {
+ try
+ {
+ return Class.forName(in.toString());
+ }
+ catch (ClassNotFoundException e)
+ {
+ return null;
+ }
+ }
+
+ if (desiredType.isAssignableFrom(String.class) && in instanceof InputStream)
+ {
+ return read(((InputStream) in));
+ }
+
+ if (in instanceof Function && desiredType.isInterface()
+ && desiredType.getDeclaredMethods().length == 1)
+ {
+ return Proxy.newProxyInstance(desiredType.getClassLoader(),
+ new Class[] { desiredType }, new InvocationHandler()
+ {
+ Function command = ((Function) in);
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable
+ {
+ return command.execute(null, Arrays.asList(args));
+ }
+ });
+ }
+
+ return null;
+ }
+
+ private Object convertServiceReference(Object in) throws InvalidSyntaxException
+ {
+ String s = in.toString();
+ if (s.startsWith("(") && s.endsWith(")"))
+ {
+ ServiceReference refs[] = context.getServiceReferences((String) null, String.format(
+ "(|(service.id=%s)(service.pid=%s))", in, in));
+ if (refs != null && refs.length > 0)
+ {
+ return refs[0];
+ }
+ }
+
+ ServiceReference refs[] = context.getServiceReferences((String) null, String.format(
+ "(|(service.id=%s)(service.pid=%s))", in, in));
+ if (refs != null && refs.length > 0)
+ {
+ return refs[0];
+ }
+ return null;
+ }
+
+ private Object convertBundle(Object in)
+ {
+ String s = in.toString();
+ try
+ {
+ long id = Long.parseLong(s);
+ return context.getBundle(id);
+ }
+ catch (NumberFormatException nfe)
+ {
+ // Ignore
+ }
+
+ Bundle bundles[] = context.getBundles();
+ for (Bundle b : bundles)
+ {
+ if (b.getLocation().equals(s))
+ {
+ return b;
+ }
+
+ if (b.getSymbolicName().equals(s))
+ {
+ return b;
+ }
+ }
+
+ return null;
+ }
+
+ public CharSequence format(Object target, int level, Converter converter)
+ throws IOException
+ {
+ if (level == INSPECT && target instanceof InputStream)
+ {
+ return read(((InputStream) target));
+ }
+ if (level == LINE && target instanceof Bundle)
+ {
+ return print((Bundle) target);
+ }
+ if (level == LINE && target instanceof ServiceReference)
+ {
+ return print((ServiceReference) target);
+ }
+ if (level == PART && target instanceof Bundle)
+ {
+ return ((Bundle) target).getSymbolicName();
+ }
+ if (level == PART && target instanceof ServiceReference)
+ {
+ return getShortNames((String[]) ((ServiceReference) target).getProperty("objectclass"));
+ }
+ return null;
+ }
+
+ private CharSequence read(InputStream in) throws IOException
+ {
+ int c;
+ StringBuffer sb = new StringBuffer();
+ while ((c = in.read()) > 0)
+ {
+ if (c >= 32 && c <= 0x7F || c == '\n' || c == '\r')
+ {
+ sb.append((char) c);
+ }
+ else
+ {
+ String s = Integer.toHexString(c).toUpperCase();
+ sb.append("\\");
+ if (s.length() < 1)
+ {
+ sb.append(0);
+ }
+ sb.append(s);
+ }
+ }
+ return sb;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/DelayedStarted.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/DelayedStarted.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/DelayedStarted.java
new file mode 100644
index 0000000..0277e4e
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/DelayedStarted.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi;
+
+import java.io.InputStream;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.startlevel.FrameworkStartLevel;
+
+/**
+ * Delay the start of the console until the desired start level is reached or enter is pressed
+ */
+class DelayedStarted extends Thread implements FrameworkListener {
+ private static final String SYSTEM_PROP_KARAF_CONSOLE_STARTED = "karaf.console.started";
+
+ private final AtomicBoolean started = new AtomicBoolean(false);
+ private final InputStream in;
+ private final Runnable console;
+ private final BundleContext bundleContext;
+
+ DelayedStarted(Runnable console, String name, BundleContext bundleContext, InputStream in) {
+ super(name);
+ this.console = console;
+ this.bundleContext = bundleContext;
+ this.in = in;
+ int defaultStartLevel = Integer.parseInt(System.getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+ int startLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class).getStartLevel();
+ if (startLevel >= defaultStartLevel) {
+ started.set(true);
+ } else {
+ bundleContext.addFrameworkListener(this);
+ frameworkEvent(new FrameworkEvent(FrameworkEvent.STARTLEVEL_CHANGED, bundleContext.getBundle(), null));
+ }
+ }
+
+ public void run() {
+ try {
+ while (!started.get()) {
+ if (in.available() == 0) {
+ Thread.sleep(10);
+ }
+ while (in.available() > 0) {
+ char ch = (char) in.read();
+ if (ch == '\r' || ch == '\n') {
+ started.set(true);
+ break;
+ }
+ }
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+
+ // Signal to the main module that it can stop displaying the startup progress
+ System.setProperty(SYSTEM_PROP_KARAF_CONSOLE_STARTED, "true");
+ this.bundleContext.removeFrameworkListener(this);
+ console.run();
+ }
+
+ public void frameworkEvent(FrameworkEvent event) {
+ if (event.getType() == FrameworkEvent.STARTLEVEL_CHANGED) {
+ int defaultStartLevel = Integer.parseInt(System.getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+ int startLevel = this.bundleContext.getBundle(0).adapt(FrameworkStartLevel.class).getStartLevel();
+ if (startLevel >= defaultStartLevel) {
+ started.set(true);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/LocalConsoleManager.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/LocalConsoleManager.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/LocalConsoleManager.java
new file mode 100644
index 0000000..0814d1e
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/LocalConsoleManager.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi;
+
+import java.nio.charset.Charset;
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.jaas.boot.principal.UserPrincipal;
+import org.apache.karaf.jaas.modules.JaasHelper;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.impl.console.JLineTerminal;
+import org.apache.karaf.shell.impl.console.TerminalFactory;
+import org.apache.karaf.shell.support.ShellUtil;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class LocalConsoleManager {
+
+ private SessionFactory sessionFactory;
+ private BundleContext bundleContext;
+ private TerminalFactory terminalFactory;
+ private Session session;
+ private ServiceRegistration<?> registration;
+ private boolean closing;
+
+ public LocalConsoleManager(BundleContext bundleContext,
+ TerminalFactory terminalFactory,
+ SessionFactory sessionFactory) throws Exception {
+ this.bundleContext = bundleContext;
+ this.terminalFactory = terminalFactory;
+ this.sessionFactory = sessionFactory;
+ }
+
+ public void start() throws Exception {
+ final jline.Terminal terminal = terminalFactory.getTerminal();
+ final Runnable callback = new Runnable() {
+ public void run() {
+ try {
+ if (!closing) {
+ bundleContext.getBundle(0).stop();
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ };
+
+
+ final Subject subject = createLocalKarafSubject();
+ this.session = JaasHelper.<Session>doAs(subject, new PrivilegedAction<Session>() {
+ public Session run() {
+ String encoding = getEncoding();
+ session = sessionFactory.create(
+ StreamWrapUtil.reWrapIn(terminal, System.in),
+ StreamWrapUtil.reWrap(System.out),
+ StreamWrapUtil.reWrap(System.err),
+ new JLineTerminal(terminal),
+ encoding,
+ callback);
+ String name = "Karaf local console user " + ShellUtil.getCurrentUserName();
+ boolean delayconsole = Boolean.parseBoolean(System.getProperty("karaf.delay.console"));
+ if (delayconsole) {
+ DelayedStarted watcher = new DelayedStarted(session, name, bundleContext, System.in);
+ new Thread(watcher).start();
+ } else {
+ new Thread(session, name).start();
+ }
+ return session;
+ }
+ });
+ // TODO: register the local session so that ssh can add the agent
+// registration = bundleContext.register(CommandSession.class, console.getSession(), null);
+
+ }
+
+ private String getEncoding() {
+ String ctype = System.getenv("LC_CTYPE");
+ String encoding = ctype;
+ if (encoding != null && encoding.indexOf('.') > 0) {
+ encoding = encoding.substring(encoding.indexOf('.') + 1);
+ } else {
+ encoding = System.getProperty("input.encoding", Charset.defaultCharset().name());
+ }
+ return encoding;
+ }
+
+ private Subject createLocalKarafSubject() {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new UserPrincipal("karaf"));
+
+ String roles = System.getProperty("karaf.local.roles");
+ if (roles != null) {
+ for (String role : roles.split("[,]")) {
+ subject.getPrincipals().add(new RolePrincipal(role.trim()));
+ }
+ }
+ return subject;
+ }
+
+ public void stop() throws Exception {
+ closing = true;
+ if (registration != null) {
+ registration.unregister();
+ }
+ // The bundle is stopped
+ // so close the console and remove the callback so that the
+ // osgi framework isn't stopped
+ if (session != null) {
+ session.close();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/StreamWrapUtil.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/StreamWrapUtil.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/StreamWrapUtil.java
new file mode 100644
index 0000000..2b3afcd
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/StreamWrapUtil.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.impl.console.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+
+import jline.Terminal;
+import org.fusesource.jansi.AnsiConsole;
+
+final class StreamWrapUtil {
+ private StreamWrapUtil() {
+ }
+
+ private static Object invokePrivateMethod(Object o, String methodName, Object[] params) throws Exception {
+ final Method methods[] = o.getClass().getDeclaredMethods();
+ for (int i = 0; i < methods.length; ++i) {
+ if (methodName.equals(methods[i].getName())) {
+ methods[i].setAccessible(true);
+ return methods[i].invoke(o, params);
+ }
+ }
+ return o;
+ }
+
+ /**
+ * unwrap stream so it can be recognized by the terminal and wrapped to get
+ * special keys in windows
+ *
+ * @param stream
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private static <T> T unwrapBIS(T stream) {
+ try {
+ return (T) invokePrivateMethod(stream, "getInIfOpen", null);
+ } catch (Throwable t) {
+ return stream;
+ }
+ }
+
+ private static PrintStream wrap(PrintStream stream) {
+ OutputStream o = AnsiConsole.wrapOutputStream(stream);
+ if (o instanceof PrintStream) {
+ return ((PrintStream) o);
+ } else {
+ return new PrintStream(o);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T unwrap(T stream) {
+ try {
+ Method mth = stream.getClass().getMethod("getRoot");
+ return (T) mth.invoke(stream);
+ } catch (Throwable t) {
+ return stream;
+ }
+ }
+
+ static InputStream reWrapIn(Terminal terminal, InputStream stream) {
+ try {
+ return terminal.wrapInIfNeeded(unwrapBIS(unwrap(stream)));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static PrintStream reWrap(PrintStream stream) {
+ return wrap(unwrap(stream));
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
new file mode 100644
index 0000000..0fc6cde
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi.secured;
+
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.Closure;
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Function;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+
+public class SecuredCommand implements Command, Function {
+
+ private final SecuredSessionFactoryImpl factory;
+ private final Command command;
+
+ public SecuredCommand(SecuredSessionFactoryImpl factory, Command command) {
+ this.command = command;
+ this.factory = factory;
+ }
+
+ public String getScope() {
+ return command.getScope();
+ }
+
+ public String getName() {
+ return command.getName();
+ }
+
+ @Override
+ public String getDescription() {
+ return command.getDescription();
+ }
+
+ @Override
+ public Completer getCompleter(boolean scoped) {
+ return command.getCompleter(scoped);
+ }
+
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ factory.checkSecurity(this, session, arguments);
+ return command.execute(session, arguments);
+ }
+
+ @Override
+ public Object execute(final CommandSession commandSession, List<Object> arguments) throws Exception {
+ // TODO: remove the hack for .session
+ Session session = (Session) commandSession.get(".session");
+ // When need to translate closures to a compatible type for the command
+ for (int i = 0; i < arguments.size(); i++) {
+ Object v = arguments.get(i);
+ if (v instanceof Closure) {
+ final Closure closure = (Closure) v;
+ arguments.set(i, new org.apache.karaf.shell.api.console.Function() {
+ @Override
+ public Object execute(Session session, List<Object> arguments) throws Exception {
+ return closure.execute(commandSession, arguments);
+ }
+ });
+ }
+ }
+ return execute(session, arguments);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
new file mode 100644
index 0000000..38b542e
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.osgi.secured;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.felix.gogo.runtime.CommandNotFoundException;
+import org.apache.felix.service.command.Function;
+import org.apache.felix.service.threadio.ThreadIO;
+import org.apache.karaf.jaas.boot.principal.RolePrincipal;
+import org.apache.karaf.service.guard.tools.ACLConfigurationParser;
+import org.apache.karaf.shell.api.console.Command;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SecuredSessionFactoryImpl extends SessionFactoryImpl implements ConfigurationListener, SingleServiceTracker.SingleServiceListener {
+
+ private static final String PROXY_COMMAND_ACL_PID_PREFIX = "org.apache.karaf.command.acl.";
+ private static final String CONFIGURATION_FILTER =
+ "(" + Constants.SERVICE_PID + "=" + PROXY_COMMAND_ACL_PID_PREFIX + "*)";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SecuredSessionFactoryImpl.class);
+
+ private BundleContext bundleContext;
+ private Map<String, Dictionary<String, Object>> scopes = new HashMap<String, Dictionary<String, Object>>();
+ private SingleServiceTracker<ConfigurationAdmin> configAdminTracker;
+ private ServiceRegistration registration;
+
+ public SecuredSessionFactoryImpl(BundleContext bundleContext, ThreadIO threadIO) {
+ super(threadIO);
+ this.bundleContext = bundleContext;
+ this.registration = bundleContext.registerService(ConfigurationListener.class, this, null);
+ this.configAdminTracker = new SingleServiceTracker<ConfigurationAdmin>(bundleContext, ConfigurationAdmin.class, this);
+ this.configAdminTracker.open();
+ }
+
+ public void stop() {
+ this.registration.unregister();
+ this.configAdminTracker.close();
+ super.stop();
+ }
+
+ @Override
+ protected Function wrap(Command command) {
+ return new SecuredCommand(this, command);
+ }
+
+ @Override
+ protected boolean isVisible(Object service) {
+ if (service instanceof Command) {
+ return isVisible((Command) service);
+ } else {
+ return super.isVisible(service);
+ }
+ }
+
+ protected boolean isVisible(Command command) {
+ Dictionary<String, Object> config = getScopeConfig(command.getScope());
+ if (config != null) {
+ List<String> roles = new ArrayList<String>();
+ ACLConfigurationParser.getRolesForInvocation(command.getName(), null, null, config, roles);
+ if (roles.isEmpty()) {
+ return true;
+ } else {
+ for (String role : roles) {
+ if (currentUserHasRole(role)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void checkSecurity(SecuredCommand command, Session session, List<Object> arguments) {
+ Dictionary<String, Object> config = getScopeConfig(command.getScope());
+ if (config != null) {
+ if (!isVisible(command)) {
+ throw new CommandNotFoundException(command.getScope() + ":" + command.getName());
+ }
+ List<String> roles = new ArrayList<String>();
+ ACLConfigurationParser.Specificity s = ACLConfigurationParser.getRolesForInvocation(command.getName(), new Object[] { arguments.toString() }, null, config, roles);
+ if (s == ACLConfigurationParser.Specificity.NO_MATCH) {
+ return;
+ }
+ for (String role : roles) {
+ if (currentUserHasRole(role)) {
+ return;
+ }
+ }
+ throw new SecurityException("Insufficient credentials.");
+ }
+ }
+
+ static boolean currentUserHasRole(String requestedRole) {
+ String clazz;
+ String role;
+ int index = requestedRole.indexOf(':');
+ if (index > 0) {
+ clazz = requestedRole.substring(0, index);
+ role = requestedRole.substring(index + 1);
+ } else {
+ clazz = RolePrincipal.class.getName();
+ role = requestedRole;
+ }
+
+ AccessControlContext acc = AccessController.getContext();
+ if (acc == null) {
+ return false;
+ }
+ Subject subject = Subject.getSubject(acc);
+
+ if (subject == null) {
+ return false;
+ }
+
+ for (Principal p : subject.getPrincipals()) {
+ if (clazz.equals(p.getClass().getName()) && role.equals(p.getName())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void configurationEvent(ConfigurationEvent event) {
+ if (!event.getPid().startsWith(PROXY_COMMAND_ACL_PID_PREFIX))
+ return;
+
+ try {
+ switch (event.getType()) {
+ case ConfigurationEvent.CM_DELETED:
+ removeScopeConfig(event.getPid().substring(PROXY_COMMAND_ACL_PID_PREFIX.length()));
+ break;
+ case ConfigurationEvent.CM_UPDATED:
+ ConfigurationAdmin configAdmin = bundleContext.getService(event.getReference());
+ try {
+ addScopeConfig(configAdmin.getConfiguration(event.getPid()));
+ } finally {
+ bundleContext.ungetService(event.getReference());
+ }
+ break;
+ }
+ } catch (Exception e) {
+ LOGGER.error("Problem processing Configuration Event {}", event, e);
+ }
+ }
+
+ private void addScopeConfig(Configuration config) {
+ if (!config.getPid().startsWith(PROXY_COMMAND_ACL_PID_PREFIX)) {
+ // not a command scope configuration file
+ return;
+ }
+ String scope = config.getPid().substring(PROXY_COMMAND_ACL_PID_PREFIX.length());
+ if (scope.indexOf('.') >= 0) {
+ // scopes don't contains dots, not a command scope
+ return;
+ }
+ scope = scope.trim();
+ synchronized (scopes) {
+ scopes.put(scope, config.getProperties());
+ }
+ }
+
+ private void removeScopeConfig(String scope) {
+ synchronized (scopes) {
+ scopes.remove(scope);
+ }
+ }
+
+ private Dictionary<String, Object> getScopeConfig(String scope) {
+ synchronized (scopes) {
+ return scopes.get(scope);
+ }
+ }
+
+ @Override
+ public void serviceFound() {
+ try {
+ ConfigurationAdmin configAdmin = this.configAdminTracker.getService();
+ Configuration[] configs = configAdmin.listConfigurations(CONFIGURATION_FILTER);
+ if (configs != null) {
+ for (Configuration config : configs) {
+ addScopeConfig(config);
+ }
+ }
+ } catch (Exception e) {
+ // Ignore, should never happen
+ }
+ }
+
+ @Override
+ public void serviceLost() {
+ }
+
+ @Override
+ public void serviceReplaced() {
+ serviceFound();
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
new file mode 100644
index 0000000..fb57ee1
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.karaf.shell.impl.console.osgi.secured;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+//This is from aries util
+public final class SingleServiceTracker<T> {
+ public static interface SingleServiceListener {
+ public void serviceFound();
+
+ public void serviceLost();
+
+ public void serviceReplaced();
+ }
+
+ private final BundleContext ctx;
+ private final String className;
+ private final AtomicReference<T> service = new AtomicReference<T>();
+ private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
+ private final AtomicBoolean open = new AtomicBoolean(false);
+ private final SingleServiceListener serviceListener;
+ private String filterString;
+ private Filter filter;
+
+ private final ServiceListener listener = new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ if (open.get()) {
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ ServiceReference deadRef = event.getServiceReference();
+ if (deadRef.equals(ref.get())) {
+ findMatchingReference(deadRef);
+ }
+ } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
+ findMatchingReference(null);
+ }
+ }
+ }
+ };
+
+ public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
+ ctx = context;
+ this.className = clazz.getName();
+ serviceListener = sl;
+ }
+
+ public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
+ this(context, clazz, sl);
+ this.filterString = filterString;
+ if (filterString != null) filter = context.createFilter(filterString);
+ }
+
+ public T getService() {
+ return service.get();
+ }
+
+ public ServiceReference getServiceReference() {
+ return ref.get();
+ }
+
+ public void open() {
+ if (open.compareAndSet(false, true)) {
+ try {
+ String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
+ if (filter != null) filterString = "(&" + filterString + filter + ')';
+ ctx.addServiceListener(listener, filterString);
+ findMatchingReference(null);
+ } catch (InvalidSyntaxException e) {
+ // this can never happen. (famous last words :)
+ }
+ }
+ }
+
+ private void findMatchingReference(ServiceReference original) {
+ boolean clear = true;
+ ServiceReference ref = ctx.getServiceReference(className);
+ if (ref != null && (filter == null || filter.match(ref))) {
+ @SuppressWarnings("unchecked")
+ T service = (T) ctx.getService(ref);
+ if (service != null) {
+ clear = false;
+
+ // We do the unget out of the lock so we don't exit this class while holding a lock.
+ if (!!!update(original, ref, service)) {
+ ctx.ungetService(ref);
+ }
+ }
+ } else if (original == null) {
+ clear = false;
+ }
+
+ if (clear) {
+ update(original, null, null);
+ }
+ }
+
+ private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
+ boolean result = false;
+ int foundLostReplaced = -1;
+
+ // Make sure we don't try to get a lock on null
+ Object lock;
+
+ // we have to choose our lock.
+ if (newRef != null) lock = newRef;
+ else if (deadRef != null) lock = deadRef;
+ else lock = this;
+
+ // This lock is here to ensure that no two threads can set the ref and service
+ // at the same time.
+ synchronized (lock) {
+ if (open.get()) {
+ result = this.ref.compareAndSet(deadRef, newRef);
+ if (result) {
+ this.service.set(service);
+
+ if (deadRef == null && newRef != null) foundLostReplaced = 0;
+ if (deadRef != null && newRef == null) foundLostReplaced = 1;
+ if (deadRef != null && newRef != null) foundLostReplaced = 2;
+ }
+ }
+ }
+
+ if (serviceListener != null) {
+ if (foundLostReplaced == 0) serviceListener.serviceFound();
+ else if (foundLostReplaced == 1) serviceListener.serviceLost();
+ else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
+ }
+
+ return result;
+ }
+
+ public void close() {
+ if (open.compareAndSet(true, false)) {
+ ctx.removeServiceListener(listener);
+
+ synchronized (this) {
+ ServiceReference deadRef = ref.getAndSet(null);
+ service.set(null);
+ if (deadRef != null) ctx.ungetService(deadRef);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.java
new file mode 100644
index 0000000..6a603d0
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/CommandLineImpl.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.impl.console.parsing;
+
+import java.util.List;
+
+import org.apache.karaf.shell.api.console.CommandLine;
+
+/**
+ * The result of a delimited buffer.
+ */
+public class CommandLineImpl implements CommandLine {
+
+ private final String[] arguments;
+ private final int cursorArgumentIndex;
+ private final int argumentPosition;
+ private final int bufferPosition;
+ private final String buffer;
+
+ public static CommandLine build(String buffer, int cursor) {
+ 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 CommandLineImpl(pipe.toArray(new String[pipe.size()]), parser.c2, parser.c3, cursor, buffer);
+ } catch (Throwable t) {
+ return new CommandLineImpl(new String[] { buffer }, 0, cursor, cursor, buffer);
+ }
+ }
+
+ /**
+ * @param arguments the array of tokens
+ * @param cursorArgumentIndex the token index of the cursor
+ * @param argumentPosition the position of the cursor in the
+ * current token
+ * @param bufferPosition the position of the cursor in the whole buffer
+ * @param buffer the whole buffer
+ */
+ public CommandLineImpl(String[] arguments, int cursorArgumentIndex, int argumentPosition, int bufferPosition, String buffer) {
+ this.arguments = arguments;
+ this.cursorArgumentIndex = cursorArgumentIndex;
+ this.argumentPosition = argumentPosition;
+ this.bufferPosition = bufferPosition;
+ this.buffer = buffer;
+ }
+
+ public int getCursorArgumentIndex() {
+ return this.cursorArgumentIndex;
+ }
+
+ public String getCursorArgument() {
+ if ((cursorArgumentIndex < 0)
+ || (cursorArgumentIndex >= arguments.length)) {
+ return null;
+ }
+
+ return arguments[cursorArgumentIndex];
+ }
+
+ public int getArgumentPosition() {
+ return this.argumentPosition;
+ }
+
+ public String[] getArguments() {
+ return this.arguments;
+ }
+
+ public int getBufferPosition() {
+ return this.bufferPosition;
+ }
+
+ public String getBuffer() {
+ return this.buffer;
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/Parser.java
new file mode 100644
index 0000000..16f6a21
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/parsing/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.impl.console.parsing;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Parser {
+
+ int current = 0;
+ String text;
+ boolean escaped;
+ static final String SPECIAL = "<;|{[\"'$`(=";
+
+ List<List<List<String>>> program;
+ List<List<String>> statements;
+ List<String> statement;
+ int cursor;
+ int start = -1;
+ int c0;
+ int c1;
+ int c2;
+ int c3;
+
+ 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
new file mode 100644
index 0000000..842a248
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/standalone/Main.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.impl.console.standalone;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.felix.service.threadio.ThreadIO;
+import org.apache.karaf.shell.api.action.lifecycle.Manager;
+import org.apache.karaf.shell.api.console.Registry;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.action.command.ManagerImpl;
+import org.apache.karaf.shell.support.NameScoping;
+import org.apache.karaf.shell.impl.console.JLineTerminal;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.impl.console.TerminalFactory;
+import org.apache.karaf.shell.support.ShellUtil;
+import org.fusesource.jansi.AnsiConsole;
+
+public class Main {
+
+ private String application = System.getProperty("karaf.name", "root");
+ private String user = "karaf";
+
+ public static void main(String args[]) throws Exception {
+ Main main = new Main();
+ main.run(args);
+ }
+
+ /**
+ * Use this method when the shell is being executed as a top level shell.
+ *
+ * @param args
+ * @throws Exception
+ */
+ public void run(String args[]) throws Exception {
+
+ ThreadIOImpl threadio = new ThreadIOImpl();
+ threadio.start();
+
+ InputStream in = unwrap(System.in);
+ PrintStream out = wrap(unwrap(System.out));
+ PrintStream err = wrap(unwrap(System.err));
+ run(threadio, args, in, out, err);
+
+ // TODO: do we need to stop the threadio that was started?
+ // threadio.stop();
+ }
+
+ private void run(ThreadIO threadio, String[] args, InputStream in, PrintStream out, PrintStream err) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ String classpath = null;
+ boolean batch = false;
+ String file = null;
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.startsWith("--classpath=")) {
+ classpath = arg.substring("--classpath=".length());
+ } else if (arg.startsWith("-c=")) {
+ classpath = arg.substring("-c=".length());
+ } else if (arg.equals("--classpath") || arg.equals("-c")) {
+ classpath = args[++i];
+ } else if (arg.equals("-b") || arg.equals("--batch")) {
+ batch = true;
+ } else if (arg.startsWith("--file=")) {
+ file = arg.substring("--file=".length());
+ } else if (arg.startsWith("-f=")) {
+ file = arg.substring("-f=".length());
+ } else if (arg.equals("--file") || arg.equals("-f")) {
+ file = args[++i];
+ } else {
+ sb.append(arg);
+ sb.append(' ');
+ }
+ }
+
+ if (file != null) {
+ Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+ try {
+ sb.setLength(0);
+ for (int c = reader.read(); c >= 0; c = reader.read()) {
+ sb.append((char) c);
+ }
+ } finally {
+ reader.close();
+ }
+ } else if (batch) {
+ Reader reader = new BufferedReader(new InputStreamReader(System.in));
+ sb.setLength(0);
+ for (int c = reader.read(); c >= 0; reader.read()) {
+ sb.append((char) c);
+ }
+ }
+
+ ClassLoader cl = Main.class.getClassLoader();
+ if (classpath != null) {
+ List<URL> urls = getFiles(new File(classpath));
+ cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl);
+ }
+
+ SessionFactory sessionFactory = createSessionFactory(threadio);
+
+ run(sessionFactory, sb.toString(), in, out, err, cl);
+ }
+
+ private void run(final SessionFactory sessionFactory, String command, final InputStream in, final PrintStream out, final PrintStream err, ClassLoader cl) throws Exception {
+
+ final TerminalFactory terminalFactory = new TerminalFactory();
+ try {
+ final Terminal terminal = new JLineTerminal(terminalFactory.getTerminal());
+ Session session = createSession(sessionFactory, command.length() > 0 ? null : in, out, err, terminal);
+ session.put("USER", user);
+ session.put("APPLICATION", application);
+
+ discoverCommands(session, cl, getDiscoveryResource());
+
+ if (command.length() > 0) {
+ // Shell is directly executing a sub/command, we don't setup a console
+ // in this case, this avoids us reading from stdin un-necessarily.
+ session.put(NameScoping.MULTI_SCOPE_MODE_KEY, Boolean.toString(isMultiScopeMode()));
+ session.put(Session.PRINT_STACK_TRACES, "execution");
+ try {
+ session.execute(command);
+ } catch (Throwable t) {
+ ShellUtil.logException(session, t);
+ }
+
+ } else {
+ // We are going into full blown interactive shell mode.
+ session.run();
+ }
+ } finally {
+ terminalFactory.destroy();
+ }
+ }
+
+ /**
+ * Allow sub classes of main to change the ConsoleImpl implementation used.
+ *
+ * @param sessionFactory
+ * @param in
+ * @param out
+ * @param err
+ * @param terminal
+ * @return
+ * @throws Exception
+ */
+ protected Session createSession(SessionFactory sessionFactory, InputStream in, PrintStream out, PrintStream err, Terminal terminal) throws Exception {
+ return sessionFactory.create(in, out, err, terminal, null, null);
+ }
+
+ protected SessionFactory createSessionFactory(ThreadIO threadio) {
+ SessionFactoryImpl sessionFactory = new SessionFactoryImpl(threadio);
+ sessionFactory.register(new ManagerImpl(sessionFactory, sessionFactory));
+ return sessionFactory;
+ }
+
+ /**
+ * Sub classes can override so that their registered commands do not conflict with the default shell
+ * implementation.
+ */
+ public String getDiscoveryResource() {
+ return "META-INF/services/org/apache/karaf/shell/commands";
+ }
+
+ protected void discoverCommands(Session session, ClassLoader cl, String resource) throws IOException, ClassNotFoundException {
+ Manager manager = new ManagerImpl(session.getRegistry(), session.getFactory().getRegistry(), true);
+ Enumeration<URL> urls = cl.getResources(resource);
+ while (urls.hasMoreElements()) {
+ URL url = urls.nextElement();
+ BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream()));
+ String line = r.readLine();
+ while (line != null) {
+ line = line.trim();
+ if (line.length() > 0 && line.charAt(0) != '#') {
+ final Class<?> actionClass = cl.loadClass(line);
+ manager.register(actionClass);
+ }
+ line = r.readLine();
+ }
+ r.close();
+ }
+ }
+
+ public String getApplication() {
+ return application;
+ }
+
+ public void setApplication(String application) {
+ this.application = application;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ /**
+ * Returns whether or not we are in multi-scope mode.
+ * <p/>
+ * The default mode is multi-scoped where we prefix commands by their scope. If we are in single
+ * scoped mode then we don't use scope prefixes when registering or tab completing commands.
+ */
+ public boolean isMultiScopeMode() {
+ return true;
+ }
+
+ private static PrintStream wrap(PrintStream stream) {
+ OutputStream o = AnsiConsole.wrapOutputStream(stream);
+ if (o instanceof PrintStream) {
+ return ((PrintStream) o);
+ } else {
+ return new PrintStream(o);
+ }
+ }
+
+ private static <T> T unwrap(T stream) {
+ try {
+ Method mth = stream.getClass().getMethod("getRoot");
+ return (T) mth.invoke(stream);
+ } catch (Throwable t) {
+ return stream;
+ }
+ }
+
+ private static List<URL> getFiles(File base) throws MalformedURLException {
+ List<URL> urls = new ArrayList<URL>();
+ getFiles(base, urls);
+ return urls;
+ }
+
+ private static void getFiles(File base, List<URL> urls) throws MalformedURLException {
+ for (File f : base.listFiles()) {
+ if (f.isDirectory()) {
+ getFiles(f, urls);
+ } else if (f.getName().endsWith(".jar")) {
+ urls.add(f.toURI().toURL());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/CommandException.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/CommandException.java b/shell/core/src/main/java/org/apache/karaf/shell/support/CommandException.java
new file mode 100644
index 0000000..15fb4e7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/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.support;
+
+import org.apache.karaf.shell.support.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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/MultiException.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/MultiException.java b/shell/core/src/main/java/org/apache/karaf/shell/support/MultiException.java
new file mode 100644
index 0000000..c05f185
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/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.support;
+
+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 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/NameScoping.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/NameScoping.java b/shell/core/src/main/java/org/apache/karaf/shell/support/NameScoping.java
new file mode 100644
index 0000000..fc3c5ed
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/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.support;
+
+
+import org.apache.karaf.shell.api.console.Session;
+
+/**
+ * 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(Session 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(Session 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(Session 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/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/ShellUtil.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/ShellUtil.java b/shell/core/src/main/java/org/apache/karaf/shell/support/ShellUtil.java
new file mode 100644
index 0000000..3887565
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/ShellUtil.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.karaf.shell.support;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+
+import javax.security.auth.Subject;
+
+import org.apache.karaf.jaas.boot.principal.UserPrincipal;
+import org.apache.karaf.shell.api.console.Session;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.startlevel.BundleStartLevel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_DEFAULT;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.COLOR_RED;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_BOLD;
+import static org.apache.karaf.shell.support.ansi.SimpleAnsi.INTENSITY_NORMAL;
+
+public class ShellUtil {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ShellUtil.class);
+
+ public static String getBundleName(Bundle bundle) {
+ if (bundle != null) {
+ String name = (String) bundle.getHeaders().get(Constants.BUNDLE_NAME);
+ return (name == null)
+ ? "Bundle " + Long.toString(bundle.getBundleId())
+ : name + " (" + Long.toString(bundle.getBundleId()) + ")";
+ }
+ return "[STALE BUNDLE]";
+ }
+
+ public static String getUnderlineString(String s) {
+ StringBuilder sb = new StringBuilder(s.length());
+ for (int i = 0; i < s.length(); i++) {
+ sb.append('-');
+ }
+ return sb.toString();
+ }
+
+ public static String getValueString(Object obj) {
+ if (obj == null) {
+ return "null";
+ } else if (obj.getClass().isArray()) {
+ Object[] array = (Object[]) obj;
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ for (int i = 0; i < array.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(getValueString(array[i]));
+ }
+ sb.append("]");
+ return sb.toString();
+ } else if (obj instanceof String) {
+ return (String) obj;
+ } else if (obj instanceof Boolean) {
+ return ((Boolean) obj).toString();
+ } else if (obj instanceof Long) {
+ return ((Long) obj).toString();
+ } else if (obj instanceof Integer) {
+ return ((Integer) obj).toString();
+ } else if (obj instanceof Short) {
+ return ((Short) obj).toString();
+ } else if (obj instanceof Double) {
+ return ((Double) obj).toString();
+ } else if (obj instanceof Float) {
+ return ((Float) obj).toString();
+ } else if (obj instanceof URL) {
+ return ((URL) obj).toExternalForm();
+ } else if (obj instanceof URI) {
+ try {
+ return ((URI) obj).toURL().toExternalForm();
+ } catch (MalformedURLException e) {
+ LOGGER.error("URI could not be transformed to URL", e);
+ return obj.toString();
+ }
+ } else {
+ return obj.toString();
+ }
+ }
+
+ /**
+ * Check if a bundle is a system bundle (start level < 50)
+ *
+ * @param bundleContext
+ * @param bundle
+ * @return true if the bundle has start level minor than 50
+ */
+ public static boolean isASystemBundle(BundleContext bundleContext, Bundle bundle) {
+ int level = bundle.adapt(BundleStartLevel.class).getStartLevel();
+ int sbsl = 49;
+ final String sbslProp = bundleContext.getProperty("karaf.systemBundlesStartLevel");
+ if (sbslProp != null) {
+ try {
+ sbsl = Integer.valueOf(sbslProp);
+ } catch (Exception ignore) {
+ // ignore
+ }
+ }
+ return level <= sbsl;
+ }
+
+ public static boolean getBoolean(Session session, String name) {
+ Object s = session.get(name);
+ if (s == null) {
+ s = System.getProperty(name);
+ }
+ if (s == null) {
+ return false;
+ }
+ if (s instanceof Boolean) {
+ return (Boolean) s;
+ }
+ return Boolean.parseBoolean(s.toString());
+ }
+
+ public static void logException(Session session, Throwable t) {
+ try {
+ // Store last exception in session
+ session.put(Session.LAST_EXCEPTION, t);
+ // Log exception
+ String name = t.getClass().getSimpleName();
+ if ("CommandNotFoundException".equals(name)) {
+ LOGGER.debug("Unknown command entered", t);
+ } else if ("CommandException".equals(name)) {
+ LOGGER.debug("Command exception (Undefined option, ...)", t);
+ } else {
+ LOGGER.error("Exception caught while executing command", t);
+ }
+ // Display exception
+ String pst = getPrintStackTraces(session);
+ if ("always".equals(pst)) {
+ session.getConsole().print(COLOR_RED);
+ t.printStackTrace(session.getConsole());
+ session.getConsole().print(COLOR_DEFAULT);
+ } else if ("CommandNotFoundException".equals(name)) {
+ String str = COLOR_RED + "Command not found: "
+ + INTENSITY_BOLD + t.getClass().getMethod("getCommand").invoke(t) + INTENSITY_NORMAL
+ + COLOR_DEFAULT;
+ session.getConsole().println(str);
+ } else if ("CommandException".equals(name)) {
+ String str;
+ try {
+ str = (String) t.getClass().getMethod("getNiceHelp").invoke(t);
+ } catch (Throwable ignore) {
+ str = COLOR_RED + t.getMessage() + COLOR_DEFAULT;
+ }
+ session.getConsole().println(str);
+ } else if ("execution".equals(pst)) {
+ session.getConsole().print(COLOR_RED);
+ t.printStackTrace(session.getConsole());
+ session.getConsole().print(COLOR_DEFAULT);
+ } else {
+ String str = COLOR_RED + "Error executing command: "
+ + (t.getMessage() != null ? t.getMessage() : t.getClass().getName())
+ + COLOR_DEFAULT;
+ session.getConsole().println(str);
+ }
+ } catch (Exception ignore) {
+ // ignore
+ }
+ }
+
+ private static String getPrintStackTraces(Session session) {
+ Object pst = session.get(Session.PRINT_STACK_TRACES);
+ if (pst == null) {
+ pst = System.getProperty(Session.PRINT_STACK_TRACES);
+ }
+ if (pst == null) {
+ return "never";
+ } else if (pst instanceof Boolean) {
+ return ((Boolean) pst) ? "always" : "never";
+ } else {
+ return pst.toString().toLowerCase();
+ }
+ }
+
+ public static String getCurrentUserName() {
+ AccessControlContext acc = AccessController.getContext();
+ final Subject subject = Subject.getSubject(acc);
+ if (subject != null && subject.getPrincipals(UserPrincipal.class).iterator().hasNext()) {
+ return subject.getPrincipals(UserPrincipal.class).iterator().next().getName();
+ } else {
+ return null;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/karaf/blob/e7d23bef/shell/core/src/main/java/org/apache/karaf/shell/support/ansi/SimpleAnsi.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/support/ansi/SimpleAnsi.java b/shell/core/src/main/java/org/apache/karaf/shell/support/ansi/SimpleAnsi.java
new file mode 100644
index 0000000..d7d75d7
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/support/ansi/SimpleAnsi.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.support.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();
+}
[06/10] git commit: [KARAF-2805] Add a compatibility layer and switch
to the new console
Posted by gn...@apache.org.
[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