Skip to content

Commit

Permalink
Refactoring classes to solve the issue
Browse files Browse the repository at this point in the history
  • Loading branch information
jrdalpra committed Dec 30, 2015
1 parent f908536 commit 1186a87
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 102 deletions.
114 changes: 114 additions & 0 deletions src/main/java/com/jcabi/ssh/AbstractSSHShell.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* Copyright (c) 2014-2015, jcabi.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met: 1) Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer. 2) Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution. 3) Neither the name of the jcabi.com nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jcabi.ssh;

import com.jcraft.jsch.Session;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.Validate;

/**
* Common module for any ssh shell.
* @author Jose Volmei Dal Pra Junior ([email protected])
* @version $Id$
* @since 2.0
*/
@ToString
@EqualsAndHashCode(of = { "addr", "port", "login" })
@Getter
@SuppressWarnings({ "PMD.UnusedPrivateField", "PMD.SingularField" })
abstract class AbstractSSHShell implements Shell {

/**
* IP address of the server.
*/
private final transient String addr;

/**
* Port to use.
*/
private final transient int port;

/**
* User name.
*/
private final transient String login;

/**
* Constructor.
* @param adr Address that you want to connect to.
* @param prt Port that you want to reach.
* @param user User that will be used when connecting.
* @throws UnknownHostException when host is unkwon.
*/
public AbstractSSHShell(
final String adr,
final int prt,
final String user) throws UnknownHostException {
this.addr = InetAddress.getByName(adr).getHostAddress();
this.port = prt;
this.login = user;
Validate.matchesPattern(
this.addr,
"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
"Invalid IP address of the server `%s`",
this.addr
);
Validate.notEmpty(user, "user name can't be empty");
}

// @checkstyle ParameterNumberCheck (6 lines)
@Override
public int exec(final String command, final InputStream stdin,
final OutputStream stdout, final OutputStream stderr)
throws IOException {
return new Execution.Default(
command,
stdin,
stdout,
stderr,
this.session()
).exec();
}

/**
* Create and return a session, connected.
* @return JSch session
* @throws IOException If some IO problem inside
*/
protected abstract Session session() throws IOException;

}
60 changes: 8 additions & 52 deletions src/main/java/com/jcabi/ssh/SSH.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
import com.jcraft.jsch.Session;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
Expand All @@ -48,7 +46,6 @@
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.Validate;

