FELIX-1817: Backspace does not work anymore when connecting from the karaf-client
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@831272 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/client/pom.xml b/karaf/client/pom.xml
index 829d15a..b6d5ef1 100644
--- a/karaf/client/pom.xml
+++ b/karaf/client/pom.xml
@@ -55,7 +55,7 @@
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
- <artifactId>slf4j-nop</artifactId>
+ <artifactId>slf4j-simple</artifactId>
</dependency>
</dependencies>
<build>
diff --git a/karaf/client/src/main/java/org/apache/felix/karaf/client/Main.java b/karaf/client/src/main/java/org/apache/felix/karaf/client/Main.java
index 1fcfca0..e17434c 100644
--- a/karaf/client/src/main/java/org/apache/felix/karaf/client/Main.java
+++ b/karaf/client/src/main/java/org/apache/felix/karaf/client/Main.java
@@ -16,17 +16,19 @@
*/
package org.apache.felix.karaf.client;
+import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
-import java.io.PrintWriter;
import jline.Terminal;
import org.apache.felix.karaf.shell.console.jline.TerminalFactory;
import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
+import org.apache.sshd.client.channel.ChannelShell;
import org.apache.sshd.client.future.ConnectFuture;
-import jline.ConsoleReader;
+import org.fusesource.jansi.AnsiConsole;
+import org.slf4j.impl.SimpleLogger;
/**
* A very simple
@@ -39,6 +41,7 @@
String user = "karaf";
String password = "karaf";
StringBuilder sb = new StringBuilder();
+ int level = 1;
for (int i = 0; i < args.length; i++) {
if (args[i].charAt(0) == '-') {
@@ -50,6 +53,8 @@
user = args[++i];
} else if (args[i].equals("-p")) {
password = args[++i];
+ } else if (args[i].equals("-v")) {
+ level++;
} else if (args[i].equals("--help")) {
System.out.println("Apache Felix Karaf client");
System.out.println(" -a [port] specify the port to connect to");
@@ -57,6 +62,7 @@
System.out.println(" -u [user] specify the user name");
System.out.println(" -p [password] specify the password");
System.out.println(" --help shows this help message");
+ System.out.println(" -v raise verbosity");
System.out.println(" [commands] commands to run");
System.out.println("If no commands are specified, the client will be put in an interactive mode");
System.exit(0);
@@ -70,8 +76,7 @@
sb.append(' ');
}
}
-
- // TODO: implement sending a direct command
+ SimpleLogger.setLevel(level);
SshClient client = null;
Terminal terminal = null;
@@ -89,13 +94,11 @@
} else {
terminal = new TerminalFactory().getTerminal();
channel = session.createChannel("shell");
- ConsoleReader reader = new ConsoleReader(System.in, new PrintWriter(System.out),
- TerminalFactory.class.getResourceAsStream("keybinding.properties"),
- terminal);
- channel.setIn(reader.getInput());
- }
- channel.setOut(System.out);
- channel.setErr(System.err);
+ channel.setIn(System.in);
+ ((ChannelShell) channel).setupSensibleDefaultPty();
+ }
+ channel.setOut(AnsiConsole.wrapOutputStream(System.out));
+ channel.setErr(AnsiConsole.wrapOutputStream(System.err));
channel.open();
channel.waitFor(ClientChannel.CLOSED, 0);
} catch (Throwable t) {
diff --git a/karaf/client/src/main/java/org/slf4j/impl/SimpleLogger.java b/karaf/client/src/main/java/org/slf4j/impl/SimpleLogger.java
new file mode 100644
index 0000000..1bf6e2d
--- /dev/null
+++ b/karaf/client/src/main/java/org/slf4j/impl/SimpleLogger.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.slf4j.impl;
+
+import org.slf4j.helpers.MarkerIgnoringBase;
+import org.slf4j.helpers.MessageFormatter;
+
+/**
+ * A simple logger that can be controlled from the ssh client
+ */
+public class SimpleLogger extends MarkerIgnoringBase {
+
+ public static final int ERROR = 0;
+ public static final int WARN = 1;
+ public static final int INFO = 2;
+ public static final int DEBUG = 3;
+ public static final int TRACE = 4;
+
+ private static int level = 0;
+ private static long startTime = System.currentTimeMillis();
+ public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ public static int getLevel() {
+ return level;
+ }
+
+ public static void setLevel(int level) {
+ SimpleLogger.level = level;
+ }
+
+ private String name;
+
+ SimpleLogger(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isTraceEnabled() {
+ return isLogEnabled(TRACE);
+ }
+
+ public void trace(String msg) {
+ log(TRACE, msg);
+ }
+
+ public void trace(String format, Object arg) {
+ log(TRACE, format, arg);
+ }
+
+ public void trace(String format, Object arg1, Object arg2) {
+ log(TRACE, format, arg1, arg2);
+ }
+
+ public void trace(String format, Object[] argArray) {
+ log(TRACE, format, argArray);
+ }
+
+ public void trace(String msg, Throwable t) {
+ log(TRACE, msg, t);
+ }
+
+ public boolean isDebugEnabled() {
+ return isLogEnabled(DEBUG);
+ }
+
+ public void debug(String msg) {
+ log(DEBUG, msg);
+ }
+
+ public void debug(String format, Object arg) {
+ log(DEBUG, format, arg);
+ }
+
+ public void debug(String format, Object arg1, Object arg2) {
+ log(DEBUG, format, arg1, arg2);
+ }
+
+ public void debug(String format, Object[] argArray) {
+ log(DEBUG, format, argArray, null);
+ }
+
+ public void debug(String msg, Throwable t) {
+ log(DEBUG, msg, t);
+ }
+
+ public boolean isInfoEnabled() {
+ return isLogEnabled(INFO);
+ }
+
+ public void info(String msg) {
+ log(INFO, msg);
+ }
+
+ public void info(String format, Object arg) {
+ log(INFO, format, arg);
+ }
+
+ public void info(String format, Object arg1, Object arg2) {
+ log(INFO, format, arg1, arg2);
+ }
+
+ public void info(String format, Object[] argArray) {
+ log(INFO, format, argArray);
+ }
+
+ public void info(String msg, Throwable t) {
+ log(INFO, msg, t);
+ }
+
+ public boolean isWarnEnabled() {
+ return isLogEnabled(WARN);
+ }
+
+ public void warn(String msg) {
+ log(WARN, msg);
+ }
+
+ public void warn(String format, Object arg) {
+ log(WARN, format, arg);
+ }
+
+ public void warn(String format, Object arg1, Object arg2) {
+ log(WARN, format, arg1, arg2);
+ }
+
+ public void warn(String format, Object[] argArray) {
+ log(WARN, format, argArray);
+ }
+
+ public void warn(String msg, Throwable t) {
+ log(WARN, msg, t);
+ }
+
+ public boolean isErrorEnabled() {
+ return isLogEnabled(ERROR);
+ }
+
+ public void error(String msg) {
+ log(ERROR, msg);
+ }
+
+ public void error(String format, Object arg) {
+ log(ERROR, format, arg);
+ }
+
+ public void error(String format, Object arg1, Object arg2) {
+ log(ERROR, format, arg1, arg2);
+ }
+
+ public void error(String format, Object[] argArray) {
+ log(ERROR, format, argArray);
+ }
+
+ public void error(String msg, Throwable t) {
+ log(ERROR, msg, t);
+ }
+
+ protected boolean isLogEnabled(int level) {
+ return SimpleLogger.level >= level;
+ }
+
+ protected void log(int level, String msg) {
+ if (isLogEnabled(level)) {
+ doLog(level, msg, null);
+ }
+ }
+
+ protected void log(int level, String format, Object arg) {
+ if (isLogEnabled(level)) {
+ String msg = MessageFormatter.format(format, arg);
+ doLog(level, msg, null);
+ }
+ }
+
+ protected void log(int level, String format, Object arg1, Object arg2) {
+ if (isLogEnabled(level)) {
+ String msg = MessageFormatter.format(format, arg1, arg2);
+ doLog(level, msg, null);
+ }
+ }
+
+ protected void log(int level, String format, Object[] args) {
+ if (isLogEnabled(level)) {
+ String msg = MessageFormatter.format(format, args);
+ doLog(level, msg, null);
+ }
+ }
+
+ protected void log(int level, String msg, Throwable t) {
+ if (isLogEnabled(level)) {
+ doLog(level, msg, t);
+ }
+ }
+
+ protected void doLog(int level, String msg, Throwable t) {
+ StringBuffer buf = new StringBuffer();
+ long millis = System.currentTimeMillis();
+ buf.append(millis - startTime);
+ buf.append(" [");
+ buf.append(Thread.currentThread().getName());
+ buf.append("] ");
+ switch (level) {
+ case TRACE:
+ buf.append("TRACE"); break;
+ case DEBUG:
+ buf.append("DEBUG"); break;
+ case INFO:
+ buf.append("INFO"); break;
+ case WARN:
+ buf.append("WARN"); break;
+ case ERROR:
+ buf.append("ERROR"); break;
+ }
+ buf.append(" ");
+ buf.append(name);
+ buf.append(" - ");
+ buf.append(msg);
+ buf.append(LINE_SEPARATOR);
+ System.err.print(buf.toString());
+ if (t != null) {
+ t.printStackTrace(System.err);
+ }
+ System.err.flush();
+ }
+}
diff --git a/karaf/pom.xml b/karaf/pom.xml
index 5a2d3e5..0413f80 100644
--- a/karaf/pom.xml
+++ b/karaf/pom.xml
@@ -170,13 +170,6 @@
<artifactId>org.apache.felix.karaf.client</artifactId>
<version>${pom.version}</version>
</dependency>
- <!--
- <dependency>
- <groupId>org.apache.felix.karaf.deployer</groupId>
- <artifactId>org.apache.felix.karaf.deployer.filemonitor</artifactId>
- <version>${pom.version}</version>
- </dependency>
- -->
<dependency>
<groupId>org.apache.felix.karaf.deployer</groupId>
<artifactId>org.apache.felix.karaf.deployer.spring</artifactId>
@@ -198,8 +191,8 @@
<version>${pom.version}</version>
</dependency>
<dependency>
- <groupId>org.apache.felix.karaf</groupId>
- <artifactId>org.apache.felix.karaf.demos</artifactId>
+ <groupId>org.apache.felix.karaf.demos</groupId>
+ <artifactId>demos</artifactId>
<version>${pom.version}</version>
</dependency>
<dependency>
@@ -234,21 +227,11 @@
</dependency>
<dependency>
<groupId>org.apache.felix.karaf.shell</groupId>
- <artifactId>org.apache.felix.karaf.shell.core</artifactId>
- <version>${pom.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix.karaf.shell</groupId>
<artifactId>org.apache.felix.karaf.shell.console</artifactId>
<version>${pom.version}</version>
</dependency>
<dependency>
<groupId>org.apache.felix.karaf.shell</groupId>
- <artifactId>org.apache.felix.karaf.shell.run</artifactId>
- <version>${pom.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.felix.karaf.shell</groupId>
<artifactId>org.apache.felix.karaf.shell.obr</artifactId>
<version>${pom.version}</version>
</dependency>
@@ -299,7 +282,7 @@
</dependency>
<dependency>
<groupId>org.apache.felix.karaf.demos</groupId>
- <artifactId>smx4web</artifactId>
+ <artifactId>web</artifactId>
<version>${pom.version}</version>
</dependency>
<dependency>
@@ -544,11 +527,6 @@
<version>3.0-alpha-1</version>
</dependency>
<dependency>
- <groupId>org.apache.servicemix.bundles</groupId>
- <artifactId>org.apache.servicemix.bundles.commons-io</artifactId>
- <version>${commons.io.version}</version>
- </dependency>
- <dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>${mina.version}</version>
@@ -579,6 +557,11 @@
<version>1.4.3</version>
</dependency>
<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.4.3</version>
+ </dependency>
+ <dependency>
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-api</artifactId>
<version>${pax.logging.version}</version>
@@ -610,11 +593,6 @@
<version>${geronimo.servlet.version}</version>
</dependency>
<dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-annotation_1.0_spec</artifactId>
- <version>${geronimo.annotation.version}</version>
- </dependency>
- <dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>${easymock.version}</version>
diff --git a/karaf/shell/ssh/src/main/java/org/apache/felix/karaf/shell/ssh/SshTerminal.java b/karaf/shell/ssh/src/main/java/org/apache/felix/karaf/shell/ssh/SshTerminal.java
index 57e4db6..e42da15 100644
--- a/karaf/shell/ssh/src/main/java/org/apache/felix/karaf/shell/ssh/SshTerminal.java
+++ b/karaf/shell/ssh/src/main/java/org/apache/felix/karaf/shell/ssh/SshTerminal.java
@@ -23,6 +23,7 @@
import java.io.InputStreamReader;
import jline.Terminal;
+import org.apache.sshd.common.PtyMode;
import org.apache.sshd.server.ShellFactory;
import org.apache.sshd.server.Signal;
@@ -46,6 +47,7 @@
private String encoding = System.getProperty("input.encoding", "UTF-8");
private ReplayPrefixOneCharInputStream replayStream = new ReplayPrefixOneCharInputStream(encoding);
private InputStreamReader replayReader;
+ private boolean isWindowsTerminal;
public SshTerminal(ShellFactory.Environment environment) {
this.environment = environment;
@@ -55,6 +57,9 @@
} catch (Exception e) {
throw new RuntimeException(e);
}
+ Integer verase = this.environment.getPtyModes().get(PtyMode.VERASE);
+ backspaceDeleteSwitched = verase != null && verase == DELETE;
+ this.isWindowsTerminal = "windows".equals(environment.getEnv().get("TERM"));
}
public void initializeTerminal() throws Exception {
@@ -63,12 +68,17 @@
public void restoreTerminal() throws Exception {
}
+ @Override
+ public boolean isANSISupported() {
+ return !isWindowsTerminal;
+ }
+
public int getTerminalWidth() {
- return Integer.valueOf(this.environment.getEnv().get("COLUMNS"));
+ return Integer.valueOf(this.environment.getEnv().get(ShellFactory.Environment.ENV_COLUMNS));
}
public int getTerminalHeight() {
- return Integer.valueOf(this.environment.getEnv().get("LINES"));
+ return Integer.valueOf(this.environment.getEnv().get(ShellFactory.Environment.ENV_LINES));
}
public boolean isSupported() {
@@ -97,8 +107,8 @@
if (backspaceDeleteSwitched)
if (c == DELETE)
- c = '\b';
- else if (c == '\b')
+ c = BACKSPACE;
+ else if (c == BACKSPACE)
c = DELETE;
// in Unix terminals, arrow keys are represented by
@@ -215,5 +225,5 @@
return byteLength - byteRead;
}
}
-
+
}