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 implements LogicReloadListener {
public static final int DEFAULT_PORT = 7777;
static Class EVENT_CONSOLE_INPUT_CLASS;
static Class EVENT_CONSOLE_EXPIRED_CLASS;
static Class EVENT_NEW_CONNECTION_CLASS;
static Class EVENT_CONSOLE_DISCONNECT_CLASS;
static Class EVENT_PROMPT_CLASS;
private static final int CHECK_PERIOD_IN_PULSE = 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(CHECK_PERIOD_IN_PULSE, PERIOD_IN_PULSE);
this.port = port;
Core.getLogicLoader().addLogicReloadListener(this);
}
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) throws Exception {
Console console;
int nCons = consoles.size();
if (EVENT_PROMPT_CLASS == null) {
initEventClasses();
}
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_CLASS, 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_CLASS, 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_CLASS, 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_CLASS, 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 {
if (EVENT_PROMPT_CLASS==null) {
initEventClasses();
}
Core.processEvent(EVENT_PROMPT_CLASS, console);
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
}
public synchronized Set consoles() {
return new HashSet(consoles);
}
private static void initEventClasses() throws Exception {
LogicLoadingManager llm = Core.getLogicLoader();
EVENT_CONSOLE_INPUT_CLASS = llm.provideEventClass("console.ConsoleInputEvent");
EVENT_CONSOLE_EXPIRED_CLASS = llm.provideEventClass("console.ConsoleExpiredEvent");
EVENT_NEW_CONNECTION_CLASS = llm.provideEventClass("console.LoginEvent");
EVENT_CONSOLE_DISCONNECT_CLASS = llm.provideEventClass("console.ConnectionLostEvent");
EVENT_PROMPT_CLASS = llm.provideEventClass("console.ShowPrompt");
}
public void onLogicReloading() {
EVENT_CONSOLE_INPUT_CLASS = null;
EVENT_CONSOLE_EXPIRED_CLASS = null;
EVENT_NEW_CONNECTION_CLASS = null;
EVENT_CONSOLE_DISCONNECT_CLASS = null;
EVENT_PROMPT_CLASS = null;
}
}