/* * Copyright (C) 2008 Manish Pandya, [manish at meetamanish dot com] * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * */ package org.hooliguns.ninja.telnet; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.text.ParseException; /** * A class that starts a socket and provides parsed commands out of strings * received from the socket. It opens socket in a run method, thus running in a * separate thread. It listens for specific commands like 'a' for "abort current * instruction", 'q' for "quit session" and 'shutdown' to "shutdown the telnet * server" and immediately executes them. All other strings are parsed. * * @author Manish Pandya (July 1 2008) * */ public class CommandProcessor implements Runnable, ShutdownListener { /** * The abort current execution command */ public static final String ABORT_COMMAND = "a"; /** * The quit session command */ public static final String QUIT_COMMAND = "q"; /** * The shutdown command string */ public static final String SHUTDOWN_COMMAND = "shutdown"; /** * The abort event listener */ private AbortExecutionListener ael = null; /** * Shutdown event listener */ private ShutdownListener sl = null; /** * The input buffered reader (from the telnet server) */ private BufferedReader in = null; /** * The output buffer to write prompt and parsing error feedback */ private BufferedWriter out = null; /** * A flag indicating a pending shutdown request */ private boolean shutdownRequested = false; /** * A flag to indicate a quit request */ private boolean quitRequested = false; /** * The server socket for command port */ private ServerSocket commandServerSocket = null; /** * The Queue that holds parsed commands for execution */ private CommandQueue commandQueue = null; /** * The command parser implementation of the mod in use */ private CommandParser commandParser = null; /** * Creates an instance of a command processor * * @param ael * the abort execution listener * @param sl * the shutdown request listener * @param commandServerSocket * the TCP server socket that is used to communicate commands and * parse errors * @param commandQueue * the command execution queue * @param commandParser * the parser implementation for the mod in use */ public CommandProcessor(AbortExecutionListener ael, ShutdownListener sl, ServerSocket commandServerSocket, CommandQueue commandQueue, CommandParser commandParser) { super(); this.ael = ael; this.sl = sl; this.commandServerSocket = commandServerSocket; this.commandQueue = commandQueue; this.commandParser = commandParser; } /** * The method that listens to command socket and processes requested commands * till session is quit or shutdown is requested */ public void socketAcceptAndProcessCommand() { if (commandServerSocket != null) { String line = null; try { while (!shutdownRequested) { quitRequested = false; Socket commandSocket = commandServerSocket.accept(); this.in = new BufferedReader(new InputStreamReader(commandSocket .getInputStream())); this.out = new BufferedWriter(new OutputStreamWriter(commandSocket .getOutputStream())); writeAndFlush(">"); while (!shutdownRequested && !quitRequested && (line = in.readLine()) != null) { processCommand(line); if (!shutdownRequested && !quitRequested) { writeAndFlush(">"); } if (quitRequested) { try { in.close(); } catch (IOException ex) { ex.printStackTrace(); } try { out.close(); } catch (IOException ex) { ex.printStackTrace(); } try { commandSocket.close(); } catch (IOException ex) { ex.printStackTrace(); } } } } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException ex) { ex.printStackTrace(); } try { out.close(); } catch (IOException ex) { ex.printStackTrace(); } try { commandServerSocket.close(); } catch (IOException ex) { ex.printStackTrace(); } } } } /** * A method that takes a command string and processes that. It parses and * identifies shutdown, quit or abort requests and notifies proper listeners. * It constructs Command[] out of supplied line and puts them in the command * queue. The put operation blocks if the queue is full. * * @param line * the String that has the commands to be interpreted */ private void processCommand(String line) { if (SHUTDOWN_COMMAND.equals(line)) { sl.shutdown(); } else if (ABORT_COMMAND.equals(line)) { ael.abortExecution(); } else if (QUIT_COMMAND.equals(line)) { quit(); } else { Command[] c; try { c = commandParser.parse(line); } catch (ParseException e) { writelnAndFlush(e.getMessage() + " at charactor " + e.getErrorOffset()); return; } for (Command cmd : c) { try { commandQueue.put(cmd); } catch (InterruptedException e) { e.printStackTrace(); } } } } /* * (non-Javadoc) * * @see org.hooliguns.ninja.telnet.ShutdownListener#shutdown() */ public void shutdown() { shutdownRequested = true; writelnAndFlush("Shutting down.. goodbye!"); } /** * A method that processes quit request and acknowledges by printing * "goodbuy!". */ public void quit() { quitRequested = true; writeAndFlush("goodbye!"); } /** * A write and flush method that prints carrige return and new line at the end * of the message. * * @param message */ private void writelnAndFlush(String message) { writeAndFlush(message + "\r\n"); } /** * A method that writes the message to the command socket and flushes it for * imeediate consumption. * * @param message */ private void writeAndFlush(String message) { try { out.write(message); out.flush(); } catch (IOException e) { e.printStackTrace(); } } /* * (non-Javadoc) * * @see java.lang.Runnable#run() */ public void run() { socketAcceptAndProcessCommand(); } }