/**
* Single SSH Channel.
Expand All @@ -67,39 +64,21 @@
* <p>It is highly recommended to use classes from {@link Shell} interface,
* they will simplify operations.</p>
*
* @todo #21:30min This class has common data, implementation of exec() and
* constructor validations with SSHByPassword class. Common functionality
* should be extracted into a separate module.
* @author Yegor Bugayenko ([email protected])
* @version $Id$
* @since 1.0
* @see <a href="http://www.yegor256.com/2014/09/02/java-ssh-client.html">article by Yegor Bugayenko</a>
*/
@ToString
@EqualsAndHashCode(of = { "addr", "port", "login", "key" })
@EqualsAndHashCode(of = { "key" }, callSuper = true)
@SuppressWarnings("PMD.TooManyMethods")
public final class SSH implements Shell {
public final class SSH extends AbstractSSHShell implements Shell {

/**
* Default SSH port.
*/
public static final int PORT = 22;

/**
* IP address of the server.
*/
private final transient String addr;

/**
* Port to use.
*/
private final transient int port;

/**
* User name.
*/
private final transient String login;

/**
* Private SSH key.
*/
Expand Down Expand Up @@ -198,27 +177,8 @@ public SSH(final InetAddress adr, final int prt,
*/
public SSH(final String adr, final int prt,
final String user, final String priv) throws UnknownHostException {
this.addr = InetAddress.getByName(adr).getHostAddress();
Validate.matchesPattern(
this.addr,
"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
"Invalid IP address of the server `%s`",
this.addr
);
this.login = user;
Validate.notEmpty(this.login, "user name can't be empty");
super(adr, prt, user);
this.key = priv;
this.port = prt;
}

// @checkstyle ParameterNumberCheck (5 lines)
@Override
public int exec(final String command, final InputStream stdin,
final OutputStream stdout, final OutputStream stderr)
throws IOException {
return new Execution.Default(
command, stdin, stdout, stderr, this.session()
).exec();
}

/**
Expand All @@ -230,11 +190,7 @@ public static String escape(final String arg) {
return String.format("'%s'", arg.replace("'", "'\\''"));
}

/**
* Create and return a session, connected.
* @return JSch session
* @throws IOException If some IO problem inside
*/
@Override
@RetryOnFailure(
attempts = Tv.SEVEN,
delay = 1,
Expand All @@ -243,7 +199,7 @@ public static String escape(final String arg) {
randomize = true,
types = IOException.class
)
private Session session() throws IOException {
public Session session() throws IOException {
try {
JSch.setConfig("StrictHostKeyChecking", "no");
JSch.setLogger(new JschLogger());
Expand All @@ -262,14 +218,14 @@ private Session session() throws IOException {
Logger.debug(
this,
"Opening SSH session to %s@%s:%s (%d bytes in RSA key)...",
this.login, this.addr, this.port,
this.getLogin(), this.getAddr(), this.getPort(),
file.length()
);
final Session session = jsch.getSession(
this.login, this.addr, this.port
this.getLogin(), this.getAddr(), this.getPort()
);
session.setServerAliveInterval(
(int) TimeUnit.SECONDS.toMillis((long) Tv.TEN)
(int) TimeUnit.SECONDS.toMillis(Tv.TEN)
);
session.setServerAliveCountMax(Tv.MILLION);
session.connect();
Expand Down
58 changes: 8 additions & 50 deletions src/main/java/com/jcabi/ssh/SSHByPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,10 @@
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.commons.lang3.Validate;

/**
* SSH channel with authentication by password.
Expand All @@ -53,23 +49,8 @@
* @see SSH For SSH channel with authenticaton using private key.
*/
@ToString
@EqualsAndHashCode(of = { "addr", "port", "login", "password" })
public final class SSHByPassword implements Shell {

/**
* IP address of the server.
*/
private final transient String addr;

/**
* Port to use.
*/
private final transient int port;

/**
* User name.
*/
private final transient String login;
@EqualsAndHashCode(of = { "password" }, callSuper = true)
public final class SSHByPassword extends AbstractSSHShell implements Shell {

/**
* User password.
Expand All @@ -86,36 +67,13 @@ public final class SSHByPassword implements Shell {
* @checkstyle ParameterNumberCheck (6 lines)
*/
public SSHByPassword(final String adr, final int prt,
final String user, final String passwd)
final String user, final String passwd)
throws UnknownHostException {
this.addr = InetAddress.getByName(adr).getHostAddress();
Validate.matchesPattern(
this.addr,
"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
"Invalid IP address of the server `%s`",
this.addr
);
this.port = prt;
this.login = user;
Validate.notEmpty(this.login, "user name can't be empty");
super(adr, prt, user);
this.password = passwd;
}

// @checkstyle ParameterNumberCheck (6 lines)
@Override
public int exec(final String command, final InputStream stdin,
final OutputStream stdout, final OutputStream stderr)
throws IOException {
return new Execution.Default(
command, stdin, stdout, stderr, this.session()
).exec();
}

/**
* Create and return a session, connected.
* @return JSch session
* @throws IOException If some IO problem inside
*/
@RetryOnFailure(
attempts = Tv.SEVEN,
delay = 1,
Expand All @@ -124,22 +82,22 @@ public int exec(final String command, final InputStream stdin,
randomize = true,
types = IOException.class
)
private Session session() throws IOException {
public Session session() throws IOException {
try {
JSch.setConfig("StrictHostKeyChecking", "no");
JSch.setLogger(new JschLogger());
final JSch jsch = new JSch();
Logger.debug(
this,
"Opening SSH session to %s@%s:%s (auth with password)...",
this.login, this.addr, this.port
this.getLogin(), this.getAddr(), this.getPort()
);
final Session session = jsch.getSession(
this.login, this.addr, this.port
this.getLogin(), this.getAddr(), this.getPort()
);
session.setPassword(this.password);
session.setServerAliveInterval(
(int) TimeUnit.SECONDS.toMillis((long) Tv.TEN)
(int) TimeUnit.SECONDS.toMillis(Tv.TEN)
);
session.setServerAliveCountMax(Tv.MILLION);
session.connect();
Expand Down

0 comments on commit 1186a87

Please sign in to comment.