Implemented global and per-project expression histories and hooked them up to the expression preview dialog.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@176 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-03-03 21:21:38 +00:00
parent 91b10039ca
commit c1498448e4
18 changed files with 239 additions and 26 deletions

View File

@ -25,6 +25,7 @@ import com.metaweb.gridworks.commands.edit.UndoRedoCommand;
import com.metaweb.gridworks.commands.info.ComputeFacetsCommand;
import com.metaweb.gridworks.commands.info.ExportRowsCommand;
import com.metaweb.gridworks.commands.info.GetAllProjectMetadataCommand;
import com.metaweb.gridworks.commands.info.GetExpressionHistoryCommand;
import com.metaweb.gridworks.commands.info.GetHistoryCommand;
import com.metaweb.gridworks.commands.info.GetModelsCommand;
import com.metaweb.gridworks.commands.info.GetOperationsCommand;
@ -41,6 +42,7 @@ import com.metaweb.gridworks.commands.recon.ReconcileCommand;
import com.metaweb.gridworks.commands.util.CancelProcessesCommand;
import com.metaweb.gridworks.commands.util.GetExpressionLanguageInfoCommand;
import com.metaweb.gridworks.commands.util.GuessTypesOfColumnCommand;
import com.metaweb.gridworks.commands.util.LogExpressionCommand;
import com.metaweb.gridworks.commands.util.PreviewExpressionCommand;
import com.metaweb.gridworks.commands.util.PreviewProtographCommand;
@ -91,6 +93,9 @@ public class GridworksServlet extends HttpServlet {
_commands.put("preview-expression", new PreviewExpressionCommand());
_commands.put("get-expression-language-info", new GetExpressionLanguageInfoCommand());
_commands.put("get-expression-history", new GetExpressionHistoryCommand());
_commands.put("log-expression", new LogExpressionCommand());
_commands.put("preview-protograph", new PreviewProtographCommand());
_commands.put("guess-types-of-column", new GuessTypesOfColumnCommand());
}

View File

