mv.Main.java Source code

Java tutorial

Introduction

Here is the source code for mv.Main.java

Source

/*
 * This file is part of jASM.
 *
 * jASM 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.
 *
 * jASM 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 jASM.  If not, see <http://www.gnu.org/licenses/>.
 */

package mv;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import commons.exceptions.EmptyFileException;
import commons.exceptions.UnrecoverableException;
import mv.cpu.CPU;
import mv.cpu.ProgramMV;
import mv.strategies.InStrategy;
import mv.strategies.OutStrategy;
import mv.strategies.in.ConsoleInputStrategy;
import mv.strategies.in.FileInputStrategy;
import mv.strategies.in.NullInputStrategy;
import mv.strategies.in.WindowIn;
import mv.strategies.out.ConsoleWriteStrategy;
import mv.strategies.out.FileWriteStrategy;
import mv.strategies.out.NullWriteStrategy;
import mv.strategies.out.WindowOut;
import ui.SwingController;
import ui.SwingView;
import ui.TextController;
import ui.TextView;

import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;

/**
 * jASM
 *
 * @author Borja
 */
public class Main {

    private static final String ERR_CLI_HEAD = "Wrong usage: ";
    private static final String SHOW_CLI_HELP = "\nUse -h|--help for more details.";
    private static final String ERR_BAD_MODE = ERR_CLI_HEAD + "unknown execution mode (-m|--mode)" + SHOW_CLI_HELP;

    private static final String ERR_NO_IN = "Error: Couldn't open input file";
    private static final String ERR_NO_ASM = "Error: No ASM source file given" + SHOW_CLI_HELP;
    private static final String ERR_ASM_NOT_FOUND = "Error: Couldn't open ASM source file (file not found)"
            + SHOW_CLI_HELP;

    public static enum ExecutionMode {
        INTERACTIVE, BATCH, WINDOW
    }

    /**
     * Processes execution mode arguments and starts the program
     *
     * @see mv.Main#optionSelector(String[])
     */
    public static void main(String[] args) {

        SetupConfigurator setupConfiguration;
        ExecutionMode mode;
        String asmFile, inFile, outFile;
        InStrategy inStr;
        OutStrategy outStr;
        boolean writeLog;

        /**
         * @see mv.Main#optionSelector(String[])
         */
        setupConfiguration = optionSelector(args); // parses all input arguments

        if (setupConfiguration == null) {
            System.exit(1);
        }

        mode = setupConfiguration.getMode();
        asmFile = setupConfiguration.getAsm();
        inFile = setupConfiguration.getIn();
        outFile = setupConfiguration.getOut();
        inStr = setupConfiguration.getInputStrategy();
        outStr = setupConfiguration.getOutputStrategy();
        writeLog = setupConfiguration.getLogOption();

        if (!setupIO(inFile, outFile, inStr, outStr)) {
            System.exit(1);
        }

        switch (mode) {
        case INTERACTIVE:
            doInteractive(asmFile, inStr, outStr, writeLog);
            break;

        case WINDOW:
            doVisual(asmFile, inStr, outStr, writeLog);
            break;

        case BATCH:
            doBatch(asmFile, inStr, outStr, writeLog);
            break;

        default:
            doBatch(asmFile, inStr, outStr, writeLog);
        }
    }

