diff --git a/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java b/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java index 546b6cfe3..0a221b83f 100644 --- a/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java +++ b/src/main/java/com/metaweb/gridworks/commands/util/PreviewExpressionCommand.java @@ -73,14 +73,16 @@ public class PreviewExpressionCommand extends Command { } } - if (result != null) { - if (result instanceof EvalError) { - result = "[Error: " + ((EvalError) result).message + "]"; - } else if (result instanceof HasFields) { + if (ExpressionUtils.isError(result)) { + writer.object(); + writer.key("message"); writer.value(((EvalError) result).message); + writer.endObject(); + } else { + if (result != null && result instanceof HasFields) { result = "[object " + result.getClass().getSimpleName() + "]"; - } + } + writer.value(result); } - writer.value(result); } writer.endArray(); } catch (ParserException e) { diff --git a/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java b/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java index 545f40a77..a5822f312 100644 --- a/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java +++ b/src/main/java/com/metaweb/gridworks/expr/ControlFunctionRegistry.java @@ -8,6 +8,11 @@ import java.util.Map.Entry; import com.metaweb.gridworks.expr.controls.ForEach; import com.metaweb.gridworks.expr.controls.ForNonBlank; import com.metaweb.gridworks.expr.controls.If; +import com.metaweb.gridworks.expr.controls.IsBlank; +import com.metaweb.gridworks.expr.controls.IsNonBlank; +import com.metaweb.gridworks.expr.controls.IsNotNull; +import com.metaweb.gridworks.expr.controls.IsNull; +import com.metaweb.gridworks.expr.controls.IsNumeric; import com.metaweb.gridworks.expr.controls.With; import com.metaweb.gridworks.expr.functions.Get; import com.metaweb.gridworks.expr.functions.Length; @@ -56,11 +61,6 @@ import com.metaweb.gridworks.expr.functions.strings.Trim; import com.metaweb.gridworks.expr.functions.strings.Unescape; import com.metaweb.gridworks.expr.functions.strings.Unicode; import com.metaweb.gridworks.expr.functions.strings.UnicodeType; -import com.metaweb.gridworks.expr.functions.tests.IsBlank; -import com.metaweb.gridworks.expr.functions.tests.IsNotBlank; -import com.metaweb.gridworks.expr.functions.tests.IsNotNull; -import com.metaweb.gridworks.expr.functions.tests.IsNull; -import com.metaweb.gridworks.expr.functions.tests.IsNumeric; public class ControlFunctionRegistry { @@ -83,7 +83,7 @@ public class ControlFunctionRegistry { static public Control getControl(String name) { return s_nameToControl.get(name); } - static public String getControlName(Function f) { + static public String getControlName(Control f) { return s_controlToName.get(f); } static public Set> getControlMapping() { @@ -156,15 +156,16 @@ public class ControlFunctionRegistry { registerFunction("and", new And()); registerFunction("or", new Or()); registerFunction("not", new Not()); - registerFunction("isNull", new IsNull()); - registerFunction("isNotNull", new IsNotNull()); - registerFunction("isBlank", new IsBlank()); - registerFunction("isNotBlank", new IsNotBlank()); - registerFunction("isNumeric", new IsNumeric()); registerControl("if", new If()); registerControl("with", new With()); registerControl("forEach", new ForEach()); registerControl("forNonBlank", new ForNonBlank()); + + registerControl("isNull", new IsNull()); + registerControl("isNotNull", new IsNotNull()); + registerControl("isBlank", new IsBlank()); + registerControl("isNonBlank", new IsNonBlank()); + registerControl("isNumeric", new IsNumeric()); } } diff --git a/src/main/java/com/metaweb/gridworks/expr/EvalError.java b/src/main/java/com/metaweb/gridworks/expr/EvalError.java index ee855a9fc..4eceb26d3 100644 --- a/src/main/java/com/metaweb/gridworks/expr/EvalError.java +++ b/src/main/java/com/metaweb/gridworks/expr/EvalError.java @@ -1,5 +1,6 @@ package com.metaweb.gridworks.expr; +import java.io.Serializable; import java.util.Properties; import org.json.JSONException; @@ -7,7 +8,9 @@ import org.json.JSONWriter; import com.metaweb.gridworks.Jsonizable; -public class EvalError implements Jsonizable { +public class EvalError implements Serializable, Jsonizable { + private static final long serialVersionUID = -102681220092874080L; + final public String message; public EvalError(String message) { diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java b/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java index d4d37d247..328343b33 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/ForEach.java @@ -8,6 +8,7 @@ import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.EvalError; import com.metaweb.gridworks.expr.Evaluable; import com.metaweb.gridworks.expr.ExpressionUtils; @@ -16,9 +17,9 @@ import com.metaweb.gridworks.expr.VariableExpr; public class ForEach implements Control { public String checkArguments(Evaluable[] args) { if (args.length != 3) { - return "forEach expects 3 arguments"; + return ControlFunctionRegistry.getControlName(this) + " expects 3 arguments"; } else if (!(args[1] instanceof VariableExpr)) { - return "forEach expects second argument to be a variable name"; + return ControlFunctionRegistry.getControlName(this) + " expects second argument to be a variable name"; } return null; } diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java b/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java index 12d24a080..557bea0d9 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/ForNonBlank.java @@ -6,6 +6,7 @@ import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Evaluable; import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.VariableExpr; @@ -13,9 +14,9 @@ import com.metaweb.gridworks.expr.VariableExpr; public class ForNonBlank implements Control { public String checkArguments(Evaluable[] args) { if (args.length != 4) { - return "forNonBlank expects 4 arguments"; + return ControlFunctionRegistry.getControlName(this) + " expects 4 arguments"; } else if (!(args[1] instanceof VariableExpr)) { - return "forNonBlank expects second argument to be a variable name"; + return ControlFunctionRegistry.getControlName(this) + " expects second argument to be a variable name"; } return null; } diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/If.java b/src/main/java/com/metaweb/gridworks/expr/controls/If.java index 63b5732de..dcbfed226 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/If.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/If.java @@ -6,13 +6,14 @@ import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Evaluable; import com.metaweb.gridworks.expr.ExpressionUtils; public class If implements Control { public String checkArguments(Evaluable[] args) { if (args.length != 3) { - return "if expects 3 arguments"; + return ControlFunctionRegistry.getControlName(this) + " expects 3 arguments"; } return null; } diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsBlank.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsBlank.java new file mode 100644 index 000000000..00aba58ff --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsBlank.java @@ -0,0 +1,15 @@ +package com.metaweb.gridworks.expr.controls; + +import com.metaweb.gridworks.expr.ExpressionUtils; + +public class IsBlank extends IsTest { + @Override + protected String getDescription() { + return "Returns whether o is null or an empty string"; + } + + @Override + protected boolean test(Object o) { + return !ExpressionUtils.isNonBlankData(o); + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsNonBlank.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsNonBlank.java new file mode 100644 index 000000000..9c88c4688 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsNonBlank.java @@ -0,0 +1,15 @@ +package com.metaweb.gridworks.expr.controls; + +import com.metaweb.gridworks.expr.ExpressionUtils; + +public class IsNonBlank extends IsTest { + @Override + protected String getDescription() { + return "Returns whether o is not null and not an empty string"; + } + + @Override + protected boolean test(Object o) { + return ExpressionUtils.isNonBlankData(o); + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsNotNull.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsNotNull.java new file mode 100644 index 000000000..8c6c6de85 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsNotNull.java @@ -0,0 +1,13 @@ +package com.metaweb.gridworks.expr.controls; + +public class IsNotNull extends IsTest { + @Override + protected String getDescription() { + return "Returns whether o is not null"; + } + + @Override + protected boolean test(Object o) { + return o != null; + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsNull.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsNull.java new file mode 100644 index 000000000..9c9ae2222 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsNull.java @@ -0,0 +1,13 @@ +package com.metaweb.gridworks.expr.controls; + +public class IsNull extends IsTest { + @Override + protected String getDescription() { + return "Returns whether o is null"; + } + + @Override + protected boolean test(Object o) { + return o == null; + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsNumeric.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsNumeric.java new file mode 100644 index 000000000..6c3714c86 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsNumeric.java @@ -0,0 +1,19 @@ +package com.metaweb.gridworks.expr.controls; + +import org.apache.commons.lang.StringUtils; + +public class IsNumeric extends IsTest { + @Override + protected String getDescription() { + return "Returns whether o can represent a number"; + } + + @Override + protected boolean test(Object o) { + if (o instanceof Number) return true; + + String s = (o instanceof String) ? (String) o : o.toString(); + + return StringUtils.isNumeric(s); + } +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/IsTest.java b/src/main/java/com/metaweb/gridworks/expr/controls/IsTest.java new file mode 100644 index 000000000..ea95b41c6 --- /dev/null +++ b/src/main/java/com/metaweb/gridworks/expr/controls/IsTest.java @@ -0,0 +1,42 @@ +package com.metaweb.gridworks.expr.controls; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONWriter; + +import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; +import com.metaweb.gridworks.expr.Evaluable; + +abstract class IsTest implements Control { + public String checkArguments(Evaluable[] args) { + if (args.length != 1) { + return ControlFunctionRegistry.getControlName(this) + " expects one argument"; + } + return null; + } + + public Object call(Properties bindings, Evaluable[] args) { + Object o = args[0].evaluate(bindings); + + return test(o); + } + + public void write(JSONWriter writer, Properties options) + throws JSONException { + + writer.object(); + writer.key("description"); writer.value( + "Evaluates expression o. If it is true, evaluates expression eTrue and returns the result. " + + "Otherwise, evaluates expression eFalse and returns that result instead." + ); + writer.key("params"); writer.value("expression o"); + writer.key("returns"); writer.value("boolean"); + writer.endObject(); + } + + abstract protected boolean test(Object v); + + abstract protected String getDescription(); +} diff --git a/src/main/java/com/metaweb/gridworks/expr/controls/With.java b/src/main/java/com/metaweb/gridworks/expr/controls/With.java index f4288645a..10d87b204 100644 --- a/src/main/java/com/metaweb/gridworks/expr/controls/With.java +++ b/src/main/java/com/metaweb/gridworks/expr/controls/With.java @@ -1,31 +1,27 @@ package com.metaweb.gridworks.expr.controls; -import java.util.Properties; +import java.util.Properties; import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.expr.Control; +import com.metaweb.gridworks.expr.ControlFunctionRegistry; import com.metaweb.gridworks.expr.Evaluable; -import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.VariableExpr; public class With implements Control { public String checkArguments(Evaluable[] args) { if (args.length != 3) { - return "with expects 3 arguments"; + return ControlFunctionRegistry.getControlName(this) + " expects 3 arguments"; } else if (!(args[1] instanceof VariableExpr)) { - return "with expects second argument to be a variable name"; + return ControlFunctionRegistry.getControlName(this) + " expects second argument to be a variable name"; } return null; } public Object call(Properties bindings, Evaluable[] args) { Object o = args[0].evaluate(bindings); - if (ExpressionUtils.isError(o)) { - return o; - } - String name = ((VariableExpr) args[1]).getName(); Object oldValue = bindings.get(name); diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsBlank.java b/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsBlank.java deleted file mode 100644 index 47595b83d..000000000 --- a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsBlank.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.metaweb.gridworks.expr.functions.tests; - -import java.util.Properties; - -import org.json.JSONException; -import org.json.JSONWriter; - -import com.metaweb.gridworks.expr.ExpressionUtils; -import com.metaweb.gridworks.expr.Function; - -public class IsBlank implements Function { - - public Object call(Properties bindings, Object[] args) { - return args.length == 0 || !ExpressionUtils.isNonBlankData(args[0]); - } - - public void write(JSONWriter writer, Properties options) - throws JSONException { - - writer.object(); - writer.key("description"); writer.value("Returns whether o is null or an empty string"); - writer.key("params"); writer.value("o"); - writer.key("returns"); writer.value("boolean"); - writer.endObject(); - } -} diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotBlank.java b/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotBlank.java deleted file mode 100644 index da7c37480..000000000 --- a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotBlank.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.metaweb.gridworks.expr.functions.tests; - -import java.util.Properties; - -import org.json.JSONException; -import org.json.JSONWriter; - -import com.metaweb.gridworks.expr.ExpressionUtils; -import com.metaweb.gridworks.expr.Function; - -public class IsNotBlank implements Function { - - public Object call(Properties bindings, Object[] args) { - return args.length > 0 && ExpressionUtils.isNonBlankData(args[0]); - } - - public void write(JSONWriter writer, Properties options) - throws JSONException { - - writer.object(); - writer.key("description"); writer.value("Returns whether o is not null, not an error, and not an empty string"); - writer.key("params"); writer.value("o"); - writer.key("returns"); writer.value("boolean"); - writer.endObject(); - } -} diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotNull.java b/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotNull.java deleted file mode 100644 index 505427ee9..000000000 --- a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNotNull.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.metaweb.gridworks.expr.functions.tests; - -import java.util.Properties; - -import org.json.JSONException; -import org.json.JSONWriter; - -import com.metaweb.gridworks.expr.Function; - -public class IsNotNull implements Function { - - public Object call(Properties bindings, Object[] args) { - return args.length > 0 && args[0] != null; - } - - public void write(JSONWriter writer, Properties options) - throws JSONException { - - writer.object(); - writer.key("description"); writer.value("Returns whether o is not null"); - writer.key("params"); writer.value("o"); - writer.key("returns"); writer.value("boolean"); - writer.endObject(); - } -} diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNull.java b/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNull.java deleted file mode 100644 index bc211a481..000000000 --- a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNull.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.metaweb.gridworks.expr.functions.tests; - -import java.util.Properties; - -import org.json.JSONException; -import org.json.JSONWriter; - -import com.metaweb.gridworks.expr.Function; - -public class IsNull implements Function { - - public Object call(Properties bindings, Object[] args) { - return args.length == 0 || args[0] == null; - } - - public void write(JSONWriter writer, Properties options) - throws JSONException { - - writer.object(); - writer.key("description"); writer.value("Returns whether o is null"); - writer.key("params"); writer.value("o"); - writer.key("returns"); writer.value("boolean"); - writer.endObject(); - } -} diff --git a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNumeric.java b/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNumeric.java deleted file mode 100644 index 7561a76a0..000000000 --- a/src/main/java/com/metaweb/gridworks/expr/functions/tests/IsNumeric.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.metaweb.gridworks.expr.functions.tests; - -import java.util.Properties; - -import org.apache.commons.lang.StringUtils; -import org.json.JSONException; -import org.json.JSONWriter; - -import com.metaweb.gridworks.expr.ControlFunctionRegistry; -import com.metaweb.gridworks.expr.EvalError; -import com.metaweb.gridworks.expr.Function; - -public class IsNumeric implements Function { - - public Object call(Properties bindings, Object[] args) { - if (args.length == 1 && args[0] != null) { - Object o = args[0]; - if (o instanceof Number) return true; - String s = (o instanceof String) ? (String) o : o.toString(); - return StringUtils.isNumeric(s); - } - return new EvalError(ControlFunctionRegistry.getFunctionName(this) + " expects an argument"); - } - - public void write(JSONWriter writer, Properties options) - throws JSONException { - - writer.object(); - writer.key("description"); writer.value("Returns whether o can represent a number"); - writer.key("params"); writer.value("o"); - writer.key("returns"); writer.value("boolean"); - writer.endObject(); - } -} diff --git a/src/main/java/com/metaweb/gridworks/model/Cell.java b/src/main/java/com/metaweb/gridworks/model/Cell.java index 8a19acd59..8af556b32 100644 --- a/src/main/java/com/metaweb/gridworks/model/Cell.java +++ b/src/main/java/com/metaweb/gridworks/model/Cell.java @@ -7,6 +7,8 @@ import org.json.JSONException; import org.json.JSONWriter; import com.metaweb.gridworks.Jsonizable; +import com.metaweb.gridworks.expr.EvalError; +import com.metaweb.gridworks.expr.ExpressionUtils; import com.metaweb.gridworks.expr.HasFields; public class Cell implements Serializable, HasFields, Jsonizable { @@ -31,8 +33,13 @@ public class Cell implements Serializable, HasFields, Jsonizable { public void write(JSONWriter writer, Properties options) throws JSONException { writer.object(); - writer.key("v"); - writer.value(value); + if (ExpressionUtils.isError(value)) { + writer.key("e"); + writer.value(((EvalError) value).message); + } else { + writer.key("v"); + writer.value(value); + } if (recon != null) { writer.key("r"); diff --git a/src/main/webapp/scripts/dialogs/expression-preview-dialog.js b/src/main/webapp/scripts/dialogs/expression-preview-dialog.js index 82d573691..615ace65e 100644 --- a/src/main/webapp/scripts/dialogs/expression-preview-dialog.js +++ b/src/main/webapp/scripts/dialogs/expression-preview-dialog.js @@ -189,13 +189,15 @@ ExpressionPreviewDialog.prototype._renderPreview = function(expression, data) { if (v !== null && v !== undefined) { if ($.isArray(v)) { td.html(JSON.stringify(v)); + } else if ($.isPlainObject(v)) { + $('').addClass("expression-preview-special-value").text("Error: " + v.message).appendTo(td); } else if (typeof v === "string" && v.length == 0) { - $('empty string').addClass("expression-preview-empty").appendTo(td); + $('empty string').addClass("expression-preview-special-value").appendTo(td); } else { td.html(v.toString()); } } else { - $('null').addClass("expression-preview-empty").appendTo(td); + $('null').addClass("expression-preview-special-value").appendTo(td); } }; @@ -214,7 +216,7 @@ ExpressionPreviewDialog.prototype._renderPreview = function(expression, data) { // error var message = (data.type == "parser") ? data.message : "internal error"; - $('').text(message).addClass("expression-preview-empty").appendTo(tdValue); + $('').text(message).addClass("expression-preview-special-value").appendTo(tdValue); } } }; \ No newline at end of file diff --git a/src/main/webapp/scripts/views/data-table-cell-ui.js b/src/main/webapp/scripts/views/data-table-cell-ui.js index 8d1253834..04e303018 100644 --- a/src/main/webapp/scripts/views/data-table-cell-ui.js +++ b/src/main/webapp/scripts/views/data-table-cell-ui.js @@ -15,13 +15,11 @@ DataTableCellUI.prototype._render = function() { $(this._td).empty(); var divContent = $('
').appendTo(this._td); - if (cell == null || cell.v == null) { + if (cell == null || ("v" in cell && cell.v == null)) { $(divContent).html(" "); - // TODO: content editing UI - return; - } - - if (!("r" in cell) || cell.r == null) { + } else if ("e" in cell) { + $('').addClass("data-table-error").text(cell.e).appendTo(divContent); + } else if (!("r" in cell) || cell.r == null) { $(divContent).html(cell.v); } else { var r = cell.r; diff --git a/src/main/webapp/styles/data-table-view.css b/src/main/webapp/styles/data-table-view.css index 95f58d0f3..34708f533 100644 --- a/src/main/webapp/styles/data-table-view.css +++ b/src/main/webapp/styles/data-table-view.css @@ -60,6 +60,9 @@ img.column-header-menu { } +.data-table-error { + color: red; +} div.data-table-recon-candidates { margin: 0.5em 0; min-width: 15em; diff --git a/src/main/webapp/styles/expression-preview-dialog.css b/src/main/webapp/styles/expression-preview-dialog.css index 3a4e2faa7..3eabb699f 100644 --- a/src/main/webapp/styles/expression-preview-dialog.css +++ b/src/main/webapp/styles/expression-preview-dialog.css @@ -19,7 +19,7 @@ td.expression-preview-heading { font-weight: bold; } -.expression-preview-empty { +.expression-preview-special-value { color: #aaa; }