/* * Copyright (C) 2012 Sebastian Straub <sebastian-straub@gmx.net> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.nx42.wotcrawler; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Scanner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import com.beust.jcommander.ParameterException; import com.beust.jcommander.Parameters; import de.nx42.wotcrawler.db.TanksDB; import de.nx42.wotcrawler.ext.Evaluator; import de.nx42.wotcrawler.ext.FieldDef; import de.nx42.wotcrawler.util.Download; import de.nx42.wotcrawler.xml.Crawler; import de.nx42.wotcrawler.xml.Serializer; import de.nx42.wotcrawler.xml.Transformer; /** * Command Line Parser and Program Launcher * * @author Sebastian Straub <sebastian-straub@gmx.net> */ public class Launcher { private static final Logger log = LoggerFactory.getLogger(Launcher.class); /** * Launches the program * @param args the command line arguments */ public static void main(String[] args) { Launcher l = new Launcher(args); l.launch(); } @Parameter(names = { "-h", "--help" }, description = "Print this help text") protected boolean help; @Parameter(names = { "-s", "--schema" }, description = "Generate an xml schema file. " + "Please specify the full path (including filename) of the new schema.") protected String schema; protected String[] args; protected final Command[] commands = { new CommandDownload(), new CommandCrawl(), new CommandEvaluate(), new CommandExport(), new CommandRunall() }; /** * Initializes the Launcher and Command Line Parser * @param args the command line args, as provided by the main method */ public Launcher(String[] args) { this.args = args; } /** * Parses command line args and launches the requested program parts. */ public void launch() throws ParameterException { if(args.length < 1) { System.out.println("No arguments specified. Type --help for more information."); return; } // setup JCommander jc = new JCommander(this); jc.setProgramName("java -jar wotcrawler.jar"); for(Command c : commands) { jc.addCommand(c.cmd1, c, c.cmd2); } // parse try { jc.parse(args); if (this.help) { jc.usage(); } if (this.schema != null) { Serializer.generateSchema(this.schema); } if (jc.getParsedCommand() != null) { String parsed = jc.getParsedCommand(); for (Command c : commands) { if(parsed.equals(c.cmd1)) { c.launch(); } } } } catch (ParameterException e) { System.err.println("Could not correctly parse command line args: " + e.getMessage() + "\nPlease type -h or --help to get usage information."); } } /** * Abstract command definition * (A command is part of the command line args and usually entered without * a preceding -, as in git commit [args]; commit is the command) */ protected abstract class Command { /** command identifier */ public final String cmd1; /** second command identifier */ public final String cmd2; /** * Sets the command identifiers * @param cmd1 first identifiers * @param cmd2 second identifiers */ public Command(String cmd1, String cmd2) { this.cmd1 = cmd1; this.cmd2 = cmd2; } /** * Launches the action behind this command */ public abstract void launch(); } /** * Download-Command. Downloads all relevant Wiki-Pages into a local folder */ @Parameters(commandDescription = "Download source data for future crawling") protected class CommandDownload extends Command { public CommandDownload() { super("download", "dl"); } /** The folder where the wiki pages will be downloaded in */ @Parameter(names = { "-f", "--folder" }, required = true, description = "The folder where the wiki pages will be downloaded in.") protected String folderDownload; /** * Downloads all relevant Wiki-Pages into the specified local folder */ @Override public void launch() { Download.downloadAll(folderDownload); } } /** * Crawl Command. Reads the data from the wiki pages and stores it in an xml * database. */ @Parameters(commandDescription = "Crawl through Wiki-pages, generate Tank Database (xml)") protected class CommandCrawl extends Command { public CommandCrawl() { super("crawl", "cr"); } /** * If specified, the files from this local folders are used. * Else they are downloaded on the fly. */ @Parameter(names = { "-l", "--local" }, description = "Uses the html files " + "downloaded in the specified local folder to build the database. " + "Downloads stuff directly, if not specified.") protected String folderLocal; /** The file where the xml database will be stored */ @Parameter(names = { "-db", "--database" }, required = true, description = "Write the database into this xml file. " + "Please specify the full path (including filename) of the new xml.") protected String dbFile; /** * Reads the data from the wiki pages and stores it in an xml database. */ @Override public void launch() { Crawler cr = new Crawler(folderLocal); Serializer.serialize(TanksDB.class, cr.buildTankDB(), new File(dbFile)); } } /** * Evaluate Command. Analyzes a given database, creates an error log. */ @Parameters(commandDescription = "Evaluate an existing database, show detailed error messages") protected class CommandEvaluate extends Command { public CommandEvaluate() { super("evaluate", "ev"); } /** The XML database to evaluate */ @Parameter(names = { "-src", "--source" }, required = true, description = "The XML database to evaluate.") protected String dbFile; /** The corresponding xml schema file to check that the database is valid */ @Parameter(names = { "-sch", "--schema" }, description = "Optional: The corresponding xml schema file to " + "check that the database is valid.") protected String schema; /** if set, the report will be written in this file (else on the command line) */ @Parameter(names = { "-r", "--report" }, description = "Optional: Specify a file to write the report into.") protected String report; /** * Analyzes a given database, creates an error log */ @Override public void launch() { TanksDB db; if (schema != null) { // use schema to validate db = Serializer.deserialize(TanksDB.class, new File(dbFile), new File(schema)); } else { // ignore schema db = Serializer.deserialize(TanksDB.class, new File(dbFile)); } if (report != null) { // write to file try { PrintWriter out = new PrintWriter(report); out.write(Evaluator.writeReportOf(db)); out.flush(); out.close(); } catch (FileNotFoundException ex) { log.error("Writing of report to file failed", ex); } } else { // print Evaluator.printReportOf(db); } } } /** * Export Command. Transforms and exports the data from the database in html tables. */ @Parameters(commandDescription = "Generates HTML tables from the given database.") protected class CommandExport extends Command { public CommandExport() { super("export", "ex"); } /** The XML database to use as source */ @Parameter(names = { "-src", "--source" }, required = true, description = "The XML database to use as source.") protected String dbFile; /** The corresponding xml schema file to check that the database is valid */ @Parameter(names = { "-sch", "--schema" }, description = "Optional: The corresponding xml schema file to " + "check that the database is valid.") protected String schema; /** Path to store the detailed table in */ @Parameter(names = { "-td", "--detailed" }, description = "Generates one big HTML table containing all raw data") protected String detailed; /** Path to store the module-table in */ @Parameter(names = { "-tm", "--modules" }, description = "Generates one table with all tanks and one for each module " + "type, with links between tanks and modules.") protected String modules; /** Path to store the rating-table in */ @Parameter(names = { "-tr", "--rating" }, description = "Generates one table for each tank type, comparing " + "each tank to it's competitors.") protected String rating; /** * Transforms and exports the data from the database in html tables */ @Override public void launch() { // build database TanksDB db; if (schema != null) { db = Serializer.deserialize(TanksDB.class, new File(dbFile), new File(schema)); } else { db = Serializer.deserialize(TanksDB.class, new File(dbFile)); } // export Transformer tr = new Transformer(db); if(detailed != null) { tr.writeTableTank(detailed, FieldDef.detailed_Combined); } if(modules != null) { tr.writeTablesLinked(modules); } if(rating != null) { tr.writeRatingTable(rating); } } } /** * Command Runall. Runs all at once: Download, Crawl, Export. Fire and forget... */ @Parameters(commandDescription = "Runs all at once: Download, Crawl, Export. Fire and forget...") protected class CommandRunall extends Command { public CommandRunall() { super("runall", "ra"); } /** The folder where all the results will be stored */ @Parameter(names = { "-o", "--output" }, required = true, description = "The folder where all the results will be stored") protected String folderOutput; /** * Tries to warn the user, before the actual work starts... */ @Override public void launch() { System.out.print("Using this function is not recommended for the following reason:\n" + "In the next step, about 350 wiki pages will be downloaded and " + "a database will be created from them. If anything " + "goes wrong, the data may be useless, and you have to download everything " + "again, which is not very nice towards the server administrator.\n" + "The better approach is to use the commands 'download', 'crawl', " + "'evaluate' and 'export' one at a time, so you always know where " + "things go wrong, without losing any data.\n" + "So, are you sure you wanna run this? (y/n) "); Scanner sc = new Scanner(System.in); String input; boolean abort = false; while (!abort) { input = sc.next(); if (input.charAt(0) == 'y') { abort = true; System.out.println("All right, your choice. Here we go..."); sc.close(); run(); } else if (input.charAt(0) == 'n') { abort = true; System.out.println("Wise choice :)\nCall --help, if you are not sure how to continue"); sc.close(); } else { System.out.print("Don't write a poem, just press 'y' or 'n': "); } } } /** * Run everything */ protected void run() { // crawl Crawler cr = new Crawler(); TanksDB db = cr.buildTankDB(); // report //Evaluator.printReportOf(db); // serialize Serializer.generateSchema(folderOutput + "/tanks.xsd"); Serializer.serialize(TanksDB.class, db, new File(folderOutput, "tanks.xml")); // export Transformer tr = new Transformer(db); tr.writeTableTank(folderOutput + "/table-detailed.html", FieldDef.detailed_Combined); tr.writeTablesLinked(folderOutput + "/table-linked.html"); tr.writeRatingTable(folderOutput + "/table-rating.html"); } } }