Refactor expression commands for Jackson serialization

This commit is contained in:
Antonin Delpeuch 2018-10-01 17:27:29 +01:00
parent fd69e4b980
commit 553a73ec40
7 changed files with 238 additions and 103 deletions

View File

@ -37,19 +37,71 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.preference.TopList; import com.google.refine.preference.TopList;
public class GetExpressionHistoryCommand extends Command { public class GetExpressionHistoryCommand extends Command {
public static class ExpressionState implements Jsonizable {
@JsonProperty("code")
protected String code;
@JsonProperty("global")
protected boolean global = false;
@JsonProperty("starred")
protected boolean starred;
protected ExpressionState(String code, boolean starred) {
this.code = code;
this.starred = starred;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("code"); writer.value(code);
writer.key("global"); writer.value(false);
writer.key("starred"); writer.value(starred);
writer.endObject();
}
}
public static class ExpressionsList implements Jsonizable {
@JsonProperty("expressions")
List<ExpressionState> expressions;
protected ExpressionsList(List<ExpressionState> states) {
this.expressions = states;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("expressions");
writer.array();
for (ExpressionState e : expressions) {
e.write(writer, options);
}
writer.endArray();
writer.endObject();
}
}
static protected List<String> toExpressionList(Object o) { static protected List<String> toExpressionList(Object o) {
return o == null ? new ArrayList<String>() : ((TopList) o).getList(); return o == null ? new ArrayList<String>() : ((TopList) o).getList();
@ -60,40 +112,14 @@ public class GetExpressionHistoryCommand extends Command {
throws ServletException, IOException { throws ServletException, IOException {
try { try {
List<String> localExpressions = toExpressionList(ProjectManager.singleton.getPreferenceStore().get("scripting.expressions"));
localExpressions = localExpressions.size() > 20 ? localExpressions.subList(0, 20) : localExpressions;
List<String> globalExpressions = toExpressionList(ProjectManager.singleton.getPreferenceStore().get("scripting.expressions")); List<String> expressions = toExpressionList(ProjectManager.singleton.getPreferenceStore().get("scripting.expressions"));
Set<String> starredExpressions = new HashSet<String>(((TopList)ProjectManager.singleton.getPreferenceStore().get("scripting.starred-expressions")).getList()); Set<String> starredExpressions = new HashSet<String>(((TopList)ProjectManager.singleton.getPreferenceStore().get("scripting.starred-expressions")).getList());
ExpressionsList expressionsList = new ExpressionsList(expressions.stream()
Set<String> done = new HashSet<String>(); .map(s -> new ExpressionState(s, starredExpressions.contains(s)))
.collect(Collectors.toList()));
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json"); respondJSON(response, expressionsList);
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.key("starred"); writer.value(starredExpressions.contains(s));
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.key("starred"); writer.value(starredExpressions.contains(s));
writer.endObject();
}
}
writer.endArray();
writer.endObject();
} catch (Exception e) { } catch (Exception e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.refine.commands.expr; package com.google.refine.commands.expr;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
@ -41,8 +42,12 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.grel.Control; import com.google.refine.grel.Control;
import com.google.refine.grel.ControlFunctionRegistry; import com.google.refine.grel.ControlFunctionRegistry;
@ -50,23 +55,27 @@ import com.google.refine.grel.Function;
public class GetExpressionLanguageInfoCommand extends Command { public class GetExpressionLanguageInfoCommand extends Command {
@Override public static class LanguageInfo implements Jsonizable {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try { @JsonProperty("functions")
response.setCharacterEncoding("UTF-8"); Map<String, Function> functions;
response.setHeader("Content-Type", "application/json"); @JsonProperty("controls")
Map<String, Control> controls;
JSONWriter writer = new JSONWriter(response.getWriter());
Properties options = new Properties(); public LanguageInfo() {
functions = ControlFunctionRegistry.getFunctionMap();
controls = ControlFunctionRegistry.getControlMap();
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object(); writer.object();
writer.key("functions"); writer.key("functions");
writer.object(); writer.object();
{ {
for (Entry<String, Function> entry : ControlFunctionRegistry.getFunctionMapping()) { for (Entry<String, Function> entry : functions.entrySet()) {
writer.key(entry.getKey()); writer.key(entry.getKey());
entry.getValue().write(writer, options); entry.getValue().write(writer, options);
} }
@ -76,7 +85,7 @@ public class GetExpressionLanguageInfoCommand extends Command {
writer.key("controls"); writer.key("controls");
writer.object(); writer.object();
{ {
for (Entry<String, Control> entry : ControlFunctionRegistry.getControlMapping()) { for (Entry<String, Control> entry : controls.entrySet()) {
writer.key(entry.getKey()); writer.key(entry.getKey());
entry.getValue().write(writer, options); entry.getValue().write(writer, options);
} }
@ -84,6 +93,16 @@ public class GetExpressionLanguageInfoCommand extends Command {
writer.endObject(); writer.endObject();
writer.endObject(); writer.endObject();
}
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
respondJSON(response, new LanguageInfo());
} catch (Exception e) { } catch (Exception e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -2,13 +2,19 @@ package com.google.refine.commands.expr;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.preference.TopList; import com.google.refine.preference.TopList;
@ -16,27 +22,52 @@ import com.google.refine.preference.TopList;
public class GetStarredExpressionsCommand extends Command { public class GetStarredExpressionsCommand extends Command {
protected static class Expression implements Jsonizable {
@JsonProperty("code")
protected String code;
protected Expression(String c) {
code = c;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("code"); writer.value(code);
writer.endObject();
}
}
protected static class ExpressionList implements Jsonizable {
@JsonProperty("expressions")
protected List<Expression> expressions;
protected ExpressionList(List<Expression> e) {
expressions = e;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("expressions");
writer.array();
for (Expression s : expressions) {
s.write(writer, options);
}
writer.endArray();
writer.endObject();
}
}
public static ExpressionList getExpressionsList() {
List<String> starredExpressions = ((TopList)ProjectManager.singleton.getPreferenceStore().get("scripting.starred-expressions")).getList();
return new ExpressionList(starredExpressions.stream().map(e -> new Expression(e)).collect(Collectors.toList()));
}
@Override @Override
public void doGet(HttpServletRequest request, HttpServletResponse response) public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
try { try {
List<String> starredExpressions = ((TopList)ProjectManager.singleton.getPreferenceStore().get("scripting.starred-expressions")).getList(); respondJSON(response, getExpressionsList());
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 : starredExpressions) {
writer.object();
writer.key("code"); writer.value(s);
writer.endObject();
}
writer.endArray();
writer.endObject();
} catch (Exception e) { } catch (Exception e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -41,7 +41,6 @@ import javax.servlet.http.HttpServletResponse;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.model.Project;
import com.google.refine.preference.TopList; import com.google.refine.preference.TopList;
public class LogExpressionCommand extends Command { public class LogExpressionCommand extends Command {
@ -51,7 +50,6 @@ public class LogExpressionCommand extends Command {
throws ServletException, IOException { throws ServletException, IOException {
try { try {
Project project = getProject(request);
String expression = request.getParameter("expression"); String expression = request.getParameter("expression");
((TopList) ProjectManager.singleton.getPreferenceStore().get("scripting.expressions")) ((TopList) ProjectManager.singleton.getPreferenceStore().get("scripting.expressions"))

View File

@ -36,6 +36,7 @@ package com.google.refine.commands.expr;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
@ -48,6 +49,12 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.refine.Jsonizable;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.expr.EvalError; import com.google.refine.expr.EvalError;
import com.google.refine.expr.Evaluable; import com.google.refine.expr.Evaluable;
@ -64,6 +71,85 @@ import com.google.refine.util.ParsingUtilities;
public class PreviewExpressionCommand extends Command { public class PreviewExpressionCommand extends Command {
protected static interface ExpressionValue extends Jsonizable { }
protected static class ErrorMessage implements ExpressionValue {
@JsonProperty("message")
protected String message;
public ErrorMessage(String m) {
message = m;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("message"); writer.value(message);
writer.endObject();
}
}
protected static class SuccessfulEvaluation implements ExpressionValue {
@JsonValue
protected String value;
protected SuccessfulEvaluation(String value) {
this.value = value;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.value(value);
}
}
protected static class PreviewResult implements Jsonizable {
@JsonProperty("code")
protected String code;
@JsonProperty("message")
@JsonInclude(Include.NON_NULL)
protected String message;
@JsonProperty("type")
@JsonInclude(Include.NON_NULL)
protected String type;
@JsonProperty("results")
List<ExpressionValue> results;
public PreviewResult(String code, String message, String type) {
this.code = code;
this.message = message;
this.type = type;
this.results = null;
}
public PreviewResult(List<ExpressionValue> evaluated) {
this.code = "ok";
this.message = null;
this.type = null;
this.results = evaluated;
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("code"); writer.value(code);
if(message != null) {
writer.key("message"); writer.value(message);
}
if(type != null) {
writer.key("type"); writer.value(type);
}
if(results != null) {
writer.key("results");
writer.array();
for(ExpressionValue v : results) {
v.write(writer, options);
}
writer.endArray();
}
writer.endObject();
}
}
@Override @Override
public void doPost(HttpServletRequest request, HttpServletResponse response) public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
@ -77,7 +163,7 @@ public class PreviewExpressionCommand extends Command {
String expression = request.getParameter("expression"); String expression = request.getParameter("expression");
String rowIndicesString = request.getParameter("rowIndices"); String rowIndicesString = request.getParameter("rowIndices");
if (rowIndicesString == null) { if (rowIndicesString == null) {
respond(response, "{ \"code\" : \"error\", \"message\" : \"No row indices specified\" }"); respondJSON(response, new PreviewResult("error", "No row indices specified", null));
return; return;
} }
@ -91,21 +177,13 @@ public class PreviewExpressionCommand extends Command {
} }
} }
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
JSONArray rowIndices = ParsingUtilities.evaluateJsonStringToArray(rowIndicesString); JSONArray rowIndices = ParsingUtilities.evaluateJsonStringToArray(rowIndicesString);
int length = rowIndices.length(); int length = rowIndices.length();
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
try { try {
Evaluable eval = MetaParser.parse(expression); Evaluable eval = MetaParser.parse(expression);
writer.key("code"); writer.value("ok"); List<ExpressionValue> evaluated = new ArrayList<>();
writer.key("results"); writer.array();
Properties bindings = ExpressionUtils.createBindings(project); Properties bindings = ExpressionUtils.createBindings(project);
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Object result = null; Object result = null;
@ -140,31 +218,23 @@ public class PreviewExpressionCommand extends Command {
} }
if (result == null) { if (result == null) {
writer.value(null); evaluated.add(null);
} else if (ExpressionUtils.isError(result)) { } else if (ExpressionUtils.isError(result)) {
writer.object(); evaluated.add(new ErrorMessage(((EvalError) result).message));
writer.key("message"); writer.value(((EvalError) result).message);
writer.endObject();
} else { } else {
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
writeValue(sb, result, false); writeValue(sb, result, false);
writer.value(sb.toString()); evaluated.add(new SuccessfulEvaluation(sb.toString()));
} }
} }
writer.endArray(); respondJSON(response, new PreviewResult(evaluated));
} catch (ParsingException e) { } catch (ParsingException e) {
writer.key("code"); writer.value("error"); respondJSON(response, new PreviewResult("error", e.getMessage(), "parser"));
writer.key("type"); writer.value("parser");
writer.key("message"); writer.value(e.getMessage());
} catch (Exception e) { } catch (Exception e) {
writer.key("code"); writer.value("error"); respondJSON(response, new PreviewResult("error", e.getMessage(), "other"));
writer.key("type"); writer.value("other");
writer.key("message"); writer.value(e.getMessage());
} }
writer.endObject();
} catch (Exception e) { } catch (Exception e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -7,8 +7,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.json.JSONWriter;
import com.google.refine.ProjectManager; import com.google.refine.ProjectManager;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.preference.TopList; import com.google.refine.preference.TopList;
@ -30,21 +28,7 @@ public class ToggleStarredExpressionCommand extends Command {
if(request.getParameter("returnList") != null) { if(request.getParameter("returnList") != null) {
try { try {
response.setCharacterEncoding("UTF-8"); respondJSON(response, GetStarredExpressionsCommand.getExpressionsList());
response.setHeader("Content-Type", "application/json");
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
writer.key("expressions");
writer.array();
for (String s : starredExpressions) {
writer.object();
writer.key("code");
writer.value(s);
writer.endObject();
}
writer.endArray();
writer.endObject();
} catch (Exception e) { } catch (Exception e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -33,6 +33,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.refine.grel; package com.google.refine.grel;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@ -168,6 +169,9 @@ public class ControlFunctionRegistry {
static public Set<Entry<String, Function>> getFunctionMapping() { static public Set<Entry<String, Function>> getFunctionMapping() {
return s_nameToFunction.entrySet(); return s_nameToFunction.entrySet();
} }
static public Map<String,Function> getFunctionMap() {
return Collections.unmodifiableMap(s_nameToFunction);
}
static public Control getControl(String name) { static public Control getControl(String name) {
return s_nameToControl.get(name); return s_nameToControl.get(name);
@ -178,6 +182,9 @@ public class ControlFunctionRegistry {
static public Set<Entry<String, Control>> getControlMapping() { static public Set<Entry<String, Control>> getControlMapping() {
return s_nameToControl.entrySet(); return s_nameToControl.entrySet();
} }
static public Map<String,Control> getControlMap() {
return Collections.unmodifiableMap(s_nameToControl);
}
static public void registerFunction(String name, Function f) { static public void registerFunction(String name, Function f) {
s_nameToFunction.put(name, f); s_nameToFunction.put(name, f);