ca.uqac.info.trace.execution.BabelTrace.java Source code

Java tutorial

Introduction

Here is the source code for ca.uqac.info.trace.execution.BabelTrace.java

Source

/******************************************************************************
  Execution of trace validation tools
  Copyright (C) 2012 Sylvain Halle
      
  This program 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.
      
  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 Lesser General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 ******************************************************************************/
package ca.uqac.info.trace.execution;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import ca.uqac.info.ltl.*;
import ca.uqac.info.ltl.Operator.ParseException;
import ca.uqac.info.trace.*;
import ca.uqac.info.trace.conversion.*;
import ca.uqac.info.trace.execution.Execution.ReturnVerdict;
import ca.uqac.info.util.FileReadWrite;

import org.apache.commons.cli.*;

public class BabelTrace {
    /**
     * Build string
     */
    public static final String BUILD_STRING = "20130619";

    /**
     * Return codes
     */
    public static final int ERR_OK = 0;
    public static final int ERR_CONVERSION = 1;
    public static final int ERR_PARSE = 2;
    public static final int ERR_IO = 3;
    public static final int ERR_ARGUMENTS = 4;
    public static final int ERR_NO_SUCH_TOOL = 5;
    public static final int ERR_TOOL_EXECUTION = 6;

    /**
     * Main program loop
     * @param args
     */
    public static void main(String[] args) {
        String trace_type = "", tool_name = "";
        String trace_in_filename = "", formula_in_filename = "";
        String out_formula = "", out_trace = "", out_signature = "", output_dir = "";
        File formula_in, trace_in;
        trace_in = null;
        Operator op = null;
        EventTrace trace = null;
        boolean run_tool = false, show_command = false;

        // Parse command line arguments
        Options options = setupOptions();
        CommandLine c_line = setupCommandLine(args, options);
        assert c_line != null;
        if (c_line.hasOption("version")) {
            System.out.println("\nBabelTrace build " + BUILD_STRING);
            System.out.println("(C) 2012-2013 Sylvain Hall et al., Universit du Qubec  Chicoutimi");
            System.out.println("This program comes with ABSOLUTELY NO WARRANTY.");
            System.out.println("This is a free software, and you are welcome to redistribute it");
            System.out.println("under certain conditions. See the file COPYING for details.\n");
            System.exit(ERR_OK);
        }
        if (c_line.hasOption("h")) {
            showUsage(options);
            System.exit(ERR_OK);
        }
        if (c_line.hasOption("t"))
            trace_in_filename = c_line.getOptionValue("t");
        else {
            showUsage(options);
            System.exit(ERR_ARGUMENTS);
        }
        if (c_line.hasOption("f"))
            formula_in_filename = c_line.getOptionValue("f");
        else {
            showUsage(options);
            System.exit(ERR_ARGUMENTS);
        }
        if (c_line.hasOption("i"))
            trace_type = c_line.getOptionValue("i");
        else {
            showUsage(options);
            System.exit(ERR_ARGUMENTS);
        }
        if (c_line.hasOption("c"))
            tool_name = c_line.getOptionValue("c");
        else {
            showUsage(options);
            System.exit(ERR_ARGUMENTS);
        }
        if (c_line.hasOption("o"))
            output_dir = c_line.getOptionValue("o");
        else {
            showUsage(options);
            System.exit(ERR_ARGUMENTS);
        }
        if (c_line.hasOption("b")) {
            run_tool = false;
            show_command = true;
        }
        if (c_line.hasOption("r")) {
            run_tool = true;
            show_command = false;
        }

        // Read input formula
        formula_in = new File(formula_in_filename);
        if (!formula_in.exists()) {
            System.err.println("Error reading " + formula_in_filename);
            System.exit(ERR_IO);
        }
        try {
            out_formula = ca.uqac.info.util.FileReadWrite.readFile(formula_in_filename);
        } catch (java.io.FileNotFoundException e) {
            System.err.println("File not found: " + formula_in_filename);
            System.exit(ERR_IO);
        } catch (java.io.IOException e) {
            System.err.println("IO Exception: " + formula_in_filename);
            e.printStackTrace();
            System.exit(ERR_IO);
        }

        // Get trace file
        trace_in = new File(trace_in_filename);

        // Get execution
        Execution ex = getExecution(tool_name);

        // Get filenames for each part
        String base_filename = FileReadWrite.baseName(trace_in) + "." + FileReadWrite.baseName(formula_in);
        String trace_filename = output_dir + "/" + base_filename + "." + ex.getTraceExtension();
        String formula_filename = output_dir + "/" + base_filename + "." + ex.getFormulaExtension();
        String signature_filename = output_dir + "/" + base_filename + "." + ex.getSignatureExtension();

        // Setup execution environment
        ex.setProperty(formula_filename);
        ex.setSignature(signature_filename);
        ex.setTrace(trace_filename);

        // Show command lines and leave
        if (show_command) {
            String[] cl = ex.getCommandLines();
            for (String c : cl) {
                System.out.println(c);
            }
            System.exit(ERR_OK);
        }

        // Initialize the translator
        Translator tt = getTraceTranslator(tool_name);
        if (tt == null) {
            System.err.println("Error: unrecognized conversion format \"" + tool_name + "\"");
            System.exit(ERR_NO_SUCH_TOOL);
        }
        tt.setTrace(trace);

        // Parse the trace
        TraceReader t_read = getTraceReader(trace_type);
        try {
            trace = t_read.parseEventTrace(new FileInputStream(trace_in));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.exit(ERR_IO);
        }

        // Get the formula as an operator
        try {
            op = Operator.parseFromString(out_formula);
        } catch (ParseException e) {
            System.err.println("Error parsing the input formula");
            System.exit(ERR_PARSE);
        }
        assert op != null;

        // Does the formula require flat messages and formulas?
        if (tt.requiresFlat()) {
            // Convert the first-order formula to a propositional one
            FlatTranslator pt = new FlatTranslator();
            pt.setFormula(op);
            pt.setTrace(trace);
            // Flatten the trace
            String tr_trans = pt.translateTrace();
            TraceReader xtr = new XmlTraceReader();
            trace = xtr.parseEventTrace(new ByteArrayInputStream(tr_trans.getBytes()));
            // Flatten the formula
            String op_trans = pt.translateFormula();
            try {
                op = Operator.parseFromString(op_trans);
            } catch (ParseException e) {
                System.err.println("Error parsing the formula once translated to propositional");
                System.exit(ERR_PARSE);
            }
        }

        // Is the formula first-order while the tool requires propositional?
        if (tt.requiresPropositional() && FirstOrderDetector.isFirstOrder(op)) {
            // Convert the first-order formula to a propositional one
            PropositionalTranslator pt = new PropositionalTranslator();
            pt.setFormula(op);
            pt.setTrace(trace);
            String op_trans = pt.translateFormula();
            try {
                op = Operator.parseFromString(op_trans);
            } catch (ParseException e) {
                System.err.println("Error parsing the formula once translated to propositional");
                System.exit(ERR_PARSE);
            }
            // We also convert equalities between constants produced by the translator
            // into Booleans
            ConstantConverter cc = new ConstantConverter();
            op.accept(cc);
            op = cc.getFormula();
            // And then propagate those constants
            UnitPropagator up = new UnitPropagator();
            op.accept(up);
            op = up.getFormula();
        }

        // Convert
        tt.setTrace(trace);
        tt.setFormula(op);
        tt.translateAll();
        out_trace = tt.getTraceFile();
        out_formula = tt.getFormulaFile();
        out_signature = tt.getSignatureFile();

        // Save conversions to files
        try {
            if (!out_trace.isEmpty()) {
                ca.uqac.info.util.FileReadWrite.writeToFile(trace_filename, out_trace);
            }
            if (!out_formula.isEmpty()) {
                ca.uqac.info.util.FileReadWrite.writeToFile(formula_filename, out_formula);
            }
            if (!out_signature.isEmpty()) {
                ca.uqac.info.util.FileReadWrite.writeToFile(signature_filename, out_signature);
            }
        } catch (java.io.IOException e) {
            System.err.println("Error writing to file");
            System.err.println(e.getMessage());
            System.exit(ERR_IO);
        }

        // Now that all conversions have been made, run the tool
        if (run_tool) {
            try {
                ex.run();
            } catch (Execution.CommandLineException e) {
                System.err.println("Error running command");
                System.exit(ERR_TOOL_EXECUTION);
            }

            // Print results
            ReturnVerdict ex_retval = ex.getReturnVerdict();
            float ex_time = (float) ex.getTime() / (float) 1000000000; // We show seconds, not s
            float ex_memory = (float) ex.getMemory() / (float) 1024; // We show megabytes, not bytes
            System.out.printf("%s,%.2f,%.2f\n", ex_retval, ex_time, ex_memory);

            // If an error occurred, dump it
            if (ex_retval == ReturnVerdict.ERROR) {
                System.err.println("Error while executing " + tool_name);
                System.err.println("Command line(s):");
                for (String cl : ex.getCommandLines()) {
                    System.err.println(cl);
                }
                System.err.println("Below is the string returned by the tool\n");
                System.err.println(ex.getErrorString());
                System.exit(ERR_TOOL_EXECUTION);
            }
        }

        // Quit
        System.exit(ERR_OK);
    }

