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); } }