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.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable;
import com.google.refine.ProjectManager;
import com.google.refine.commands.Command;
import com.google.refine.preference.TopList;
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) {
return o == null ? new ArrayList<String>() : ((TopList) o).getList();
@ -60,40 +112,14 @@ public class GetExpressionHistoryCommand extends Command {
throws ServletException, IOException {
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> 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.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();
ExpressionsList expressionsList = new ExpressionsList(expressions.stream()
.map(s -> new ExpressionState(s, starredExpressions.contains(s)))
.collect(Collectors.toList()));
respondJSON(response, expressionsList);
} catch (Exception 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;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
@ -41,8 +42,12 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
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.grel.Control;
import com.google.refine.grel.ControlFunctionRegistry;
@ -50,23 +55,27 @@ import com.google.refine.grel.Function;
public class GetExpressionLanguageInfoCommand extends Command {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
public static class LanguageInfo implements Jsonizable {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
JSONWriter writer = new JSONWriter(response.getWriter());
Properties options = new Properties();
@JsonProperty("functions")
Map<String, Function> functions;
@JsonProperty("controls")
Map<String, Control> controls;
public LanguageInfo() {
functions = ControlFunctionRegistry.getFunctionMap();
controls = ControlFunctionRegistry.getControlMap();
}
@Override
public void write(JSONWriter writer, Properties options)
throws JSONException {
writer.object();
writer.key("functions");
writer.object();
{
for (Entry<String, Function> entry : ControlFunctionRegistry.getFunctionMapping()) {
for (Entry<String, Function> entry : functions.entrySet()) {
writer.key(entry.getKey());
entry.getValue().write(writer, options);
}
@ -76,7 +85,7 @@ public class GetExpressionLanguageInfoCommand extends Command {
writer.key("controls");
writer.object();
{
for (Entry<String, Control> entry : ControlFunctionRegistry.getControlMapping()) {
for (Entry<String, Control> entry : controls.entrySet()) {
writer.key(entry.getKey());
entry.getValue().write(writer, options);
}
@ -84,6 +93,16 @@ public class GetExpressionLanguageInfoCommand extends Command {
writer.endObject();
writer.endObject();
}
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
respondJSON(response, new LanguageInfo());
} catch (Exception e) {
respondException(response, e);
}

View File

@ -2,13 +2,19 @@ package com.google.refine.commands.expr;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONWriter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.Jsonizable;
import com.google.refine.ProjectManager;
import com.google.refine.commands.Command;
import com.google.refine.preference.TopList;
@ -16,27 +22,52 @@ import com.google.refine.preference.TopList;
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
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
List<String> starredExpressions = ((TopList)ProjectManager.singleton.getPreferenceStore().get("scripting.starred-expressions")).getList();
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();
respondJSON(response, getExpressionsList());
} catch (Exception e) {
respondException(response, e);
}

View File

@ -41,7 +41,6 @@ import javax.servlet.http.HttpServletResponse;
import com.google.refine.ProjectManager;
import com.google.refine.commands.Command;
import com.google.refine.model.Project;
import com.google.refine.preference.TopList;
public class LogExpressionCommand extends Command {
@ -51,7 +50,6 @@ public class LogExpressionCommand extends Command {
throws ServletException, IOException {
try {
Project project = getProject(request);
String expression = request.getParameter("expression");
((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.Serializable;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
@ -48,6 +49,12 @@ import org.json.JSONException;
import org.json.JSONObject;
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.expr.EvalError;
import com.google.refine.expr.Evaluable;
@ -64,6 +71,85 @@ import com.google.refine.util.ParsingUtilities;
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
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
@ -77,7 +163,7 @@ public class PreviewExpressionCommand extends Command {
String expression = request.getParameter("expression");
String rowIndicesString = request.getParameter("rowIndices");
if (rowIndicesString == null) {
respond(response, "{ \"code\" : \"error\", \"message\" : \"No row indices specified\" }");
respondJSON(response, new PreviewResult("error", "No row indices specified", null));
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);
int length = rowIndices.length();
JSONWriter writer = new JSONWriter(response.getWriter());
writer.object();
try {
Evaluable eval = MetaParser.parse(expression);
writer.key("code"); writer.value("ok");
writer.key("results"); writer.array();
List<ExpressionValue> evaluated = new ArrayList<>();
Properties bindings = ExpressionUtils.createBindings(project);
for (int i = 0; i < length; i++) {
Object result = null;
@ -140,31 +218,23 @@ public class PreviewExpressionCommand extends Command {
}
if (result == null) {
writer.value(null);
evaluated.add(null);
} else if (ExpressionUtils.isError(result)) {
writer.object();
writer.key("message"); writer.value(((EvalError) result).message);
writer.endObject();
evaluated.add(new ErrorMessage(((EvalError) result).message));
} else {
StringBuffer sb = new StringBuffer();
writeValue(sb, result, false);
writer.value(sb.toString());
evaluated.add(new SuccessfulEvaluation(sb.toString()));
}
}
writer.endArray();
respondJSON(response, new PreviewResult(evaluated));
} catch (ParsingException e) {
writer.key("code"); writer.value("error");
writer.key("type"); writer.value("parser");
writer.key("message"); writer.value(e.getMessage());
respondJSON(response, new PreviewResult("error", e.getMessage(), "parser"));
} catch (Exception e) {
writer.key("code"); writer.value("error");
writer.key("type"); writer.value("other");
writer.key("message"); writer.value(e.getMessage());
respondJSON(response, new PreviewResult("error", e.getMessage(), "other"));
}
writer.endObject();
} catch (Exception e) {
respondException(response, e);
}

View File

@ -7,8 +7,6 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONWriter;
import com.google.refine.ProjectManager;
import com.google.refine.commands.Command;
import com.google.refine.preference.TopList;
@ -30,21 +28,7 @@ public class ToggleStarredExpressionCommand extends Command {
if(request.getParameter("returnList") != null) {
try {
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();
respondJSON(response, GetStarredExpressionsCommand.getExpressionsList());
} catch (Exception 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;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
@ -168,6 +169,9 @@ public class ControlFunctionRegistry {
static public Set<Entry<String, Function>> getFunctionMapping() {
return s_nameToFunction.entrySet();
}
static public Map<String,Function> getFunctionMap() {
return Collections.unmodifiableMap(s_nameToFunction);
}
static public Control getControl(String name) {
return s_nameToControl.get(name);
@ -178,6 +182,9 @@ public class ControlFunctionRegistry {
static public Set<Entry<String, Control>> getControlMapping() {
return s_nameToControl.entrySet();
}
static public Map<String,Control> getControlMap() {
return Collections.unmodifiableMap(s_nameToControl);
}
static public void registerFunction(String name, Function f) {
s_nameToFunction.put(name, f);