    /**
     * Get the proper instance of {@link TraceReader}, based on the
     * declared input format. Currently the following formats are supported:
     * <ul>
     * <li>CSV</li>
     * <li>SQL</li>
     * <li>XML</li>
     * </ul>
     * @param type The type
     * @return The trace reader, null if format is unrecognized
     */
    private static TraceReader getTraceReader(String type) {
        TraceReader tr = null;
        if (type.compareToIgnoreCase("xml") == 0)
            tr = new XmlTraceReader();
        /*else if (type.compareToIgnoreCase("sql") == 0)
          tr = new SqlTraceReader();*/
        else if (type.compareToIgnoreCase("csv") == 0)
            tr = new CsvTraceReader();
        return tr;
    }

    /**
     * Gets the proper instance of the {@link TraceTranslator} class, based
     * on a string representing the target tool. Currently the following
     * tools are supported:
     * <ul>
     * <li>BeepBeep (0.9 and 1.5)</li>
     * <li>Filter</li>
     * <li>ltlfo2mon</li>
     * <li>Maude</li>
     * <li>Monpoly</li>
     * <li>MySQL</li>
     * <li>NuSMV</li>
     * <li>PromLTL</li>
     * <li>Saxon</li>
     * <li>Spin</li>
     * </ul> 
     * @param type The name of the target tool
     * @return The translator, null if tool is unrecognized
     */
    private static Translator getTraceTranslator(String type) {
        Translator tr = null;
        if (type.compareToIgnoreCase("maude") == 0)
            tr = new MaudeTranslator();
        else if (type.compareToIgnoreCase("beepbeep") == 0)
            tr = new BeepBeepTranslator();
        else if (type.compareToIgnoreCase("filter") == 0)
            tr = new FilterTranslator();
        else if (type.compareToIgnoreCase("mysql-opt") == 0)
            tr = new MySQLTranslatorOptimized();
        else if (type.compareToIgnoreCase("mysql") == 0)
            tr = new MySQLTranslator();
        else if (type.compareToIgnoreCase("mysql-innodb") == 0) {
            MySQLTranslator mtr = new MySQLTranslator();
            mtr.setEngine("InnoDB");
            tr = mtr;
        } else if (type.compareToIgnoreCase("mysql-memory") == 0) {
            MySQLTranslator mtr = new MySQLTranslator();
            mtr.setEngine("MEMORY");
            tr = mtr;
        } else if (type.compareToIgnoreCase("nusmv") == 0)
            tr = new SmvTranslator();
        else if (type.compareToIgnoreCase("saxon") == 0)
            tr = new SaxonTranslator();
        else if (type.compareToIgnoreCase("spin") == 0)
            tr = new PromelaTranslator();
        else if (type.compareToIgnoreCase("monpoly") == 0)
            tr = new MonpolyTranslator();
        else if (type.compareToIgnoreCase("promltl") == 0)
            tr = new XesTranslator();
        else if (type.compareToIgnoreCase("ltlfo2mon") == 0)
            tr = new Ltlfo2monTranslator();
        else if (type.compareToIgnoreCase("newbeepbeep") == 0)
            tr = new NewBeepBeepTranslator();
        return tr;
    }

