diff --git a/src/core/config/Config.java b/src/core/config/Config.java index f351fcb..069bdfe 100644 --- a/src/core/config/Config.java +++ b/src/core/config/Config.java @@ -26,10 +26,10 @@ public class Config implements ILoggable { - public static final String RELEASE_VERSION = "5.6.3"; + public static final String RELEASE_VERSION = "5.6.4"; protected static final String CONFIG_FILE_NAME = "config.json"; public static final String EXPORTED_CONFIG_FILE_NAME = "exported_" + CONFIG_FILE_NAME; - protected static final String CURRENT_CONFIG_VERSION = "2.13"; + protected static final String CURRENT_CONFIG_VERSION = "2.14"; private static final Level DEFAULT_NATIVE_HOOK_DEBUG_LEVEL = Level.WARNING; private static final boolean DEFAULT_TRAY_ICON_USE = true; @@ -89,7 +89,8 @@ public class Config implements ILoggable { new Parser2_10(), new Parser2_11(), new Parser2_12(), - new Parser2_13() + new Parser2_13(), + new Parser2_14() }); } diff --git a/src/core/config/Parser2_13.java b/src/core/config/Parser2_13.java index 14da96f..aea4900 100644 --- a/src/core/config/Parser2_13.java +++ b/src/core/config/Parser2_13.java @@ -1,26 +1,13 @@ package core.config; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - import argo.jdom.JsonNode; import argo.jdom.JsonNodeFactories; import argo.jdom.JsonRootNode; -import core.cli.server.CliServer; -import core.controller.CoreConfig; -import core.ipc.IPCServiceManager; -import core.ipc.IPCServiceName; -import core.ipc.repeatClient.repeatPeerClient.RepeatsPeerServiceClientManager; -import core.keyChain.KeyChain; import core.userDefinedTask.TaskGroup; -import core.userDefinedTask.internals.ToolsConfig; import utilities.json.JSONUtility; public class Parser2_13 extends ConfigParser { - private static final Logger LOGGER = Logger.getLogger(Parser2_13.class.getName()); - @Override protected String getVersion() { return "2.13"; @@ -38,67 +25,6 @@ protected JsonRootNode internalConvertFromPreviousVersion(JsonRootNode previousV return JSONUtility.replaceChild(previousVersion, "global_settings", replacedGlobalSettings).getRootNode(); } - @Override - protected boolean internalExtractData(Config config, JsonRootNode root) { - try { - JsonNode globalSettings = root.getNode("global_settings"); - config.setUseTrayIcon(globalSettings.getBooleanValue("tray_icon_enabled")); - config.setEnabledHaltingKeyPressed(globalSettings.getBooleanValue("enabled_halt_by_key")); - config.setExecuteOnKeyReleased(globalSettings.getBooleanValue("execute_on_key_released")); - config.setUseClipboardToTypeString(globalSettings.getBooleanValue("use_clipboard_to_type_string")); - config.setRunTaskWithServerConfig(globalSettings.getBooleanValue("run_task_with_server_config")); - config.setUseJavaAwtToGetMousePosition(globalSettings.getBooleanValue("use_java_awt_for_mouse_position")); - - config.setNativeHookDebugLevel(Level.parse(globalSettings.getNode("debug").getStringValue("level"))); - - JsonNode globalHotkey = globalSettings.getNode("global_hotkey"); - - String mouseGestureActivation = globalHotkey.getNumberValue("mouse_gesture_activation"); - config.setMouseGestureActivationKey(Integer.parseInt(mouseGestureActivation)); - config.setRECORD(KeyChain.parseJSON(globalHotkey.getArrayNode("record"))); - config.setREPLAY(KeyChain.parseJSON(globalHotkey.getArrayNode("replay"))); - config.setCOMPILED_REPLAY(KeyChain.parseJSON(globalHotkey.getArrayNode("replay_compiled"))); - - JsonNode toolsConfigNode = globalSettings.getNode("tools_config"); - ToolsConfig toolsConfig = ToolsConfig.parseJSON(toolsConfigNode); - config.setToolsConfig(toolsConfig); - - JsonNode coreConfigNode = globalSettings.getNode("core_config"); - CoreConfig coreConfig = CoreConfig.parseJSON(coreConfigNode); - config.setCoreConfig(coreConfig); - - JsonNode peerClients = root.getNode("remote_repeats_clients"); - RepeatsPeerServiceClientManager repeatsPeerServiceClientManager = RepeatsPeerServiceClientManager.parseJSON(peerClients); - config.getBackEnd().getPeerServiceClientManager().updateClients(repeatsPeerServiceClientManager.getClients()); - - List ipcSettings = root.getArrayNode("ipc_settings"); - if (!IPCServiceManager.parseJSON(ipcSettings)) { - LOGGER.log(Level.WARNING, "IPC Service Manager failed to parse JSON metadata"); - } - - if (!config.getCompilerFactory().parseJSON(root.getNode("compilers"))) { - LOGGER.log(Level.WARNING, "Dynamic Compiler Manager failed to parse JSON metadata"); - } - - config.getBackEnd().clearTaskGroup(); - for (JsonNode taskGroupNode : root.getArrayNode("task_groups")) { - TaskGroup taskGroup = TaskGroup.parseJSON(config.getCompilerFactory(), taskGroupNode); - if (taskGroup != null) { - config.getBackEnd().addTaskGroup(taskGroup); - } - } - - if (config.getBackEnd().getTaskGroups().isEmpty()) { - config.getBackEnd().addTaskGroup(new TaskGroup("default")); - } - config.getBackEnd().setCurrentTaskGroup(config.getBackEnd().getTaskGroups().get(0)); - return true; - } catch (Exception e) { - LOGGER.log(Level.WARNING, "Unable to parse json", e); - return false; - } - } - @Override protected boolean internalImportData(Config config, JsonRootNode root) { boolean result = true; @@ -112,21 +38,4 @@ protected boolean internalImportData(Config config, JsonRootNode root) { } return result; } - - @Override - protected boolean internalExtractData(CliConfig config, JsonRootNode root) { - try { - List ipcSettings = root.getArrayNode("ipc_settings"); - if (!IPCServiceManager.parseJSON(ipcSettings)) { - LOGGER.log(Level.WARNING, "IPC Service Manager failed to parse JSON metadata"); - } - - CliServer cliServer = (CliServer) IPCServiceManager.getIPCService(IPCServiceName.CLI_SERVER); - config.setServerPort(cliServer.getPort()); - return true; - } catch (Exception e) { - LOGGER.log(Level.WARNING, "Unable to parse json", e); - return false; - } - } -} \ No newline at end of file +} diff --git a/src/core/config/Parser2_14.java b/src/core/config/Parser2_14.java new file mode 100644 index 0000000..5deba48 --- /dev/null +++ b/src/core/config/Parser2_14.java @@ -0,0 +1,154 @@ +package core.config; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import argo.jdom.JsonNode; +import argo.jdom.JsonNodeFactories; +import argo.jdom.JsonRootNode; +import core.cli.server.CliServer; +import core.controller.CoreConfig; +import core.ipc.IPCServiceManager; +import core.ipc.IPCServiceName; +import core.ipc.repeatClient.repeatPeerClient.RepeatsPeerServiceClientManager; +import core.keyChain.KeyChain; +import core.userDefinedTask.TaskGroup; +import core.userDefinedTask.internals.ToolsConfig; +import utilities.json.JSONUtility; + +public class Parser2_14 extends ConfigParser { + + private static final Logger LOGGER = Logger.getLogger(Parser2_14.class.getName()); + + @Override + protected String getVersion() { + return "2.14"; + } + + @Override + protected String getPreviousVersion() { + return "2.13"; + } + + @Override + protected JsonRootNode internalConvertFromPreviousVersion(JsonRootNode previousVersion) { + JsonNode taskGroups = previousVersion.getNode("task_groups"); + return JSONUtility.replaceChild(previousVersion, "task_groups", convertTaskGroups(taskGroups)).getRootNode(); + } + + private JsonNode convertTaskGroups(JsonNode node) { + List groups = node.getArrayNode(); + List convertedGroups = new ArrayList<>(); + for (JsonNode group : groups) { + List convertedTasks = group.getArrayNode("tasks").stream().map(task -> convertTask(task)).collect(Collectors.toList()); + convertedGroups.add(JSONUtility.replaceChild(group, "tasks", JsonNodeFactories.array(convertedTasks))); + } + + return JsonNodeFactories.array(convertedGroups); + } + + private JsonNode convertTask(JsonNode node) { + String currentPath = node.getStringValue("source_path"); + JsonNode currentSource = JsonNodeFactories.object( + JsonNodeFactories.field("path", JsonNodeFactories.string(currentPath)), + JsonNodeFactories.field("created_time", JsonNodeFactories.number(System.currentTimeMillis()))); + + return JSONUtility.addChild(node, "source_history", JsonNodeFactories.object( + JsonNodeFactories.field("entries", JsonNodeFactories.array(currentSource)))); + } + + @Override + protected boolean internalExtractData(Config config, JsonRootNode root) { + try { + JsonNode globalSettings = root.getNode("global_settings"); + config.setUseTrayIcon(globalSettings.getBooleanValue("tray_icon_enabled")); + config.setEnabledHaltingKeyPressed(globalSettings.getBooleanValue("enabled_halt_by_key")); + config.setExecuteOnKeyReleased(globalSettings.getBooleanValue("execute_on_key_released")); + config.setUseClipboardToTypeString(globalSettings.getBooleanValue("use_clipboard_to_type_string")); + config.setRunTaskWithServerConfig(globalSettings.getBooleanValue("run_task_with_server_config")); + config.setUseJavaAwtToGetMousePosition(globalSettings.getBooleanValue("use_java_awt_for_mouse_position")); + + config.setNativeHookDebugLevel(Level.parse(globalSettings.getNode("debug").getStringValue("level"))); + + JsonNode globalHotkey = globalSettings.getNode("global_hotkey"); + + String mouseGestureActivation = globalHotkey.getNumberValue("mouse_gesture_activation"); + config.setMouseGestureActivationKey(Integer.parseInt(mouseGestureActivation)); + config.setRECORD(KeyChain.parseJSON(globalHotkey.getArrayNode("record"))); + config.setREPLAY(KeyChain.parseJSON(globalHotkey.getArrayNode("replay"))); + config.setCOMPILED_REPLAY(KeyChain.parseJSON(globalHotkey.getArrayNode("replay_compiled"))); + + JsonNode toolsConfigNode = globalSettings.getNode("tools_config"); + ToolsConfig toolsConfig = ToolsConfig.parseJSON(toolsConfigNode); + config.setToolsConfig(toolsConfig); + + JsonNode coreConfigNode = globalSettings.getNode("core_config"); + CoreConfig coreConfig = CoreConfig.parseJSON(coreConfigNode); + config.setCoreConfig(coreConfig); + + JsonNode peerClients = root.getNode("remote_repeats_clients"); + RepeatsPeerServiceClientManager repeatsPeerServiceClientManager = RepeatsPeerServiceClientManager.parseJSON(peerClients); + config.getBackEnd().getPeerServiceClientManager().updateClients(repeatsPeerServiceClientManager.getClients()); + + List ipcSettings = root.getArrayNode("ipc_settings"); + if (!IPCServiceManager.parseJSON(ipcSettings)) { + LOGGER.log(Level.WARNING, "IPC Service Manager failed to parse JSON metadata"); + } + + if (!config.getCompilerFactory().parseJSON(root.getNode("compilers"))) { + LOGGER.log(Level.WARNING, "Dynamic Compiler Manager failed to parse JSON metadata"); + } + + config.getBackEnd().clearTaskGroup(); + for (JsonNode taskGroupNode : root.getArrayNode("task_groups")) { + TaskGroup taskGroup = TaskGroup.parseJSON(config.getCompilerFactory(), taskGroupNode); + if (taskGroup != null) { + config.getBackEnd().addTaskGroup(taskGroup); + } + } + + if (config.getBackEnd().getTaskGroups().isEmpty()) { + config.getBackEnd().addTaskGroup(new TaskGroup("default")); + } + config.getBackEnd().setCurrentTaskGroup(config.getBackEnd().getTaskGroups().get(0)); + return true; + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Unable to parse json", e); + return false; + } + } + + @Override + protected boolean internalImportData(Config config, JsonRootNode root) { + boolean result = true; + + for (JsonNode taskGroupNode : root.getArrayNode("task_groups")) { + TaskGroup taskGroup = TaskGroup.parseJSON(config.getCompilerFactory(), taskGroupNode); + result &= taskGroup != null; + if (taskGroup != null) { + result &= config.getBackEnd().addPopulatedTaskGroup(taskGroup); + } + } + return result; + } + + @Override + protected boolean internalExtractData(CliConfig config, JsonRootNode root) { + try { + List ipcSettings = root.getArrayNode("ipc_settings"); + if (!IPCServiceManager.parseJSON(ipcSettings)) { + LOGGER.log(Level.WARNING, "IPC Service Manager failed to parse JSON metadata"); + } + + CliServer cliServer = (CliServer) IPCServiceManager.getIPCService(IPCServiceName.CLI_SERVER); + config.setServerPort(cliServer.getPort()); + return true; + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Unable to parse json", e); + return false; + } + } +} \ No newline at end of file diff --git a/src/core/userDefinedTask/TaskSourceManager.java b/src/core/userDefinedTask/TaskSourceManager.java index d20e71b..b317f29 100644 --- a/src/core/userDefinedTask/TaskSourceManager.java +++ b/src/core/userDefinedTask/TaskSourceManager.java @@ -32,10 +32,5 @@ public static boolean submitTask(UserDefinedAction task, String source) { return true; } - public static boolean removeTask(UserDefinedAction task) { - File sourceFile = new File(task.getSourcePath()); - return FileUtility.removeFile(sourceFile); - } - private TaskSourceManager() {} } diff --git a/src/core/userDefinedTask/UserDefinedAction.java b/src/core/userDefinedTask/UserDefinedAction.java index d2624a6..94536b0 100644 --- a/src/core/userDefinedTask/UserDefinedAction.java +++ b/src/core/userDefinedTask/UserDefinedAction.java @@ -248,7 +248,8 @@ public JsonRootNode jsonize() { JsonNodeFactories.field("name", JsonNodeFactories.string(name)), JsonNodeFactories.field("activation", activation.jsonize()), JsonNodeFactories.field("enabled", JsonNodeFactories.booleanNode(enabled)), - JsonNodeFactories.field("statistics", statistics.jsonize()) + JsonNodeFactories.field("statistics", statistics.jsonize()), + JsonNodeFactories.field("source_history", sourceHistory.jsonize()) ); } @@ -301,6 +302,13 @@ protected static UserDefinedAction parsePureJSON(DynamicCompilerManager factory, LOGGER.warning("Unable to retrieve statistics for task " + name); } + TaskSourceHistory sourceHistory = TaskSourceHistory.parseJSON(node.getNode("source_history")); + if (sourceHistory == null) { + LOGGER.warning("Unable to retrieve task source history for task " + name); + } else { + output.sourceHistory = sourceHistory; + } + boolean enabled = node.getBooleanValue("enabled"); output.actionId = actionId; diff --git a/src/core/userDefinedTask/internals/TaskSourceHistory.java b/src/core/userDefinedTask/internals/TaskSourceHistory.java index 2594e5b..6ceebb3 100644 --- a/src/core/userDefinedTask/internals/TaskSourceHistory.java +++ b/src/core/userDefinedTask/internals/TaskSourceHistory.java @@ -2,10 +2,20 @@ import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; import java.util.stream.Collectors; +import argo.jdom.JsonNode; +import argo.jdom.JsonNodeFactories; +import argo.jdom.JsonRootNode; +import utilities.json.IJsonable; + /** Contains information about the source history of a task. */ -public class TaskSourceHistory { +public class TaskSourceHistory implements IJsonable { + + private static final Logger LOGGER = Logger.getLogger(TaskSourceHistory.class.getName()); + + private static final int MAX_REVISION_COUNT = 10; private List entries; @@ -30,17 +40,56 @@ public TaskSourceHistoryEntry findEntry(long timestamp) { // Adds a single entry to the history. public void addEntry(TaskSourceHistoryEntry entry) { - this.entries.add(entry); + entries.add(entry); + entries.sort((e1, e2) -> e2.getCreated().compareTo(e1.getCreated())); + if (entries.size() > MAX_REVISION_COUNT) { + // Remove the last one, which is the oldest one. + entries.remove(entries.size() - 1); + } } /// Adds all history to this history. public void addHistory(TaskSourceHistory history) { entries.addAll(history.entries); entries.sort((e1, e2) -> e2.getCreated().compareTo(e1.getCreated())); + while (entries.size() > MAX_REVISION_COUNT) { + // Remove the last one, which is the oldest one. + entries.remove(entries.size() - 1); + } } // Returns the list of entries sorted in reverse chronological order. public List getEntries() { return entries.stream().sorted((e1, e2) -> e2.getCreated().compareTo(e1.getCreated())).collect(Collectors.toList()); } + + public static TaskSourceHistory parseJSON(JsonNode node) { + if (!node.isArrayNode("entries")) { + LOGGER.warning("Unable to retrieve task source history entries."); + return null; + } + + List entries = new ArrayList<>(); + for (JsonNode entry : node.getArrayNode("entries")) { + String path = entry.getStringValue("path"); + long createdTime = Long.parseLong(entry.getNumberValue("created_time")); + entries.add(TaskSourceHistoryEntry.of(path, createdTime)); + } + + TaskSourceHistory result = new TaskSourceHistory(); + result.entries = entries; + return result; + } + + @Override + public JsonRootNode jsonize() { + return JsonNodeFactories.object(JsonNodeFactories.field("entries", JsonNodeFactories.array( + entries.stream().map( + e -> JsonNodeFactories.object( + JsonNodeFactories.field("path", JsonNodeFactories.string(e.getSourcePath())), + JsonNodeFactories.field("created_time", JsonNodeFactories.number(e.getCreated().getTimeInMillis())) + ).getNode()) + .collect(Collectors.toList())) + )); + } } diff --git a/src/core/userDefinedTask/internals/TaskSourceHistoryEntry.java b/src/core/userDefinedTask/internals/TaskSourceHistoryEntry.java index e86b653..2fe0493 100644 --- a/src/core/userDefinedTask/internals/TaskSourceHistoryEntry.java +++ b/src/core/userDefinedTask/internals/TaskSourceHistoryEntry.java @@ -16,6 +16,13 @@ public static TaskSourceHistoryEntry of(String path) { return new TaskSourceHistoryEntry(path, Calendar.getInstance()); } + public static TaskSourceHistoryEntry of(String path, long time) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(time); + return new TaskSourceHistoryEntry(path, calendar); + } + + public String getSourcePath() { return sourcePath; } diff --git a/src/frontEnd/MainBackEndHolder.java b/src/frontEnd/MainBackEndHolder.java index 021e33c..cc03e95 100644 --- a/src/frontEnd/MainBackEndHolder.java +++ b/src/frontEnd/MainBackEndHolder.java @@ -609,9 +609,6 @@ public String reloadSourceCode() { private void unregisterTask(UserDefinedAction task) { keysManager.unregisterTask(task); - if (!TaskSourceManager.removeTask(task)) { - LOGGER.warning("Encountered error removing source file " + task.getSourcePath()); - } } public void addCurrentTask() { @@ -634,6 +631,7 @@ public void addTask(UserDefinedAction task, TaskGroup group) { group.getTasks().add(task); writeConfigFile(); + cleanUnusedSource(); } /** @@ -807,6 +805,7 @@ public void overwriteTask(String taskId) { } break; } + cleanUnusedSource(); } public void changeHotkeyTask(UserDefinedAction action, TaskActivation newActivation) { @@ -865,7 +864,12 @@ public String getSourceForTask(UserDefinedAction action, long timestamp) { return null; } - return FileUtility.readFromFile(entry.getSourcePath()).toString(); + StringBuffer content = FileUtility.readFromFile(entry.getSourcePath()); + if (content == null) { + LOGGER.warning("No source content for action " + action.getName() + " at file " + entry.getSourcePath() + "."); + return null; + } + return content.toString(); } /** @@ -951,12 +955,13 @@ public String apply(File file) { Set using = new HashSet<>(); for (TaskGroup group : taskGroups) { - using.addAll(new Function() { - @Override - public String apply(UserDefinedAction task) { - return new File(task.getSourcePath()).getAbsolutePath(); - } - }.map(group.getTasks())); + for (UserDefinedAction task : group.getTasks()) { + List sources = new ArrayList<>(); + String currentSource = new File(task.getSourcePath()).getAbsolutePath(); + sources.add(currentSource); + sources.addAll(task.getTaskSourceHistory().getEntries().stream().map(e -> new File(e.getSourcePath()).getAbsolutePath()).collect(Collectors.toList())); + using.addAll(sources); + } } allNames.removeAll(using);