package edu.upenn.cit594; import java.util.HashSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import edu.upenn.cit594.datamanagement.CovidReader; import edu.upenn.cit594.datamanagement.PopulationsReader; import edu.upenn.cit594.datamanagement.PropertiesReader; import edu.upenn.cit594.logging.Logger; import edu.upenn.cit594.processor.Processor; import edu.upenn.cit594.ui.UserInterface; public class Main { public static void main(String[] args) { //check invalid runtime args int argsLength = args.length; if (argsLength > 4 || argsLength < 0) { System.out.println("Error in number of runtime arguments."); return; } //check invalid file formats ("--name=value”) if (isValidFormat(args) == false) { return; } //Make an String[] Array of argsName (Ex: population, events, covid, properties, etc.) String[] argsNames = new String[argsLength]; for (int i=0; i<argsLength; i++) { argsNames[i] = getFileName(args[i]); } //Initialize & set indexes int covidIndex = -1; int propertiesIndex = -1; int populationIndex = -1; int logIndex = -1; //Get the indexes for the arg names for (int i = 0; i<argsNames.length; i++) { if (argsNames[i].equals("population")) { populationIndex = i; } else if (argsNames[i].equals("log")) { logIndex = i; } else if (argsNames[i].equals("covid")) { covidIndex = i; } else if (argsNames[i].equals("properties")) { propertiesIndex = i; } } //To log the command line arguments to the program (a single entry, with a space between each argument) //formats the args for logging String argsString = args[0]; for (int i=1; i < args.length; i++) { argsString = argsString + " " + args[i] + " "; } //store args into local variables if they exist //get file value out of args (ex: population.csv, events.log, covid.json, properties.csv) String populationFile = null; String logFile = null; String covidFile = null; String propertiesFile = null; if (populationIndex != -1) { populationFile = getFileValue(args[populationIndex]); } if (logIndex != -1) { logFile = getFileValue(args[logIndex]); //Create logger and log program starting runtime arguments Logger logger = Logger.getInstance(); //sets existing file to log, or makes a new one. //if logger cannot be correctly initialized (e.g., the given log file cannot be opened for writing) then displays error and terminate if (logger.setFile(logFile) == false) { return; } //Logs program arguments //this needs to be adjusted to fit their formatting logger.log(argsString); //If the log file name was not specified in the runtime arguments then the logger should write to standard error } else { Logger.logError("Error: log file name was not specified in runtime arguments."); //Logger.logError(argsString); //optional } if (covidIndex != -1) { covidFile = getFileValue(args[covidIndex]); //check COVID data has proper filename extension (“csv” or “json”, case-insensitive). if(!isValidCovidExtension(covidFile)) { System.out.println("Error: " + covidFile + " does not have proper file extension of csv or json"); return; } } if (propertiesIndex != -1) { propertiesFile = getFileValue(args[propertiesIndex]); } //Check the name of an argument only contains one of the valid names in the string array below //If name of an argument is not a valid listed argument, then display error & terminate String[] validArgNames = {"population", "log", "covid", "properties"}; if (!isSubset(validArgNames, argsNames, validArgNames.length, argsNames.length)) { System.out.println("Error: the name of an argument is not valid."); return; } //If The name of an argument is used more than once then display error & terminate //Adding a duplicate element into a hashset returns false --> if so, then terminate HashSet<String> namesSet = new HashSet<String>(); for (int i=0; i<argsLength; i++) { if(!namesSet.add(argsNames[i])) { System.out.println("Error: "+ argsNames[i] + " runtime argument is used more than once"); return; } } //Make Reader Objects & Pass into Processor PopulationsReader populationsReader = null; CovidReader covidReader = null; PropertiesReader propertiesReader = null; if (populationFile != null) { populationsReader = new PopulationsReader(populationFile); Logger.getInstance().log(populationFile); } if (covidFile != null) { String covidExtension = getCovidExtension(covidFile); covidReader = Processor.createCovidReader(covidExtension, covidFile); Logger.getInstance().log(covidFile); } if (propertiesFile != null) { propertiesReader = new PropertiesReader(propertiesFile); Logger.getInstance().log(propertiesFile); } Processor processor = new Processor(populationsReader, propertiesReader, covidReader); //TODO: Create UI and run UserInterface ui = new UserInterface(processor); ui.UIProcess(processor); } /** * Helper function that gets the file name out of the runtime argument * The 4 valid optional args: covid, properties, population, and log * @param arg * @return */ private static String getFileName(String arg) { String fileName = null; String regex = "^--(?<name>.+?)=(?<value>.+)$"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(arg); if(matcher.matches()) { fileName = matcher.group("name"); //If the filename has a comma at the end, remove it. //if(filename.substring(filename.length()-1).equals(",")) { // filename = filename.substring(0, filename.length()-1); //} } return fileName.toLowerCase(); } /** * Helper function that gets the file value out of the runtime argument * Ex: the .csv, .log, .json files * @param arg * @return filename */ private static String getFileValue(String arg) { String fileValue = null; String regex = "^--(?<name>.+?)=(?<value>.+)$"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(arg); if(matcher.matches()) { fileValue = matcher.group("value"); //If the filename has a comma at the end, remove it. if(fileValue.substring(fileValue.length()-1).equals(",")) { fileValue = fileValue.substring(0, fileValue.length()-1); } } return fileValue.toLowerCase(); } /** * Helper function that checks the a filename has a file extension of either "csv" or "json" * @param filename: name of covid file * @return True is has proper file extension, else false */ private static boolean isValidCovidExtension(String filename) { //split string by period String[] fileParts = filename.toLowerCase().split("\\."); int numFileParts = fileParts.length; //get the last string in array which should contain the extension String extension = fileParts[numFileParts-1]; if (extension.equals("csv") || extension.equals("json")) { return true; } else { return false; } } /** * * @param filename * @return */ private static String getCovidExtension(String filename) { if (filename == null) { return null; } //split string by period String[] fileParts = filename.split("\\."); int numFileParts = fileParts.length; //get the last string in array which should contain the extension String extension = fileParts[numFileParts-1]; if (extension.equals("csv")) { return "csv"; } else { return "json"; } } /** * Helper function to check if any arguments to main do not match the form “--name=value”. * @param args: runtime arguments to main * @return false if they do not match, else true */ private static boolean isValidFormat(String[] args) { String regex = "^--(?<name>.+?)=(?<value>.+)$"; Pattern pattern = Pattern.compile(regex); for (int i=0; i<args.length; i++) { Matcher m = pattern.matcher(args[i]); if (!m.find()) { System.out.println("Error: " + args[i] + " is not a valid file format."); return false; } } return true; } /** * tests is argNames is a subset of validArgNames * if not, then the name of an argument is not one of the names listed as valid * @param validArgNames * @param argNames * @param m * @param n * @return true if a subset, else false */ private static boolean isSubset(String[] validArgNames, String[] argNames, int m, int n) { int i = 0; int j = 0; for(i=0; i<n; i++) { for (j = 0; j < m; j++) { if (argNames[i].equals(validArgNames[j])) { break; } } //If above loop was not broken, then argNames[i] is not present in validArgNames[] if (j == m) { return false; } } //All elements in argNames are present in validArgNames return true; } }