diff --git a/components/camel-ssh/pom.xml b/components/camel-ssh/pom.xml
new file mode 100644
index 0000000000000..e52a273ae1471
--- /dev/null
+++ b/components/camel-ssh/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+ 4.0.0
+
+
+ org.apache.camel
+ camel-parent
+ 2.10-SNAPSHOT
+ ../../parent
+
+
+ camel-ssh
+ bundle
+ Camel :: SSH
+ Camel SSH support
+
+
+ org.apache.camel.component.ssh.*
+
+
+
+
+ org.apache.camel
+ camel-core
+
+
+ org.apache.mina
+ mina-core
+ 2.0.2
+
+
+ org.apache.sshd
+ sshd-core
+ 0.6.0
+
+
+
+
+ org.apache.camel
+ camel-test
+ test
+
+
+
+ bouncycastle
+ bcprov-jdk15
+ 140
+ test
+
+
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ slf4j-log4j12
+ test
+
+
+ log4j
+ log4j
+ test
+
+
+
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java
new file mode 100644
index 0000000000000..7d36d2906b355
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import java.net.*;
+import java.util.*;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.sshd.common.KeyPairProvider;
+
+/**
+ * Represents the component that manages {@link SshEndpoint}.
+ */
+public class SshComponent extends DefaultComponent {
+ private SshConfiguration configuration;
+
+ @Override
+ protected Endpoint createEndpoint(String uri, String remaining, Map parameters) throws Exception {
+ SshConfiguration newConfig;
+
+ if (configuration == null) {
+ newConfig = new SshConfiguration(new URI(uri));
+ } else {
+ newConfig = configuration.copy();
+ }
+
+ SshEndpoint endpoint = new SshEndpoint(uri, this, newConfig);
+ setProperties(endpoint.getConfiguration(), parameters);
+ //setProperties(endpoint, parameters);
+ return endpoint;
+ }
+
+ public SshConfiguration getConfiguration() {
+ if (configuration == null) {
+ configuration = new SshConfiguration();
+ }
+ return configuration;
+ }
+
+ public void setConfiguration(SshConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getHost() {
+ return getConfiguration().getHost();
+ }
+
+ public void setHost(String host) {
+ getConfiguration().setHost(host);
+ }
+
+ public int getPort() {
+ return getConfiguration().getPort();
+ }
+
+ public void setPort(int port) {
+ getConfiguration().setPort(port);
+ }
+
+ public String getUsername() {
+ return getConfiguration().getUsername();
+ }
+
+ public void setUsername(String username) {
+ getConfiguration().setUsername(username);
+ }
+
+ public String getPassword() {
+ return getConfiguration().getPassword();
+ }
+
+ public void setPassword(String password) {
+ getConfiguration().setPassword(password);
+ }
+
+ public String getPollCommand() {
+ return getConfiguration().getPollCommand();
+ }
+
+ public void setPollCommand(String pollCommand) {
+ getConfiguration().setPollCommand(pollCommand);
+ }
+
+ public KeyPairProvider getKeyPairProvider() {
+ return getConfiguration().getKeyPairProvider();
+ }
+
+ public void setKeyPairProvider(KeyPairProvider keyPairProvider) {
+ getConfiguration().setKeyPairProvider(keyPairProvider);
+ }
+
+ public String getKeyType() {
+ return getConfiguration().getKeyType();
+ }
+
+ public void setKeyType(String keyType) {
+ getConfiguration().setKeyType(keyType);
+ }
+
+ public long getTimeout() {
+ return getConfiguration().getTimeout();
+ }
+
+ public void setTimeout(long timeout) {
+ getConfiguration().setTimeout(timeout);
+ }
+}
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java
new file mode 100644
index 0000000000000..28ef07f2cf771
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java
@@ -0,0 +1,189 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import java.net.*;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.sshd.common.KeyPairProvider;
+
+public class SshConfiguration implements Cloneable {
+ public static final int DEFAULT_SSH_PORT = 22;
+
+ private String username;
+ private String host;
+ private int port = DEFAULT_SSH_PORT;
+ private String password;
+ private String pollCommand;
+ private KeyPairProvider keyPairProvider;
+ private String keyType;
+ private long timeout = 30000;
+
+ public SshConfiguration() {
+ }
+
+ public SshConfiguration(URI uri) {
+ configure(uri);
+ }
+
+ public void configure(URI uri) {
+ // UserInfo can contain both username and password as: user:pwd@sshserver
+ // see: http://en.wikipedia.org/wiki/URI_scheme
+ String username = uri.getUserInfo();
+ String pw = null;
+ if (username != null && username.contains(":")) {
+ pw = ObjectHelper.after(username, ":");
+ username = ObjectHelper.before(username, ":");
+ }
+ if (username != null) {
+ setUsername(username);
+ }
+ if (pw != null) {
+ setPassword(pw);
+ }
+
+ setHost(uri.getHost());
+
+ // URI.getPort returns -1 if port not defined, else use default port
+ int uriPort = uri.getPort();
+ if (uriPort != -1) {
+ setPort(uriPort);
+ }
+ }
+
+ public SshConfiguration copy() {
+ try {
+ return (SshConfiguration) clone();
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeCamelException(e);
+ }
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Sets the username to use in logging into the remote SSH server.
+ *
+ * @param username String representing login username.
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ /**
+ * Sets the hostname of the remote SSH server.
+ *
+ * @param host String representing hostname of SSH server.
+ */
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Sets the port number for the remote SSH server.
+ *
+ * @param port int representing port number on remote host. Defaults to 22.
+ */
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password to use in connecting to remote SSH server.
+ * Requires keyPairProvider to be set to null.
+ *
+ * @param password String representing password for username at remote host.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getPollCommand() {
+ return pollCommand;
+ }
+
+ /**
+ * Sets the command string to send to the remote SSH server during every poll cycle.
+ * Only works with camel-ssh component being used as a consumer, i.e. from("ssh://...")
+ *
+ * @param pollCommand String representing the command to send.
+ */
+ public void setPollCommand(String pollCommand) {
+ this.pollCommand = pollCommand;
+ }
+
+ public KeyPairProvider getKeyPairProvider() {
+ return keyPairProvider;
+ }
+
+ /**
+ * Sets the KeyPairProvider reference to use when connecting using Certificates to the remote SSH Server.
+ *
+ * @param keyPairProvider KeyPairProvider reference to use in authenticating. If set to 'null',
+ * then will attempt to connect using username/password settings.
+ *
+ * @see KeyPairProvider
+ */
+ public void setKeyPairProvider(KeyPairProvider keyPairProvider) {
+ this.keyPairProvider = keyPairProvider;
+ }
+
+ public String getKeyType() {
+ return keyType;
+ }
+
+ /**
+ * Sets the key type to pass to the KeyPairProvider as part of authentication.
+ * KeyPairProvider.loadKey(...) will be passed this value.
+ *
+ * @param keyType String defining the type of KeyPair to use for authentication.
+ *
+ * @see KeyPairProvider
+ */
+ public void setKeyType(String keyType) {
+ this.keyType = keyType;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * Sets the timeout in milliseconds to wait in establishing the remote SSH server connection.
+ * Defaults to 30000 milliseconds.
+ *
+ * @param timeout long millisconeds to wait.
+ */
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+}
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java
new file mode 100644
index 0000000000000..36dbc59a4e532
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ssh;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.ScheduledPollConsumer;
+
+public class SshConsumer extends ScheduledPollConsumer {
+ private final SshEndpoint endpoint;
+
+ public SshConsumer(SshEndpoint endpoint, Processor processor) {
+ super(endpoint, processor);
+ this.endpoint = endpoint;
+ }
+
+ @Override
+ protected int poll() throws Exception {
+ String command = endpoint.getPollCommand();
+ byte[] result = endpoint.sendExecCommand(command);
+
+ Exchange exchange = endpoint.createExchange();
+ exchange.getIn().setBody(result);
+
+ try {
+ // send message to next processor in the route
+ getProcessor().process(exchange);
+ return 1; // number of messages polled
+ } finally {
+ // log exception if an exception occurred and was not handled
+ if (exchange.getException() != null) {
+ getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
+ }
+ }
+ }
+}
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
new file mode 100644
index 0000000000000..77b45eb591ec5
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
@@ -0,0 +1,229 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import java.io.*;
+import java.security.KeyPair;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.impl.ScheduledPollEndpoint;
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.KeyPairProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents an SSH endpoint.
+ */
+public class SshEndpoint extends ScheduledPollEndpoint {
+ protected final transient Logger log = LoggerFactory.getLogger(getClass());
+
+ private SshClient client;
+ private SshConfiguration sshConfiguration;
+
+ public SshEndpoint() {
+ }
+
+ public SshEndpoint(String uri, SshComponent component) {
+ super(uri, component);
+ }
+
+ public SshEndpoint(String uri, SshComponent component, SshConfiguration configuration) {
+ super(uri, component);
+ this.sshConfiguration = configuration;
+ }
+
+ @Override
+ public Producer createProducer() throws Exception {
+ return new SshProducer(this);
+ }
+
+ @Override
+ public Consumer createConsumer(Processor processor) throws Exception {
+ SshConsumer consumer = new SshConsumer(this, processor);
+
+ configureConsumer(consumer);
+
+ return consumer;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return false;
+ }
+
+ public byte[] sendExecCommand(String command) throws Exception {
+ byte[] result = null;
+
+ if (getConfiguration() == null) {
+ throw new IllegalStateException("configuration must be set");
+ }
+
+ ConnectFuture connectFuture = client.connect(getHost(), getPort());
+
+ // Wait getTimeout milliseconds for connect operation to complete
+ connectFuture.await(getTimeout());
+
+ if (!connectFuture.isDone() || !connectFuture.isConnected()) {
+ final String msg = "Failed to connect to " + getHost() + ":" + getPort() + " within timeout " + getTimeout() + "ms";
+ log.debug(msg);
+ throw new RuntimeCamelException(msg);
+ }
+
+ log.debug("Connected to {}:{}", getHost(), getPort());
+
+ AuthFuture authResult;
+ ClientSession session = connectFuture.getSession();
+
+ final KeyPairProvider keyPairProvider = getKeyPairProvider();
+ if (keyPairProvider != null) {
+ log.debug("Attempting to authenticate username '{}' using Key...", getUsername());
+ KeyPair pair = keyPairProvider.loadKey(getKeyType());
+ authResult = session.authPublicKey(getUsername(), pair);
+ } else {
+ log.debug("Attempting to authenticate username '{}' using Password...", getUsername());
+ authResult = session.authPassword(getUsername(), getPassword());
+ }
+
+ authResult.await(getTimeout());
+
+ if (!authResult.isDone() || authResult.isFailure()) {
+ log.debug("Failed to authenticate");
+ throw new RuntimeCamelException("Failed to authenticate username " + getUsername());
+ }
+
+ ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_EXEC, command);
+
+ ByteArrayInputStream in = new ByteArrayInputStream(new byte[]{0});
+ channel.setIn(in);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ channel.setOut(out);
+
+ ByteArrayOutputStream err = new ByteArrayOutputStream();
+ channel.setErr(err);
+
+ OpenFuture openFuture = channel.open();
+
+ openFuture.await(getTimeout());
+
+ if (openFuture.isOpened()) {
+ channel.waitFor(ClientChannel.CLOSED, 0);
+ result = out.toByteArray();
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+
+ client = SshClient.setUpDefaultClient();
+ client.start();
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ if (client != null) {
+ client.stop();
+ client = null;
+ }
+
+ super.doStop();
+ }
+
+ public SshConfiguration getConfiguration() {
+ return sshConfiguration;
+ }
+
+ public void setConfiguration(SshConfiguration configuration) {
+ this.sshConfiguration = configuration;
+ }
+
+ public String getHost() {
+ return getConfiguration().getHost();
+ }
+
+ public void setHost(String host) {
+ getConfiguration().setHost(host);
+ }
+
+ public int getPort() {
+ return getConfiguration().getPort();
+ }
+
+ public void setPort(int port) {
+ getConfiguration().setPort(port);
+ }
+
+ public String getUsername() {
+ return getConfiguration().getUsername();
+ }
+
+ public void setUsername(String username) {
+ getConfiguration().setUsername(username);
+ }
+
+ public String getPassword() {
+ return getConfiguration().getPassword();
+ }
+
+ public void setPassword(String password) {
+ getConfiguration().setPassword(password);
+ }
+
+ public String getPollCommand() {
+ return getConfiguration().getPollCommand();
+ }
+
+ public void setPollCommand(String pollCommand) {
+ getConfiguration().setPollCommand(pollCommand);
+ }
+
+ public KeyPairProvider getKeyPairProvider() {
+ return getConfiguration().getKeyPairProvider();
+ }
+
+ public void setKeyPairProvider(KeyPairProvider keyPairProvider) {
+ getConfiguration().setKeyPairProvider(keyPairProvider);
+ }
+
+ public String getKeyType() {
+ return getConfiguration().getKeyType();
+ }
+
+ public void setKeyType(String keyType) {
+ getConfiguration().setKeyType(keyType);
+ }
+
+ public long getTimeout() {
+ return getConfiguration().getTimeout();
+ }
+
+ public void setTimeout(long timeout) {
+ getConfiguration().setTimeout(timeout);
+ }
+}
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.java
new file mode 100644
index 0000000000000..2edc73a04a1b4
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshProducer.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.camel.component.ssh;
+
+import org.apache.camel.CamelExchangeException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultProducer;
+
+public class SshProducer extends DefaultProducer {
+ private SshEndpoint endpoint;
+
+ public SshProducer(SshEndpoint endpoint) {
+ super(endpoint);
+ this.endpoint = endpoint;
+ }
+
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ final Message in = exchange.getIn();
+ final Message out = exchange.getOut();
+
+ String command = in.getBody(String.class);
+
+ try {
+ byte[] result = endpoint.sendExecCommand(command);
+
+ out.setBody(result);
+ } catch (Exception e) {
+ throw new CamelExchangeException(e.getMessage(), exchange, e);
+ }
+
+ // propagate headers and attachments
+ out.getHeaders().putAll(in.getHeaders());
+ out.setAttachments(in.getAttachments());
+ }
+}
\ No newline at end of file
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html
new file mode 100644
index 0000000000000..f24393f50eb5b
--- /dev/null
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/package.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+Defines the SSH Component
+
+
+
diff --git a/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh b/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh
new file mode 100644
index 0000000000000..1f76f468d7f2a
--- /dev/null
+++ b/components/camel-ssh/src/main/resources/META-INF/services/org/apache/camel/component/ssh
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class=org.apache.camel.component.ssh.SshComponent
diff --git a/components/camel-ssh/src/main/resources/log4j.properties b/components/camel-ssh/src/main/resources/log4j.properties
new file mode 100644
index 0000000000000..4621723d31a1b
--- /dev/null
+++ b/components/camel-ssh/src/main/resources/log4j.properties
@@ -0,0 +1,16 @@
+
+#
+# The logging properties used
+#
+log4j.rootLogger=INFO, out
+
+# uncomment the following line to turn on Camel debugging
+#log4j.logger.org.apache.camel=DEBUG
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
\ No newline at end of file
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java
new file mode 100644
index 0000000000000..9ad5ee2aede19
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPasswordAuthenticator.java
@@ -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.
+ */
+package org.apache.camel.component.ssh;
+
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author Apache MINA SSHD Project
+ */
+public class BogusPasswordAuthenticator implements PasswordAuthenticator {
+
+ @Override
+ public boolean authenticate(String username, String password, ServerSession session) {
+ return username != null && username.equals(password);
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java
new file mode 100644
index 0000000000000..52e05d3329f08
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/BogusPublickeyAuthenticator.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ssh;
+
+import java.security.PublicKey;
+
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author Apache MINA SSHD Project
+ */
+public class BogusPublickeyAuthenticator implements PublickeyAuthenticator {
+
+ @Override
+ public boolean authenticate(String username, PublicKey key, ServerSession session) {
+ return true;
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java
new file mode 100644
index 0000000000000..5873365651855
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/EchoCommandFactory.java
@@ -0,0 +1,93 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import java.io.*;
+
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author Apache MINA SSHD Project
+ */
+public class EchoCommandFactory implements CommandFactory {
+
+ @Override
+ public Command createCommand(String command) {
+ return new EchoCommand(command);
+ }
+
+ protected static class EchoCommand implements Command, Runnable {
+ private String command;
+ private InputStream in;
+ private OutputStream out;
+ private OutputStream err;
+ private ExitCallback callback;
+ private Thread thread;
+
+ public EchoCommand(String command) {
+ this.command = command;
+ }
+
+ @Override
+ public void setInputStream(InputStream in) {
+ this.in = in;
+ }
+
+ @Override
+ public void setOutputStream(OutputStream out) {
+ this.out = out;
+ }
+
+ @Override
+ public void setErrorStream(OutputStream err) {
+ this.err = err;
+ }
+
+ @Override
+ public void setExitCallback(ExitCallback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void start(Environment env) throws IOException {
+ thread = new Thread(this, "EchoCommand");
+ thread.start();
+ }
+
+ @Override
+ public void destroy() {
+ thread.interrupt();
+ }
+
+ @Override
+ public void run() {
+ try {
+ out.write(command.getBytes());
+ out.flush();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ callback.onExit(0);
+ }
+ }
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java
new file mode 100644
index 0000000000000..7d7525e54f5ae
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentConsumerTest.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ssh;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Test;
+
+public class SshComponentConsumerTest extends SshComponentTestSupport {
+ @Test
+ public void testPollingConsumer() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived("test\r");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("ssh://smx:smx@localhost:" + port + "?useFixedDelay=true&delay=5000&pollCommand=test%0D")
+ .to("mock:result");
+ }
+ };
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java
new file mode 100644
index 0000000000000..cd51c6752786e
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentErrorHandlingTest.java
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Test;
+
+public class SshComponentErrorHandlingTest extends SshComponentTestSupport {
+ @Test
+ public void testRedelivery() throws Exception {
+ final String msg = "test\n";
+
+ MockEndpoint mockError = getMockEndpoint("mock:error");
+ mockError.expectedMinimumMessageCount(0);
+
+ MockEndpoint mock = getMockEndpoint("mock:success");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived(msg);
+ mock.expectedHeaderReceived(Exchange.REDELIVERED, true);
+
+ sshd.stop();
+
+ template.sendBody("direct:redeliver", msg);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ errorHandler(deadLetterChannel("mock:error")
+ .maximumRedeliveries(3)
+ .redeliveryDelay(0L) // speedup unit test by not waiting between redeliveries
+ .onRedelivery(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ final Message in = exchange.getIn();
+ final int count = in.getHeader(Exchange.REDELIVERY_COUNTER, Integer.class);
+ final int maxCount = in.getHeader(Exchange.REDELIVERY_MAX_COUNTER, Integer.class);
+
+ log.info("Redelivery count = {}", count);
+
+ // Restart the sshd server before the last redelivery attempt
+ if (count >= (maxCount - 1)) {
+ if (sshd != null) {
+ sshd.start();
+ log.info("Restarting SSHD");
+ }
+ }
+ }
+ }));
+
+ from("direct:redeliver")
+ .tracing()
+ .to("ssh://smx:smx@localhost:" + port)
+ .to("mock:success");
+ }
+ };
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java
new file mode 100644
index 0000000000000..1da5a1befe764
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentProducerTest.java
@@ -0,0 +1,122 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR 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.camel.component.ssh;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.junit.Test;
+
+public class SshComponentProducerTest extends SshComponentTestSupport {
+ @Test
+ public void testProducer() throws Exception {
+ final String msg = "test\n";
+
+ MockEndpoint mock = getMockEndpoint("mock:password");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived(msg);
+
+ template.sendBody("direct:ssh", msg);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testReconnect() throws Exception {
+ final String msg = "test\n";
+
+ MockEndpoint mock = getMockEndpoint("mock:password");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived(msg);
+
+ template.sendBody("direct:ssh", msg);
+
+ assertMockEndpointsSatisfied();
+
+ sshd.stop();
+ sshd.start();
+
+ mock.reset();
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived(msg);
+
+ template.sendBody("direct:ssh", msg);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testRsa() throws Exception {
+ final String msg = "test\n";
+
+ MockEndpoint mock = getMockEndpoint("mock:rsa");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedBodiesReceived(msg);
+
+ template.sendBody("direct:ssh-rsa", msg);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Test
+ public void testConnectionTimeout() throws Exception {
+ final String msg = "test\n";
+
+ MockEndpoint mock = getMockEndpoint("mock:password");
+ mock.expectedMinimumMessageCount(0);
+
+ MockEndpoint mockError = getMockEndpoint("mock:error");
+ mockError.expectedMinimumMessageCount(1);
+
+ sshd.stop();
+ sshd = null;
+
+ template.sendBody("direct:ssh", msg);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ onException(Exception.class)
+ .handled(true)
+ .to("mock:error");
+
+ from("direct:ssh")
+ .to("ssh://smx:smx@localhost:" + port + "?timeout=3000")
+ .to("mock:password");
+
+ SshComponent sshComponent = new SshComponent();
+ sshComponent.setHost("localhost");
+ sshComponent.setPort(port);
+ sshComponent.setUsername("smx");
+ sshComponent.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"}));
+ sshComponent.setKeyType(KeyPairProvider.SSH_RSA);
+
+ getContext().addComponent("ssh-rsa", sshComponent);
+
+ from("direct:ssh-rsa")
+ .to("ssh-rsa:test")
+ .to("mock:rsa");
+ }
+ };
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java
new file mode 100644
index 0000000000000..3a2eb1ddcdd3d
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentTestSupport.java
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.ssh;
+
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+
+public class SshComponentTestSupport extends CamelTestSupport {
+ protected SshServer sshd;
+ protected int port;
+
+ @Override
+ public void setUp() throws Exception {
+ port = AvailablePortFinder.getNextAvailable(22000);
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setPort(port);
+ sshd.setKeyPairProvider(new FileKeyPairProvider(new String[]{"src/test/resources/hostkey.pem"}));
+ sshd.setCommandFactory(new TestEchoCommandFactory());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.setPublickeyAuthenticator(new BogusPublickeyAuthenticator());
+ sshd.start();
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ super.tearDown();
+
+ if (sshd != null) {
+ sshd.stop(true);
+ Thread.sleep(50);
+ }
+ }
+}
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.java
new file mode 100644
index 0000000000000..f412502fcb1ea
--- /dev/null
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/TestEchoCommandFactory.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.camel.component.ssh;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.sshd.server.Command;
+
+public class TestEchoCommandFactory extends EchoCommandFactory {
+ @Override
+ public Command createCommand(String command) {
+ return new TestEchoCommand(command);
+ }
+
+ public static class TestEchoCommand extends EchoCommand {
+ public static CountDownLatch latch = new CountDownLatch(1);
+
+ public TestEchoCommand(String command) {
+ super(command);
+ }
+
+ @Override
+ public void destroy() {
+ if (latch != null) {
+ latch.countDown();
+ }
+ super.destroy();
+ }
+ }
+}
\ No newline at end of file
diff --git a/components/camel-ssh/src/test/resources/dsaprivkey.pem b/components/camel-ssh/src/test/resources/dsaprivkey.pem
new file mode 100644
index 0000000000000..c920b7fc04e23
--- /dev/null
+++ b/components/camel-ssh/src/test/resources/dsaprivkey.pem
@@ -0,0 +1,12 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQDEA7leYDKyJOFJU3h0uPpWN52iTpJk8+IM53Vc/91k7pBIjjka
++MP24BMh+sI2SRhxg2AtvwnzRRBVJWzEA4+tuCI6WukgeDQtSNp3YuWzOMefZ6Wb
+SAk1Y4goZb7nyqV9HZSFNSqUFQRZM10L768VURBlerNqR//GqdVd8bp7lwIVAM39
+h6x2DeXbqUM8iOi01bh5jpLFAoGAEi1oFGFMEZXH/hCX+Y2VE5WvR+fBaoS9WuZl
+3E0wsWPzQhbL13yD+6Htxd3XoQvrHnzyrIgi2AiAmr3mLokQbZ3d92IxEBcNB/0p
+nVi020TXSeD/lWkpk5FRvgBiJ82/LeC2Lj6cssznX73aLUhR0tsSoJoXxas0sQKa
+/UJgq5wCgYAtgeY99J0JxplWGSyGY/1DUpgzhdgpLdDA/o/qIjBEeHXN0QX4Ajoa
+vHggJ2SwNtAxbQedBxqmB3mquFRtpfEP5zGzsVx5HHnljSH8u0SqEoLnYKFpluwh
+tZ/Q3F2NHslXw8Hw+pIaPe4PAINQPAu3U+BknNUkGpLg8zU6h5+B+wIVAKRqeps1
+Xl7MxZcSZp7FnmmmMecB
+-----END DSA PRIVATE KEY-----
diff --git a/components/camel-ssh/src/test/resources/hostkey.pem b/components/camel-ssh/src/test/resources/hostkey.pem
new file mode 100644
index 0000000000000..6b6974c78e606
--- /dev/null
+++ b/components/camel-ssh/src/test/resources/hostkey.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDdfIWeSV4o68dRrKSzFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDP
+jXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHj
+W5q4OOgWhVvj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQIDAQAB
+AoGBANG3JDW6NoP8rF/zXoeLgLCj+tfVUPSczhGFVrQkAk4mWfyRkhN0WlwHFOec
+K89MpkV1ij/XPVzU4MNbQ2yod1KiDylzvweYv+EaEhASCmYNs6LS03punml42SL9
+97tOmWfVJXxlQoLiY6jHPU97vTc65k8gL+gmmrpchsW0aqmZAkEA/c8zfmKvY37T
+cxcLLwzwsqqH7g2KZGTf9aRmx2ebdW+QKviJJhbdluDgl1TNNFj5vCLznFDRHiqJ
+wq0wkZ39cwJBAN9l5v3kdXj21UrurNPdlV0n2GZBt2vblooQC37XHF97r2zM7Ou+
+Lg6MyfJClyguhWL9dxnGbf3btQ0l3KDstxMCQCRaiEqjAfIjWVATzeNIXDWLHXso
+b1kf5cA+cwY+vdKdTy4IeUR+Y/DXdvPWDqpf0C11aCVMohdLCn5a5ikFUycCQDhV
+K/BuAallJNfmY7JxN87r00fF3ojWMJnT/fIYMFFrkQrwifXQWTDWE76BSDibsosJ
+u1TGksnm8zrDh2UVC/0CQFrHTiSl/3DHvWAbOJawGKg46cnlDcAhSyV8Frs8/dlP
+7YGG3eqkw++lsghqmFO6mRUTKsBmiiB2wgLGhL5pyYY=
+-----END RSA PRIVATE KEY-----
diff --git a/components/pom.xml b/components/pom.xml
index 2103f459ff8df..439cad6610d94 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -136,6 +136,7 @@
camel-spring-security
camel-spring-ws
camel-sql
+ camel-ssh
camel-stax
camel-stream
camel-stringtemplate
diff --git a/examples/camel-example-ssh/README.txt b/examples/camel-example-ssh/README.txt
new file mode 100644
index 0000000000000..26e0c61153d0c
--- /dev/null
+++ b/examples/camel-example-ssh/README.txt
@@ -0,0 +1,42 @@
+SSH Example
+=====================
+
+This example shows how use SSH with Camel. It can be run using Maven.
+
+This example is built assuming you have a running Apache ServiceMix container with the default SSH port 8101 and
+username / password of smx/smx.
+
+Running from cmd line outside OSGi container
+============================================
+
+You will need to compile this example first:
+ mvn compile
+
+To run the example using Maven type
+ mvn camel:run
+
+To stop the example hit ctrl + c
+
+
+
+Running inside OSGi container
+=============================
+
+You will need to compile and install this example first:
+ mvn compile install
+
+If using Apache Karaf / Apache ServiceMix you can install this example
+from the shell
+
+ > features:addurl mvn:org.apache.camel/camel-example-ssh//xml/features
+ > features:install camel-example-ssh
+
+If you hit any problems please let us know on the Camel Forums
+ http://camel.apache.org/discussion-forums.html
+
+Please help us make Apache Camel better - we appreciate any feedback you
+may have. Enjoy!
+
+------------------------
+The Camel riders!
+
diff --git a/examples/camel-example-ssh/pom.xml b/examples/camel-example-ssh/pom.xml
new file mode 100644
index 0000000000000..9370c75defb12
--- /dev/null
+++ b/examples/camel-example-ssh/pom.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+ 4.0.0
+
+
+ org.apache.camel
+ examples
+ 2.10-SNAPSHOT
+ ..
+
+
+ camel-example-ssh
+ bundle
+ Camel :: Example :: SSH
+ A simple SSH example which creates a bundle that can be dropped into any OSGi container
+
+
+ org.apache.camel.example.ssh.*
+
+
+
+
+
+ org.apache.camel
+ camel-core
+
+
+ org.apache.camel
+ camel-spring
+
+
+ org.apache.camel
+ camel-ssh
+ ${project.version}
+
+
+ org.apache.mina
+ mina-core
+ 2.0.1
+
+
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j-version}
+
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ org.apache.camel.component.ssh,
+ *
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ attach-artifacts
+ package
+
+ attach-artifact
+
+
+
+
+ target/classes/features.xml
+ xml
+ features
+
+
+
+
+
+
+
+
+
+ org.apache.camel
+ camel-maven-plugin
+ ${project.version}
+
+
+
+
+
+
diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt b/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000000000..6b0b1270ff0ca
--- /dev/null
+++ b/examples/camel-example-ssh/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt b/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000000000..2e215bf2e6b1f
--- /dev/null
+++ b/examples/camel-example-ssh/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Apache Camel distribution. ==
+ =========================================================================
+
+ This product includes software developed by
+ The Apache Software Foundation (http://www.apache.org/).
+
+ Please read the different LICENSE files present in the licenses directory of
+ this distribution.
diff --git a/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml b/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml
new file mode 100644
index 0000000000000..fd75c686cd6f1
--- /dev/null
+++ b/examples/camel-example-ssh/src/main/resources/META-INF/spring/camelContext.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ features:list
+
+
+
+
+
+
+
diff --git a/examples/camel-example-ssh/src/main/resources/features.xml b/examples/camel-example-ssh/src/main/resources/features.xml
new file mode 100644
index 0000000000000..c9058427506b4
--- /dev/null
+++ b/examples/camel-example-ssh/src/main/resources/features.xml
@@ -0,0 +1,26 @@
+
+
+
+ mvn:org.apache.camel.karaf/apache-camel/${project.version}/xml/features
+
+
+ camel-ssh
+ mvn:org.apache.camel/camel-example-ssh/${project.version}
+
+
+
\ No newline at end of file
diff --git a/examples/pom.xml b/examples/pom.xml
index ba9b99f6477b0..3051cfe657461 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -63,6 +63,7 @@
camel-example-spring-ws
camel-example-spring-xquery
camel-example-spring-security
+ camel-example-ssh
camel-example-tracer
diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml
index ea78a26196d12..d47530208b090 100644
--- a/platforms/karaf/features/src/main/resources/features.xml
+++ b/platforms/karaf/features/src/main/resources/features.xml
@@ -667,6 +667,12 @@
camel-core
mvn:org.apache.camel/camel-sql/${project.version}
+
+ camel-core
+ mvn:org.apache.mina/mina-core/2.0.2
+ mvn:org.apache.sshd/sshd-core/0.6.0
+ mvn:org.apache.camel/camel-ssh/${project.version}
+
camel-core
mvn:org.apache.camel/camel-stax/${project.version}