package edu.isi.karma.controller.history; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import org.json.JSONArray; import edu.isi.karma.controller.command.Command; import edu.isi.karma.controller.command.CommandFactory; import edu.isi.karma.controller.command.selection.SuperSelectionManager; import edu.isi.karma.controller.update.AlignmentSVGVisualizationUpdate; import edu.isi.karma.controller.update.UpdateContainer; import edu.isi.karma.controller.update.WorksheetDeleteUpdate; import edu.isi.karma.controller.update.WorksheetListUpdate; import edu.isi.karma.controller.update.WorksheetUpdateFactory; import edu.isi.karma.modeling.alignment.Alignment; import edu.isi.karma.modeling.alignment.AlignmentManager; import edu.isi.karma.rep.HNode; import edu.isi.karma.rep.HNode.HNodeType; import edu.isi.karma.rep.RepFactory; import edu.isi.karma.rep.Worksheet; import edu.isi.karma.rep.Workspace; import edu.isi.karma.webserver.ExecutionController; import edu.isi.karma.webserver.WorkspaceRegistry; public class CommandHistoryUtil { private final List<Command> commands = new ArrayList<>(); private Workspace workspace; private String worksheetId; Map<String, CommandFactory> commandFactoryMap; static Logger logger = Logger.getLogger(CommandHistoryUtil.class); public CommandHistoryUtil(List<Command> commands, Workspace workspace, String worksheetId) { this.worksheetId = worksheetId; this.workspace = workspace; ExecutionController ctrl = WorkspaceRegistry.getInstance().getExecutionController(workspace.getId()); commandFactoryMap = ctrl.getCommandFactoryMap(); this.commands.addAll(commands); } private Map<Command, List<Command> > generateGraph() { Map<Command, List<Command> > dag = new HashMap<>(); Map<String, List<Command> > outputMapping = new HashMap<>(); for (Command command : commands) { Set<String> inputs = command.getInputColumns(); for (String input : inputs) { List<Command> outputCommands = outputMapping.get(input); if (outputCommands != null) { List<Command> edges = dag.get(command); if (edges == null) edges = new ArrayList<>(); for (Command tmp : outputCommands) { if (tmp != command) edges.add(tmp); } dag.put(command, edges); } } Set<String> outputs = command.getOutputColumns(); for (String output : outputs) { List<Command> tmp = outputMapping.get(output); if (tmp == null) tmp = new ArrayList<>(); tmp.add(command); outputMapping.put(output, tmp); } } return dag; } public Set<String> generateInputColumns() { Map<Command, List<Command> > dag = generateGraph(); Set<String> inputColumns = new HashSet<>(); for (Command t : commands) { if (t.getCommandName().equals("SetSemanticTypeCommand") || t.getCommandName().equals("SetMetaPropertyCommand")) { inputColumns.addAll(getParents(t, dag)); } } return inputColumns; } public Set<String> generateOutputColumns() { Set<String> outputColumns = new HashSet<>(); for (Command t : commands) { if (t.getOutputColumns() != null) outputColumns.addAll(t.getOutputColumns()); } return outputColumns; } private Set<String> getParents(Command c, Map<Command, List<Command> >dag) { List<Command> parents = dag.get(c); Set<String> terminalColumns = new HashSet<>(); if (parents == null || parents.size() == 0) terminalColumns.addAll(c.getInputColumns()); else { for (Command t : parents) { terminalColumns.addAll(getParents(t, dag)); for (String hNodeId : c.getInputColumns()) { HNode hn = workspace.getFactory().getHNode(hNodeId); if (hn != null && hn.getHNodeType() == HNodeType.Regular) terminalColumns.add(hNodeId); } } } return terminalColumns; } public UpdateContainer replayHistory() { JSONArray redoCommandsArray = new JSONArray(); for (Command refined : commands) { redoCommandsArray.put(workspace.getCommandHistory().getCommandJSON(workspace, refined)); } return replayHistory(redoCommandsArray); } public UpdateContainer replayHistory(JSONArray redoCommandsArray) { UpdateContainer uc = new UpdateContainer(); Worksheet oldWorksheet = workspace.getFactory().getWorksheet(worksheetId); logger.info("***** Replay History for worksheet :" + worksheetId + " ****"); try { Worksheet newWorksheet = oldWorksheet.getImportMethod().duplicate().generateWorksheet(); Alignment alignment = AlignmentManager.Instance().createAlignment(workspace.getId(), newWorksheet.getId(), workspace.getOntologyManager()); workspace.removeWorksheet(worksheetId); uc.add(new WorksheetDeleteUpdate(worksheetId)); this.worksheetId = newWorksheet.getId(); uc.add(new WorksheetListUpdate()); uc.append(WorksheetUpdateFactory.createWorksheetHierarchicalAndCleaningResultsUpdates(worksheetId, SuperSelectionManager.DEFAULT_SELECTION, workspace.getContextId())); commands.clear(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); newWorksheet.getHeaders().prettyPrint("", pw, new RepFactory()); logger.debug("New worksheet headers:" + sw.toString()); //Use the WorksheetCommandHistoryExecutor. It takes care of creating missing columns, //saving history only at the end of teh batch, etc WorksheetCommandHistoryExecutor histExecutor = new WorksheetCommandHistoryExecutor( worksheetId, workspace); UpdateContainer hc = histExecutor.executeAllCommands(redoCommandsArray); uc.append(hc); if(alignment != null) { alignment.align(); uc.removeUpdateByClass(AlignmentSVGVisualizationUpdate.class); uc.add(new AlignmentSVGVisualizationUpdate(worksheetId)); } workspace.getCommandHistory().clearCurrentCommand(worksheetId); workspace.getCommandHistory().clearRedoCommand(worksheetId); } catch (Exception e) { commands.clear(); logger.error("Fail to replay history", e); } return uc; } public List<Command> getCommands() { return new ArrayList<>(commands); } public void removeCommands(Set<String> commandIds) { Iterator<Command> commandItr = commands.iterator(); while (commandItr.hasNext()) { Command command = commandItr.next(); if (commandIds.contains(command.getId())) { commandItr.remove(); } } } public void retainCommands(Set<String> commandIds) { Iterator<Command> commandItr = commands.iterator(); while (commandItr.hasNext()) { Command command = commandItr.next(); if (!commandIds.contains(command.getId())) { commandItr.remove(); } } } public String getWorksheetId() { return worksheetId; } public JSONArray getCommandsJSON() { JSONArray commandsArray = new JSONArray(); for (Command command : commands) { commandsArray.put(workspace.getCommandHistory().getCommandJSON(workspace, command)); } return commandsArray; } }