package example; import com.caucho.util.L10N; import java.util.logging.Logger; import java.util.logging.Level; import com.caucho.vfs.ReadStream; import java.io.IOException; import java.util.HashMap; /** * Parse a request made using the magic8ball protocol, returning * appropriate objects that are instances of AbstractCommand. * * This class is both a parser and a command factory. */ public class Parser { static protected final Logger log = Logger.getLogger(Parser.class.getName()); static final L10N L = new L10N(Parser.class); // set in init() for each new parse private ReadStream _readStream; String _error; // parsing buffer private StringBuffer _buffer = new StringBuffer(); // commands private HashMap _commands = new HashMap(); public Parser() { _commands.put("set-prophet",new SetProphetCommand()); _commands.put("ask",new AskCommand()); } public void init(ReadStream readStream) { _readStream = readStream; _error = null; } /** * Parse one command out of the ReadStream. * Once the last command is encountered, null is returned. * * @return null if there were no more commands to parse, or there is a parse * error. */ public AbstractCommand nextCommand() throws IOException { String cmd = parseToken(); if (cmd == null) { return null; } AbstractCommand command = (AbstractCommand) _commands.get(cmd.toLowerCase(Locale.ENGLISH)); if (command == null) { _error = "Unknown command `" + cmd + "'"; } else { command.parse(this); if (command.isError()) { _error = command.getError(); command = null; } } return command; } public boolean isError() { return _error != null; } public String getError() { return _error; } /** * @return true if ch is an indication that the end-of-stream was reached */ boolean isEOS(int ch) { return ch < 0; } /** * @return true if ch is a whitespace character or end-of-stream indicator */ boolean isWhitespace(int ch) { return isEOS(ch) || Character.isWhitespace((char) ch); } /** * Eat whitespace characters out of readStream * * @return the first non-whitespace character (which * is still in the _readStream), or -1 if end of stream encountered. */ int eatWhitespace() throws IOException { int ch; while (!isEOS(ch = _readStream.read())) { if (!isWhitespace(ch)) { _readStream.unread(); break; } } return ch; } /** * Parse optional whitespace then a token containing no whitespace. * * @return the token, or null if there are no tokens left on the stream */ String parseToken() throws IOException { String token = null; int ch = eatWhitespace(); if (ch >= 0) { _buffer.setLength(0); while (!isEOS(ch = _readStream.read())) { if (isWhitespace(ch)) { _readStream.unread(); break; } _buffer.append((char)ch); } token = _buffer.toString(); } return token; } }