package net.sourceforge.pain.network.console;
import net.sourceforge.pain.*;
import net.sourceforge.pain.network.console.telnet.*;
import net.sourceforge.pain.util.*;
import java.util.*;
public final class ConsoleManager extends PeriodOfTimeListener {
public static final int DEFAULT_PORT = 7777;
private static final String EVENT_CONSOLE_INPUT = "console.ConsoleInputEvent";
private static final String EVENT_CONSOLE_EXPIRED = "console.ConsoleExpiredEvent";
private static final String EVENT_NEW_CONNECTION = "console.LoginEvent";
private static final String EVENT_CONSOLE_DISCONNECT = "console.ConnectionLostEvent";
public static final String EVENT_PROMPT = "console.ShowPrompt";
private static final int PERIOD = 10;
private ArrayList consoles = new ArrayList();
private TelnetConsoleServer server = null;
private int port = DEFAULT_PORT;
public ConsoleManager() {
this(DEFAULT_PORT);
}
public ConsoleManager(int port) {
super(PERIOD, PERIOD_IN_PULSE);
this.port = port;
}
public void init() {
if (server != null) {
throw new RuntimeException("CONSOLE_MANAGER:already inited");
}
server = new TelnetConsoleServer(port);
}
protected synchronized Console register(ConsoleAdapter adapter) {
Console console = new Console(adapter);
consoles.add(console);
return console;
}
protected synchronized void onPeriod(int time) {
Console console;
int nCons = consoles.size();
for (int i = 0; i < nCons; i++) {
console = (Console) consoles.get(i);
boolean wasPrompt = false;
if (console.state == Console.STATE_ACTIVE) {
if (console.input.size() > 0) {
try {
console.newLineProcessingStarted = true;
Core.processEvent(EVENT_CONSOLE_INPUT, console);
} catch (Exception e) {
Log.error(e);
console.popInputLine();// removing this error line from out queue
}
if (console.state == Console.STATE_ACTIVE) { // Note: console could be marked inactive during event processing!
console.expireTime = time + Console.MAX_INACTIVE_TIME;
if (console.isCommandMode()) {
actPrompt(console);
wasPrompt = true;
if (console.input.size() > 0 && console.isCommandMode()) {
console.out(ConsoleAdapter.NEW_LINE);
}
}
}
} else {
if (time > console.expireTime) {
try {
Core.processEvent(EVENT_CONSOLE_EXPIRED, console);
} catch (Exception e) { // if error occured we will force to close console
Log.error(e.getMessage(), e);
} finally {
if (console.state != Console.STATE_SYSTEM_CLOSED) {
closeConsole(console);
}
}
}
}
if (console.state == Console.STATE_ACTIVE) {
if (console.hasBufferedOutput) {
if (!wasPrompt && console.isCommandMode()) {
actPrompt(console);
}
console.flushOutput();
}
}
} else if (console.state == Console.STATE_NEW) {
try {
Core.processEvent(EVENT_NEW_CONNECTION, console);
} catch (Exception e) {
Log.error(e);
}
console.expireTime = time + Console.MAX_INACTIVE_TIME;
console.state = Console.STATE_ACTIVE;
} else if (console.state == Console.STATE_SYSTEM_CLOSED) {
if (console.adapter != null) { // if was not closed remotely (disconnected)
console.adapter.forceClose();
}
consoles.remove(i);
i--;
nCons--;
} else if (console.state == Console.STATE_REMOTE_CLOSED_1) {
console.state = Console.STATE_REMOTE_CLOSED_2;
try {
Core.processEvent(EVENT_CONSOLE_DISCONNECT, console);
} catch (Exception e) {
Log.error(e.getMessage(), e);
closeConsole(console);
}
} else {
// we do nothing with REMOTE closed consoles here
// system MUST close it from it's side -> console should become STATE_SYSTEM_CLOSED!!
}
}
}
public static synchronized void closeConsole(Console console) {
Log.debug("CONSOLE_MANAGER:manual close!");
if (console.state == Console.STATE_NEW) {
// This state is possible since we allow
// to get a consoles Set copy by consoles() method for outer code
console.flushOutput();
} else if (console.state == Console.STATE_ACTIVE) {
console.flushOutput();
} else {
// console also could have STATE_REMOTE_CLOSE_2 here
// we should not do any special in this case
}
console.state = Console.STATE_SYSTEM_CLOSED;
}
protected synchronized void onRemoteClose(Console console) {
Log.debug("CONSOLE_MANAGER:remote close!");
if (console.state == Console.STATE_NEW) {
consoles.remove(console);
} else if (console.state == Console.STATE_ACTIVE) {
console.adapter = null;
console.state = Console.STATE_REMOTE_CLOSED_1;
}
}
private static void actPrompt(Console console) {
try {
Core.processEvent(ConsoleManager.EVENT_PROMPT, console);
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
}
public synchronized Set consoles() {
return new HashSet(consoles);
}
}