    /**
     * Starts the program in interactive mode.
     *
     * @param asmFileString ASM source code filename
     * @param inStr input mode configuration
     * @param outStr output mode configuration
     * @param writeLog write to log file?
     */
    private static void doInteractive(String asmFileString, InStrategy inStr, OutStrategy outStr,
            boolean writeLog) {

        TextView view;
        TextController controller;

        Scanner sc = new Scanner(System.in);

        ProgramMV program = new ProgramMV();
        CPU cpu = new CPU(inStr, outStr, writeLog);

        if (setupProgramFile(asmFileString)) {
            try {
                program.readProgram(asmFileString);
            } catch (UnrecoverableException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        } else {
            program.readProgram(sc);
        }

        controller = new TextController(cpu, program, inStr, outStr);
        view = new TextView(controller, ExecutionMode.INTERACTIVE);

        controller.addView(view);
        view.enable();
    }

    /**
     * Starts the program in visual mode (GUI).
     *
     * All i/o streams get initialized in SwingController
     *
     * @param asmFileString ASM source code filename
     * @param inStr input mode configuration
     * @param outStr output mode configuration
     * @param writeLog write to log file?
     */
    private static void doVisual(String asmFileString, InStrategy inStr, OutStrategy outStr, boolean writeLog) {

        SwingView view;
        SwingController controller;

        ProgramMV program = new ProgramMV();
        CPU cpu = new CPU(inStr, outStr, writeLog);

        if (setupProgramFile(asmFileString)) {
            try {
                program.readProgram(asmFileString);
            } catch (UnrecoverableException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }

        controller = new SwingController(cpu, program, inStr, outStr);
        view = new SwingView(controller);

        controller.addView(view);
        view.enable();
    }

    /**
     * Starts the program in batch mode (Takes the ASM source code and runs it).
     *
     * @param asmFileString ASM source code filename
     * @param inStr input mode configuration
     * @param outStr output mode configuration
     * @param writeLog write to log file?
     */
    private static void doBatch(String asmFileString, InStrategy inStr, OutStrategy outStr, boolean writeLog) {

        TextView view;
        TextController controller;

        ProgramMV program = new ProgramMV();
        CPU cpu = new CPU(inStr, outStr, writeLog);

        if (setupProgramFile(asmFileString)) {
            try {
                program.readProgram(asmFileString);
            } catch (UnrecoverableException e) {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        }

        controller = new TextController(cpu, program, inStr, outStr);
        view = new TextView(controller, ExecutionMode.BATCH);

        controller.addView(view);
        view.enable();
    }

    /**
     * Initializes the IO of the program.
     * Opens the input and the output file, checks for any errors on them, etc
     *
     * @param inFileString input filename (for IN instructions)
     * @param outFileString output filename (for OUT instructions)
     * @param inStr input mode configuration
     * @param outStr output mode configuration
     *
     * @return the success of the operation
     */
    private static boolean setupIO(String inFileString, String outFileString, InStrategy inStr,
            OutStrategy outStr) {

        Path inFilePath;

        if (inFileString != null) {
            inFilePath = Paths.get(inFileString);
            if (Files.exists(inFilePath)) {
                inStr.open(inFilePath);
            } else {
                System.err.println(ERR_NO_IN + "(" + inFileString + ")" + SHOW_CLI_HELP);
                return false;
            }
        }

        if (outFileString != null) {
            outStr.open();
        }

        return true;
    }

    /**
     * Opens the ASM source code file and checks for any errors on it.
     * Returns false if the user did not specify a file path, if it doesn't exist or if it's empty
     *
     * @param asmFileString ASM source code filename
        
     * @return the success of the operation
     */
    private static boolean setupProgramFile(String asmFileString) {

        boolean success = false;
        Path inFilePath;
        File asmFile;

        if (asmFileString != null) {
            try {
                inFilePath = Paths.get(asmFileString);
                asmFile = new File(inFilePath.toString());
                if (Files.exists(inFilePath)) {
                    if (asmFile.length() != 0) {
                        success = true;
                    } else {
                        throw new EmptyFileException(asmFile);
                    }
                } else {
                    throw new FileNotFoundException();
                }
            } catch (FileNotFoundException e) {
                System.err.println(ERR_ASM_NOT_FOUND);
                success = false;

            } catch (EmptyFileException e) {
                System.err.println(e.getMessage());
                success = false;
            }
        }

        return success;
    }

    /**
     * Sets up the command line options and parses the user arguments
     *
     * @param args User input arguments
     *
     * @return SetupConfigurator object with all arguments set. Returns null if a parsing error happens
     * @see mv.Main.SetupConfigurator
     */
    private static SetupConfigurator optionSelector(String[] args) {

        CommandLine line;
        CommandLineParser parser = new BasicParser();
        Options options = new Options();
        boolean writeLog = false;

        options.addOption("a", "asm", true, "ASM source code file. Can be omitted in interactive mode");
        options.addOption("h", "help", false, "Shows this help");
        options.addOption("i", "in", true, "Program input file");
        options.addOption("m", "mode", true,
                "Execution mode (batch | interactive | visual). Batch is the default mode");
        options.addOption("o", "out", true, "Program output file");
        options.addOption("d", "debug", false, "Prints cpu state to log file. Check status.log");

        try {
            line = parser.parse(options, args);
        } catch (ParseException exp) {
            System.err.println("Wrong usage: " + exp.getMessage() + SHOW_CLI_HELP);
            return null;
        }

        if (line.hasOption("h")) {
            showHelp();
            return null;
        }

        if (line.hasOption("d")) {
            writeLog = true;
        }

        if (line.hasOption("m")) {
            String s = line.getOptionValue("m");
            if (s.equalsIgnoreCase(ExecutionMode.BATCH.name())) {
                return setupMode(ExecutionMode.BATCH, line, writeLog);

            } else if (s.equalsIgnoreCase(ExecutionMode.INTERACTIVE.name())) {
                return setupMode(ExecutionMode.INTERACTIVE, line, writeLog);

            } else if (s.equalsIgnoreCase(ExecutionMode.WINDOW.name())) {
                return setupMode(ExecutionMode.WINDOW, line, writeLog);

            } else {
                System.err.println(ERR_BAD_MODE);
                return null;
            }
        } else {
            return setupMode(ExecutionMode.BATCH, line, writeLog);
        }
    }

    /**
     * Parses the execution mode and the other io arguments. Shows error message if those arguments are incompatible.
     *
     * @param mode execution mode
     * @param line rest of the user input
     * @param writeLog write to log file?
     *
     * @return SetupConfigurator object with all arguments set.
     */
    private static SetupConfigurator setupMode(ExecutionMode mode, CommandLine line, boolean writeLog) {

        String asmFile, inFile, outFile;
        asmFile = inFile = outFile = null;

        if (line.hasOption("a")) {
            asmFile = line.getOptionValue("a");
            if (line.hasOption("i")) {
                inFile = line.getOptionValue("i");
            }

            if (line.hasOption("o")) {
                outFile = line.getOptionValue("o");
            }
        } else {
            if (mode == ExecutionMode.BATCH || mode == ExecutionMode.WINDOW) {
                System.err.println(ERR_NO_ASM);
                return null;
            } else {
                if (line.hasOption("i")) {
                    inFile = line.getOptionValue("i");
                }
                if (line.hasOption("o")) {
                    outFile = line.getOptionValue("o");
                }
            }
        }

        return new SetupConfigurator(mode, asmFile, inFile, outFile, writeLog);
    }

    private static void showHelp() {
        System.out.println("usage: jASM -a <asmfile> [-h] [-i <infile>] [-m <mode>] [-o <outfile>]");
        System.out.println(" -a,--asm <asmfile>  ASM source code file. Can be omitted in interactive mode");
        System.out.println(" -h,--help           Shows this help");
        System.out.println(" -i,--in <infile>    Program input file");
        System.out.println(
                " -m,--mode <mode>    Execution mode (batch | interactive | visual). Batch is the default mode");
        System.out.println(" -o,--out <outfile>  Program output file");
        System.out.println(" -d, --debug       Prints cpu state to log file. Check status.log");
    }

    /**
     * Sets the I/O strategy
     *
     * Different input args combinations will give different IO strategies.
     */
    private static class SetupConfigurator {

        private static ExecutionMode mode;
        private static String asmFile;
        private static String inFile;
        private static String outFile;

        private static InStrategy inStrategy;
        private static OutStrategy outStrategy;

        private static boolean writeLog;

        private SetupConfigurator(ExecutionMode mode, String asmFile, String inFile, String outFile,
                boolean writeLog) {
            SetupConfigurator.mode = mode;
            SetupConfigurator.asmFile = asmFile;
            SetupConfigurator.inFile = inFile;
            SetupConfigurator.outFile = outFile;
            SetupConfigurator.writeLog = writeLog;
        }

        private InStrategy getInputStrategy() {
            if (inFile != null) {
                inStrategy = new FileInputStrategy();
            } else {
                if (mode == Main.ExecutionMode.INTERACTIVE || mode == Main.ExecutionMode.WINDOW) {
                    inStrategy = new NullInputStrategy();
                } else {
                    inStrategy = new ConsoleInputStrategy();
                }
            }

            return new WindowIn(inStrategy);
        }

        private OutStrategy getOutputStrategy() {
            if (outFile != null) {
                outStrategy = new FileWriteStrategy(outFile);
            } else {
                if (mode == Main.ExecutionMode.INTERACTIVE || mode == Main.ExecutionMode.WINDOW) {
                    outStrategy = new NullWriteStrategy();
                } else {
                    outStrategy = new ConsoleWriteStrategy();
                }
            }

            return new WindowOut(outStrategy);
        }

        private ExecutionMode getMode() {
            return mode;
        }

        private String getAsm() {
            return asmFile;
        }

        private String getIn() {
            return inFile;
        }

        private String getOut() {
            return outFile;
        }

        private boolean getLogOption() {
            return writeLog;
        }
    }
}