@ -8,6 +8,8 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.codeberry.jdatapath.DataPath;
@ -17,9 +19,11 @@ import com.metaweb.gridworks.model.Project;
public class ProjectManager implements Serializable {
private static final long serialVersionUID = -2967415873336723962L;
private static final int s_expressionHistoryMax = 100; // last n expressions used across all projects
protected File _dir;
protected Map<Long, ProjectMetadata> _projectsMetadata;
protected List<String> _expressions;
transient protected Map<Long, Project> _projects;
@ -111,6 +115,7 @@ public class ProjectManager implements Serializable {
_dir.mkdirs();
_projectsMetadata = new HashMap<Long, ProjectMetadata>();
_expressions = new LinkedList<String>();
internalInitialize();
}
@ -180,6 +185,18 @@ public class ProjectManager implements Serializable {
}
}
public void addLatestExpression(String s) {
_expressions.remove(s);
_expressions.add(0, s);
while (_expressions.size() > s_expressionHistoryMax) {
_expressions.remove(_expressions.size() - 1);
}
}
public List<String> getExpressions() {
return _expressions;
}
public void save() {
File file = new File(_dir, "projects");
@ -210,7 +227,11 @@ public class ProjectManager implements Serializable {
public void saveAllProjects() {
for (Project project : _projects.values()) {
saveProject(project);
try {
saveProject(project);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -3,6 +3,8 @@ package com.metaweb.gridworks;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import org.json.JSONException;
@ -10,13 +12,15 @@ import org.json.JSONWriter;
public class ProjectMetadata implements Serializable, Jsonizable {
private static final long serialVersionUID = 7959027046468240844L;
private static final int s_expressionHistoryMax = 20; // last n expressions used in this project
private final Date _created = new Date();
private String _name;
private String _password;
private String _encoding;
private int _encodingConfidence;
private Date _modified = new Date();
private String _encoding;
private int _encodingConfidence;
private Date _modified = new Date();
private List<String> _expressions = new LinkedList<String>();
public Date getCreated() {
return _created;
@ -65,6 +69,20 @@ public class ProjectMetadata implements Serializable, Jsonizable {
public void updateModified() {
_modified = new Date();
}
public void addLatestExpression(String s) {
_expressions.remove(s);
_expressions.add(0, s);
while (_expressions.size() > s_expressionHistoryMax) {
_expressions.remove(_expressions.size() - 1);
}
ProjectManager.singleton.addLatestExpression(s);
}
public List<String> getExpressions() {
return _expressions;
}
public void write(JSONWriter writer, Properties options)
throws JSONException {

View File

@ -21,7 +21,7 @@ abstract public class EngineDependentCommand extends Command {
try {
Project project = getProject(request);
AbstractOperation op = createOperation(request, getEngineConfig(request));
AbstractOperation op = createOperation(project, request, getEngineConfig(request));
Process process = op.createProcess(project, new Properties());
boolean done = project.processManager.queueProcess(process);
@ -34,5 +34,5 @@ abstract public class EngineDependentCommand extends Command {
}
abstract protected AbstractOperation createOperation(
HttpServletRequest request, JSONObject engineConfig) throws Exception;
Project project, HttpServletRequest request, JSONObject engineConfig) throws Exception;
}

View File

@ -6,12 +6,13 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.ColumnAdditionOperation;
public class AddColumnCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String baseColumnName = request.getParameter("baseColumnName");
String expression = request.getParameter("expression");

View File

@ -6,13 +6,14 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.RowStarOperation;
public class AnnotateRowsCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String starredString = request.getParameter("starred");
if (starredString != null) {

View File

@ -6,12 +6,13 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.TextTransformOperation;
public class DoTextTransformCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String expression = request.getParameter("expression");

View File

@ -6,13 +6,14 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.FacetBasedEditOperation;
import com.metaweb.gridworks.util.ParsingUtilities;
public class FacetBasedEditCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String expression = request.getParameter("expression");

View File

@ -0,0 +1,61 @@
package com.metaweb.gridworks.commands.info;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONWriter;
import com.metaweb.gridworks.ProjectManager;
import com.metaweb.gridworks.ProjectMetadata;
import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.model.Project;
public class GetExpressionHistoryCommand extends Command {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
ProjectMetadata pm = ProjectManager.singleton.getProjectMetadata(project.id);
List<String> localExpressions = pm.getExpressions();
List<String> globalExpressions = ProjectManager.singleton.getExpressions();
Set<String> done = new HashSet<String>();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
writer.key("expressions");
writer.array();
for (String s : localExpressions) {
writer.object();
writer.key("code"); writer.value(s);
writer.key("global"); writer.value(false);
writer.endObject();
done.add(s);
}
for (String s : globalExpressions) {
if (!done.contains(s)) {
writer.object();
writer.key("code"); writer.value(s);
writer.key("global"); writer.value(true);
writer.endObject();
}
}
writer.endArray();
writer.endObject();
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -6,12 +6,13 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.ReconDiscardJudgmentsOperation;
public class ReconDiscardJudgmentsCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");

View File

@ -6,6 +6,7 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.Recon;
import com.metaweb.gridworks.model.ReconCandidate;
import com.metaweb.gridworks.model.Recon.Judgment;
@ -15,7 +16,7 @@ public class ReconJudgeSimilarCellsCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(
HttpServletRequest request, JSONObject engineConfig) throws Exception {
Project project, HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String similarValue = request.getParameter("similarValue");

View File

@ -6,13 +6,14 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.ReconMarkNewTopicsOperation;
public class ReconMarkNewTopicsCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
return new ReconMarkNewTopicsOperation(
engineConfig,

View File

@ -6,13 +6,14 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.operations.ReconMatchBestCandidatesOperation;
public class ReconMatchBestCandidatesCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");

View File

@ -6,14 +6,15 @@ import org.json.JSONObject;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.ReconCandidate;
import com.metaweb.gridworks.operations.ReconMatchSpecificTopicOperation;
public class ReconMatchSpecificTopicCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
ReconCandidate match = new ReconCandidate(

View File

@ -7,14 +7,15 @@ import org.json.JSONTokener;
import com.metaweb.gridworks.commands.EngineDependentCommand;
import com.metaweb.gridworks.model.AbstractOperation;
import com.metaweb.gridworks.model.Project;
import com.metaweb.gridworks.model.recon.ReconConfig;
import com.metaweb.gridworks.operations.ReconOperation;
public class ReconcileCommand extends EngineDependentCommand {
@Override
protected AbstractOperation createOperation(HttpServletRequest request,
JSONObject engineConfig) throws Exception {
protected AbstractOperation createOperation(Project project,
HttpServletRequest request, JSONObject engineConfig) throws Exception {
String columnName = request.getParameter("columnName");
String configString = request.getParameter("config");

View File

@ -0,0 +1,31 @@
package com.metaweb.gridworks.commands.util;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.metaweb.gridworks.commands.Command;
import com.metaweb.gridworks.model.Project;
public class LogExpressionCommand extends Command {
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
Project project = getProject(request);
String expression = request.getParameter("expression");
project.getMetadata().addLatestExpression(expression);
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
response.getWriter().write("{ \"code\" : \"ok\" }");
} catch (Exception e) {
respondException(response, e);
}
}
}

View File

@ -8,6 +8,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.metaweb.gridworks.ProjectManager;
import com.metaweb.gridworks.ProjectMetadata;
import com.metaweb.gridworks.expr.ExpressionUtils;
import com.metaweb.gridworks.history.History;
import com.metaweb.gridworks.process.ProcessManager;
@ -32,6 +34,10 @@ public class Project implements Serializable {
internalInitialize();
}
public ProjectMetadata getMetadata() {
return ProjectManager.singleton.getProjectMetadata(id);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
internalInitialize();

View File

@ -14,7 +14,7 @@ function ExpressionPreviewDialog(title, cellIndex, rowIndices, values, expressio
$('<button></button>').html("&nbsp;&nbsp;OK&nbsp;&nbsp;").click(function() {
DialogSystem.dismissUntil(self._level - 1);
self._onDone(self._previewWidget.expression);
self._onDone(self._previewWidget.getExpression(true));
}).appendTo(footer);
$('<button></button>').text("Cancel").click(function() {
@ -103,9 +103,28 @@ ExpressionPreviewDialog.Widget = function(
.focus();
this._update();
this._renderExpressionHistoryTab();
this._renderHelpTab();
};
ExpressionPreviewDialog.Widget.prototype.getExpression = function(commit) {
var s = $.trim(this.expression || "");
if (s.length == 0) {
return null;
}
if (commit) {
$.post(
"/command/log-expression?" + $.param({ project: theProject.id, expression: s }),
null,
function(data) {
},
"json"
);
}
return s;
};
ExpressionPreviewDialog.Widget.prototype._renderHelpTab = function() {
var self = this;
$.getJSON(
@ -187,6 +206,48 @@ ExpressionPreviewDialog.Widget.prototype._renderHelp = function(data) {
renderEntries(controlTable, data.controls);
};
ExpressionPreviewDialog.Widget.prototype._renderExpressionHistoryTab = function() {
var self = this;
$.getJSON(
"/command/get-expression-history?" + $.param({ project: theProject.id }),
null,
function(data) {
self._renderExpressionHistory(data);
},
"json"
);
};
ExpressionPreviewDialog.Widget.prototype._renderExpressionHistory = function(data) {
var self = this;
var elmt = this._elmts.expressionPreviewHistoryContainer.empty();
var table = $(
'<table width="100%" cellspacing="5">' +
'<tr><th>Expression</th><th>From</th><th></th></tr>' +
'</table>'
).appendTo(elmt)[0];
var renderEntry = function(entry) {
var tr = table.insertRow(table.rows.length);
$(tr.insertCell(0)).text(entry.code);
$(tr.insertCell(1)).text(entry.global ? "Other projects" : "This project");
$('<a href="javascript:{}">Re-use</a>').appendTo(tr.insertCell(2)).click(function() {
self._elmts.expressionPreviewTextarea[0].value = entry.code;
self._elmts.expressionPreviewTextarea.select().focus();
self._update();
$("#expression-preview-tabs").tabs('option', 'selected', 0);
});
};
for (var i = 0; i < data.expressions.length; i++) {
var entry = data.expressions[i];
renderEntry(entry);
}
};
ExpressionPreviewDialog.Widget.prototype._scheduleUpdate = function() {
if (this._timerID != null) {
window.clearTimeout(this._timerID);