/******************************************************************************
* Copyright (c) 2008 g-Eclipse consortium
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Initial development of the original code was made for
* project g-Eclipse founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributor(s):
* UCY (http://www.cs.ucy.ac.cy)
* - Harald Gjermundrod (harald@cs.ucy.ac.cy)
*
*****************************************************************************/
package eu.geclipse.batch;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import org.eclipse.jsch.core.IJSchService;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import eu.geclipse.core.ICoreProblems;
import eu.geclipse.core.ICoreSolutions;
import eu.geclipse.core.reporting.IProblem;
import eu.geclipse.core.reporting.ISolution;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.core.reporting.ReportingPlugin;
import eu.geclipse.core.portforward.ForwardType;
import eu.geclipse.core.portforward.IForward;
import eu.geclipse.batch.internal.Activator;
/**
* Class used to establish an ssh connection to a remote server.
*/
public class SSHConnection {
private Session session = null;
private ISSHConnectionInfo userInfo;
/**
* Creates a new SSH session using the specified ssh connection information.
*
* @param sshConnectionInfo the connection information describing the ssh
* session.
* @param forwards list of port forwards to create.
* @throws ProblemException If the ssh connection cannot be established
*/
public void createSession( final ISSHConnectionInfo sshConnectionInfo,
final List<IForward> forwards )
throws ProblemException
{
try {
IJSchService service = Activator.getDefault().getJSchService();
if( service == null ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( IBatchProblems.GET_SSH_SERVICE_FAILED,
null,
null,
Activator.PLUGIN_ID );
throw new ProblemException( problem );
}
this.userInfo = sshConnectionInfo;
this.session = service.createSession( this.userInfo.getHostname(),
this.userInfo.getPort(),
this.userInfo.getUsername() );
this.session.setUserInfo( this.userInfo );
if( null != forwards ) {
for( IForward forward : forwards ) {
if( ForwardType.LOCAL == forward.getType() ) {
this.session.setPortForwardingL( forward.getBindPort(),
forward.getHostname(),
forward.getPort() );
} else {
this.session.setPortForwardingR( forward.getBindPort(),
forward.getHostname(),
forward.getPort() );
}
}
}
this.session.connect();
} catch( JSchException exception ) {
// The user wanted to cancel, so ignore the exception
if( !sshConnectionInfo.getCanceledPWValue() ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( IBatchProblems.LOGIN_FAILED,
null,
exception,
Activator.PLUGIN_ID );
ISolution solution;
solution = ReportingPlugin.getReportingService()
.getSolution( IBatchSolutions.CHECK_USERNAME_AND_PASSWORD, null );
problem.addSolution( solution );
solution = ReportingPlugin.getReportingService()
.getSolution( IBatchSolutions.CHECK_SSH_SERVER_CONFIG, null );
problem.addSolution( solution );
throw new ProblemException( problem );
}
} catch( Exception exception ) {
Activator.logException( exception );
}
}
/**
* Tears down the established SSH session .
*/
public void endSession() {
if( null != this.session )
this.session.disconnect();
}
/**
* Test if the session to the server is established.
*
* @return Returns <code>true</code> if the session is established,
* <code>false</code> otherwise.
*/
public boolean isSessionActive() {
boolean status = false;
if( null != this.session ) {
status = this.session.isConnected();
}
return status;
}
/**
* Execute a command on the remote host and returns the output.
*
* @param command The command to be executed on the remote host.
* @return Returns the output of the executed command if executed
* successfully, if no output of the successfully executed command
* <code>null</code> is returned.
* @throws ProblemException If the command is not successfully executed.
*/
/**
* Execute a command on the remote host and returns the output.
*
* @param command The command to be executed on the remote host.
* @return Returns the output of the executed command if executed
* successfully, if no output of the successfully executed command
* <code>null</code> is returned.
* @throws ProblemException If the command is not successfully executed.
*/
public String execCommand( final String command ) throws ProblemException {
return execCommand( command, null );
}
/**
* Execute a command on the remote host and returns the output.
*
* @param command The command to be executed on the remote host.
* @param stdin
* @return Returns the output of the executed command if executed
* successfully, if no output of the successfully executed command
* <code>null</code> is returned.
*
* @throws ProblemException If the command is not successfully executed.
*/
public String execCommand( final String command, final InputStream stdin )
throws ProblemException
{
String line;
Channel channel = null;
InputStream stdout = null;
InputStream stderr = null;
String result = ""; //$NON-NLS-1$
String errResult = ""; //$NON-NLS-1$
int exitStatus = -1;
BufferedReader stdoutReader = null;
BufferedReader stderrReader = null;
// We throw exception if we don't have a session
if( !this.isSessionActive() ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( ICoreProblems.NET_CONNECTION_FAILED,
null,
null,
Activator.PLUGIN_ID );
ISolution solution;
solution = ReportingPlugin.getReportingService()
.getSolution( ICoreSolutions.NET_CHECK_INTERNET_CONNECTION, null );
problem.addSolution( solution );
throw new ProblemException( problem );
}
try {
channel = this.session.openChannel( "exec" ); //$NON-NLS-1$
( ( ChannelExec )channel ).setCommand( command );
channel.setInputStream( stdin );
stdout = channel.getInputStream();
stderr = channel.getExtInputStream();
channel.connect();
stdoutReader = new BufferedReader( new InputStreamReader( stdout ) );
stderrReader = new BufferedReader( new InputStreamReader( stderr ) );
// Make sure that the command is executed before we exit
while( !channel.isClosed() ) {
line = stdoutReader.readLine();
while( null != line ) {
result = result + line + '\n';
line = stdoutReader.readLine();
}
line = stderrReader.readLine();
while( null != line ) {
errResult = errResult + line + '\n';
line = stderrReader.readLine();
}
try {
Thread.sleep( 1000 );
} catch( Exception ee ) {
// Nothing to do here
}
}
// Read what is left after the channel is closed
line = stdoutReader.readLine();
while( null != line ) {
result = result + line + '\n';
line = stdoutReader.readLine();
}
line = stderrReader.readLine();
while( null != line ) {
errResult = errResult + line + '\n';
line = stderrReader.readLine();
}
exitStatus = channel.getExitStatus();
channel.disconnect();
} catch( JSchException jschExc ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( ICoreProblems.NET_CONNECTION_FAILED,
null,
jschExc,
Activator.PLUGIN_ID );
ISolution solution;
solution = ReportingPlugin.getReportingService()
.getSolution( ICoreSolutions.NET_CHECK_INTERNET_CONNECTION, null );
problem.addSolution( solution );
solution = ReportingPlugin.getReportingService()
.getSolution( IBatchSolutions.CHECK_USERNAME_AND_PASSWORD, null );
problem.addSolution( solution );
solution = ReportingPlugin.getReportingService()
.getSolution( ICoreSolutions.NET_CHECK_FIREWALL, null );
problem.addSolution( solution );
throw new ProblemException( problem );
} catch( IOException ioExc ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( IBatchProblems.CONNECTION_IO_ERROR,
null,
ioExc,
Activator.PLUGIN_ID );
ISolution solution = ReportingPlugin.getReportingService()
.getSolution( ICoreSolutions.NET_CHECK_INTERNET_CONNECTION, null );
problem.addSolution( solution );
throw new ProblemException( problem );
} finally {
if( null != stdoutReader ) {
try {
stdoutReader.close();
} catch( IOException e ) {
// Ignore this exception
}
}
if( null != stderrReader ) {
try {
stderrReader.close();
} catch( IOException e ) {
// Ignore this exception
}
}
}
// Was the command executed successfully
if( ( 0 != exitStatus || 0 < errResult.length() ) && 0 == result.length() )
{
if( 0 < errResult.length() ) {
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( IBatchProblems.COMMAND_FAILED,
errResult,
null,
Activator.PLUGIN_ID );
throw new ProblemException( problem );
}
IProblem problem;
problem = ReportingPlugin.getReportingService()
.getProblem( IBatchProblems.COMMAND_FAILED,
null,
null,
Activator.PLUGIN_ID );
throw new ProblemException( problem );
}
// If no output
if( 0 == result.length() )
result = null;
return result;
}
}