package org.drooms.launcher.game; import java.io.File; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.GnuParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.drooms.api.Playground; import org.drooms.impl.GameController; /** * Command-line interface for the application. It enforces following options on * the command line: * * <dl> * <dt>-s <scenario></dt> * <dd>Provides a {@link Playground} description on which the game is to be played out..</dd> * <dt>-p <file></dt> * <dd>Provides a player configuration file, as described in * {@link GameController#play(Playground, java.util.Collection, File)}.</dd> * <dt>-g <file></dt> * <dd>Provides a game configuration file, as described in * {@link GameController#play(Playground, java.util.Collection, File)}.</dd> * </dl> * * Not providing any of those or pointing to unreadable (non-existent) files * should result in a help message being printed out and the application being * terminated. */ public class CLI { private static final CLI INSTANCE = new CLI(); /** * Return the single instance of this class. * * @return The instance. */ public static CLI getInstance() { return CLI.INSTANCE; } private final Options options = new Options(); private final Option reports = new Option("r", "reports", true, "A folder to store reports in."); private final Option playground = new Option("s", "scenario", true, "A path to the playground config file."); private final Option players = new Option("p", "players", true, "A path to the player config file."); private final Option game = new Option("g", "game", true, "A path to the game config file."); private String errorMessage = null; private boolean isError = false; /** * The constructor is hidden, as should be with the singleton pattern. */ private CLI() { this.options.addOption(this.reports); this.playground.setRequired(true); this.options.addOption(this.playground); this.game.setRequired(true); this.options.addOption(this.game); this.players.setRequired(true); this.options.addOption(this.players); } /** * Prints a help message, describing the usage of the app from the * command-line. */ public void printHelp() { if (this.isError) { System.out.println(this.errorMessage); } final HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("java -jar drooms.jar", this.options, true); } /** * Process the command-line arguments. * * @param args * The arguments. * @return Files passed from the command line. First is the scenario, second * is the game config, third is the player config, fourth * (optionally) the directory in which to store reports. */ public File[] process(final String[] args) { this.isError = false; final CommandLineParser parser = new GnuParser(); try { final CommandLine cli = parser.parse(this.options, args); final File scenario = new File(cli.getOptionValue(this.playground.getOpt())); if (!scenario.exists() || !scenario.canRead()) { this.setError("Provided scenario file cannot be read!"); return null; } final File gameConfig = new File(cli.getOptionValue(this.game.getOpt())); if (!gameConfig.exists() || !gameConfig.canRead()) { this.setError("Provided game config file cannot be read!"); return null; } final File playerConfig = new File(cli.getOptionValue(this.players.getOpt())); if (!playerConfig.exists() || !playerConfig.canRead()) { this.setError("Provided player config file cannot be read!"); return null; } final String reports = cli.getOptionValue(this.reports.getOpt()); if (reports == null) { return new File[]{scenario, gameConfig, playerConfig}; } else { final File reportsDir = new File(reports + File.separator); reportsDir.mkdirs(); return new File[]{scenario, gameConfig, playerConfig, reportsDir}; } } catch (final ParseException e) { this.setError(e.getMessage()); return null; } } private boolean setError(final String message) { if (!this.isError) { this.isError = true; this.errorMessage = message; return true; } return false; } }