    /**
     * Gets the proper instance of the {@link Execution} class, based
     * on a string representing the target tool. Currently the following
     * tools are supported:
     * <ul>
     * <li>BeepBeep</li>
     * <li>Filter</li>
     * <li>ltlfo2mon</li>
     * <li>Maude</li>
     * <li>Monpoly</li>
     * <li>MySQL</li>
     * <li>NuSMV</li>
     * <li>PromLTL</li>
     * <li>Saxon</li>
     * <li>Spin</li>
     * </ul> 
     * @param type The name of the tool to execute
     * @return The Execution, null if tool is unrecognized
     */
    private static Execution getExecution(String type) {
        Execution tr = null;
        if (type.compareToIgnoreCase("maude") == 0)
            tr = new MaudeExecution();
        else if (type.compareToIgnoreCase("beepbeep") == 0)
            tr = new BeepBeepExecution();
        else if (type.compareToIgnoreCase("filter") == 0)
            tr = new FilterExecution();
        else if (type.compareToIgnoreCase("mysql") == 0)
            tr = new MySQLExecution();
        else if (type.compareToIgnoreCase("mysql-innodb") == 0)
            tr = new MySQLExecution();
        else if (type.compareToIgnoreCase("mysql-memory") == 0)
            tr = new MySQLExecution();
        else if (type.compareToIgnoreCase("mysql-opt") == 0)
            tr = new MySQLExecution();
        else if (type.compareToIgnoreCase("nusmv") == 0)
            tr = new NuSmvExecution();
        else if (type.compareToIgnoreCase("saxon") == 0)
            tr = new SaxonExecution();
        else if (type.compareToIgnoreCase("spin") == 0)
            tr = new SpinExecution();
        else if (type.compareToIgnoreCase("monpoly") == 0)
            tr = new MonpolyExecution();
        else if (type.compareToIgnoreCase("promltl") == 0)
            tr = new PromLTLExecution();
        else if (type.compareToIgnoreCase("ltlfo2mon") == 0)
            tr = new Ltlfo2monExecution();
        else if (type.compareToIgnoreCase("newbeepbeep") == 0)
            tr = new NewBeepBeepExecution();
        return tr;
    }

