import utils.ScannerHelper; import utils.TaskOption; import utils.ToolTask; import utils.ToolsConstants; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import java.util.Scanner; /** * Main entry point for tool tasks. */ public class ToolsRunner { private static final String DIR_SEPARATOR = File.separator; public static void main(String... args) { // Collect tasks and show them File toolsFolder = new File(ToolsConstants.TOOLS_SOURCE_ROOT); Map tasks = new HashMap<>(); collectTasksInDirectory(toolsFolder, tasks); showHelp(tasks); // Prompt user for task and handle input System.out.println("Please enter the task to run:"); Scanner scanner = new Scanner(System.in); String inputTask = scanner.nextLine(); ToolTask task = tasks.get(inputTask); if (task != null) { executeTask(task, scanner); } else { System.out.println("Unknown task"); } scanner.close(); } /** * Execute the given tool task after prompting the user for the required options. * * @param task The task to run * @param scanner The scanner instance */ private static void executeTask(ToolTask task, Scanner scanner) { Iterable options = task.getOptions(); Map inputOptions = new HashMap<>(); for (TaskOption option : options) { System.out.println(option.getDescription()); String input = ScannerHelper.getAnswer(option.getDefaultOption(), scanner, option.getOptions()); inputOptions.put(option.getName(), input); } task.execute(inputOptions); } private static void showHelp(Map taskCollection) { System.out.println("The following tasks are available:"); for (String key : taskCollection.keySet()) { System.out.println("- " + key); } } // Note ljacqu 20151212: If the tools folder becomes a lot bigger, it will make sense to restrict the depth // of this recursive collector private static void collectTasksInDirectory(File dir, Map taskCollection) { File[] files = dir.listFiles(); if (files == null) { throw new RuntimeException("Cannot read folder '" + dir + "'"); } for (File file : files) { if (file.isDirectory()) { collectTasksInDirectory(file, taskCollection); } else if (file.isFile()) { ToolTask task = getTaskFromFile(file); if (task != null) { taskCollection.put(task.getTaskName(), task); } } } } /** * Return a {@link ToolTask} instance from the given file. * * @param file The file to load * @return ToolTask instance or null if not applicable */ private static ToolTask getTaskFromFile(File file) { Class taskClass = loadTaskClassFromFile(file); if (taskClass == null) { return null; } try { Constructor constructor = taskClass.getConstructor(); return constructor.newInstance(); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | InstantiationException e) { throw new RuntimeException("Cannot instantiate task '" + taskClass + "'"); } } /** * Return the class the file defines if it implements a {@link ToolTask}. * * @return The class instance, or null if not applicable */ @SuppressWarnings("unchecked") private static Class loadTaskClassFromFile(File file) { if (!file.getName().endsWith(".java")) { return null; } String filePath = file.getPath(); String className = filePath .substring(ToolsConstants.TOOLS_SOURCE_ROOT.length(), filePath.length() - 5) .replace(DIR_SEPARATOR, "."); try { Class clazz = ClassLoader.getSystemClassLoader().loadClass(className); return ToolTask.class.isAssignableFrom(clazz) && isInstantiable(clazz) ? (Class) clazz : null; } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } private static boolean isInstantiable(Class clazz) { return !clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()); } }