package org.foo.shell.telnet;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import org.foo.shell.Binding;
import org.foo.shell.Command;
import org.foo.shell.Shell;
public class TelnetBinding implements Runnable, Binding {
private final ServerSocket m_socket;
private final Command m_command;
private final int m_maxConnections;
private final List<StoppableShellThread> m_threads = new ArrayList<StoppableShellThread>();
private Thread m_thread = new Thread(this);
public TelnetBinding(Command command, ServerSocket socket, int maxConnections) {
m_command = command;
m_socket = socket;
m_maxConnections = maxConnections;
}
public void run() {
while (!Thread.interrupted()) {
final Socket socket;
try {
socket = m_socket.accept();
} catch (IOException ex) {
if (Thread.interrupted()) {
break;
}
throw new RuntimeException(ex);
}
synchronized (m_threads) {
if (m_threads.size() >= m_maxConnections) {
try {
socket.close();
} catch (IOException e) {
// Ignore
}
continue;
}
}
Shell shell;
try {
shell = new Shell(m_command, new BufferedReader(new InputStreamReader(socket.getInputStream())),
new PrintStream(socket.getOutputStream()), new PrintStream(socket.getOutputStream()));
} catch (IOException e) {
e.printStackTrace();
try {
socket.close();
} catch (IOException ex) {
// Ignore
}
continue;
}
StoppableShellThread thread = new StoppableShellThread(shell, socket);
thread.start();
}
List<StoppableShellThread> threads;
synchronized (m_threads) {
threads = new ArrayList<StoppableShellThread>(m_threads);
}
for (StoppableShellThread thread : threads) {
try {
thread.stopAndWait();
} catch (InterruptedException e) {
// Ignore
}
}
Thread.currentThread().interrupt();
}
public void start() {
m_thread.start();
}
public void stop() throws InterruptedException {
m_thread.interrupt();
try {
m_socket.close();
} catch (IOException e) {
// Ignore
}
m_thread.join();
}
private final class StoppableShellThread extends Thread {
private final Socket m_socket;
public StoppableShellThread(Shell shell, Socket socket) {
super(shell);
m_socket = socket;
}
public void start() {
synchronized (m_threads) {
m_threads.add(this);
}
super.start();
}
void stopAndWait() throws InterruptedException {
if (!isAlive()) {
return;
}
interrupt();
try {
m_socket.close();
} catch (IOException e) {
// Ignore
}
join();
}
public void run() {
try {
super.run();
} finally {
synchronized (m_threads) {
m_threads.remove(this);
}
}
}
}
}