    /**
     * Sets up the command line parser
     * @param args The command line arguments passed to the class' {@link main}
     * method
     * @param options The command line options to be used by the parser
     * @return The object that parsed the command line parameters
     */
    private static CommandLine setupCommandLine(String[] args, Options options) {
        CommandLineParser parser = new PosixParser();
        CommandLine c_line = null;
        try {
            // parse the command line arguments
            c_line = parser.parse(options, args);
        } catch (org.apache.commons.cli.ParseException exp) {
            // oops, something went wrong
            System.err.println("ERROR: " + exp.getMessage() + "\n");
            //HelpFormatter hf = new HelpFormatter();
            //hf.printHelp(t_gen.getAppName() + " [options]", options);
            System.exit(ERR_ARGUMENTS);
        }
        return c_line;
    }

    /**
     * Sets up the options for the command line parser
     * @return The options
     */
    @SuppressWarnings("static-access")
    private static Options setupOptions() {
        Options options = new Options();
        Option opt;
        opt = OptionBuilder.withLongOpt("run")
                .withDescription("Run the selected tool after conversion (default: no)").create("r");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("help").withDescription("Display command line usage").create("h");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("batch")
                .withDescription("Don't run the tool, but output the command line that would be used").create("b");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("trace").withArgName("filename").hasArg()
                .withDescription("Read trace from filename").create("t");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("formula").withArgName("filename").hasArg()
                .withDescription("Read formula from filename").create("f");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("convert").withArgName("toolname").hasArg()
                .withDescription("Convert to format of toolname").create("c");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("version").withDescription("Show version of BabelTrace").create();
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("input-type").withArgName("type").hasArg()
                .withDescription("Trace input type").create("i");
        options.addOption(opt);
        opt = OptionBuilder.withLongOpt("output-dir").withArgName("dir").hasArg()
                .withDescription("Write output files to dir").create("o");
        options.addOption(opt);

        return options;
    }

    /**
     * Show the benchmark's usage
     * @param options The options created for the command line parser
     */
    private static void showUsage(Options options) {
        HelpFormatter hf = new HelpFormatter();
        hf.printHelp("BabelTrace [options]", options);
    }
}