package com.jediterm.terminal;
import com.jediterm.terminal.emulator.Emulator;
import com.jediterm.terminal.emulator.JediEmulator;
import org.apache.log4j.Logger;
import java.awt.*;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Runs terminal emulator. Manages threads to send response.
*
* @author traff
*/
public class TerminalStarter implements TerminalOutputStream {
private static final Logger LOG = Logger.getLogger(TerminalStarter.class);
private final Emulator myEmulator;
private final Terminal myTerminal;
private final TtyChannel myTtyChannel;
private final TtyConnector myTtyConnector;
private final ExecutorService myEmulatorExecutor = Executors.newSingleThreadExecutor();
public TerminalStarter(final Terminal terminal, final TtyConnector ttyConnector) {
myTtyConnector = ttyConnector;
myTtyChannel = createTtyChannel();
myTerminal = terminal;
myTerminal.setTerminalOutput(this);
myEmulator = createEmulator(myTtyChannel, this, terminal);
}
protected JediEmulator createEmulator(TtyChannel channel, TerminalOutputStream stream, Terminal terminal) {
return new JediEmulator(channel, stream, terminal);
}
private TtyChannel createTtyChannel() {
return new TtyChannel(myTtyConnector); //TODO: streams can be moved to ttyChanel, so encoding change
//can be implemented - just recreate channel and that's it
}
private void execute(Runnable runnable) {
if (!myEmulatorExecutor.isShutdown()) {
myEmulatorExecutor.execute(runnable);
}
}
public void start() {
try {
while (!Thread.currentThread().isInterrupted() && myEmulator.hasNext()) {
myEmulator.next();
}
}
catch (final InterruptedIOException e) {
LOG.info("Terminal exiting");
}
catch (final Exception e) {
if (!myTtyChannel.isConnected()) {
myTerminal.disconnected();
return;
}
LOG.error("Caught exception in terminal thread", e);
}
}
public byte[] getCode(final int key) {
return myTerminal.getCodeForKey(key);
}
public void postResize(final Dimension dimension, final RequestOrigin origin) {
execute(new Runnable() {
@Override
public void run() {
final Dimension pixelSize;
synchronized (myTerminal) {
pixelSize = myTerminal.resize(dimension, origin);
}
myTtyChannel.postResize(dimension, pixelSize);
}
});
}
@Override
public void sendBytes(final byte[] bytes) {
execute(new Runnable() {
@Override
public void run() {
try {
myTtyChannel.sendBytes(bytes);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
@Override
public void sendString(final String string) {
execute(new Runnable() {
@Override
public void run() {
try {
myTtyChannel.sendString(string);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
public void close() {
execute(new Runnable() {
@Override
public void run() {
try {
myTtyConnector.close();
}
catch (Exception e) {
LOG.error("Error closing terminal", e);
}
finally {
myEmulatorExecutor.shutdown();
}
}
});
}
}