Skip to content

Commit

Permalink
Make Execution an interface; add @todo for extracting common module f…
Browse files Browse the repository at this point in the history
…rom SSH and SSHByPassword
  • Loading branch information
gvlasov committed Jun 22, 2015
1 parent 78958b3 commit 3fa89b1
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 96 deletions.
202 changes: 109 additions & 93 deletions src/main/java/com/jcabi/ssh/Execution.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,119 +39,135 @@
import java.util.concurrent.TimeUnit;

/**
* Execution of a command in an SSH session.
* @author Georgy Vlasov ([email protected])
* Execution of a single command.
* @author Georgy Vlasov ([email protected])
* @version $Id$
* @since 1.4
*/
final class Execution {
public interface Execution {
/**
* Command.
*/
private final transient String command;

/**
* Stdin.
* Executes some command.
* @return Return code of the command.
* @throws IOException If fails
*/
private final transient InputStream stdin;
int exec() throws IOException;

/**
* Stdout.
* Execution of a command in an SSH session.
* @author Georgy Vlasov ([email protected])
* @version $Id$
* @since 1.4
*/
private final transient OutputStream stdout;
final class Default implements Execution {
/**
* Command.
*/
private final transient String command;

/**
* Stderr.
*/
private final transient OutputStream stderr;
/**
* Stdin.
*/
private final transient InputStream stdin;

/**
* Session.
*/
private final transient Session session;
/**
* Stdout.
*/
private final transient OutputStream stdout;

/**
* Uses an SSH session to execute a single command and disconnect
* immediately.
* @param cmd Command
* @param input Stdin (will be closed)
* @param out Stdout (will be closed)
* @param err Stderr (will be closed)
* @param sess SSH session (will be disconnected)
* @checkstyle ParameterNumberCheck (6 lines)
*/
Execution(final String cmd, final InputStream input,
final OutputStream out, final OutputStream err,
final Session sess) {
this.command = cmd;
this.stdin = input;
this.stdout = out;
this.stderr = err;
this.session = sess;
}
/**
* Stderr.
*/
private final transient OutputStream stderr;

/**
* Execute {@link #command} in {@link #session}.
* @return Exit code
* @throws IOException If fails
*/
public int exec() throws IOException {
try {
try {
final ChannelExec channel = ChannelExec.class.cast(
this.session.openChannel("exec")
);
channel.setErrStream(this.stderr, false);
channel.setOutputStream(this.stdout, false);
channel.setInputStream(this.stdin, false);
channel.setCommand(this.command);
channel.connect();
Logger.info(this, "$ %s", this.command);
return this.exec(channel);
} finally {
this.session.disconnect();
}
} catch (final JSchException ex) {
throw new IOException(ex);
}
}
/**
* Session.
*/
private final transient Session session;

/**
* Exec this channel and return its exit code.
* @param channel The channel to exec
* @return Exit code (zero in case of success)
* @throws IOException If fails
*/
private int exec(final ChannelExec channel) throws IOException {
try {
return this.code(channel);
} finally {
channel.disconnect();
/**
* Uses an SSH session to execute a single command and disconnect
* immediately.
* @param cmd Command
* @param input Stdin (will be closed)
* @param out Stdout (will be closed)
* @param err Stderr (will be closed)
* @param sess SSH session (will be disconnected)
* @checkstyle ParameterNumberCheck (6 lines)
*/
Default(final String cmd, final InputStream input,
final OutputStream out, final OutputStream err,
final Session sess) {
this.command = cmd;
this.stdin = input;
this.stdout = out;
this.stderr = err;
this.session = sess;
}
}

/**
* Wait until it's done and return its code.
* @param exec The channel
* @return The exit code
* @throws IOException If some IO problem inside
*/
@SuppressWarnings("PMD.AvoidCatchingGenericException")
private int code(final ChannelExec exec) throws IOException {
while (!exec.isClosed()) {
/**
* Execute {@link #command} in {@link #session}.
* @return Exit code
* @throws IOException If fails
*/
@Override
public int exec() throws IOException {
try {
this.session.sendKeepAliveMsg();
// @checkstyle IllegalCatch (1 line)
} catch (final Exception ex) {
try {
final ChannelExec channel = ChannelExec.class.cast(
this.session.openChannel("exec")
);
channel.setErrStream(this.stderr, false);
channel.setOutputStream(this.stdout, false);
channel.setInputStream(this.stdin, false);
channel.setCommand(this.command);
channel.connect();
Logger.info(this, "$ %s", this.command);
return this.exec(channel);
} finally {
this.session.disconnect();
}
} catch (final JSchException ex) {
throw new IOException(ex);
}
}

/**
* Exec this channel and return its exit code.
* @param channel The channel to exec
* @return Exit code (zero in case of success)
* @throws IOException If fails
*/
private int exec(final ChannelExec channel) throws IOException {
try {
TimeUnit.SECONDS.sleep(1L);
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
return this.code(channel);
} finally {
channel.disconnect();
}
}

/**
* Wait until it's done and return its code.
* @param exec The channel
* @return The exit code
* @throws IOException If some IO problem inside
*/
@SuppressWarnings("PMD.AvoidCatchingGenericException")
private int code(final ChannelExec exec) throws IOException {
while (!exec.isClosed()) {
try {
this.session.sendKeepAliveMsg();
// @checkstyle IllegalCatch (1 line)
} catch (final Exception ex) {
throw new IOException(ex);
}
try {
TimeUnit.SECONDS.sleep(1L);
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IOException(ex);
}
}
return exec.getExitStatus();
}
return exec.getExitStatus();
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/jcabi/ssh/SSH.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
* <p>It is highly recommended to use classes from {@link Shell} interface,
* they will simplify operations.</p>
*
* @todo 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
Expand Down Expand Up @@ -213,7 +216,7 @@ public SSH(final String adr, final int prt,
public int exec(final String command, final InputStream stdin,
final OutputStream stdout, final OutputStream stderr)
throws IOException {
return new Execution(
return new Execution.Default(
command, stdin, stdout, stderr, this.session()
).exec();
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/jcabi/ssh/SSHByPassword.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

/**
* SSH channel with authentication by password.
* @author Georgy Vlasov ([email protected])
* @author Georgy Vlasov ([email protected])
* @version $Id$
* @since 1.4
* @see SSH For SSH channel with authenticaton using private key.
Expand Down Expand Up @@ -105,7 +105,7 @@ public SSHByPassword(final String adr, final int prt,
public int exec(final String command, final InputStream stdin,
final OutputStream stdout, final OutputStream stderr)
throws IOException {
return new Execution(
return new Execution.Default(
command, stdin, stdout, stderr, this.session()
).exec();
}
Expand Down

0 comments on commit 3fa89b1

Please sign in to comment.