/**
*
*/
package net.sf.commons.ssh.impl.j2ssh;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.connection.Channel;
import com.sshtools.j2ssh.connection.ChannelEventListener;
import com.sshtools.j2ssh.connection.ChannelState;
import com.sshtools.j2ssh.session.SessionChannelClient;
import net.sf.commons.ssh.common.Status;
import net.sf.commons.ssh.common.UnexpectedRuntimeException;
import net.sf.commons.ssh.event.AbstractEventProcessor;
import net.sf.commons.ssh.event.events.ClosedEvent;
import net.sf.commons.ssh.event.events.ReadAvailableEvent;
import net.sf.commons.ssh.options.Properties;
import net.sf.commons.ssh.session.AbstractSession;
import net.sf.commons.ssh.session.ShellSession;
import net.sf.commons.ssh.session.ShellSessionPropertiesBuilder;
/**
* @author fob
* @date 28.08.2011
* @since 2.0
*/
public class J2SSHShellSession extends AbstractSession implements ShellSession
{
protected SessionChannelClient session;
/**
* @param properties
*/
public J2SSHShellSession(Properties properties,SshClient connection)
{
super(properties);
try
{
session = connection.openSessionChannel();
}
catch (IOException e)
{
log.error("can't create j2ssh shell session");
throw new UnexpectedRuntimeException(e.getMessage(),e);
}
setContainerStatus(Status.CREATED);
session.addEventListener(new EventNotificator(this));
}
/**
* @see net.sf.commons.ssh.session.Session#isOpened()
*/
@Override
public boolean isOpened()
{
Status status = getContainerStatus();
return session.isOpen() && (status == Status.OPENNED || status == Status.INPROGRESS);
}
/**
* @see net.sf.commons.ssh.common.Closable#isClosed()
*/
@Override
public boolean isClosed()
{
return session.isClosed() && getContainerStatus() == Status.CLOSED;
}
/**
* @see net.sf.commons.ssh.session.ShellSession#getInputStream()
*/
@Override
public InputStream getInputStream() throws IOException
{
return session.getInputStream();
}
/**
* @see net.sf.commons.ssh.session.ShellSession#getOutputStream()
*/
@Override
public OutputStream getOutputStream() throws IOException
{
return session.getOutputStream();
}
/**
* @see net.sf.commons.ssh.session.ShellSession#getErrorStream()
*/
@Override
public InputStream getErrorStream() throws IOException
{
if(ShellSessionPropertiesBuilder.getInstance().isSeparateErrorStream(this))
return session.getStderrInputStream();
else
return session.getInputStream();
}
@Override
public boolean isEOF() throws IOException
{
return session.isRemoteEOF();
}
/**
* @see net.sf.commons.ssh.session.AbstractSession#openImpl()
*/
@Override
protected void openImpl() throws IOException
{
log.trace("openImpl(): open j2ssh shell session");
ShellSessionPropertiesBuilder sspb = ShellSessionPropertiesBuilder.getInstance();
sspb.verify(this);
try
{
boolean isSuccess = session.requestPseudoTerminal(sspb.getTerminalType(this),
sspb.getTerminalCols(this),
sspb.getTerminalRows(this),
sspb.getTerminalWidth(this),
sspb.getTerminalHeight(this),
"");
if(!isSuccess)
throw new IOException("Can't open pseudo terminal");
if(!session.startShell())
throw new IOException("Can't start shell");
}
catch (Exception e)
{
try
{
session.close();
}
catch (Exception e1)
{
log.error("can't close session",e);
}
if(e instanceof RuntimeException)
throw (RuntimeException) e;
if(e instanceof IOException)
throw (IOException)e;
throw new UnexpectedRuntimeException(e.getMessage(),e);
}
}
/**
* @see net.sf.commons.ssh.common.AbstractClosable#closeImpl()
*/
@Override
protected void closeImpl() throws IOException
{
session.close();
ChannelState state = session.getState();
try
{
state.waitForState(ChannelState.CHANNEL_CLOSED);
}
catch (Exception e)
{
log.trace("can't wait for state CLOSED",e);
}
setContainerStatus(Status.CLOSED);
fire(new ClosedEvent(this));
}
private class EventNotificator implements ChannelEventListener
{
private AbstractEventProcessor producer;
/**
* @param producer
*/
public EventNotificator(AbstractEventProcessor producer)
{
super();
this.producer = producer;
}
/**
* @see com.sshtools.j2ssh.connection.ChannelEventListener#onChannelOpen(com.sshtools.j2ssh.connection.Channel)
*/
@Override
public void onChannelOpen(Channel channel)
{
}
/**
* @see com.sshtools.j2ssh.connection.ChannelEventListener#onChannelEOF(com.sshtools.j2ssh.connection.Channel)
*/
@Override
public void onChannelEOF(Channel channel)
{
}
/**
* @see com.sshtools.j2ssh.connection.ChannelEventListener#onChannelClose(com.sshtools.j2ssh.connection.Channel)
*/
@Override
public void onChannelClose(Channel channel)
{
}
/**
* @see com.sshtools.j2ssh.connection.ChannelEventListener#onDataReceived(com.sshtools.j2ssh.connection.Channel, byte[])
*/
@Override
public void onDataReceived(Channel channel, byte[] data)
{
try
{
fire(new ReadAvailableEvent(producer, getInputStream(), false));
}
catch (IOException e)
{
log.error("failed obtain inputStream",e);
}
}
/**
* @see com.sshtools.j2ssh.connection.ChannelEventListener#onDataSent(com.sshtools.j2ssh.connection.Channel, byte[])
*/
@Override
public void onDataSent(Channel channel, byte[] data)
{
}
}
}