package main; import io.DataWriter; import io.OAuthRequester; import io.StreamImpl; import java.io.IOException; import java.util.Arrays; import java.util.NoSuchElementException; import java.util.Scanner; import mining.Stream; import mining.TwitterApi; import org.json.JSONObject; import provider.ExceptionListener; import provider.ResultListener; import utils.Configuration; /** * Provides an interactive shell where requests can be made and displayed. */ public class TweetShell implements TwitterApi.PinSupplier { private final Scanner scanner = new Scanner(System.in); private TwitterApi api_cached; private Stream stream_cached; private TwitterApi getApi() throws IOException { if (api_cached == null) { api_cached = TwitterApi.getOAuth(this); } return api_cached; } private Stream getStream() throws IOException { if (stream_cached == null) { OAuthRequester requester = (OAuthRequester) getApi().getRequester(); StreamHandler handler = new StreamHandler(); stream_cached = new StreamImpl(requester); StreamImpl streamObserver = (StreamImpl) stream_cached; streamObserver.setExceptionListener(handler); streamObserver.setResultListener(new StreamHandler()); } return stream_cached; } private class StreamHandler implements ResultListener, ExceptionListener { @Override public void exceptionGenerated(Exception ex) { System.err.println("Stream closed due to " + ex); } @Override public void tweetGenerated(JSONObject obj) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public void profileGenerated(JSONObject obj) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } } @Override public String requestPin(String url) throws IOException { System.err.println(url); System.err.println("Please open the above URL and enter PIN:"); return scanner.nextLine(); } private void printPrompt() { if (stream_cached == null) { System.out.print("$ "); } else { System.out.print("€ "); } } /** * Processes commands from stdin until the exit command is received or EOF. */ public void process_forever() { System.err.println("Entering interactive shell, type 'help' for help " + "or 'exit' to leave."); // print prompt for reading first command printPrompt(); while (scanner.hasNextLine()) { String line = scanner.nextLine().trim(); String[] args = line.split("\\s+", 2); if (!args[0].isEmpty()) { // non-empty command, let's see whether it makes sense? if (!execute(args)) { // requested to terminate break; } } // print prompt for reading next line printPrompt(); } } /** * Executes a command with optional parameters. * * @param args An array with the first argument containing the command with * optional parameters in following arguments. * @return true if more commands are allowed to be executed, false * otherwise. */ public boolean execute(String[] args) { try { Command command = Command.fromString(args[0]); String[] params = Arrays.copyOfRange(args, 1, args.length); execute(command, params); } catch (IllegalArgumentException ex) { System.err.println(ex.getMessage()); } catch (IOException ex) { System.err.println("Command " + args[0] + " failed with " + ex); ex.printStackTrace(); } catch (NoSuchElementException ex) { // thrown by the "exit" command to signal exit return false; } // another satisfied customer, next! return true; } enum Command { add("Adds a keyword to search", 1), del("Deletes a keyword from search", 1), commit("Activate the stream or apply the stream keyword changes"), close("Close the stream"), test(""), exit("Returns to shell"), help("Get help"), target("Set output target: {file, shell}."); private final String description; private final int paramCount; Command(String description) { this.description = description; this.paramCount = 0; } Command(String description, int paramCount) { this.description = description; this.paramCount = paramCount; } public String getDescription() { return description; } public int getParamCount() { return paramCount; } public static Command fromString(String command) { for (Command cmd : values()) { if (cmd.name().equals(command)) { return cmd; } } throw new IllegalArgumentException("Unrecognized command. Hint: help"); } }; private final String[] HELP = new String[]{ "Interactive TweetShell", "", "Available commands:" }; private void execute(Command command, String[] params) throws IOException { if (params.length < command.getParamCount()) { throw new IllegalArgumentException("Expected " + command.getParamCount() + " parameters, got only " + params.length); } switch (command) { case add: getStream().watchKeyword(params[0]); break; case del: getStream().unwatchKeyword(params[0]); break; case commit: getStream().commit(); break; case close: getStream().close(); break; case test: getStream().poll(); break; case help: for (String line : HELP) { System.out.println(line); } for (Command cmd : Command.values()) { System.out.printf(" %-10s", cmd.name()); if (!cmd.getDescription().isEmpty()) { System.out.print(" " + cmd.getDescription()); } if (cmd.getParamCount() == 1) { System.out.print(" (1 arg)"); } else if (cmd.getParamCount() > 1) { System.out.printf(" (%d args)", cmd.getParamCount()); } System.out.println(); } break; case exit: throw new NoSuchElementException(); case target: StreamImpl stream = (StreamImpl) getStream(); ResultListener oldListener = stream.getResultListener(); if (oldListener instanceof DataWriter) { ((DataWriter) oldListener).close(); } switch (params[0]) { case "file": if (!(oldListener instanceof DataWriter)) { Configuration config = Configuration.getConfig(); String profilesFilename = config.getProperty(DataWriter.CFG_PROFILE_FILENAME); String tweetsFilename = config.getProperty(DataWriter.CFG_TWEETS_FILENAME); stream.setResultListener(new DataWriter(profilesFilename, tweetsFilename)); // save the changes to the config. config.save(); } break; case "shell": if (!(oldListener instanceof StreamHandler)) { stream.setResultListener(new StreamHandler()); } break; } break; default: throw new AssertionError(command.name()); } } ; }