/** * This file is part of CloudML [ http://cloudml.org ] * * Copyright (C) 2012 - SINTEF ICT * Contact: Franck Chauvel <franck.chauvel@sintef.no> * * Module: root * * CloudML 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 3 of * the License, or (at your option) any later version. * * CloudML 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 CloudML. If not, see * <http://www.gnu.org/licenses/>. */ package org.cloudml.ui.shell; import java.io.FileNotFoundException; import java.io.IOException; import org.cloudml.facade.CloudML; import org.cloudml.facade.commands.CloudMlCommand; import org.cloudml.ui.shell.commands.Script; import org.cloudml.ui.shell.commands.ShellCommand; import org.cloudml.ui.shell.commands.ShellCommandHandler; import org.cloudml.ui.shell.configuration.Command; import org.cloudml.ui.shell.configuration.Configuration; import org.cloudml.ui.shell.configuration.Loader; import org.cloudml.ui.shell.terminal.Formatter; import org.cloudml.ui.shell.terminal.InputDevice; import org.cloudml.ui.shell.terminal.OutputDevice; import static org.cloudml.ui.shell.terminal.Message.*; import static org.cloudml.ui.shell.terminal.Color.*; import static org.cloudml.ui.shell.util.dbc.Contracts.*; import static org.hamcrest.Matchers.*; /** * The CloudML Shell * * It allows the user to interact with the models and, in turn, with the * application deployed in the Cloud. This shell is based on the well-known * "command pattern": the input of the user is first parsed to get a Command * object, which can be stored or execute, or forwarded to the cloudML facade. * */ public class Shell implements ShellCommandHandler { private final CloudML proxy; private final Configuration configuration; private final History history; private final InputDevice input; private final Formatter output; private final Mailbox mailbox; private boolean running; public Shell(InputDevice input, OutputDevice output, CloudML proxy) { require(proxy, is(not(nullValue()))); this.proxy = proxy; require(input, is(not(nullValue()))); this.input = input; require(output, is(not(nullValue()))); this.output = new Formatter(output); this.configuration = Loader.getInstance().getConfiguration(); this.history = new History(output, configuration); this.mailbox = new Mailbox(output); proxy.register(mailbox.new EventHandler()); } /** * Start the interaction with the user */ public void start() { running = true; displayOpening(); while (running) { execute(prompt()); } proxy.terminate(); } private void displayOpening() { output.print(format(configuration.getVersion()).eol().in(WHITE)); output.print(format(configuration.getCopyright()).eol().in(WHITE)); output.print(format(configuration.getLogo()).eol().in(CYAN)); output.print(format(configuration.getDisclaimer()).eol().in(WHITE)); } private String prompt() { if (mailbox.hasNewMessages()) { output.print(format("%d new message(s).", mailbox.size()).eol().in(GREEN)); } return input.prompt(); } /** * Parse and execute the command whose text is given as input * * @param text the text of the command to execute */ public void execute(String text) { if (!text.isEmpty()) { final ShellCommand command = ShellCommand.fromText(text); history.record(command); command.execute(this); } } public void unknownCommand() { output.print(format("command not supported yet!").in(RED)); } public void exit() { running = false; output.print(format(configuration.getClosingMessage()).eol()); } public void version() { output.print(format(configuration.getVersion()).eol()); } public void history(int depth) { output.showHistory(history.selectLast(depth)); } public void help(String subject) { if (subject == null) { output.showHelp(configuration.getCommands()); } else { output.showHelp(findCommandAbout(subject)); } } private Command findCommandAbout(String subject) { for(Command each: configuration.getCommands()) { if (each.getSyntax().contains(subject)) { return each; } } return null; } public void dumpTo(int depth, String destination) { try { new Script(history.selectLast(depth)).toFile(destination); output.success(); } catch (FileNotFoundException ex) { output.error(format("Error: Unable to find in file '%s'. Is this path valid?", destination)); } } public void replay(String pathToScript) { try { ShellCommand script = ShellCommand.fromFile(pathToScript); script.execute(this); } catch (FileNotFoundException ex) { output.print(format("Error: Unable to open the script at '%s'. Is this path valid?", pathToScript).eol().in(RED)); } catch (IOException ex) { output.print(format("Error: Unexpected I/O error while reading the script at '%s'", pathToScript).eol().in(RED)); } } public void showMessages(int depth) { mailbox.showMessages(depth); } public void delegate(CloudMlCommand command, boolean runInBackground) { if (runInBackground) { proxy.fireAndForget(command); } else { mailbox.followUp(command); proxy.fireAndWait(command); mailbox.discard(command); } } }